응집도와 캡슐화 (Encapsulation)
객체 내부의 상태를 캡슐화하고 객체 간에는 오직 메시지를 통해서만 상호작용하도록 만드는 것을 캡슐화(Encapsulation)이라 한다.
자신 이외의 객체는 내부의 상태, 구현등을 알 수 없어야 한다.
어느 한 객체가 다른 객체의 내부를 속속들이 알 수 있을 때, 결함도가 높다 할 수 있다. 결합도가 높을 수록 변경이 발생할 때 그 범위가 커진다.
알고있는 것이 많을 수록 건드려야 할 부분이 많아진다.
반대로 객체가 적절히 캡슐화되어 자신이 해야할 일만 하게 되어 자율적인 객체가 될 수록 응집도가 높아지고, 결합도가 낮아진다 할 수 있다.
결합도가 낮을 수록, 응집도가 높을 수록 변경에 유연해진다. 유지 보수에 필요한 수고가 줄어들게 된다.
객체는 자신의 데이터를 스스로 처리하는 자율적인 존재여야한다.외부의 간섭을 ㅊ최대한 배체하고 메시지를 통해서만 협력하는 자율적인 객체들의 공동체를 만드는 것이 객체지향 설계이다.
절차지향과 객체지향
절차적 프로그래밍?
하나의 기능에 여러 다른 데이터를 알고, 사용하는 방식의 프로그래밍을 절차적이라 할 수 있다.
프로세스와 데이터를 각기 다른 모듈로 위치하고, 프로세스에서 데이터를 다루는 방식을 절차적 프로그래밍이라 할 수 있다.
이 경우, 어느 한 곳에서 변경이 발생하면, 해당 프로세스에 참여한 다른 구성원에도 변경이 필요할 수 있다. 즉, 변경에 유연하지 않다.
이 경우, 절차를 말로 서술해보면 직관에 맞지 않게 된다.
저자는 이에 소극장을 예로 들며 설명한다.
소극장은 관람객의 가방을 열어 그 안에 초대장이 들어있는지 살펴본다. 가방 안에 초대장이 들어 있으면 판매원은 매표소에 보관 돼있는 티켓을 관람객의 가방 안으로 옮긴다.
가방 안에 초대장이 들어있지 않다면 관람객의 가방에서 티켓 금액만큼의 현금을 꺼내 매표소에 적립한 후에 매표소에 보관돼 있는 티켓을 관람객의 가방 안으로 옮긴다.
절차지향 프로그래밍은 우리의 일반적인 관념과 일치하지 않는 모습을 보인다. 이는 데이터에 해당하는 구성원들은 모두 수동적인 존재로 취금되었기 때문이다.
프로세스가 모든 데이터에 접근해 변화를 일으키고, 모든 변화를 관리하기 때문에 직관과 다른 작업 흐름이 발생한 것이다.
또한 위 예로도 결합도가 아주 높다는 것을 알 수 있을 것이다. 소극장은 관람객, 가방, 티켓, 판매원 모두에게 의존하고있다.
객체지향 프로그래밍?
위의 절차적 프로그래밍의 단점을 해결하기 위해선, 각 구성원이 자신의 데이터를 스스로 처리하도록 프로세스의 적절한 단계를 각 구성원의 내부로 옮기는 것이다. 위 서술에서 첫 부분을 바꿔보면 아래와 같을 것이다.
소극장은 관람객의 가방을 열어 그 안에 초대장이 들어있는지 살펴본다. -> 판매원은 관람객에게 초대장이 있는지 확인을 요청한다. 관람객은 자신의 가방을 열어 초대장이 있는지 확인해 판매원에게 알려준다.
위 변화는 우리가 일반적으로 생각할 수 있는 구성원의 행동이다. 객체지향 프로그래밍을 생각할 때 이렇게 우리가 생각할 수있는 행동을 서술해보면 알기 쉽게 어디가 문제인지 알수 있다.
만약 관람객이 초대장을 확인하기위해 지갑을 확인해야 한다 가정하면 절차적 프로그래밍의 예에서는 관람객은 물론 소극장에도 변화가 필요하게 된다.
책임의 이동
절차적 프로그래밍과 객체지향 프로그래밍의 근본적인 차이를 만드는 것은 "책임의 이동" 이다. 여기서 책임은 기능이라 할수 있다.
위 절차적 프로그래밍의 예시는 소극장에게 책임이 집중되어있다. 반면 객체지향 프로그래밍의 예시 서술은 한소절 뿐이지만 이미 소극장은 보이지 않고, 같은 일을 위한 단계가 적절히 나눠져있음을 알수 있다.
객체 지향에서는 독재자는 존재하지 않는다. 구성원 모두에게 적절한 책임이 있고, 각 구성원은 각자의 책임을 벗어나는 행위를 하지 않는다.
설계가 왜 필요한가?
책에서는 설계를 다음과같이 인용하고있다
설계란 코드를 배치하는 것이다 [Metz12]
한창 학과 공부를 할때는 설계가 굉장히 귀찮고, 힘든 일이며 구현하는 것보다 더 어려운 것으로 여겼다.
그러나 실무를 해보며 느낀 바로는 전혀 그렇지 않았다. 설계와 구현은 함께 가야하는 것이며, 코드를 작성하는 매 순간이 설계이며 설계는 코드 없이는 검증할 수 없다.
좋은 설계란 무엇인가? 오늘 완성해야 하는 기능을 구현하는 코드를 작성하는 동시에 내일 쉽게 변경할 수 있는 코드를 작성할수있는 설계이다.
변경을 수용할수 없는 설계는 이후에 비싼 대가를 치루며 더 어려운 코드를 만들거나, 새로만들게 된다. 최소한의 수정으로 원하는 변경을 충족해야한다.
객체지향 설계
객체지향 설계는 우리가 세상을 보는 관념대로 코드를 작성할 수 있게 돕는다. 객체는 서로를 의존하며 메시지를 주고받으며 기능을 구성한다.
훌륭한 객체지향 설계는 객체 사이의 의존성을 적절하게 관리하는 설계이다. 객체간의 의존성은 프로그램의 변경을 어렵게하는 주범이다.