본문 바로가기

기술 서적/객체지향의 사실과 오해

[객체지향의 사실과 오해] ch4. 역할, 책임, 협력

최후통첩 게임이라는 것이 있다. 연구팀은 사람들에게 일정 금액을 주고, 제안자는 금액 일부를 응답자와 나누어 가져야 한다. 제안자는 6:4, 7:3처럼 분배비율을 단 한번 제안할 수 있고 응답자는 제안을 수용하거나 거부할 수 있다. 수용하면 비율대로 금액을, 거부하면 둘다 상금을 받지 못한다.

 

인간이 합리적이라면 응답자는 단 1원이 떨어지는 분배비율에 대해서도 수용해야 한다.

반대로 제안자는 최대한 적은 비율을 응답자에게 제안할 것이다.

 

그러나, 실제 제안결과는 40%이상을 제안한 비율이  가장 높았다. 수용결과 또한 20%미만에 대해서는 제안을 거부했다. 

 

이 실험은 인간은 '합리적'이라는 본질을 가지고 있는 것이 아니라,

상황(context)이 인간의 행동을 결정한다는 사실을 보여준다.

 

그러나, 객체설계를 할때 우리는 인간이 합리적이다 라는 본질처럼, 객체가 가져야할 상태와 행동부터 고민할 때가 많다. 실제 객체를 결정하는 것은 협력이라는 문맥인데도 말이다. 객체의 모양을 빚는 것은 객체가 참여하는 협력이다.


협력

- 협력은 한 객체가 도움을 요청할 때 시작된다.

- 요청받는 사람은 지식이나 서비스 제공을 위해 응답한다.

- 즉, 협력은 다수의 연쇄적인 요청과 응답의 흐름으로 구성된다.

 

[앨리스의 재판 사례]
1) 누군가 -> 왕         : 재판 시작 요청
2) 왕 -> 하얀토끼     : 목격자 호출
3) 하얀토끼 -> 증인 : 증인 입장 요청
4) 왕   -> 모자장수   : 증언 요청 

 

여기서 각 주체가 요청을 받아들일 수 있는 요청 응답에 필요한 지식과 행동 방식을 지니기 때문이다.

 


책임

 

해당객체가 책임을 진다 == 요청에 응답을 할 수 있다 / 행동을 할 의무가 있다.

ex)

왕 : 재판수행하라 라는 요청에 응답 => 재판을 수행할 책임

토끼 : 목격자를 불러오라 => 목격자를 불러올 책임

모자장수 : 증인석에 입장 => 증언할 책임

 

객체 지향 개발에서 가장 중요한 능력은 책임을 능숙하게 소프트웨어 객체에 할당하는 것
-크레이그 라만(Craig Larman)-


책임을 어떻게 구현할 것인가 => 책임이 자리를 잡은 이후에 고려해도 늦지 않음

 

 

책임의 분류 : 하는 것 + 아는 것

하는 것 아는 것
- 스스로 하는 것(객체 생성, 계산)

- 다른 객체 행동을 시작시키는 것

- 다른 객체 활동을 제어하고 조절하는 것
- 개인적인 정보에 관해 아는 것

- 관련된 객체에 관해 아는 것

- 자시닝 유도하거나 계산할 수 있는 것에 관해 아는 것

 

즉, 책임은 객체의 외부에 제공해줄 수 있는 정보(아는 것)+ 외부에 제공해  줄 수 있는 서비스(하는 것)의 목록이다. 따라서 책임은 객체의 공용인터페이스를 구성한다.

 


책임과 메시지

- 메세지 전송 : 객체가 다른 객체에게 주어진 책임을 수행하도록 요청을 보내는 것

- 책임이 협력 속에서 요청을 수신하는 한쪽의 객체 관점에서 무엇을 하는 지 나열한 것이라면, 메시지는 협력에 참여하는 두 객체 사이의 관계를 강조한 것이다.

 

ex)

왕은 '증언하라'는 메시지를 전송할 수 있고 모자장수는 '증언하라'는 메시지를 수신할 수 있다.

 

그러나, 책임과 메시지의 수준은 같지 않다. 책임은 협력을 위한 객체의 행위를 상위수준에서 서술한 것이기에, 하나의 책임을 여러 메시지가 구성할 수 있다. 예를 들어 증인이라는 책임을 수행하기 위해서는 하얀토끼의 증인 입장 메시지를 수신할 수 있어야 하며 왕의 "증언하라"라는 메시지도 수신할 수 있어야 한다.

 

역할 : 책임의 집합이 의미하는 것

- 역할은 협력 내에서 다른 객체로 대체할 수 있음을 나타내는 일종의 표식이다.

- 역할이 대체가능한 이유는 메시지를 동일한 방식으로 이해하기 때문이다.

- 메시지를 동일한 방식으로 이해한다는 것은 동일한 책임을 수행할 수 있다는 것과 동치이다.

-역할은 객체지향 설계의 단순성 / 유연성 / 재사용성을 뒷받침한다.

 

- ex)

역할 객체
판사 왕, 왕비
증인 모자장수, 앨리스, 요리사
토끼 토끼

 

 

역할의 역할1. 협력의 추상화

- 역할은 협력을 추상화하여 단순화한다. 앨리스의 이야기에서 [왕-하얀토끼-모자장수]의 협력, [왕- 하얀토끼- 요리사]의 협력, ["여왕-하얀토끼- 앨리스"]의 협력은 ["판사-하얀토끼-증인"]의 협력으로 대체할 수 있다.

 

역할의 역할2. 대체가능성

- 역할을 대체하기 위해서는 행동이 호환디어야 한다.

- 그러나, 객체는 여러 역할을 내포할 수 있다.

- 객체의 타입과 역할 사이에는 일반화 특수화 관계가 성립된다. 역할(상위 개념) --- 객체 타입(하위 개념)


객체의 모양을 결정하는 협력

 

- 흔한 오류 : 협력이라는 문맥을 고려하지 않고 클래스 설계에만 집중한다.

객체지향의 핵심은 클래스를 어떻게 구현할 것인가가 아니라, 객체가 협력 안에서 어떤 책임과 역할을 수행할 것인지 결정하는 것이다. 

 

클래스 중심 설계는 협력이라는 문맥을 고려하지 않고 객체를 독립적으로 바라본 결과이다. 그러나, 재판 일화에서 왕이 중요한 이유는 왕관을 쓰고 근엄한 표정으로 앉아있기 때문이 아니라, 재판이라는 협력에 판사의 역할로 참여해서 죄를 판결하는 책임을 수행할 수 있기 때문이다.

 

-협력을 따라 흐르는 객체의 책임

: 협력을 먼저 떠올리고 => 이에 맞는 책임을 세분화한다 = > 그 책임을 수행하는데 필요한 객체들을 선택한다


객체지향 설계 기법

 

1) 책임 주도 설계(RDD)

: 협력에 필요한 책임을 식별하고 적합한 객체에게 책임을 할당하는 방식의 설계

 

2) 디자인 패턴

: 반복적으로 사용하는 해결방법 설계 템플릿, 전문가들이 문제 해결을 위해 이미 식별해 놓은 역할, 책임, 협력의 모음

 

3) 테스트 주도 개발(TDD)

: 테스트를 먼저 작성하고 통과하는 코드를 추가하면서 애플리케이션을 완성해나가는 방식으로 테스트 그 자체보다 역할, 책임, 협력 식별하고 적합한지 피드백 받는 것

 

1) 책임 주도 설계

- 객체의 책임을 중시믕로 시스템을 구축하는 것

- 시스템의 책임 > 객체의 책임 > 협력자를 찾아 책임을 할당하는 순차적 방식

1) 시스템 책임(사용자에게 제공할 기능)을 파악
2) 시스템 책임을 작은 책임으로 분할
3) 각 책임을 수행하는 적절한 객체/역할을 찾아 책임을 할당
4) 책임 수행 중, 도움이 필요한 경우 이를 책임질 적절한 객체/역할 탐색
5) 해당 객체 또는 역할에게 책임을 할당함으로써 두 객체가 협력하게 함

 

 

2) 디자인 패턴

- 책임 주도 설계의 결과

- 반복적으로 발생하는 문제와 문제에 대한 해법의 쌍으로 정의됨

 

3) 테스트 주도 개발

1) 실패하는 테스트를 작성
2) 테스트를 토과하는 가장 간단한 코드를 작성
3) 리팩터링을 통해 중복을 제거
=> 작동하는 가장 깔끔한 코드를 얻는 것

 

테스트 주도 개발은 테스트를 작성하는 것이 아니라 책임을 수행할 객체 또는 클라이언트가 기대하는 객체의 역할이 메시지를 수신할 때 어떤 결과를 반환하고 그 과정에서 어떤 객체와 협력할 것인지에 대한 기대를 코드의 형태로 작성하는 것이다.

 

테스트 주도 개발은 책임주도 설계의 기본 개념과 다양한 원칙과 프랙티스, 패턴을 종합적으로 이해하고 좋은 설계에 대한 감각과 경험을 길러야만 적용할 수 있는 설계기법이다. 역할, 책임, 협력에 집중하고 객체지향의 원칙을 적용하려는 깊이 있는 고민과 노력을 통해서만 테스트-주도 개발의 혜택을 누릴 수 있다.