[개발 서적] 객체지향의 사실과 오해(핵심 개념 모음)

5 분 소요

🔗 들어가며

지난 게시글에서는 객체지향이 무엇이고, 객체는 어떤 특징을 갖는지를 자세히 다뤄보았다. 해당 게시글에서 가장 중요한 내용은 다음 한 문장으로 요약할 수 있을 것 같다.

객체 지향 시스템은 상호작용하는 자율적인 객체들의 공동체이다.

책의 전반적인 내용은 위의 내용을 조금 더 세부적으로 설명한다. 모든 내용을 유기적으로 연결하며 읽을 때 가장 이해하기가 쉽지만, 그 중에서 내가 중요하다고 생각하는 핵심만을 요약해 이번 게시글에 정리해보고자 한다.

🔗 객체: 상태(state) + 행동(behvior) + 식별자(identity)

객체의 다양한 특성을 효과적으로 설명하기 위해서는 객체를 (상태+행동+식별자)를 지닌 실체로 보는 것이 가장 효과적이다.

1. 상태(행동의 과정과 결과)

  • property라고 표현한다.
    • property = 연관관계 + 속성
  • 상태의 캡슐화
    • 행동을 경계로 상태를 캡슐화한다.
    • 즉, 송신자는 수신자의 상태 변경을 모른다.
    • 수신자가 스스로 판단/결정 -> 자율성 증가

2. 행동

  • side effect를 야기한다.
    • 행동을 통해서 상태 변경이 일어난다.
    • 외부 요청 & 수신된 메시지에 응답하기 위해 반응/동작하는 것
  • 행동을 통해 협력에 참여한다.
    • 메시지 수신 -> 행동 -> 상태 변화(or 다른 객체에게 메시지 전달)

3. 식별자

  • 값과 달리 객체는 식별자를 가진다.
    • 값은 상태가 같으면 동등한 값으로 취급
    • 객체는 식별자가 같아야 동일한 값으로 취급

🔗 객체지향 설계의 핵심: “협력”

해당 내용은 정말 책에서 수도 없이 강조한 내용이다. 나역시 객체지향 설계하면 클래스를 가장 먼저 떠올릴 만큼 객체를 기준으로 지금까지 설계를 진행하고 있었다. 하지만 객체지향 설계의 핵심은 “협력”이다.

협력 -> 필요한 행동 -> 수행할 객체 선택

  • 행동이 객체를 결정한다.
    • 객체를 기준으로 설계한다면 객체가 행동을 선택하게 된다.
    • 여기서 핵심은 “행동”이 적절한 “객체”를 선택하는 것이다!
  • 객체의 행동 = 협력에서의 책임
    • 추후 RDD(책임 주도 설계)에서 다룰 것
    • 객체의 재사용성 = 협력에 참여할 수 있는 능력

🔗 객체지향 세계 = 현실 세계 “은유”

객체지향 세계 = 현실 세계 “추상화”?

현실 세계 추상화?, 이 말도 정말 많이 들었다. 하지만 이 말은 객체지향 설계를 정확히 설명하지 못하는 말이다.

  • 이유) 객체지향 속 객체는 현실 세계보다 많은 역할을 수행한다.
    • 객체를 의인화해서 표현하기 때문이다.

결국, 객체지향 세계를 가장 잘 표현하는 것은 현실 세계의 은유이다.

  • a를 b의 관점에서 이해하고 경험하는 것을 은유라고 한다.
  • 객체 지향에서 현실 세계의 naming을 권장하는 이유
    • 동일한 naming을 사용해 구조를 쉽게 예측하도록 하기 위해서이다.

🔗 행동이 객체의 타입을 결정한다.

현실 세계에서도 복잡성을 다루기 위해 추상화를 적용한다. 이때 활용하는 것이 개념이다. 개념은 특정 객체가 어느 그룹에 속할 것인지를 결정해준다.

우리는 평소 개발을 하며 데이터 타입이라는 말을 많이 쓴다. 이러한 데이터의 타입은 다음과 같은 특징이 있다.

  • 타입은 데이터가 어떻게 사용되느냐에 관한 것이다.
  • 타입에 속한 데이터를 메모리에 어떻게 표현하는지는 외부로부터 감춰진다.

객체 타입도 위와 동일한 특성을 가지게 되며 우리는 다음의 중요한 내용들을 추론할 수 있다.

  • 객체의 타입을 결정하는 것은 객체의 행동이다.
    • 객체가 어떤 데이터를 보유하고 있는지는 타입 결정에 아무 영향을 미치지 않는다.
  • 객체의 내부 표현은 감춰진다.
    • 다형성, 동일한 메시지를 객체마다 다르게 처리할 수 있다.

객체지향하면 가장 먼저 떠올리는 클래스! 클래스는 단순히 객체지향에서 객체의 타입을 구현하는 방식 중 하나에 해당한다.

🔗 역할을 통한 협력의 추상화

책임의 집합이 역할이다. 그렇다면 객체의 역할이 왜 중요할까? 역할을 통해서 협력을 추상화할 수 있기 때문이다.

이상한 나라의 앨리스에서 재판을 하는 내용이 나온다. 여기서 왕은 재판을 진행하고, 모자장수는 증인석에 나와 증언을 한다. 여기서 왕에게는 판사, 모자장수에게는 증인이라는 역할을 부여할 때 협력은 단순화된다.

이렇게 협력을 단순화 하면 좋은 점은 다음과 같다.

  1. 다양한 객체들이 협력에 참여할 수 있다.(협력의 유연성)
  2. 다양한 객체들이 동일한 협력에 참여할 수 있다. (협력의 재사용성)

🔗 RDD(책임 주도 설계)와 TDD(테스트 주도 설계)

1. RDD

객체지향 설계에서 중요한 것은 협력이라고 했다. RDD올바른 책임을 올바른 객체에게 할당하는 것이 핵심인 설계 기법이다.

what - who 사이클

  • 올바른 책임: 어떤 행위를 수행할 것인가?
  • 올바른 객체: 누가 그 행위를 수행할 것인가?

객체의 행위를 결정하는 것이 객체의 속성이 아니다! 행위를 먼저 식별하고 적절한 객체를 선택하자!

2. TDD

TDD는 RDD를 통해 도달해야 하는 목적지를 테스트라는 안전장치를 통해 좀 더 빠르고 견고한 방식으로 도달할 수 있도록 한다.

  • 무얼 test로 작성하는 걸까?
    • 기대되는 객체의 역할이 메시지를 수신할 때 어떤 결과를 반환하는가?
    • 어떤 객체와 협력할 것인가?
    • 위 두 기대에 대해 코드를 작성

🔗 적절한 책임 -> 자율적인 객체

어떠한 메시지를 받느냐, 즉 어떠한 요청을 받느냐가 객체의 책임을 결정한다. 하지만 이때 적절한 책임이 되기 위한 조건이 존재한다.

  1. 수행방법을 지나치게 제한하는 구체적인 책임
  2. 협력의 의도를 명확하게 표현하지 않는 추상적인 책임
  • 자율성 보장 + 협력의 의도 뚜렷 => 좋은 책임
  • how보다는 what에 초점을 두는 책임

🔗 메시지와 객체

객체는 메시지를 기준으로 외부/내부가 분리된다.

  • 외부: 메시지
  • 내부: 메시지 처리를 위해 수행하는 방법

객체가 메시지를 받고 책임을 수행하는 과정을 한 번 살펴보자.

메시지(what) -> 행동 요청 -> 메서드 수행(how) -> 책임을 받아들임

여기서 what:how = 1:多라는 점을 주목하자. 이것이 바로 다형성이다. 다형성을 통해 송/수신자의 객체 타입 결합도가 메시지에 대한 결합도로 낮춰지게 된다.

  • 송신자는 수신자가 어떤 타입인지 정확히 알 필요가 없다.
  • 수신자는 메시지에 대한 행동을 자율적으로 선택하고 송신자에게 노출하지 않는다.

이를 통해 설계는 유연해지고, 확장 및 재사용이 가능해진다.

🔗 메시지 -> 인터페이스

인터페이스라는 것은 상호작용을 할 수 있게 이어주는 방법이나 장치를 의미한다. 라디오를 사용하기 위해 버튼을 누를 경우, 버튼이 바로 인터페이스이 되는 것이다.

메시지는 객체의 책임을 결정한다. 이러한 책임은 외부에서 객체에게 요청할 수 있는 행동을 의미한다. 따라서 이러한 책임은 인터페이스를 통해 외부에 노출이되어야 한다. 이를 통해 우리는 메시지가 인터페이스를 결정한다는 사실을 알 수 있게 된다.

인테페이스를 설계할 때 고려해야 하는 세가지 원칙이 존재한다.

  • 좀 더 추상적인 인터페이스
    • 위에서 말한 구체적이지 않은 책임이 더 좋은 책임이라는 맥락과 동일하다.
  • 최소 인터페이스
    • 불필요한 정보 노출은 피하자!
  • 인터페이스와 구현 분리
    • 인터페이스: 변경했을 때 외부에 영향을 미치는 위험 지대
    • 구현: 안전 지대
    • 구현을 인터페이스 뒤로 감추는 것을 통해 객체의 자율성을 높이자!

🔗 안정적인 구조를 따라 설계하자

설계할 때 우리가 신경써야 하는 것은 자주 변경되는 기능이 아니라 안정적인 구조에 따라 역할/책임/협력을 구성하는 것이다.

즉, 관련된 책임을 안정적인 객체 구조에 분배하는 것이다.

일반적으로 기능을 수집하고 표현하기 위한 기법유즈케이스 모델링이라고 하고 구조를 수집하고 표현하기 위한 기법도메인 모델링이라고 한다.

1. 도메인 모델


도메인 모델은 소프트웨어가 목적하는 영역 내의 개념과 개념간의 관계, 다양한 규칙이나 제약 등을 주의 깊게 추상화한 것이다. 이는 단순 다이어그램을 의미하는 것이 아니라 이해 관계자들이 바라보는 멘탈 모델(mental model)이기도 하다.

  • 사람들이 자신이 상호작용하는 사람들에 대해 갖는 모형이다.
  • 도멘인의 본질적인 내용을 담고 있어 변경으로부터 안정적이다.

즉, 도메인 모델은 변경으로부터 안정적인 구조이기 때문에 도메인 모델을 기반으로 기능 구현이 이루어져야 한다.

  • 비즈니스 정칙 & 규칙이 변경되지 않는다면 일정하게 유지된다.
  • 기능적 요구사항이 변경된다면 책임과 객체 간의 관계만 수정되고 구조는 유지된다.

2. 유즈케이스


유즈케이스는 공통의 사용자 목표를 통해 강하게 연관된 시나리오의 집합이다. 유즈케이스는 다음의 특징들을 가진다.

  • 시스템 사용자 사이 상호작용을 text로 표현
  • 여러 시나리오들의 집합
  • 연관된 피처들을 묶는 기능
  • ui/내부 설계 세부 정보 포함하지 않음

유즈케이스를 사용하는 핵심은 다음 세 가지다!

  1. 사용자가 바라보는 시스템의 외부 관점만을 표현
  2. 피처를 사용자 목표를 중심으로 묶기 위한 정리 기법
  3. 객체의 구조나 책임에 대한 정보 제공 x

3. RDD와 도메인 모델/유즈케이스의 관계


RDD <-> 도메인 모델 / 유즈케이스

RDD는 시스템의 기능을 역할과 책임을 수행하는 객체들의 협력 관계로 바라보게 함으로써 유즈케이스와 도메인 모델을 통한다. 하지만 여기서 짚고 넘어갈 점이 있다.

  • RDD를 위해 꼭 도메인 모델 / 유즈케이스가 필요한 것이 아니다.
  • 도메인 모델과 유즈케이스가 RDD에서만 사용되는 것은 아니다.

핵심을 기억하자.

  • 견고한 객체지향 어플리케이션을 개발하기 위해 사용자의 관점에서 시스템의 기능을 명시하고,
  • 사용자가 설계자가 공유하는 안정적인 구조를 기반으로 기능을 책임으로 변환하는 체계적인 절차를 따라야 한다.

마인드맵

댓글남기기