루비로 배우는 객체지향 디자인 1장

2018-09-07

루비로 배우는 객체지향 디자인 1장


이 세상은 순차적이다. 일어날 사건의 순서를 알고 있기 때문에 사건 하나하나를 실행하는 코드를 짠 후 사건들을 내 마음대로 엮을 수 있는 절차적 프로그램을 작성할 수 있다.

이 세상은 객체지향적이기도 하다. 객체의 세계에서 객체들의 행동은 자연스럽게 뒤섞이기 때문에 예상치 못한 행동들의 조합이 나타날 수 있다.

절차적 프로그램은 예상치 못한 행동들의 조합을 프로그래밍하기 어렵다. 프로그래머가 모든 사건의 조합을 작성하기에는 힘들기 때문이다. 이를 해결하기 위해서 객체지향 디자인이 등장했다. 객체지향 디자인은 이미 정해진 절차들의 묶음으로 생각하지 않고, 객체가 서로 주고 받는 메시지들의 연쇄로 파악할 것을 요구한다. 이로인해 프로그래머는 객체들의 연관성만 작성하고나면 예전 처럼 모든 사건의 조합을 작성할 필요가 사라졌다.

객체지향 디자인 공부에 앞서서

객체지향 디자인의 실패는 코딩 능력 부족이 아닌 관점의 실패다. 객체지향 디자인을 배우기위한 첫걸음은 객체지향적 관점을 얻는 것이다. 객체지향적 관점을 얻고나면 나머지는 자연스럽게 해결된다.

디자인이 해결해 줄 수 있는 문제들

오늘 새로운 애플리케이션을 만든다고 상상해보자. 또, 이 애플리케이션을 작성하기 위한 모든 요구사항이 완벽하고 기획이 절대 바뀌지 않는다고 가정해보자. 이런 경우에 디자인은 중요하지 않다. 한 번 프로그램을 작성한 뒤 영원히 애플리케이션이 돌아가는 모습을 바라보면 된다. 하지만 프로그램은 반드시 변한다. 유행, 시대, 기술의 발전, 유저의 변덕 등 모든 외부 조건으로부터 프로그램 기획은 변하기 마련이다. 쉽게 변경할 수 있는 애플리케이션은 프로그래밍을 하는 과정도 즐겁고 확장하는 과정도 즐겁다. 하지만 그 반대의 경우 즐겁게 작업을 할 수 없다. 어쩌면 고통스러울 수 있다. 요구사항의 변경은 반드시 일어나기 때문에 디자인이 중요한 것이다.

디자인의 실용적 정의

여러 디자인 원칙은 서로 겹칠 수 있고 하나의 디자인 문제를 해결하는 방법에는 여러가지가 있을 수 있다. 그렇기 때문에 기능을 구현할 때 선택할 수 있는 디자인 종류가 어떤 것이 있는지 알아야 한다. 실용적 디자인은 애플리케이션에서 어떤 일이 벌어질 지 예측하는 것이 아니라 변화하고 움직일 수 있는 공간을 남겨 놓을뿐이다.

프로그램 수정이 어려운 이유

객체지향 애플리케이션은 상호작용하는 여러 부분으로 구성되어 있다. 여기서 여러 부분이 객체이고, 상호작용이 객체가 주고받는 메시지다. 여기서 송신하고 수신하는 객체가 두 객체 사이의 의존성을 만들어 내고, 이런 의존성이 애플리케이션을 수정하기 어렵게 만든다.

객체지향 디자인은 의존성을 관리하는 것이고, 의존성을 관리하는 기술이 객체지향 디자인이다. 디자인이 결여되어 있을 때, 관리되지 않은 의존성은 재앙을 불러온다.

예를 들어 객체가 서로에 대해서 너무 많이 알고 있을 때 하나의 객체를 수정할 경우 그 객체와 연결된 다른 객체까지 수정해야 한다. 이어서 다른 객체의 다른 객체까지 수정해야한다. 별거 없는 기능을 추가할 때에도 모든 코드를 수정해야할 수 있다.

디자인 원칙

디자인 원칙을 뜻하는 SOLID는 객체지향 디자인의 잘 알려진 디자인 원칙다섯 가지를 대변한다.

  1. 단일 책임(Single Responsibility)
  2. 개방-폐쇄(Open-Closed)
  3. 리스코프 치환(Liskov Substitution)
  4. 인터페이스 분리(Interface Segregation)
  5. 의존성 역전(Dependenc Inversion)

그 외에는 DRY데메테르의 원칙(Law of Demeter — LoD)등이 있다.

디자인 패턴

객체지향 디자인은 원칙뿐만 아니라 패턴을 가지고 있다. 1995년에 출판된 한국 출판명 은 패턴이란 객체지향 소프트웨어 디자인에서 명확한 문제를 처리하는 간단하고도 우아한 해결책이라고 말한다. 디자인 패턴은 **동일한 문제 같은 방식으로 해결할 수 있는 방법**에 이름을 부여한 것을 말한다. 디자인 패턴은 프로그래머들이 서로 소통하고 협업할 수 있는 도구를 제공해 주었다.

패턴이 유명해지면서 초보 프로그래머가 패턴을 오용하는 문제도 발생했다. 좋은 패턴을 잘못된 문제에 적용하면 복잡하고 혼란스러운 코드를 낳게 된다. 그렇기 때문에 올바른 패턴을 선택하고 제대로 사용할 수 있는 지식을 알아야 한다.

조심해야할 점

디자인 없는 애플리케이션은 점점 더 수정할 수 없는 애플리케이션이 된다. 그러나 지나친 디자인을 적용한 애플리케이션도 마찬가지로 점점 더 수정할 수 없는 애플리케이션이 될 수 있다. 이런 경우는 원칙을 적용할 수 없는 곳에 원칙을 적용하고 패턴이 없는 곳에서 패턴을 본다.

마지막으로 디자인은 반복적인 피드백과 함께하는 점진적인 발견의 과정이다. 그리고 디자인은 지속적인 자기조절 능력을 갖추고, 자연스럽게 발전하는 것이 가장 좋다. 때문에 반복과 점진적인 발전을 중시하는 애자일 소프트웨어 개발은 잘 디자인된 애플리케이션을 만드는 데 매우 적합하다.

언제 디자인을 해야하는가?

애자일은 고객이 직접 결과물을 보기 전까지는 자신이 원하는 소프트웨어가 무엇인지 말해주지 못한다고 생각한다. 소프트웨어를 작게 한 조각을 만들고 결과를 보여줄 때마다, 고객에게 다음에 무엇을 해야 할지 판단하고 생각을 수정할 수 있는 기회를 준다.

앞서 말한 애자일 소프트웨어 개발이 잘 디자인된 애플리케이션을 만드는 데 적합하다면 두 가지 주장 역시 사실이다. 첫째, 커다란 디자인을 먼저 구상하는 방식(BUFD)을 취할 이유가 하나도 없다. 둘째, 애플리케이션이 완성되는 시점을 누구도 예상할 수 없다.

커다란 디자인을 먼저 구상하는 방식은 프로그래머와 고객이 서로 대립하게 만든다. 앞서 구성해놓은 커다란 디자인이 고객이 원하는 바일 확률은 상당히 낮기 때문에(흔히 고객은 자신이 원하는 바를 잘 알지 못한다) 프로그램을 수정하게 되고 지켜야하는 일정이 있는 프로그래머는 수정사항들을 처리할 수 없다고 말한다. 결국 프로젝트 자체도 점점 파멸의 길에 들어선다. 마감일이 다가왔는데도 프로젝트가 끝나지 않는다면 수정사항이 너무 많아서 그랬더라도 책임은 프로그래머가 진다. 그렇기 때문에 애자일 개발을 통한 디자인 변경은 중간 중간 변하는 기획에 대해서 대처하기 위한 좋은 방법이다.

결국 좋은 애플리케이션을 위해서는 초기에 큰 디자인을 구상하지 않고 계속해서 디자인을 변경해주는 게 좋다.

디자인 평가하기

프로그래머를 평가하는 데 있어서 코드 줄 수는 중요하지 않다. 오히려 코드 줄 수를 가지고 프로그래머를 평가하는 방식은 애플리케이션의 품질을 저하시키는 지름길이다. 최근에는 코드 품질을 측정하는 새로운 측정법이 많이 등장했다. 이러한 측정 소프트웨어들은 소스 코드를 검사하여 몰랐던 문제나 개선할 수 있는 방법을 제공해준다. 잘 디자인된 애플리케이션처럼 보였을지라도 실제로는 객체지향 디자인의 원칙을 너무 많이 위반하고 있을 수 있다.

하지만 객체지향 디자인 점수가 높더라도 좋은 디자인을 구현하고 있다고 확신할 수는 없다. 다음번 수정이 쉽다고 보장해주지 않는다는 것이다. 과도한 디자인은 ‘객체지향 디자인 점수’를 높게 받을 수 있겠지만 미래의 수정사항을 잘못 예상했다면 수정사항은 배로 높아질 것이다.

결국 소프트웨어의 질을 측정하는 궁극적인 기준은 ‘주어진 시간 안에서의 기능별 구현 비용‘일 것이다. 만일 필요한 기능이 구현되어 있지 않아 당장 시장에서 퇴출될 상황이라면 유지보수 비용이 얼마나 증가할지는 중요하지 않다. 주어진 시간 이내에 최대한 빨리 구현하는 것이 중요하다. 이러한 방식으로 타협하는 것은 미래의 시간을 빌려오는 것과 같다. 이 빚은 언젠가 갚아야 한다. 그렇기 때문에 우리는 디자인의 손익분기점을 원하는 대로 조절하는 기술이 필요하다.

요약

  1. 객체지향적
  2. 디자인 원칙과 패턴
  3. 주어진 시간 안에서의 기능별 구현
  4. 성공적