호댕의 iOS 개발

[독서 후기] 객체 지향의 사실과 오해 4장 본문

Book/개발

[독서 후기] 객체 지향의 사실과 오해 4장

호르댕댕댕 2022. 4. 18. 10:11

4장에서는 각 객체 간의 협력에 대해 중점으로 이야기를 한다. 

종종 공식문서를 보며 문맥(Context)이라는 단어를 접할 수 있었는데, 이 책에서는 객체의 행동 방식이 협력이라는 문맥(Context)에 의해 결정이 된다고 하고 있다. 

 

이전 장에선 객체의 행동이 상태보다 중요하다고 했다면 이번 장에서 가장 중요한 것은 객체 간 협력이라고 하고 있다.

 

즉, 객체를 설계할 때 중요한 것은 다음과 같다는 것이다. 

 

협력 > 행동 > 상태

 

🤝 협력

협력의 본질은 요청과 응답의 연쇄적인 흐름이다. 

만약 물건을 주문하고 택배로 받는 상황을 고려해보자. 

여기선 손님, 상점, 택배 3개의 객체로 구성이 되어 있다. 

 

  • 손님이 상점에게 물건을 주문하고 택배 요청
  • 상점은 이에 응답하여 택배에 상품 배송 요청
  • 택배는 이에 응답하여 손님에게 물건 전달

이렇게 3개의 객체 사이에도 요청과 응답이 연쇄적으로 발생허며 서로 협력하고 있는 것이다. 

 

이렇게 요청을 받게되면 필연적으로 따라오게 되는 것이 있다. 

 

🙌 책임

객체 지향의 세계에서는 어떤 객체가 어떤 요청에 대해 대답해줄 수 있거나, 적절한 행동을 할 의무가 있는 경우 해당 객체가 책임을 가진다고 말한다. 
- 객체 지향의 사실과 오해, P114 -

특정 대상에 대한 요청은 그 대상이 처리해야 할 책임이 있다는 것을 의미하는 것이다. 

따라서 책임을 적절한 객체에 할당하는 것은 중요하며 실제로 Craig Larman도 "객체 지향 개발에서 가장 중요한 능력은 책임을 능숙하게 소프트웨어 객체에 할당하는 것"이라고 했다. 

 

여기서 책임은 2가지로 구성된다. 

  • 객체가 무엇을 알고 있는가 - ex) 관련된 객체, 자신이 계산할 수 있는 프로퍼티 등
  • 객체가 무엇을 할 수 있는가 - ex) 다른 객체의 행동을 요청하는 것, 메서드 등

 

책임을 한 마디로 정리해보자면, 객체의 외부에 공개할 수 있는 정보와 행동이라고 볼 수 있다. 이는 공용 인터페이스를 구성하게 되며 책임을 적절하게 할당하며 캡슐화가 발생한다. 

 

객체 간에는 협력을 하며 이런 책임을 수행하도록 객체가 다른 객체에게 메세지를 전송한다. 

메세지는 협력을 위해 다른 객체에 접근할 수 있는 유일한 방법이다. 

 

다만 객체의 책임은 협력에 응하기 위해 수행해야 할 행위들을 모아놓은 것이기 때문에, 하나의 책임에 여러 메세지로 분할되는 것이 일반적이다. 

 

🧑🏻‍💻 역할

이런 책임들이 모이게 되면 객체의 역할이 만들어진다. 역할이 만들어지게 되면 이를 통해 생성된 객체들은 모두 해당 역할을 수행할 수 있기 때문에, 역할은 재사용 가능한 유연한 코드를 만드는데 중요한 역할을 한다. 

 

위 예시를 다시 살펴보면 손님도 주문만 할 수 있다면 어떤 객체가 와도 된다. 상점도 택배 배송을 요청할 수 있다면 어떤 상점이어도 상관없고, 택배도 대한통운이든, 한진택배든, 우체국 택배든 전혀 상관이 없다. 

 

위 예시는 이미 세 객체 간 협력을 하나의 협력으로 추상화해놓은 것이라 볼 수 있는 것이다. 

 

역할을 통해 설계가 단순화, 유연성, 재사용성의 특징을 갖게 된 것이다.

 

🗺 올바른 객체지향 설계

객체 지향 설계를 할 때 흔히 가지는 오류는 클래스나 구조체 등의 관계를 표현하는 정적인 관계에 중점을 둔다는 것이다.

하지만 중요한 것은 동적으로 협력하는 객체이다. 클래스나 구조체는 객체를 생성하기 위한 구현 매커니즘에 지나지 않는다. 

 

올바른 객체를 설계하기 위해선 먼저 협력을 설계해야 한다. 협력을 설계하면 객체들이 어떤 요청과 응답을 주고 받을 지 흐름을 결정할 수 있게 되고 이런 흐름을 통해 객체들의 책임이 결정된다. 책임, 즉 행동이 결정이 된다면 이 행동에 필요한 데이터가 결정되게 된다. 

 

1️⃣  책임 주도 설계

이는 협력에 필요한 책임들을 식별하고 적합한 객체에 책임을 할당하는 방식으로 설계를 한다. 

  1. 전체적인 시스템의 책임 파악
  2. 전체적인 책임을 더 작은 책임으로 분할
  3. 분할된 책임을 수행할 수 있는 객체 또는 역할을 찾아 적합한 객체에 할당
  4. 객체가 책임을 수행하며 다른 객체가 필요하다면 이를 책임질 적합한 객체 또는 역할을 찾는다. 
  5. 찾은 객체 또는 역할에게 책임을 할당하여 두 객체 간 협력이 발생하도록 한다.

여기서 객체 지향 언어를 쓰거나 UML을 통해 설계를 한다고 해서 좋은 객체 지향 설계가 보장되는 것은 아니다. 전체적인 개발 단계에 걸쳐 객체의 역할과 책임, 협력을 분명이 하는 것이 가장 중요한 부분이다.

 

2️⃣ 디자인 패턴

패턴의 경우 특정한 상황에서 설계를 돕기 위해 있는 과거의 경험이다. 

즉, 검증된 선배들의 삽질 기록이라 볼 수 있다. 

 

공통으로 사용할 수 있는 역할, 책임, 협력의 템플릿인 만큼 책임 주도 설계의 전과정을 따르지 않더라도 빠르고 쉽게 객체 지향 설계를 할 수 있게 된다. 

 

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

테스트 주도 개발을 하기 위해선 객체의 특정 메서드를 호출하고 반환 값이 적합한지 검증을 해야 하는 만큼 객체의 책임에 대해 명확히 생각하고 진행을 해야 한다. 

간접적인 입력 값을 제공하기 위해 Stub을 이용하거나 Mock 객체를 사용하는 것은 객체 간 협력에 관해 고민이 충분히 이뤄져야 가능하다. 

 

따라서 적용하기란 쉽지 않지만 책임-주도 설계를 통해 좋은 객체 지향 설계를 하는데, 테스트를 통해 조금 더 견고한 방법으로 도달할 수 있도록 돕니다.

 

 

Comments