ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • '오브젝트' 책 보고 공부하기 - ⑤ 책임 할당하기
    JAVA공부/JAVA 2023. 6. 5. 22:40

    1) 책임 주도 설계를 향해

     

    객체가 수행해야할 책임은 무엇인가로 시작해서 객체가 수행하는데 필요한 데이터는 무엇인가로 설계하자.

    책임 중심의 설계가 될 수 있다.

     

    협력의 문맥 아래서 책임을 결정하자.

    책임이 어색하더라도 협력에 적합하면 해당 책임은 좋은 것이다.

    메시지를 먼저 선택하고나서 메시지를 처리할 객체를 선택하여 적합한 객체를 사용 할 수 있게 노력하자.

     


     

    2) 책임 할당을 위한 GRASP 패턴

     

    설계를 시작하기전 도메인에 대한 개략적인 모습을 그려보는것이 유용하다.

    필자도 머리속으로 정리하기가 어려울 때는 PPT를 사용하든 다른 툴을 사용하든 데이터의 흐름을 그려보는데, 그리다보면

    고쳐야될 점도 보이고, 파악하기도 쉽다는게 좋다. (물론, 틀렸을때 다시 그리기도 조금 벅차지만 말이다.)

     

    올바른 도메인 모델은 존재하지 않는다. 우선 설계를 시작하고 실제 구현을 하면서 다듬어 가자, 가장 실용적이면서 유용한 모델, 
    유연한 모델에 가까워질 수록 올바른 도메인모델에 가까워지는 것이다.

     

    GRASP패턴은 크레이그 라만이 패턴형식으로 제안한 책임 할당 기법중 하나이다. 패턴을 하나씩 알아보자.

    책임을 수행할 정보를 알고 있는 객체에게 책임을 할당하는 것을 INFORMATION EXPERT(정보전문가) 패턴이라고 한다.

    데이터를 '저장'하고 있는 것이 아니라 정보를 '알고' 있는 객체가 전문가이다.

     

    이미 결합되어있는 객체에게 협력을 실행하자 그러면 다른객체와의 낮은 결합도를 유지 할 수 있다.

    이를 LOW COUPLING 패턴이라고 한다.

     

    객체가 책임지고 있는 처리에 대해 스스로 처리하게 하거나 반드시 협력해야하는 관계안에서만 실행하게 하자. 

    이를 잘 지키면 HIGH COHESION(높은 응집도) 패턴을 가질 수 있다.

     

    객체 A를 생성해야 할 때, 어떤 객체에게 생성해야할 책임을 할당하겠는가? 

    A에 대해 잘 알고, 포함하고 참조하고, 기록하고, 긴밀하게 사용하고 초기화시에 필요한 데이터가 있는 객체에게 할당하자.

    이를 CREATOR 패턴 이라고 한다.

     

     


     

    3) 구현을 통한 검증

     

    조건문 개선 - if ~ else 구문을 생각해보면 조건이 하나씩 늘어날때마다 if else 구문으로 하나씩 늘려야가야 했고, case문도 마찬가지이다.

    이렇게 if문이 증가할때마다 단순 수정이 필요할때마다 불필요한 생각, 중복 코드 등이 발생할 확률이 높아진다.

     

    책에서는 순번조건, 기간조건 로직변경시에 내부 속성들이 변경되야한다는 점을 단점으로 꼽고있는데,
    이는 어떻게 구현하더라도 당연한거 아닌가? 이런생각이 드는데 이부분은 조금 이해가 가지 않았다. 

    물론 연관성이 없는 데이터가 하나의 클래스안에 뭉쳐져 있다는것은 동의하며,

    이 데이터들의 변경의 이유에 따라 클래스를 분리해야 한다는 것은이해가 간다. (아마 이부분을 얘기하신 것 같다.)

     

    여기서 힌트를 얻을 수 있는데, 변경의 이유가 하나 이상인 클래스를 찾는 것부터 설계 개선을 진행하자.

    어느 부분에서 개선을 해야할지 개선포인트를 잡기 힘든 경우가 있는데, 이런 관점에서 찾아보면 조금 더 쉽게 찾을 수 있을 것같다.

     

    변경의 이유를 찾는 방법은 책에서 2개를 소개해준다.

    인스턴스 변수가 초기화되는 시점
    인스턴스 생성시 모든 속성을 초기화 하는지: 응집도 높음
    다른시점에 초기화 하는지, 일부만 초기화하지 않는지: 응집도 낮음

    >>>
    함께 초기화 되는 속성을 기준으로 코드를 분리하자.

    메서드들이 인스턴스 변수를 사용하는 방식

    모든 메서드가 객체의 모든 속성을 사용하면: 응집도는 높음.

    메서드를 사용하는 속성에 따라 그룹이 나뉜다면:  응집도가 낮음

    >>>

    속성 그룹과 해당 그룹에 접근하는 메서드 그룹을 기준으로 코드를 분리하자.

     

    분리만 해서 끝나지 않는다.

    추상화를 진행해서 퍼블릭 인터페이스를 설계하고 같은 메시지를 전송하여 다른 응답을 받을 수 있게 해보자.

    POLYMORPHISM(다형성) 패턴을 이용하자.

     

    퍼블릭 인터페이스를 통해 여러 구현체를 메시지를 주고받을 수 있게 되면 구현체가 계속 추가되어도 다른 코드에 영향이 1도 가지 않는다.

    이렇게 변경을 캡슐화하도록 책임을 할당하는 것을  PROTECTED VARIATIONS(변경 보호) 패턴 이라고 한다.

     

    구현을 공유할 필요가 있는 경우 추상 클래스를 이용해 역할을 구현하자, 공유할 구현이 없는 경우 인터페이스를 이용하자

    책에는 이렇게 내용이 나와있지만 팀원분과 많은 얘기를 나누었던 결과 추상클래스도 합성을 이용해 이끌어내는 방법은 어떨까 생각해본다.

    공통적인 부분은 합성을 통해 전달받고 아닌 부분은 인터페이스를 통해 분리하는것이다.

    생각해보니 공통적인 코드부분도 언젠가 다르게 나뉘어질 수도 있으니 합성을 통해 이끌어내는것이 조금 더 유연하리라 생각이든다.

    책 저자분께서도 영화와 영화 할인 정책에 대해 합성관계를 이끌어내는 거로 보아서 책임을 계속 분리해나가는것이 좋은 코드라 생각이

    든다.

    google을 통한 stackoverflow 를 보면 대부분 합성을 통해 코드를 해결하라는 말이 많이 보인다.

     

     


    4) 책임 주도 설계의 대안

     

    실력이 부족할때 (나같은) , 일단 실행하는 코드를 작성 후 리팩토링을 하는 것도 훌륭한 설계를 얻을 수 있다.

    나도 실제 구현해보면서 생각해보지 못한 정책들이 많이 나오는데(경험이 별로없어서 그런가) 

    완성 후 조금씩 리팩토링 한 기억이 많다. (물론 좋은 설계는 아니었던 것 같다.)

     

    리팩토링의 방향성

    책에서 안내해주는 안좋은 메서드(긴 코드)를 보자면

    - 어떤 일을 수행하는지 한눈에 파악하기 어렵다.

    - 수정할 부분을 찾기 어렵다.

    - 메서드 내부 일부 수정하다가 나머지 부분에서 버그 발생할 확률이 있다.

    - 로직 일부 재사용이 힘들다.

    - 재사용방법이 코드 복붙이다.

    주석을 사용하기 보다 작은 메서드 들로 나누어서 주석처럼 보이게 하자. 

    물론 나눌때는 응집도 있게 나누는게 베스트이다.

    (그래도 주석이 꼭 나쁜것만은 아니라 생각한다.)

     

    메서드의 이름 길이는 신경쓰지말고 의미에 신경쓰자. (메서드 구현내용을 뒷받침할 이름을 만들자.)

     

    리팩토링을 통해 메서드 분리가 끝나고나면 객체를 자율적으로 만들기위해  객체 각자의 책임으로 이동시키자.

    메서드안에서 어떤 클래스의 접근자 메서드를 사용하는지 확인해보면 데이터의 주인을 쉽게 찾을 수 있다.

    그 다음 접근자 메서드를 지워버리든가, 내부 에서만 접근 할 수 있도록 접근제한자를 변경하도록 하자.

    (다른 사람이 쉽게 캡슐화를 깨지 않도록...)

     

     

     

     

     

Designed by Tistory.