이 장에서는 이전 장에서 추상적으로 말하던 "협력", "책임", "역할"에 대해 보다 구체적으로 말한 장이라 생각합니다. 그렇기에 지금까지 보았던 챕터중 가장 핵심적이며 도움되는 장이라고도 생각합니다. 4장에서 가장 기억에 남는 내용은 ,책의 제목과는 무관하게도, TDD에 대한 내용이였습니다. 해당 내용은 챕터의 마지막 부분에 짧막하게 나오지만 객체지향 패러다임과 TDD를 엮어 이야기를 했다는 점이 특히 기억에 남습니다.
협력
요청하고 응답하며 협력하는 사람들
협력은 한 사람이 다른 사람에게 도움을 요청할 때 시작된다.
...
결과적으로 협력은 다수의 요청과 응답으로 구성되며 전체적으로 협력은 다수의 연쇄적인 요청과 응답의 흐름으로 구성된다.
제가 생각하는 협력의 핵심은 "다수", "요청과 응답"이라고 생각합니다. 또한 하나의 인물 혹은 객체에게 요청이 몰리는 것 역시 피할 수 있다면 피하도록 설계하는 것이 좋지 않을까 라는 생각을 듭니다. (하나의 인물 혹은 객체에게 너무 많은 책임이 부과되면 응집도가 떨어질 수 있다 생각하기 때문입니다.)
누가 파이를 훔쳤지?
결국 어떤 등장인물들이 특정한 요청을 받아들일 수 있는 이유는 그 요청에 대해 적절한 방식으로 응답하는 데 필요한 지식과 행동 방식을 가지고 있기 때문이다. 그리고 요청과 응답은 협력에 참여하는 객체가 수행할 책임을 정의한다.
이 문장에서의 핵심은 실제로 책임 혹은 역할을 수행하는 인물(객체)가 누구이든 그 행동을 수행하는데 적합해야 한다는 것입니다. 그렇기에 아무나 해당 역할을 맡을수는 없다는 것이 제가 생각하는 해당 문장의 중요한 내용이라 생각합니다.
책임
책임은 객체지향 설계의 가장 중요한 재료다.
...
객체의 책임은 "객체가 무엇을 알고 있는가(knowing)"과 무엇을 할 수 있는가(doing)"로 구성된다.
객체의 책임은 두 가지 측면에서 생각해볼 수 있다는 것이며 책임을 할당하고 이 책임이 올바른가? 라고 자문하였을때 위의 문장을 생각하면 답이 나오리라 생각이 듭니다. 실제로 제가 현재 진행하고 있는 프로젝트에서도 객체지향 설계를 준수하기 위해 책임을 생각해 설계를 하였으며 많은 도움이 되었습니다. 추가로 둘중 하나 이상의 책임을 지니고 있으면 된다고 책에서는 후술합니다.
책임은 객체지향 설계의 품질을 결정하는 가장 중요한 요소다. 객체지향 설계의 예술은 적절한 객체에게 적절한 책임을 할당하는 데 있다.
...
책임은 객체의 외부에 제공해 줄 수 있는 정보(아는 것의 측면)와 외부에 제공해 줄 수 있는 서비스(하는 것의 측면)의 목록이다. 따라서 책임은 객체의 공용 인터페이스(public interface)를 구성한다.
여기서 책임의 구체적인 설명이 나오며 실제 구현을 할 때 어떻게 해야할지를 참고 할 수 있는 대목이라 생각합니다.
책임과 메시지
객체가 다른 객체에게 주어진 책임을 수행하도록 요청을 보내는 것을 메시지 전송(message-send)이라고 한다. 따라서 두 객체 간의 협력은 메시지를 통해 이뤄진다. 메시지를 전송함으로써 협력을 요청하는 객체를 송신자라고 하고 메시지를 받아 요청을 처리하는 객체를 수신자라고 한다. 메시지는 협력을 위해 한 객체가 다른 객체로 접근할 수 있는 유일한 방법이다.
협력을 이루는 방법을 책에서는 "메시지 전송" 이라고 합니다. 그리고 이러한 메시지 전송은 공용 인터페이스를 통해 가능하다 생각합니다. 해당 책은 아니지만 동일한 저자가 쓴 책인 "오브젝트"에서는 메시지를 전송하고 이를 처리하는 구현 방법을 메소드라고 칭합니다. 즉 메시지는 일종의 추상적인 내용으로 간주할 수 있다 생각합니다.
책임을 결정한 후 실제로 협력을 정제하면서 이를 메시지로 변환할 때는 하나의 책임이 여러 메시지로 분할되는 것이 일반적이다.
저자는 '하나의 책임 != 하나의 메시지' 라는 말을 하고 싶었을 것이라 생각합니다. 실제로 프로젝트를 진행하며 설계를 할 때는 하나의 책임이였지만 실제로 구현을 하다보니 여러 메시지가 필요한 경우를 겪었습니다. 그리고 제가 겪은 경험을 요약하면 위의 인용한 문장이라 생각합니다.
객체지향 설계는 협력에 참여하기 위해 어떤 객체가 어떤 책임을 수행해야 하고 어떤 객체로부터 메시지를 수신할 것인지를 결정하는 것으로부터 시작된다. 어떤 클래스가 필요하고 어떤 메서드를 포함해야 하는지를 결정하는 것은 책임과 메시지에 대한 대략적인 윤곽를 잡은 후에 시작해도 늦지 않다.
책임 주도 설계를 할 때 구현에 신경쓰며 설계를 하지말라는 말과 동일하다 생각합니다. 그리고 위의 인용한 문장은 1장부터 쭉 반복했던 내용과 일맥상통한다 생각합니다.
역할
역할이 답이다.
역할은 협력 내에서 다른 객체로 대체할 수 있음을 나타내는 일종의 표식이다. 협력 안에서 역할은 "이 자리는 해당 역할을 수행할 수 있는 어떤 객체라도 대신할 수 있습니다."라고 말하는것과 같다.
이는 후술한 추상화와도 관련이 있습니다. 그리고 조금 더 구체적으로 Spring으로 예시를 들어 설명하면 @Autowired를 통해 객체를 주입받는 것 역시 역할을 이용했다고도 말할 수 있을듯 합니다.
따라서 역할을 대체할 수 있는 객체는 동일한 메시지를 이해할 수 있는 객체로 한정된다.
역할은 아무나 맡을 수 없으며 공용 인터페이스(public interface)를 구현한 객체로 한정된다 생각합니다.
역할은 객체지향 설계의 단순성(simplicity), 유연성(flexibility), 재사용성(reusablilty)을 뒷받침하는 핵심 개념이다.
역할이라는 개념을 도입하였기에 외부에서는 객체에 대한 구체적인 정보를 알 필요 없이 단순히 해당 객체가 수행하는 역할이 집중할 수 있게 되었고 어떤 객체에 관심 없이 수행할 수 있는 행동에 대해서만 초점을 두었기에 유연성을 지닐수 있었으며 객체를 여러번 교체할 수 있기에 재사용성을 지닐수 있었다 생각합니다.
협력의 추상화
역할의 가장 큰 가치는 하나의 협력안에 여러 종류의 객체가 참여할 수 있게 함으로써 협력을 추상화할 수 있다는 것이다.
바로 위에 작성한 내용과 이어집니다. 역할은 결국 누가(who)에 초점을 두는 것이 아니라 무엇(what)에 초점을 두기에 추상화가 가능하다는 생각을 합니다.
대체 가능성
객체지향의 용어를 빌려 설명하면 객체가 역할을 대체 가능하기 위해서는 협력 안에서 역할이 수행하는 모든 책임을 동일하게 수행할 수 있어야 한다.
위에서 한번 언급을 하였지만 한번 더 언급을 하면 역할에 아무 객체가 들어올 수 는 없습니다. 역할은 객체들 간 협력을 구성하고 있는 부품중 하나라고 생각을 하며 협력중 특정 역할에 맞지 않는 객체가 해당 역할을 수행할 수 없기 때문입니다.
객체는 역할이 암시하는 책임보다 더 많은 책임을 가질 수 있다. 따라서 대부분의 경우에 객체의 타입과 역할 사이에는 일반화/특수화 관계가 성립하는 것이 일반적이다. 일반화/특수화 관점에서 좀 더 일반적인 개념을 의미하는 역할은 일반화이며 좀 더 구체적인 개념을 의미하는 객체의 타입은 특수화다.
구체적인 예시로 풀어 쓰면 java의 interface와 이를 구현한 class 정도의 관계가 된다 생각합니다. 그리고 interface에는 협력에 필요한 public interface를 작성해놓기에 그외의 책임(메서드)는 class 내부에서 구현할 수 있습니다. 결국 class 내부에 존재하는 별도의 메소드들은 더 많은 책임을 의미합니다.
객체의 모양을 결정하는 협력
협력에 따라 흐르는 객체의 책임
올바른 객체를 설계하기 위해서는 먼저 견고하고 깔끔한 협력을 설계해야 한다.
...
결정된 요청과 응답의 흐름은 객체가 협력에 참여하기 위해 수행될 책임이 된다.
...
객체에게 책임을 할당하고 나면 책임은 객체가 외부에 제공하게 될 행동이 된다.
책에서 올바르게 설계를 하는 방법을 차근차근 제시하고 있다 생각합니다. 협력 -> 책임 -> 행동 순으로 설계가 진행됩니다. 그리고 이것은 책 전반에서 말하는 내용을 요약한 것이라 생각합니다.
결과적으로 클래스와 데이터는 협력과 책임의 집합이 결정된 후에야 무대 위에 등장할 수 있다.
아마도 책의 저자는 클래스와 데이터 같은 구현적인 측면은 설계가 완성되후에서야 생각을 하는게 맞다고 넌지시 알려주고 있다 생각합니다.
객체지향 설계 기법
책임-주도 설계(Responsiblity-Driven-Design) 방법은 협력에 필요한 책임들을 식별하고 적합한 객체에게 책임을 할당하는 방식으로 애플리케이션을 설계한다.
구현(클래스, 데이터 등등..)에 대한 고려없이 협력을 먼저 생각하는 책임 주도 설계 방법이 대한 정의를 말하고 있습니다. 그러나 이는 그동안 계속해서 이야기한 내용이라 생각합니다.
디자인 패턴(Design Pattern)은 전문가들이 반복적으로 사용하는 해결 방법을 정의해 놓은 설계 템플릿의 모음이다.
디자인 패턴은 우리가 알지 못할 뿐 이미 익숙하게 사용하고 있다 생각합니다. 우리가 이미 사용하고 있는 프레임워크들, 라이브러리들은 이미 디자인 패턴을 적용해 문제를 해결하고 있기 때문이며 언젠가는 디자인 패턴 역시 공부를 해야하는 대상중 하나라 생각합니다.
테스트-주도 개발(Test-Driven-Developmen)방법
TDD는 4장에서 가장 인상깊은 내용이였다고 생각합니다. 해당 대목을 읽기 이전에는 TDD가 구현을 하기 이전 테스트 코드를 먼저 작성하고 난 후 테스트를 만족하게끔 구현한다. 정도로만 알고 있었으나 저자는 여기서 더 나아가 테스트 코드를 책임이 올바르게 수행하고 있는 지에 대한 테스트라고 주장을 하였습니다. 그렇기에 객체지향에 대해 배운후 디자인 패턴과 더불어 TDD역시 공부를 해보고 싶다는 생각이 듭니다.
책임-주도 설계
현재 가장 널리 받아들여지는 객체지향 설계 방법은 레베카 워프스브록이 고안한 책임-주도 설계 방법이다.
...
시스템의 기능은 더 작은 규모의 책임으로 분할되고 각 책임은 책임을 수행할 적절한 객체에게 할당된다. 객체가 책임을 수행하는 도중에 스스로 처리할 수 없는 정보나 기능이 필요한 경우 적절한 객체를 찾아 필요한 작업을 요청한다.
책임 주도 설계의 핵심을 말하고 있으며 단어가 어려울 뿐이지 이미 계속해서 반복한 내용입니다.
디자인 패턴
디자인 패턴은 책임-주도 설계의 결과를 표현한다. 패턴은 모범이 되는 설계다.
해당 대목을 읽기 이전까진 디자인 패턴에 대해 단순히 '특정 문제를 해결하기 위한 방법들을 모아놓은 무언가' 정도로만 생각을 하였지만 읽은 후에는 책임-주도 설계의 결과물이기에 각 역할들은 무엇인지에 대해 고민을 해보는 계기가 되었습니다.
테스트-주도 개발
테스트-주도 개발은 객체가 이미 존재한다고 가정하고 객체에게 어떤 메시지를 전송할 것인지에 관해 먼저 생각하라고 충고한다. 그러나 이 같은 종류의 충고는 역할, 책임, 협력의 관점에서 객체를 바라보지 않을 경우 무의미하다.
위의 인용한 문장이 해당 장에서 가장 와닿았습니다. TDD는 단순히 유지 보수 하기 편하게 하는 방법중 하나가 아닌 설계가 올바르게 되었는지를 확인하는 방법중 하나라고 책에서는 주장을 합니다. 그리고 해당 문장뿐 아니라 책을 읽고 있는 저에게 있어 이는 새로운 방향에서 생각을 할 수 있는 계기가 되었습니다.
테스트-주도 개발은 책임-주도 설계를 통해 도달해야 하는 목적지를 테스트라는 안전장치를 통해 좀 더 빠르고 견고한 방법으로 도달할 수 있도록 해주는 최상의 설계 프랙티스다.
즉 TDD를 하는 것이 핵심이 아니라 RDD를 통해 올바른 설계를 할 수 있게끔 도와주는 방법중 하나가 TDD라는 말을 하고 있습니다.
'책 > 객체지향의 사실과 오해 (완)' 카테고리의 다른 글
06 객체지도 (0) | 2024.03.15 |
---|---|
05 책임과 메시지 (1) | 2024.01.23 |
03 타입과 추상화 (0) | 2024.01.10 |
02 이상한 나라의 객체 (0) | 2024.01.07 |
01 협력하는 객체들의 공동체 (1) | 2023.12.31 |