역할, 책임, 협력
- 객체지향 설계의 핵심 — 협력
- 책임의 분류
- 책임-주도 설계
- 디자인 패턴
- 테스트-주도 개발(TDD)
드디어 설계 방법론으로 들어가보자. 1~3장이 "객체지향이 뭔지"에 대한 개념 정리였다면, 이번엔 "그래서 어떻게 설계하는데?"에 대한 답을 주는 거야. 핵심 키워드는 역할, 책임, 협력 — 이 세 가지가 객체지향 설계의 기둥이지.
저자는 이 세 개념의 관계를 이렇게 정리해:
- **협력(collaboration)**이 문맥을 결정해
- 협력이 필요한 **책임(responsibility)**을 결정하고
- 책임을 수행할 **역할(role)**을 결정하지
순서가 중요해. 협력 -> 책임 -> 역할 -> 객체. 많은 개발자가 객체(클래스)부터 시작하는데, 그러면 설계가 삐뚤어져.
왜 협력이 먼저냐면, 객체는 혼자서는 아무 의미가 없기 때문이야. 객체의 존재 이유는 협력에 참여하는 것이고, 협력 안에서 어떤 책임을 맡느냐에 따라 객체의 행동이 결정되고, 행동이 결정되어야 상태가 결정되거든. 이 흐름을 거꾸로 가면 — 데이터를 먼저 정하고, 메서드를 붙이고, 어거지로 객체 간에 연결하면 — 절차지향적인 코드가 객체지향 옷을 입은 꼴이 되지.
책임은 크게 두 가지로 나뉘어.
하는 것(doing):
- 스스로 무언가를 계산하거나 처리하는 것
- 다른 객체의 행동을 시작시키는 것 (메시지를 보내는 것)
- 다른 객체의 활동을 제어하고 조율하는 것
아는 것(knowing):
- 자기 자신에 대한 정보를 아는 것 (사적인 정보)
- 관련된 객체에 대해 아는 것 (다른 객체의 참조)
- 자신이 유도하거나 계산할 수 있는 것을 아는 것
이 분류가 실전에서 왜 중요하냐면 — 책임을 적절하게 배분하는 게 설계의 핵심이기 때문이야. "하는 것"과 "아는 것"이 한 객체에 너무 많이 몰리면 그 객체는 **갓 오브젝트(God Object)**가 돼. 반대로 너무 잘게 쪼개면 협력이 복잡해지고 메시지가 난무하지.
좋은 설계는 책임이 고르게 분배된 설계야. 각 객체가 자기가 "아는 것"에 기반해서 "하는 것"을 수행하고, 자기가 모르는 건 아는 놈에게 물어보는(메시지를 보내는) 구조거든.
**책임-주도 설계(Responsibility-Driven Design, RDD)**는 이 장의 핵심 방법론이야. 이름 그대로 책임을 중심으로 설계하는 방법이지.
절차는 이래:
- 시스템이 사용자에게 제공해야 할 기능을 시스템의 책임으로 봐
- 시스템의 책임을 더 작은 책임으로 분할해
- 분할된 책임을 수행하기에 적절한 **객체(역할)**를 찾아서 할당해
- 객체가 책임을 수행하다가 다른 객체의 도움이 필요하면 메시지를 보내
- 메시지를 수신할 적절한 객체를 찾아서 책임을 할당해
- 이 과정을 반복하지
핵심은 3번과 5번에서 "적절한 객체를 찾는다"는 부분이야. 어떤 객체가 적절한가? 정보 전문가(Information Expert) 패턴에 따르면, 책임을 수행하는 데 필요한 정보를 가장 많이 알고 있는 객체가 적절하지. 주문 총액을 계산하는 책임은 주문 항목들의 정보를 알고 있는 주문 객체가 맡는 게 당연하잖아.
책임-주도 설계가 데이터-주도 설계와 다른 점: 데이터-주도 설계는 "이 객체가 어떤 데이터를 가질까?"로 시작하고, 책임-주도 설계는 "이 객체가 뭘 해야 할까?"로 시작해. 이 출발점의 차이가 최종 설계의 품질을 갈라놓거든.
저자는 디자인 패턴을 책임-주도 설계의 맥락에서 소개해.
디자인 패턴이란 뭐냐면, 특정 문맥에서 반복적으로 나타나는 설계 문제에 대한 검증된 해결 방법이야. 이걸 저자 나름의 언어로 번역하면 — 반복되는 협력 패턴에 대한 템플릿이지.
GoF의 디자인 패턴을 예로 들면:
- STRATEGY 패턴 — 알고리즘(행동)을 객체로 캡슐화해서, 동일한 문맥에서 다른 알고리즘으로 교체할 수 있게 하는 거야. 책임-주도 설계 관점에서 보면, "어떤 알고리즘으로 계산할 것인가"라는 책임을 별도의 객체에 할당하고, 그 역할을 대체 가능하게 만든 거지
- OBSERVER 패턴 — 상태 변화를 통보하는 책임과 통보를 받아서 처리하는 책임을 분리한 것
- COMPOSITE 패턴 — 개별 객체와 복합 객체를 동일한 역할로 추상화한 것
저자가 하고 싶은 말: 디자인 패턴을 "이런 상황에서 이렇게 코드를 짜라"는 레시피로 외우지 마. 패턴의 핵심은 역할, 책임, 협력의 관점에서 왜 이 구조가 좋은지를 이해하는 거야. 그래야 패턴을 응용할 수 있고, 새로운 상황에서 적절히 변형할 수 있지.
저자는 **TDD(Test-Driven Development)**도 책임-주도 설계와 연결짓거든.
TDD의 사이클: 실패하는 테스트 작성 -> 테스트를 통과하는 최소한의 코드 작성 -> 리팩토링.
이걸 책임-주도 설계 관점에서 보면:
- 테스트를 먼저 작성한다는 것은 객체에게 어떤 책임을 요구할 것인가를 먼저 결정한다는 뜻이야
- 테스트는 객체의 **인터페이스(외부에서 보이는 행동)**를 정의하지
- 구현은 그 다음이고
TDD가 좋은 설계를 유도하는 이유가 여기에 있어. 테스트를 먼저 쓰면 자연스럽게 "이 객체가 뭘 해야 하지?"를 먼저 생각하게 되고, 내부 구현은 나중에 결정하게 되거든. 이게 바로 책임-주도 설계가 말하는 "행동 먼저, 상태 나중에"와 같은 방향이야.
하지만 저자는 TDD의 한계도 짚어. TDD는 구현 레벨에서의 피드백 루프이지, 전체 시스템의 협력 구조를 설계해주지는 않거든. TDD로 개별 객체의 책임과 인터페이스를 다듬을 수는 있지만, 객체 간의 역할 분배와 협력 구조는 더 큰 그림에서 봐야 해. TDD는 책임-주도 설계의 보완재이지, 대체재가 아니야.
정리
4장 읽고 기억할 거 세 가지:
- 협력 -> 책임 -> 역할 -> 객체. 이 순서를 뒤집지 마. 클래스부터 시작하면 설계가 틀어져
- 책임을 적절하게 분배하는 것이 설계의 핵심이야. 하나의 객체에 몰리면 갓 오브젝트, 너무 쪼개면 협력 복잡도 폭발. 정보 전문가 패턴을 기준으로 삼아
- 디자인 패턴과 TDD는 책임-주도 설계의 실천 도구야. 패턴은 검증된 협력 템플릿, TDD는 책임을 먼저 결정하게 해주는 피드백 루프. 둘 다 역할/책임/협력의 관점에서 이해해야 제대로 활용할 수 있지