이전 내용에 대해 간략하게 요약을 해봤을 때 나는 데이터 주도설계가 아닌 책임 주도 설계를 해라 였다.
이때 책임 주도 설계에서 중요한 건 캡슐화를 강조했다.
해당 장에서는 4장의 내용에 이어 책임 주도 설계에서 책임을 할당하는 것에 대해 자세하게 나와 있었다.
그럼 한번 살펴보도록 하자!
책임 주도 설계를 향해
데이터 중심의 설계에서 책임 중심의 설계로 전환하기 위해서는 다음의 두 가지 원칙을 따라야한다고 한다.
- 데이터보다 행동을 먼저 결정해라
- 협력이라는 문맥 안에서 책임을 결정해라
데이터주도 설계 vs 책임 주도 설계
데이터주도 설계
- 이 객체가 포함해야 하는 데이터가 무엇인가?
- 데이터를 처리하는데 필요한 오퍼레이션은 무엇인가?
책임 주도 설계
- 이 객체가 수행해야 하는 책임은 무엇인가?
- 이 책임을 수행하는 데 필요한 데이터는 무엇인가?
해당 두가지의 내용을 보았을 때, 내가 생각이 들었던 건 데이터 주도 설계는 핵심에 포커스를 맞춘다면 책임 주도는 흐름이라고 해야 하나?
그 부분에 포커스를 맞추는 것처럼 보였다. ( 내가 말한부분이 어떤 느낌인지 이해가 되려나.. 싶다)
데이터보다 행동을 먼저 결정해라
- 객체에게 중요한건 데이터가 아닌, 외부에게 제공하는 행동
- 데이터는 객체가 책임을 수행하는 데 필요한 재료를 제공할 뿐이다.
즉, 요약하면 위에서 말한 것처럼 책임에 대해 먼저 생각한 후에 해당 객체의 상태를 결정해야 한다가 핵심 내용으로 보였다.
협력이라는 문맥 안에서 책임을 결정해라
해당 챕터에서는 이전, 3장 책임 주도 설계 방법에 대한 이야기와 동일함을 알 수 있었고, 마지막에도 해당 문구가 있었다.
해당 부분에 이야기를 해보자면 다음과 같다.
객체에게 적절한 책임을 할당하기 위해선 협력이라는 문맥을 고려해야 한다.
협력이란 문맥의 적절한 책임은 곧 클라이언트의 관점에서 적절한 책임을 의미하게 된다.
올바른 객체지향 설계는 클라이언트가 전송할 메시지를 결정한 후에야 비로소 객체의 상태를 저장하는데 필요한 데코레이터에 관해 고민하기 시작한다.
책임 주도 설계
해당 부분에서는 이전, 책임주도 설계에 대한 흐름을 다시 한번 리마인드를 시켜주고 있다.
- 시스템이 사용자에게 제공해야 하는 기능인 시스템 책임을 파악한다.
- 시스템 책임을 더 작은 책임으로 분할한다.
- 분할된 책임을 수행할 수 있는 적절한 객체 또는 역할을 찾아 책임을 할당한다.
- 객체가 책임을 수행하는 도중 다른 객체의 도움이 필요한 경우 이를 책임질 적절한 객체 또는 역할을 찾는다.
- 해당 객체 또는 역할에게 책임을 할당함으로써 두 객체가 협력하게 한다.
책임 할당을 위한 GRASP 패턴
- GRASP 패턴은, 크레이크 라만 ( Craig Larman)이 제안한 패턴 형식
- GRASP (General Responsibility Assignment Software Pattern)의 줄임말로서, 객체에게 책임을 할당할 때 지침으로 삼을 수 있는 원칙들의 집합을 패턴 형식으로 정리한 것이다.
도메인 개념에서 출발하기
- 도메인 개념으로 설계를 할 때
- 설계를 시작하기 전, 도메인에 대한 개략적인 모습을 그려보는 것이 유용하다.
- 도메인 안에는 무수히 많은 개념들이 존재하며, 이 개념들을 책임 할당의 대상으로 사용하면 코드에 도메인의 모습을 투영하기가 좀 더 수월해진다.
이 전장들에서도 다뤘던 영화 예매 시스템의 도메인 개념을 살펴보자
해당 그림은, 도메인 개념과 개념 사이의 관계를 대략적으로 표현했다. 설계를 시작하는 단계에서는 개념들의 의미와 관계가 정확하거나 완벽할 필요가 없다.
해당 단계에서는 책임을 할당받을 객체들의 종류와 관계에 대한 유용한 정보를 제공할 수 있다면 충분하다.
중요한 건 설계를 시작하는 것이지 도메인 개념들을 완벽하게 정리하는 것이 아니다.
하지만 책에서도 이야기하듯, 올바른 도메인 모델은 존재하지 않는다.
결론적으로, 필요한 건 도메인을 그대로 투영한 모델이 아닌 구현에 도움이 되는 모델 즉, 실용적이면서 유용한 모델이 답이라고 이야기한다.
정답은 없다. 어떠한 설계를 진행함에 있어 해당 프로젝트의 각 책임을 기반으로 짜임새 있는 설계를 한다면 된 게 아닐까?
정보 전문가에게 책임을 할당하라
- 애플리케이션이 제공해야 하는 기능을 애플리케이션의 책임으로 생각하는 것이다.
- 해당 책임을 애플리케이션에 대해 전송된 메시지로 간주하고 이 메시지를 책임질 첫 번째 객체를 선택하는 것으로 설계를 시작한다.
메시지는 메시지를 수신할 객체가 아닌 메시지를 전송할 객체의 의도를 반영해 결정해야 한다.
그렇기에, 다음과 같은 질문을 남길 수 있다.
- 메시지를 전송할 객체는 무엇을 원하지?
- 메시지를 수신할 적합한 객체는 누구지?
객체의 책임과 책임을 수행하는 데 필요한 상태는 동일한 객체 안에 존재해야 한다.
따라서, 객체에게 책임을 할당하는 첫번째 원칙은 책임을 수행할 정보를 알고 있는 객체에게 책임을 할당하는 것
GRASP에서는 이를 정보 전문가 ( INFORMATION EXPERT ) 패턴이라고도 한다.
해당 예제를 살펴보면, Screening은 상영을 위한 정보 전문가, Movie는 영화에 대한 정보 전문가일 것이다.
위 흐름을 보면, Screeing은 해당 가격에 대한 정보를 가지고 있는 Movie에게 가격을 계산하라로 요청하는 게 보이는가?
즉, Movie는 가격에 대한 책임을 지게 되고 할인 여부 또한 해당 정보를 가지고 있는 DiscountCondition이 책임을 진다.
정보 전문가 패턴은 상태와 행동을 함께 가지는 단위라는 객체지향의 가장기본적인 원리를 책임 할당의 관점에서 표현한다.
정보 전문가 패턴을 따르는 것만으로도 자율성이 높은 객체들로 구성된 협력 공동체를 구축할 가능성이 높아진다.
높은 응집도와 낮은 결합도
해당 챕터에서는 GRASP에서의 각 패턴에 대해 이야기하고 있다.
LOW COUPLING 패턴
- 설계의 전체적인 결합도가 낮게 유지되도록 책임을 할당하라
- 낮은 결합도는 모든 설계 결정에서 염두에 둬야 하는 원리이다.
- 설계 결정을 평가할 때 적용할 수 있는 평가 원리다.
- 현재의 책임 할당을 검토하거나 여러 설계 대안들이 있을 때 낮은 결합도를 유지할 수 있는 설계를 선택해라
HIGH COHESION 패턴
- 높은 응집도를 유지할 수 있게 책임을 할당하라
- 낮은 결합도처럼 높은 응집도 역시 모든 설계 결정에서 염두에 둬야 할 원리이다.
- 설계 결정을 평가할 때, 적용할 수 있는 평가 원리이다.
- 현재의 책임 할당을 검토하고 있거나 여러 설계 대안 중 하나를 선택해야 한다면 높은 응집도를 유지할 수 있는 설계를 선택해라
창조자에게 객체 생성 책임을 할당하라
- 창조자 패턴 ( CREATOR PATTERN)은 이 같은 경우에 사용할 수 있는 책임 할당 패턴으로서 객체를 생성할 책임을 어떤 객체에게 할당할지에 대한 지침을 제공한다.
- 해당 객체가 만들 객체를 포함하거나 참조
- 해당 객체가 만들 객체를 기록한다.
- 해당 객체가 만들 객체를 긴밀하게 사용한다.
- 해당 객체가 만들 객체를 초기화하는 데 필요한 데이터를 가지고 있다. ( 정보 전문가 패턴 )
코드 개선의 경우, 예제를 통한 수정으로 인해 스킵...
책임 주도 설계의 대안
책임 주도 설계에 익숙해지기 위해선 부단한 노력과 시간이 필요하다. 그러나 어느 정도 경험을 쌓은 숙련된 설계자조차 적절한 책임과 객체를 선택하는 일에 어려움을 느낀다.
책임과 객체 사이에서 방황할 때 돌파구를 찾기 위해 선택하는 방법은 최대한 빠르게 목적한 기능을 수행하는 코드를 작성하는 것이다.
여기서 주의할 점은, 코드를 수정한 후에 겉으로 드러나는 동작이 바뀌어서는 안 된다는 것!
캡슐화를 항상 시키고, 응집도를 높이고, 결합도를 낮춰야 하지만 동작은 그대로 유지해야 한다.
이처럼 이해하기 쉽고 수정하기 쉬운 소프트웨어로 개선하기 위해 겉으로 보이는 동작은 바꾸지 않은 채 내부 구조를 변경하는 것을 리 펙터 링 (Refactoring)이라고 한다.
메서드 응집도
긴 메서드는 다양한 측면에서 코드의 유지보수에 부정적인 영향을 미치게 된다.
- 어떤 일을 수행하는지 한눈에 파악하기 어렵기에, 코드를 전체적으로 이해하는데 너무 많은 시간이 걸린다.
- 하나의 메서드 안에서 너무 많은 직업을 처리하기 때문에 변경이 필요할 때 수정해야 할 부분을 찾기 어렵다.
- 메서드 내부의 일부 로직만 수정하더라도 메서드의 나머지 부분에서 버그가 발생할 확률이 높다.
- 로직의 일부만 재사용하는 것이 불가능하다.
- 코드를 재사용하는 유일한 방법은 원하는 코드를 복사해서 붙여 넣는 것뿐이므로 코드 중복을 초래하기 쉽다.
객체를 자율적으로 만들자
자신이 소유하고 있는 데이터를 자기 스스로 처리하도록 만드는 것이 자율적인 객체를 만드는 지름길이다.
해당 내용은 이전 계속 이야기했던 캡슐화와도 연관성이 깊다고 판단했다. 그만큼 강조하고 싶은 부분이 아닐까 싶다.
메서드가 사용하는 데이터를 저장하고 있는 클래스로 메서드를 이동시키면 된다.
만약 책임 주도 설계 방법에 익숙하지 않다면, 데이터 중심으로 구현한 후 이를 리 펙터 링 하더라도 유사한 결과를 얻을 수 있다.
처음부터 책임 주도 설계 방법을 따르는 것보다 동작하는 코드를 작성한 후에 리 펙터 링 하는 것이 더 훌륭한 결과물을 낳을 수 있다.
캡슐화, 결합도, 응집도를 이해하고 훌륭한 객체지향 원칙을 적용하기 위해 노력한다면 책임 주도 설계 방법을 단계적으로 따르지 않더라도 유연하고 깔끔한 코드를 얻을 수 있다.
마치며
해당 내용들에 대해 배워야 할 내용들도 많았지만, 실질적으로 와닿았던 건 마지막 객체를 자율적으로 만들자 부분이었던 것 같다.
이전, 나는 책임 주도 설계에 익숙하지 않았었기에 해당 부분을 계속 고려하다 보니 생산성 자체가 매우 저하되었던 경우가 생겼다.
물론, 처음부터 잘하는 경우가 없겠지만 이 부분에 대해 매우 스트레스를 받았었고 이 부분을 읽으며 선배가 나에게 해줬던 조언이 생각이 났다.
" 야! 처음부터 잘하는 사람은 없어, 나도 먼저 구현한 후에 리펙토링을 하면서 개선했지 처음부터 완벽하려고 욕심부리지 마! "
이 책의 도메인 파트에서도 처음부터 완벽하게 짜는 게 아닌 실용적이며 유연하게 짜는게 핵심이라고 이야기하지 않았는가?
해당 책을 보며 먼저 내가 할 수 있는 최선을 다한 후 공부를 진행하며 추후 리펙토링을 하며 내가 부족한 부분을 찾아보면 더 습득할 부분이 많아지지 않을까 싶었다.
'BOOK' 카테고리의 다른 글
[BOOK: 오브젝트 7장] 객체 분해 (0) | 2022.11.11 |
---|---|
[BOOK: 오브젝트 6장] 메시지와 인터페이스 (0) | 2022.11.07 |
[BOOK : 오브젝트 4장] 설계 품질과 트레이드 오프 (0) | 2022.10.30 |
[BOOK : 3장] 역할, 책임, 협력 (2) | 2022.10.27 |
[BOOK : 클린코드 1장] 깨끗한 코드 (0) | 2022.10.23 |