본문 바로가기
Study/오브젝트

[오브젝트] 5장. 책임 할당하기

by Nahwasa 2022. 12. 2.

스터디 메인 페이지

목차

    - ☆ 표시가 붙은 부분은 스터디 중 나온 얘기 혹은 제 개인적인 생각이나 제가 이해한 방식을 적어놓은 것으로, 책에 나오지 않는 내용입니다. 따라서 책에서 말하고자 하는 바와 다를 수 있습니다.

    - 모든 이미지의 출처는 오브젝트(조용호 저) 책 입니다.

     


    CHAPTER 05. 책임 할당하기

     

      2장에서는 책임을 중심으로 설계된 객체지향 코드의 대략적인 모양을 살펴봄. 5장에서는 2장에서 소개한 코드의 설계 과정을 따라가 보면서 객체에 책임을 할당하는 기본적인 원리를 살펴보는 챕터.

     


    01 책임 주도 설계를 향해

    ⚈ 데이터 중심의 설계에서 책임 중심의 설계로 전환하기 위한 원칙

    • 데이터보다 행동을 먼저 결정하라
    • 협력이라는 문맥 안에서 책임을 결정하라

     

     

    [ 데이터보다 행동을 먼저 결정하라 ]

    ⚈ 데이터는 객체가 책임을 수행하는 데 필요한 재료를 제공할 뿐이다.

     

    객체를 설계하기 위한 질문의 순서를 바꾸자.

    • 데이터 중심의 설계 : "이 객체가 포함해야 하는 데이터가 무엇인가" -> "데이터를 처리하는 데 필요한 오퍼레이션은 무엇인가"
    • 책임 중심의 설계 : "이 객체가 수행해야 하는 책임은 무엇인가" -> "이 책임을 수행하는 데 필요한 데이터는 무엇인가"

     

     

    [ 협력이라는 문맥 안에서 책임을 결정하라 ]

    ⚈ 적합한 책임이란 메시지 수신자가 아니라 메시지 전송자에게 적합한 책임을 의미한다. 즉, 메시지를 전송하는 클라이언트의 의도에 적합한 책임을 할당해야 한다.

     

    "객체를 가지고 있기 때문에 메시지를 보내는 것이 아니다. 메시지를 전송하기 때문에 객체를 갖게 된 것이다."

     

     

    [ 책임 주도 설계 ]

    핵심은 책임을 결정한 후에 책임을 수행할 객체를 결정하는 것. -> 협력에 참여하는 객체들의 책임이 어느 정도 정리될 때까지는 객체의 내부 상태에 대해 관심을 가지지 않는 것.

     

    책임 주도 설계의 흐름

    • 시스템이 사용자에게 제공해야 하는 기능인 시스템 책임을 파악
    • 시스템 책임을 더 작은 책임으로 분할
    • 분할된 책임을 수행할 수 있는 적절한 객체 또는 역할을 찾아 책임을 할당
    • 다른 객체의 도움이 필요한 경우 이를 책임질 적절한 객체 또는 역할을 찾는다
    • 해당 객체 또는 역할에게 책임을 할당함으로써 두 객체가 협력하게 된다.

     


    02 책임 할당을 위한 GRASP 패턴

    ⚈ GRASP

    • General Responsibility Assignment Software Pattern (일반적인 책임 할당을 위한 소프트웨어 패턴)
    • 객체에게 책임을 할당할 때 지침으로 삼을 수 있는 원칙들의 지합을 패턴 형식으로 정리한 것

     

    도메인 개념에서 출발하기

    • 설계를 시작하기 전에 도메인에 대한 개략적인 모습을 그려 보는 것이 유용하다. -> 출발점으로 삼기 위해.

     

    정보 전문가에게 책임을 할당하라 - Information Expert

    • 객체에게 책임을 할당하는 첫 번째 원칙은 책임을 수행할 정보를 알고 있는 객체에게 책임을 할당하는 것이다.
    • 객체가 정보를 '알고' 있다고 해서 그 정보를 '저장'하고 있을 필요는 없다. -> '정보' 전문가에서 '정보'는 '데이터'와 다르다.
    • 스스로 처리할 수 없는 작업이 있다면 외부에 도움을 요청해야 한다.

     

    높은 응집도와 낮은 결합도 - High Cohesion & Low Coupling

    • Low Coupling : 설계의 전체적인 결합도가 낮게 유지되도록 책임을 할당하라.
    • High Cohesion : 높은 응집도를 유지할 수 있게 책임을 할당하라
    • 책임과 협력의 품질을 검토하는 데 사용할 수 있는 중요한 평가 기준

     

    창조자에게 객체 생성 책임을 할당하라 - Creator

    • 객체를 생성할 책임을 어떤 객체에게 할당할지에 대한 지침
    • 객체 A를 생성해야 할 때 이하 조건을 최대한 많이 만족하는 B에게 객체 생성 책임을 할당하라.
      • B가 A 객체를 포함하거나 참조한다.
      • B가 A 객체를 기록한다.
      • B가 A 객체를 긴밀하게 사용한다.
      • B가 A 객체를 초기화하는 데 필요한 데이터를 가지고 있다(이 경우 B는 A에 대한 정보 전문가다)

     

    협력과 책임이 제대로 동작하는지 확인할 수 있는 유일한 방법은 코드를 작성하고 실행해 보는 것뿐이다. 올바르게 설계하고 있는지 궁금한가? 코드를 작성하라.

     


    03 구현을 통한 검증

    ⚈ 변경에 취약한 클래스 : 코드를 수정해야 하는 이유를 하나 이상 가지는 클래스 -> 낮은 응집도 -> 연관성이 없는 기능이나 데이터가 하나의 클래스 안에 뭉쳐져 있다 -> 변경의 이유에 따라 클래스를 분리해야 한다.

     

    객체지향 설계에 갓 입문한 개발자들은 클래스 안에서 변경의 이유를 찾는 것이 생각보다 어렵다.

    • 인스턴스 변수가 초기화되는 시점을 살펴보자. -> 응집도가 높은 클래스는 인스턴스를 생성할 때 모든 속성을 함께 초기화한다. -> 함께 초기화되는 속성을 기준으로 코드를 분리해야 한다.
    • 모든 메서드가 객체의 모든 속성을 사용한다면 클래스의 응집도는 높다고 볼 수 있다. -> 메서드 그룹이 속성 그룹을 사용하는지 여부로 나뉜다면 응집도가 낮은 것이다 -> 이들 그룹을 기준으로 클래스를 분리해야 한다.

     

    ⚈ 다형성을 통해 분리하기 - Polymorphism

    •  객체의 타입에 따라 변하는 행동이 있다면 타입을 분리하고 변화하는 행동을 각 타입의 책임으로 할당하라. (역할)

     

    변경으로부터 보호하기 - Protected Variations

    • 변경을 캡슐화하도록 책임을 할당하는 것

     

    설계를 주도하는 것은 변경이다.

    • 1. 코드를 이해하고 수정하기 쉽도록 최대한 단순하게 설계
    • 2. 코드를 수정하지 않고도 변경을 수용할 수 있도록 코드를 더 유연하게 만드는 것
    • 대부분의 경우 '1'이 더 좋은 방법이지만 유사한 변경이 반복적으로 발생하고 있다면 복잡성이 상승하더라도 유연성을 추가하는 '2'의 방법이 더 좋다.

     


    04 책임 주도 설계의 대안

    ⚈ 책임 주도 설계에 익숙해지기 위해서는 부단한 노력과 시간이 필요하다.

     

    책임 주도 설계 방법에 익숙하지 않다면 일단 데이터 중심으로 구현한 후 이를 리팩터링하더라도 유사한 결과를 얻을 수 있다.

     

    ⚈ 책임과 객체 사이에서 방황할 때 돌파구를 찾기 위한 방법

    • 최대한 빠르게 목적한 기능을 수행하는 코드를 작성
    • 아무것도 없는 상태에서 책임과 협력에 관해 고민하기 보다는 일단 실행되는 코드를 얻고 난 후에 코드 상에 명확하게 드러나는 책임들을 올바른 위치로 이동시키기

     

    리팩터링 : 겉으로 보이는 동작은 바꾸지 않은 채 내부 구조를 변경하는 것

     

    긴 메서드(몬스터 메서드)가 유지보수에 미치는 부정적 영향

    • 코드를 전체적으로 이해하는 데 너무 많은 시간이 걸린다.
    • 변경이 필요할 때 수정해야 할 부분을 찾기 어렵다.
    • 일부 로직만 수정하더라도 버그가 발생할 확률이 높다.
    • 로직의 일부만 재사용하는 것이 불가능
    • 코드를 재사용하는 유일한 방법은 복붙 뿐이므로 코드 중복을 초래하기 쉽다.

     

    메서드를 응집도 있는 수준으로 분해

    • public 메서드가 상위 수준의 명세를 읽는 것 같은 느낌이 든다.
    • 단, 이름을 잘 지었을 때만 그 진가가 드러난다.

    댓글