[Chap 04] 역할, 책임, 협력
[Chap 04] 역할, 책임, 협력
협력
우리 모두를 합친 것보다 현명한 사람은 없다.
협력은 한 사람이 다른 사람에게 도움을 요청할 때 시작된다. 오늘도 그렇듯 앨리스의 예시로 시작된다.
하트 여왕이 만든 파이를 훔쳐 달아나다 붙잡힌 하트 잭에 대한 공판이 열리는 법정에서 이야기가 시작된다.
판사인 왕이 재판을 시작했다.
“첫 번째 목격자를 불러라”
그러자 하얀 토끼는 트럼펫을 세 번 불고 큰 소리로 목격자를 불렀다. 첫 번째 목격자는 모자 장수였다.
“증언하라”
“저는 보잘것없는 사람입니다. 폐하”
여기서 왕과 하얀 토끼 모자 장수라고 불리는 객체들은 하트 잭을 재판하기 위해 서로 협력하고 있다. 즉, 재판이라는 동일한 목적을 달성하기 위해서 서로 협력하고 있는 것이다. 이를 다시 객체지향의 세계 기준으로 해석을 해보자면 다음과 같다.
- 왕 -> 하얀 토끼: 모자 장수를 증인석으로 입장할 것을 요청
- 하얀 토끼: 모자 장수를 증인석에 입장하게 함으로써 요청에 응답
- 왕 -> 모자 장수: 증언할 것을 요청
- 모자 장수: 자신이 알고 있는 내용을 증언함으로써 응답
위 글에서 특정 객체들이 요청과 응답을 하고 있는 것을 확인할 수 있다. 그렇다면 모든 객체들이 왕의 요청에 응답을 할 수 있을까?
그렇지 않다. 왜냐하면 어떤 등장인물들이 특정한 요청을 받아들일 수 있는 이유는 그 요청에 대한 적절한 방식으로 응답하는 데 필요한 지식과 행동 방식을 가지고 있기 때문이다. 그리고 요청과 응답은 협력에 참여하는 객체가 수행할 책임을 정의한다.
- 왕: 재판의 진행 방식을 알고, 진행을 할 수 있다.
- 하얀 토끼: 목격자가 누구인지 알고, 증인석에 입장시킨다.
- 모자 장수: 하얀 잭에 행동을 목격했고, 증인석에 입장한다.
책임
객체지향의 세계에서는 어떤 객체가 어떤 요청에 대해 대답해 줄 수 있거나, 적절한 행동을 할 의무가 있는 경우 해당 객체가 책임 을 가진다고 말한다.
- 왕: 재판을 수행하라는 요청에 응답 = 재판을 수행할 책임을 가짐
- 하얀 토끼: 목격자를 불러오라는 요청에 응답 = 목격자를 불러와야되는 책임을 가짐
- 모자 장수: 증언하라는 요처에 응답 = 증연해야되는 책임을 가짐
즉, 객체의 책임은 ‘객체가 무엇을 알고 있는가’ 와 ‘무엇을 할 수 있는가’ 로 구분된다.
책임은 객체지향 설계의 품질을 결정하는 가장 중요한 요소다.
객체의 외부에 제공해 줄 수 있는 정보(아는 것을 기준으로)와 외부에 제공해 줄 수 있는 서비스(하는 것을 기준으로)의 목록이다.
근데 이런 책임을 다른 객체에게 어떻게 전달할까?
=> 메시지의 형태로 전달한다.
즉, 객체가 다른 객체에게 주어진 책임을 수행하도록 요청하는 것을 보내는 것(수신자)을 메시지 전송 이라고 하고 메시지를 전송함으로써 협력을 요청하는 객체를 송신자 라고 한다.
위에서도 말했던 것처럼 모든 객체가 메시지에 대한 요청을 이해하고 응답을 할 수는 없다. 요청에 대해 이해를 하고 객체가 알고 있는 것과 할 수 있는 것을 기준으로 응답을 해야 되는 것이다.
왕과 모자 장수가 협력할 수 잇는 것은 왕이 모자 장수가 이해할 수 있는 메시지를 전송할 수 있고 모자 장수는 왕의 전송하는 메시지에 대해 적절한 책임을 수행할 수 있기 때문이다.
책임은 객체가 협력에 참여하기 위해 수행해야 하는 행위를 상위 수준에서 개략적으로 서술한 것이다. 책임을 결정한 후 실제로 협력을 정제하면서 이를 메시지로 변환할 때는 하나의 책임이 여러 메시지로 분할되는 것이 일반적이다.
여기서 하나의 책임이 여러 메시지로 분활되는 것이 무슨 의미인지 이해가 잘 되지 않았다. 하지만 다음 역할 챕터에서의 앨리스 얘기를 읽다보니 이래서 여러 메시지로 분할되는 것이 일반적인 것이라는 말이 나왔다는 것을 이해했다.
역할
1장에서 설명했던 것을 보면 “객체는 자신의 역할에 맞는 책임이 있다.” 라고 했었다. 1장의 예를 다시 들어보자면 캐시어라는 역할을 가진 사람은 “손님에게 주문을 받는 것(할 수 있는 것)”, “바리스타에게 주문 내용을 전달하는 것”, “커피가 완성되었으면 손님에게 알려 주는 것” 이런 3가지 책임이 있다.
즉, 역할은 책임의 집합 이라고 할 수 있다.
근데 여기서 캐시어라는 역할은 지금 일하고 있는 사람만이 할 수 있는 역할일까? 그렇지는 않다. 그 사람이 누구든 캐시어라는 사람이 될 수 있고, 결국, 캐시어는 같은 역할을 하게 될 것이다.
앨리스의 예시로 보자면, 왕은 현재 판사라는 역할을 수행하고 있다. 근데 왕은 판사이기 때문에 결국 판사로 불려도 된다. 당연한 사실이다. 하지만 이를 굳이 왕이라고 분류를 하고 증인을 모자 장수라고 분류를 하게 된다면 만약 다음에 다른 증인을 부르게 되면 다른 객체들이 필요할 것이다. 그렇게 된다면 역할의 재사용이 불가능하다.
역할의 재사용이 불가하다?
결국 판사는 증인에게 증언하라는 메시지를 전달해야되고, 증인은 이 메시지에 대한 응답을 해야 된다. 하지만 증인이 될 수 있는 객체들을 따로 분류해서 증인이라는 역할에 참여를 하게 하는 것이 아니라, 심플하게 판사-증인 관계로 협력에 참여하게 하는 것이 역할의 재사용이다.
따라서 역할을 수행할 수 있는 어떤 객체라도 대신할 수 있다. 이때 모든 객체가 대신할 수 있는 것이 아니라 역할이 수신할 수 있는 메시지를 동일한 방식으로 이해해하고 응답할 수 있는 객체가 역할을 대신할 수 있는 것이다.
협력의 추상화
역할의 가장 큰 가치는 하나의 협력 안에 여러 종류의 객체가 참여할 수 있게 함으로써 협력을 추상화할 수 있다는 것이다. 역할을 이용하면 협력을 추상화함으로써 단순화할 수 있다.
대체 가능성
증인이라는 역할이 모자 장수 외의 다른 객체들도 가능하다.
본질적으로 역할은 다른 객체에 의해 대체 가능함을 의미한다.
그리고 객체는 역할이 암시하는 책임보다 더 많은 책임을 가질 수 있다. 위에 예시로 들었던 캐시어가 바로 나라면 카페에서는 캐시어라는 역할을 가지고 책임을 다하겠지만, 알바가 끝난다면 나는 대학생이라는 역할을 가지고 공부라는 책임을 다하는 객체가 될 수 있다. 아니면 방학에 놀아야된다는 책임을 다하는 객체가 될 수 있다.
나라는 객체가 캐시어, 대학생 등 여러 역할을 맡을 수 있고 이에 맞게 여러 책임을 가질 수 있다.
좀 더 일반적인 개념을 의미하는 역할은 일반화이며 좀 더 구체적인 개념을 의미하는 객체의 타입은 특수화다. 역할이 협력을 추상적으로 만들 수 있는 이유는 역할 자체가 객체의 추상화이기 때문이다.
역할의 대체 가능성은 행위 호환성을 의미하고, 행위 호환성은 동일한 책임의 수행을 의미한다.
객체의 모양을 결정하는 협력
흔한 오류
- 객체는 시스템에 필요한 데이터를 저장하기 위해 존재한다. -> ❌
여러 번 말했지만 객체에게 중요한 것은 객체의 행동이고 이에 맞는 책임이다. - 객체지향의 클래스와 클래스 간의 관계를 표현하는 시스템의 정적인 측면에 중점을 둔다. -> ❌
객체는 협력이라는 공동의 목표를 두고 참여하는 동적인 객체이다. 실제로 동작하는 애플리케이션을 구축하기 위해서는 협력을 우선적으로 역할에 대한 책임을 결정하는 것이다.
협력에 따라 흐르는 객체의 책임
위의 오류들을 하지 않고 객체를 설계하기 위해서는 설계에 참여하는 객체들이 주고받을 요청과 응답의 흐름을 결정한다는 것을 의미한다.
객체에게 책임을 할당하고 나면 책임은 객체가 외부에게 제공하게 될 행동이 된다. 행동을 결정한 후에 그 행동을 수행하는 데 필요한 데이터를 고민해야된다. 그리고 나서 클래스의 구현 방법을 결정해야 하는 것이다.
앨리스의 이야기에서 누군가는 재판을 진행해야 하고 누군가는 증인을 증인석으로 불러야하며 누군가는 증언을 해야한다.
이렇게 먼저 책임을 고안하고 나면 그 책임을 수행하는 데 필요한 객체를 선택하게 된다.
왕이 재판을 진행하고, 하얀 토끼가 증인을 증인석으로 불러오고, 모자 장수가 증언을 하도록 책임을 할당했으면 객체들이 외부에 제공하게 될 행동을 정의하게 된다.
그 후 객체가 필요로 하는 데이터를 정의할 수 있다.
다시 정리를 해보자면 공통의 목표를 위해서 책임을 결정을 했다면 그 책임에 맞는 객체를 지정을 하고 책임에 맞는 행동을 결정한다. 그 다음 행동에 맞는 데이터를 정의하고 클래스를 개발하는 것이다.
객체지향 설계 기법
역할, 책임, 협력의 관점에서 애플리케이션을 설계하는 유용한 세 가지 기법
- 책임 - 주도 설계
- 디자인 패턴
- 테스트 - 주도 개발
책임 - 주도 설계
책임을 여러 종류의 객체가 수행할 수 있다면 협력자는 객체가 아니라 추상적인 역할로 대체된다.
이 과정에서 시스템의 책임을 객체의 책임으로 변환하고, 각 객체가 책임을 수행하는 중에 필요한 정보나 서비스를 제공해줄 협력자를 찾아 해당 협력자에게 책임을 할당하는 순차적인 방식으로 객체들의 협력 공동체를 구축한다.
디자인 패턴
디자인 패턴은 책임 - 주도 설계의 결과를 표현한다. 패턴은 모범이 되는 설계다.
테스트 - 주도 개발
테스트를 통과하는 가장 간단한 코드를 작성한 후, 리팩터링을 통해 중북을 제거하는 것이다.
정리
이번 챕터를 통해서 역할, 책임, 협력이라는 3가지 단어에 대해서 다시 한 번 생각해볼 수 있었다. 특히 역할의 재사용 이라는 말이 가장 기억에 남는다. 왜냐하면 증인이라는 역할은 메시지 응답이 가능한 객체 내에서 어떤 객체든 증인이라는 역할을 할 책임이 있고, 또 그 객체는 증인이라는 역할 외에도 다른 역할을 맡을 수 있다는 말이 확실히 이해가 되었기 때문이다.
그 외에도 이번 챕터에서는 객체지향 설계를 옳바르게 하는 방법에 대해서 나욌는데, 이 부분에 대해서는 솔직히 경험을 해본적은 없어서 완전 이해가 된 것 같지는 않다. 관련 내용은 같이 스터디하는 분들 중에서도 내용을 다루는 분이 계신 것 같아서 주의깊에 내용을 읽어보면 좋을 것 같다는 생각이 들었다.
댓글남기기