만들면서 배는 클린 아키텍처를 읽고 공부한 내용을 정리. - 1
모든 소스는 이곳에 있습니다:)
계층형 아키텍처의 문제점
1. 서비스에서 영속성에 강한 결합이 생긴다
일반적인 프로젝트 구조상 서비스는 영속성 모델을 비지니스 모델처럼 사용하게 되고 이로 인해 도메인 로직뿐만 아니라 여러 영속성 계층과 관련된 작업들을(트랜잭션, 즉시로딩, 지연로딩, 캐시 플러시)등등을 해야한다.
2. 지름길을 택하기 쉬워진다
여러명이 개발하고 시간이 지나다보면 유틸리티, 헬퍼 등 여러 컴포넌트들이 영속성에 추가하여 개발을 하기쉽고 편하기 때문에 결국 영속성 레이어가 비대해지는 현상이 일어나게된다.
3. 서비스 계층을 스킵 할 수가 있다
간단한 디비 저장일뿐인 단순한 API일 경우 중간에 있는 서비스를 건너뛰고 바로 컨트롤러에서 영속성 계층에 접근을 해서 작업을 할 때가 있는데 이렇게 되면 여러 문제들이 발생 할 수 있다.
첫 번째 문제는 요구사항이 변경이되면 Controller 여러 추가적인 책임들이 추가가되기 쉬워지는데(혼자 할 때는 괜찮지만, 여러사람이 협업을하다 보면), 레이어간의 책임이 정말 애매모호해 지게된다.
두 번째 문제는 테스트 코드에서의 복잡도가 올라가게 된다. mock을 만드는 등 추가적인 작업을 해야 할 필요가 있게되는데 이러면 테스트 코드를 이해하는데도 시간이 더 걸리고 그러면 테스트 코드 짜기가 점점 더 힘들어지고 싫어지게된다.
4. 수정이 힘들어진다.
여러명이 협업을하면서 시간이 흐르다보면 서비스계층의 책임이 점점 많아지게 되는데, 이렇게 진행되다보면 테스트 코드도 짜기가 점점 힘들어지고, 기능을 추가 혹은 수정 해야 할 때 선뜻 사이드 이펙트를 예측하기가 힘들어지게 된다.
기획자: 이거 기획이 추가되어서, 간단한 기능 하나 추가 할 수 있을까요?
나: 음.. 이건 한 번 봐야할 거 같아요. 조금 소스가 복잡해서… (또르륵)
육각형 아키텍쳐(헥사고날)
육각형 아키텍처는 알리스테어 코번이 만든 용어로, 로버트 마틴이 클린 차키텍처에서 조금 더 일반적인 용어로 설명 하였다.
안에는 도메인 엔티티와 이와 상호작용하는 유스케이스가 있다. 육각형 바깥에는 애플리케이션과 상호작용하는 다양한 어댑터들이 있다.
왼쪽에 있는 어댑터들은 애플리케이션을 주도하는 어댑터들이다. 코어와 어댑터들간에 통신을 하려면 각각의 포트들을 제공해야한다. 이 포트들은 인터페이스들이 되는 것이다.
가장 바깥쪽에 있는 계층은 애플리케이션과 다른 시스템 간의 번역을 담당하는 어댑터로 구성되어 있다.
Case마다 다른 출력 모델
항상 나는 이 질문에 고민을 많이 했다. 호출자에게 정보를 어디까지 줘야할까라는 질문에 사실 정답이 없지만, 여러 컨트롤러에서 같은 서비스에 접근을 해야 할 때 처음에는 같은 모델로 돌려주게 개발을 하고 나중에 시간이 지나 점점 눈덩이처럼 점점 커지는 모델들을 경험을 많이 해서 고민이 많았는데 책에서 하는 말이
유스케이스를 가능한 한 구체적으로 유지하기 위해서는 계속 질문을 해야한다. 만약 의심스럽다면 가능한 한 적게 반환하자. 유스케이스들 간에 같은 출력 모델을 공유하게 되면 유스케이스들도 강하게 결합된다. 한 유스케이스에서 출력 모델에 새로운 필드가 필요해지면 이 값과 관련이 없는 다른 유스케이스들에서도 이 필드를 처리해야 한다. 공유 모델은 장기적으로 봤을 때 갖가지 이유로 점점 커지게 돼 있다. 단일 책임 원칙을 적용하고 모델을 분리해서 유지하는 것은 유스케이스의 결합을 제거하는 데 도움이 된다.
웹 어댑터의 책임
- HTTP 요청을 자바 객체로 매핑
- 권한 검사
- 입력 유효성검증
- 유스케이스에서의 입력 모델 검증과 어댑터에서의 검증의 차이는 맥락의 차이인데 유스케이스에서의 입력 모델에서 유효한 입력만 허용해야한다. 내 생각에는 출금과 관련된 유스케이스에서 유스케이스에서 검증 할 때 있을 때 ‘잔금은 돈은 0원 보다 더 커야 한다’ 의 차이 이지 않을까라고 생각든다.
- 입력을 유스케이스의 입력 모델로 매핑
- 유스케이스 호출
- 유스케이스의 출력을 HTTP로 매핑
- HTTP 응답을 반환
Create로 이름을 짖는거는 지양하자
이미 어딘가에 많이 쓰이고 있는 예약어이기 때문에 Create→Register 로 변경하여 이름을 짖자.
CreteAccountController → RegisterAccountController
Create, Update, Delete … naming으로 역할을 만들기 전에 한 번더 생각을 해보는 게 좋다.
여러 작은 클래스들을 만드는 것을 두려워해서는 안된다.
여러 작은 클래스들을 만드는 것을 두려워해서는 안된다. 작은 클래스들은 파악하기 쉽고, 테스트하기 쉽고, 여러명이서 작업을 할 수 있게된다. 처음에는 공수가 더 들겠지만 나중에 유지보수 할 때에는 시간이 단축될 것이다.
영속성 어댑터
영속성 어댑터의 책임
- 입력을 받는다.
- 입력을 데이터베이스 포맷으로 매핑한다.
- 입력을 데이터베이스로 보낸다
- 데이터베이스 출력을 애플리케이션 포맷으로 매핑한다.
- 출력을 반환한다.
요기서도 마찬가지로 평소에 영속성 레포지토리가 여러 책임들을 한 번에 가지고 있는 부분이 많아서 얘를 어떻게 해야하나 고민이많았는데, 이 책에서 ISP를 지키지 않는지 확인해보라고 조언을 해준다. 지키려고 노력을 하다보면 책임을 분산 할 수 있어진다.