본문으로 건너뛰기

14장 일관성 있는 협력

서론

  • 앱을 개발하다 보면 유사한 요구사항을 반복적으로 추가하거나 수정하게 되는 경우가 있다.
    • 객체들의 협력 구조가 다르면 코드를 이해하기 어렵고 수정으로 인한 버그가 발생할 위험성이 높아진다.
    • 유사한 요구사항을 계속 추가해야 하는 상황에서 각 협력이 서로 다른 패턴을 따를 경우에는 전체적인 설계의 일관성이 무너지게 된다.
  • 객체지향 패러다임의 장점은 설계를 재사용할 수 있다는 것이다.
    • 재사용을 위해 객체 협력방식을 일관성있게 만들어야 한다.
    • 일관성은 설계에 드는 비용을 감소시킨다. - 이미 알고있는 해결방법을 사용하기 때문.
  • 가능하면 유사한 기능을 구현하기 위해 유사한 협력 패턴을 사용하라.

01. 핸드폰 과금 시스템 변경하기

  • 예제 코드 구현에 대한 내용

02. 설계에 일관성 부여하기

  • 일관성 있는 설계를 만드는 데 가장 훌륭한 조언은 다양한 설계 경험을 익히라는 것이다.
    • 풍부한 설계 경험을 가진 사람은 어떤 변경이 중요한지, 어떻게 다뤄야 하는지 통찰력을 가지게 된다.
    • 설계 경험이 풍부하면 할수록 어떤 위치에서 일관성을 보장해야 하고 일관성을 제공하기 위해 어떤 방법을 사용해야 하는지 직관적으로 결정할 수 있다.
  • 협력을 일관성 있게 만들기 위해 다음과 같은 기본 지침을 따라라
    • 변하는 개념을 변하지 않는 개념으로부터 분리하라.
    • 변하는 개념을 캡슐화하라.
  • 클래스를 분리하기 위해 어떤 기준을 따라야 하나?
    • 변경의 이유와 주기다.
    • 클래스는 명확히 단 하나의 이유에 의해서만 변경돼야 하고 클래스 안의 모든 코드는 함께 변경되어야 한다.
    • 단일 책임 원칙을 따르도록 클래스를 분리하라.
  • 큰 메서드 안에 뭉쳐있던 조건 로직들을 변경의 압력에 맞춰 작은 클래스들로 분리하면 인스턴스들 사이의 협력 패턴에 일관성을 부여하기 쉬워진다.
    • 유사한 행동을 하는 작은 클래스들이 자연스럽게 역할이라는 추상화로 묶이게 되고 역할 사이에서 이뤄지는 협력 방식이 전체 설계의 일관성을 유지할 수 있게 이끌어주기 때문이다.
    • 핵심은 훌륭한 추상화를 찾아 추상화에 의존하도록 만드는 것이다.
    • 추상화에 대한 의존은 결합도를 낮추고 결과적으로 대체 가능한 역할로 구성된 협력을 설계할 수 있도록 해주기 때문이다.
  • 변경에 초점을 맞추고 캡슐화의 관점에서 설계를 바라보면 일관성 있는 협력 패턴을 얻을 수 있다.

캡슐화 다시 살펴보기

  • 캡슐화는 소프트웨어 안에서 변할 수 있는 모든 ‘개념'을 감추는 것이다.
    • 데이터 은닉의 이상이다.

      설계에서 무엇이 변화될 수 있는지 고려하라. 이 접근법은 재설계의 원인에 초점을 맞추는 것과 반대되는 것이다. 설계에 변경을 강요하는 것이 무엇인지에 대해 고려하기보다는 재설계 없이 변경할 수 있는 것이 무엇인지 고려하라. 여기서의 초점은 많은 디자인 패턴의 주제인 변화하는 개념을 캡슐화하는 것이다.

  • 캡슐화의 대표적인 예는 객체의 퍼블릭 인터페이스와 구현을 분리하는 것이다.
    • 객체를 구현한 개발자는 필요할 때 객체의 내부 구현을 수정하길 원한다.
    • 객체와 협력하는 클라이언트의 개발자는 객체의 인터페이스가 변하지 않기를 원한다.
    • 따라서 자주 변경되는 내부 구현을 안정적인 퍼블릭 인터페이스 뒤로 숨겨야한다.
  • 캡슐화란 단지 데이터 은닉을 의미하는 것이 아니다.
    • 코드 수정으로 인한 파급효과를 제어할 수 있는 모든 기법이 캡슐화의 일종이다.
    • 변경을 캡슐화할 수 있는 다양한 방법이 존재하지만 협력을 일관성 있게 만들기 위해 가장 일반적으로 사용하는 방법은 서브타입 캡슐화와 객체 캡슐화를 조합하는 것이다.
  • 서브타입 캡슐화와 객체 캡슐화를 적용하는 방법은 아래와 같다.
    • 변하는 부분을 분리해서 타입 계층을 만든다.
      • 변하지 않는 부분으로부터 변하는 부분을 분리한다.
      • 변하는 부분들의 공통적인 행동을 추상 클래스나 인터페이스로 추상화한 후 변하는 부분들이 이 추상 클래스나 인터페이스를 상속받게 만든다.
      • 이제 변하는 부분은 변하지 않는 부분의 서브타입이 된다.
    • 변하지 않는 부분의 일부로 타입 계층을 합성한다.
      • 앞에서 구현한 타입 계층을 변하지 않는 부분에 합성한다.
      • 변하지 않는 부분에서는 변경되는 구체적인 사항에 결합돼서는 안된다.
      • 의존성 주입과 같이 결합도를 느슨하게 유지할 수 있는 방법을 이용해 오직 추상화에만 의존하게 만든다.
      • 이제 변하지 않는 부분은 변하는 부분의 구체적인 종류에 대해서 알지 못한다. 변경이 캡슐화된 것이다.

03. 일관성 있는 기본 정책 구현하기

  • 1장의 코드를 수정

패턴을 찾아라

  • 일관성 있는 협력의 핵심은 변경을 분리하고 캡슐화하는 것이다.
    • 변경을 캡슐화하는 방법이 협력에 찹여하는 객체들의 역할과 책임을 결정하고 이렇게 결정된 협력이 코드의 구조를 결정한다.
    • 따라서 훌륭한 설계자가 되는 첫걸음은 변경의 방향을 파악할 수 있는 감각을 기르는 것이다.
    • 그리고 이 변경에 탄력적으로 대응할 수 있는 다양한 캡슐화 방법과 설계 방법을 익히는 것 역시 중요하다.
  • 애플리케이션에서 유사한 기능에 대한 변경이 지속적으로 발생하고 있다면 변경을 캡슐화할 수 있는 적절한 추상화를 찾은 후, 이 추상화에 변하지 않는 공통적인 책임을 할당하라.
    • 현재의 구조가 변경을 캡슐화하기에 적합하지 않다면 코드를 수정하지 않고도 원하는 변경을 수용할 수 있도록 협력과 코드를 리팩터링하라.
    • 변경을 수용할 수 있는 적절한 역할과 책임을 찾다보면 협력의 일관성이 윤곽을 드러낼 것이다.