[객체지향의 사실과 오해] 4장

2020. 4. 21. 11:20책/객체지향의 사실과 오해

4장 역할,책임,협력

우리 모두를 합친 것보다 더 현명한 사람은 없다. - 켄 블랜차드

최후통첩게임

1982년 독일 훔볼트 대학의 베르너 귀스 교수는 흥미로운 경제학 게임 하나를 고안했다고 한다.

'인간은 항상 자신에게 최대의 이익이 돌아올 수 있도록 합리적인 의사결정을 내리는가?'라는 질문에 대한 답을 얻기 위한 이 실험의 이름은 '최후 통첩 게임'이다.

룰은 매우 간단하다. 이 게임에는 '제안자'와 '응답자'가 존재한다.

1. '제안자'는 연구팀으로부터 일정한 금액을 제시받는다.

'제안자'가 이 금액을 얻기 위해서는 '응답자'와 일정 비율로 나누어 가져야 하며, 그 비율은 '제안자'가 결정할 수 있다.

2. '응답자'는 '제안자'로부터의 제안을 승낙하거나 거부 할 수 있다.

승낙할 경우 '제안자'가 정한 비율로 돈을 나누어 갖게된다.

거부할 경우 '제안자'와 '응답자' 모두 돈을 갖지 못하게 된다.

 

인간이 항상 자신에게 이익이 돌아오도록 의사결정을 내린다는 명제하에 '제안자'는 어떠한 비율로 제안을 할 것이며, '응답자'는 승낙을 할 것인가 거부할 것인가를 생각해보았다.

당연히 '제안자'는 최대한 자신에게 많은 비율로 제안을 할 것이며, '응답자'는 자신에게 돌아오는 비율이 많든 적든 공짜이기 때문에 승낙을 할 것이라고 예측해 볼 수 있었다.

하지만, 위 실험에서 80%가 넘는 '제안자'가 30%가 넘는 비율을 '응답자'에게 제안했고,

반대로 30%가 안되는 비율을 제안받은 '응답자'는 공짜임에도 불구하고 제안을 거절 하였다. 금액이 크건 적건 말이다.

이 사실은 나에게 매우 흥미로웠다. 내가 당사자라면 '과연 그렇게 할까?' 라는 의문도 들었다.

이 책에서는 위와 같은 상황이 벌어진 이유가, 인간의 행동이 인간의 특성에 의해 이루어 지는 것이 아니라 타인과의 관계에 의해 이루어지기 때문이라고 하였다.

즉, 타인과의 협력의 문맥에 맞추어 인간이 행동한다는 것이다.

이것은 곧, 객체지향의 세계에도 적용이 될 수 있다.

협력이라는 문맥을 고려하지 않고 객체가 가져야할 상태와 행동만을 고민한다는 것은 의미가 없다는 것이다.

중요한 것은 개별 객체가 아니라 객체들 사이에 이뤄지는 협력이라고 할 수 있겠다.

 

협력

협력은 요청과 응답으로 이루어지는 시스템이다.

협력이 시작되기 위해서는 한 사람이 다른 사람에게 도움을 요청할 때 비로소 시작된다.

이상한 나라의 앨리스 일화를 통해 협력을 이해해 보자.

이 책에서는 하트 잭의 재판을 통한 일화를 통해, 협력에 대해 설명하고있다.

요약해 보자면, 하트 잭의 재판을 진행하기 위해  '왕'과 '토끼'와 '모자장수'가 협력관계를 이루고 있다.

- 왕은 토끼에게 증인을 재판장에 세우도록 요청한다.

- 토끼는 증인인 모자장수에게 재판장에 서도록 요청한다.

- 증인은 토끼의 요청에 대한 응답으로서 재판장에 선다. (이것은 왕이 토끼에게 요청한것에 대한 응답도 동시에 만족시킨다.)

- 왕은 증인에게 증언을 하도록 요청한다.

- 증인은 왕의 요청에 대한 응답으로서 증언을 한다.

이렇듯, 재판은 각 객체간의 요청과 응답을 통해 이루어지고 이 과정이 협력인 것이다.

요청에 대한 응답이 이루어 질 수 있는 이유는, 그 요청에 대해 적절한 방식으로 응답하는데 필요한 지식과 행동을 가지고 있기 때문이다. 이러한 요청과 응답은 객체가 수행할 책임을 정의한다.

 

책임

객체지향의 세계에서 어떤 객체가 어떤 요청에 대해 대답해 줄 수 있거나, 적절한 행동을 할 의무가 있는경우 책임을 가진다고 말한다. 다시 앨리스로 예를 들자면,

왕은 '재판을 수행하라'라는 요청에 응답해야 하므로 '재판을 수행할'책임을 가진다.

토끼는 '목격자를 불러오라'라는 요청에 응답해야 하므로 '목격자를 불러올'책임을 가진다.

모자장수는 '증인석에 입장'하고 '증언할'책임을 가진다.

결국 어떤 대상에 대한 요청은 그 대상이 요청을 처리할 책임이 있음을 암시해 주는 것이다.

이러한 책임은 두가지로 분류 해 볼 수 있는데 '무엇을 알고 있는가' 와 '무엇을 할 수 있는가' 이다.

'무엇을 하는가' 는 객체를 생성하거나 계산을 하는 등의 스스로 어떤 행동을 하는것을 포함해,

다른 객체의 행동을 시작시키거나 다른 객체의 활동을 제어하고 조절하는 것을 뜻한다.

'무엇을 아는가'는 개인적인 정보에 관해 아는 것을 포함하여

관련된 객체에 관해 아는것과 자신이 유도하거나 계산할 수 있는 것에 관해 아는 것을 뜻한다.

몇번이고 읽어봐도 이 부분은 정확한 예시가 없으면 이해하기 힘든 것 같다.

간략하게, 책임이란 요청에 대한 응답을 할 수 있는 객체라고 생각해 두고 넘어 가기로 하였다.

또 하나, 한 객체가 다른 객체에게 전송한 요청은 그 요청을 수신한 객체의 책임이 수행되게 한다는 사실도 알고 넘어가야 겠다.

 

역할

위에서 계속 예시를 들었던 재판과정에서 

왕 대신 여왕이 재판을 집행하고, 모자 장수 대신 요리사나 앨리스가 재판을 집행하게 된다면

그 대상만 바뀌었을 뿐 재판과정은 같은 시스템으로 돌아 갈 것이다. 

그렇다면 이러한 협력과정을 따로 분리해서 볼 것이냐 하나로 볼 것이냐인데, 당연히 하나로 보는 것이 바람직하겠다. 

그러기 위해서는 왕과 여왕이 같은 책임을 가지고 모자장수와 요리사와 앨리스가 같은 책임을 가져야 한다. 

같은 책임을 가진다는 것은 위에서 말한 것처럼 어떠한 요청에 대한 적절한 응답을 할 수 있다는 의미이다. 

같은 책임을 가지는 객체들에게 역할을 부여 함으로서 우리는 협력을 추상화 할 수 있다. 

판사-토끼-증인 으로 협력과정을 추상화 하는 것이다. 그렇다면 판사역할과 토끼역할, 증인역할에 어떤 객체가 오든 하나의 협력과정을 이루게 되어, 협력이 무한정 늘어나는 것을 막을 수 있다.

이러한 역할을 이용하면 객체지향 설계의 단순성,유연성,재사용성을 뒷받침 할 수 있을 것이다. 

 

객체지향 설계 기법

이 책에서는 역할,책입,협력의 관점에서 애플리케이션을 설계하는 유용한 세가지 기법을 소개하고 있다.

 

1. 책임-주도 설계

2. 디자인 패턴

3. 테스트-주도 개발

 

1. 책임-주도 설계

이 설계 방식은 먼저 애플리케이션의 기능을 구현하기 위한 협력 관계를 고안하고, 

협력에 필요한 역할과 책임을 식별한 후 이를  수행할 수 있는 적절한 객체를 식별해 나가는 설계 방식이다.

매우 어려운 설명이지만, 요약해 보자면

1) 시스템이 사용자에게 제공해아 하는 기능인 시스템 책임이 무엇인지를 파악한다.

2) 그리고 그 시스템 책임을 더 작은 책임으로 분할한다.

3) 분할된 책임을 수행할 수 있는 적절한 객체 또는 역할을 찾아서 책임을 할당한다.

4) 객체가 책임으르 수행하는 중에 다른 객체의 도움이 필요한 경우 이를 책임질 적절한 객체 또는 역할을 찾는다.

5) 해당 객체 또는 역할에게 책임을 할당함으로써 협력관계를 넓혀간다.

위의 과정이라고 할 수 있겠다.


2. 디자인 패턴

디자인 패턴은 책임-주도 설계가 잘 이루어진 결과를 표현한다.

패턴이란 모범이 되는 설계를 의미하며, 사람들은 무에서 시작하는 것보다 훌륭한 결과물을 모방하고 약간의 수정을 거쳐 원하는 결과물을 만들어 낼 때 더 좋은 결과물을 얻는다는 관점에서 사용 되는 것이다.

GOF의 '디자인 패턴'이라는 책이 있다고 하는데 언젠가 한번 읽어봐야 겠다는 생각이 들었다. 

 

3. 테스트-주도 개발

테스트 주도 개발은 요새 내가 연습하고 있는 부분이기도 하다.

테스트-주도 개발의 기본 흐름은 실패하는 테스트를 작성하고, 테스트를 통과하는 가장 간단한 코드를 작성한 후 

리팩토링을 통해 중복을 제거하는 방식이라고 정의 되어있다.

하지만 여전히 나는 개발을 주도하기 위해 어떤 테스트를 어떤식으로 작성해야 하는지를 결정하는데 큰 어려움을 겪는 중이다. 테스트-주도 개발은 객체가 이미 존재한다고 가정하고 객체에게 어떤 메시지를 전송할 것인지에 관해 먼저 생각하라는데, 그것을 코드로 옮기는 것은 역시 또 다른 문제인 것 같다. 

 

 

느낀점

설계를 시작하는 초반에 어떤 객체가 어떤 책임을 가지고 어떤 방식으로 서로 협력해야 하는지를 먼저 아는 것이 중요함을 느꼈다. 이 책을 읽고 난 후에도 나는 책임을 구현하는 방법에 대한 고민을 먼저 했던 것 같다. 

설계와 구현을 분리하는 습관은 나에게 반드시 필요한 것 같다. 

올바른 설계가 구현을 더 쉽게 해줄 것이다. 

협력에 참여하기 위해 어떤 객체가 어떤 책임을 수행해야 하고,

어떤 객체로부터 메시지를 수신할 것인지를 결정하는 연습을 먼저 하자.

또 하나 느낀 것은 테스트-주도 개발은 역시 어렵다는 것이다.

책에서도 이 개발 방법은 책임-주도 설계의 기본 개념과 다양한 원칙과 프랙티스, 패턴을 종합적으로 이해하고 좋은 설계에 대한 감각과 경험을 길러야만 적용할 수 있는 설계 기법이라고 설명하고 있다.

테스트-주도 개발이 책임-주도 설계를 기본으로 한다는 점에서 그 연습을 열심히 해봐야겠다.

테스트를 작성하는 것이 아니라 책임을 수행할 객체가 어떠한 결과를 반환하고 그 과정에서 어떤 객체와 협력할 것인지에 대한 기대값을 코드로 작성하는 것이 테스트-주도 개발임을 잊지 말아야겠다.