애플리케이션의 핵심 로직을 담당하는 Application 계층에서 특정 기술을 의존하지 않도록 의존관계를 끊어냄.
서비스 계층에서는 내부 인터페이스 통해 기능을 호출하고, 실제 기능 구현은 영속성 계층에서 구현함.
별도의 인터페이스를 두어야하기 때문에 구조가 복잡해지는 단점이 존재한다.
그 외 아키텍처
특정 기술을 끊어내고자 하는 관점은 클린 아키텍처, 헥사고날 아키텍처 등의 아키텍처에도 주장하는 핵심 요지이다.
내부에서 계층을 어떻게 부르느냐, 어느 단위로 쪼개느냐의 차이가 있는 정도이다.
이들의 본질은 결국 의존성 역전을 적용한 레이어드 아키텍처 와 일맥상통하다.
아키텍처 선택
우리 서비스에서는 헥사고날 아키텍처의 아이디어를 적용해서 기능을 구현했다.
다만 일부 간단하게 구현가능한 모듈단위에서는 헥사고날 아키텍처를 굳이 사용하지 않아도 될듯하여, 간소화하기도 했다.
단일모듈의 한계
아키텍처를 결정하고 실제 코드로 구현하려고 해보면, 결국 맞닥들이게 되는 문제가 있다.
계층의 의존 방향을 통제하기 어려운 점이다.
단순히 패키지 기능만으로는 의존성의 방향을 완벽히 통제할 수 없다.
기능 구현의 편의를 위해 애플리케이션 계층에 영속성 계층의 코드를 둔다거나 하는 문제 등...
다른 맥락의 코드를 재활용하려는 유혹에 빠지기 쉽고, 다른 맥락의 의존을 가진 코드를 작성하게 되면서 기능 분리가 힘들어질 수 있다.
게시글 개념이 게시글 좋아요 개념을 알게되고, 게시글 좋아요 개념이 게시글 개념을 안다고 생각해보자.
이들 기능이 서로 강하게 결합되게 되면, 이후 좋아요 기능만을 따로 빼서 서비스를 분리하기 어려워진다.
단일 모듈은 이런 계층방향, 개념 맥락 등에 대해서 제약을 두지 못 하는 한계가 있다.
느슨한 제약은 오히려 모호한 코드를 만들 수 있고, 향후 기능을 독립적으로 발전시키는데 장애를 만들 수 있다.
빌드 테스트를 위해 전혀 상관없는 기술도 끌어서 빌드해야한다.
표현계층 기능만 테스트 해보고 싶으나, 데이터베이스를 작동시켜야 하거나.
데이터베이스 테스트만 해보고 싶은데, 레디스도 따로 또 켜야하거나.
멀티모듈
관련있는 계층끼리 모듈화시킬 수 있다.
공통적으로 의존할 수 있는 기능은 따로 모듈을 분리하여 재사용할 수 있게 하고, 전혀 상관없는 맥락들은 의존을 시키지 않는다.
계층의 의존방향을 통제한다.
표현 계층 모듈에서는 도메인 계층의 지식을 모르게 함을 강제한다.
애플리케이션 계층에서는 영속성 계층의 지식을 모르게 함을 강제한다.
게시글 맥락은 게시글 좋아요에 대한 지식을 모르게 함을 강제한다.
게시글 댓글 맥락은 게시글 좋아요에 대한 지식을 모르게 함을 강제한다.
향후 서비스 규모가 커졌을 때, 모듈 단위로 서비스를 독립, 분리시키기 쉬워진다.
모듈 구성
board-system-app : 실행 모듈 (설정 구성)
board-system-common
core : 공통 코어 지식 및 기능(전 계층 공용), 외부 기술 연결 포트
data-serializer : 데이터 직렬화(JSON)
id-generator: 식별자 생성기(snowflake)
logger : 로깅
token : 액세스토큰/리프레시토큰 도메인 지식, 외부 기술 연결 포트
board-system-user: 사용자
user-web-adapter : 웹 API 진입점 (표현계층)
user-application-input-port : 애플리케이션 서비스 진입점(인터페이스)
user-application-service : 애플리케이션 서비스 구현
user-application-output-port : 외부기술 연결 포트
user-domain : 도메인 지식, 정책
user-email-format-validate-adapter: 사용자 이메일주소 포맷 검증기[외부기술]
user-oauth2-client-adapter: OAuth2 관련 설정, 소셜서비스 토큰/사용자정보 획득 기능 구현[외부 기술]
user-password-adapter: 패스워드 인코딩 기술[외부 기술]
board-system-board: 게시판
board-web-adapter : 웹 API 진입점 (표현계층)
board-application-input-port : 애플리케이션 서비스 진입점(인터페이스)
board-application-service : 애플리케이션 서비스 구현
board-application-output-port : 외부기술 연결 포트
board-domain : 도메인 지식, 정책
board-system-article: 게시글
article-web-adapter : 웹 API 진입점 (표현계층)
article-application-input-port : 애플리케이션 서비스 진입점(인터페이스)
article-application-service : 애플리케이션 서비스 구현
article-application-output-port : 외부기술 연결 포트
article-domain : 도메인 지식, 정책
board-system-article-comment: 게시글 댓글
article-comment-web-adapter : 웹 API 진입점 (표현계층)
article-comment-application-input-port : 애플리케이션 서비스 진입점(인터페이스)
article-comment-application-service : 애플리케이션 서비스 구현
article-comment-application-output-port : 외부기술 연결 포트
article-comment-domain : 도메인 지식, 정책
board-system-article-like : 게시글 좋아요
article-like-web-adapter : 웹 API 진입점 (표현계층)
article-like-application-input-port : 애플리케이션 서비스 진입점(인터페이스)
article-like-application-service : 애플리케이션 서비스 구현
article-like-application-output-port : 외부기술 연결 포트
article-like-domain : 도메인 지식, 정책
board-system-article-view : 게시글 조회수 처리
article-view-web-adapter : 웹 API 진입점 (표현계층)
article-view-application-input-port : 애플리케이션 서비스 진입점(인터페이스)
article-view-application-service : 애플리케이션 서비스 구현
article-view-application-output-port : 외부기술 연결 포트
article-view-domain : 도메인 지식, 정책
board-system-article-read : 게시글 조회 특화
article-read-web-adapter : 웹 API 진입점 (표현계층)
article-read-application-input-port : 애플리케이션 서비스 진입점(인터페이스)
article-read-application-service : 애플리케이션 서비스 구현
article-read-application-output-port : 외부기술 연결 포트
article-read-domain : 도메인 지식, 정책
board-system-email-sender: 이메일 발송처리 (이벤트 구독, 이메일 발송 외부 기술)
board-system-infrastructure: 외부기술
database-adapter: 관계형 데이터베이스 접근기술
event-publisher : 애플리케이션 내부 이벤트 발행기
jwt : 액세스토큰/리프레시토큰 JWT 기술 처리
redis-adapter: Redis 접근기술
web-support: 웹 관련 공통 기술(인증/인가, 예외 API, 로케일, 메시지)
board-system-test : 테스트 관련
rest-docs-support : Rest Docs 문서화테스트 관련 공통 기능, 설정
모듈간 관계
web-adapter 에 위치한 ~~~Controller 는 application-input-port 에 위치한 ~~UseCase 를 호출한다.
application-service 에 위치한 ~~~ApplicationService 는 ~~~UseCase 를 구현했다.
~~~ApplicationService 는 기본적으로 요청을 애플리케이션 명령으로 변환하는 ~~~CommandMapper, 명령을 처리하는 ~~~Processor 를 통해 요청을 처리한다.
application-service 의 기능들은 domain 에 위치한 도메인 개념, 정책에 기반하여 동작하고, 애플리케이션 기능 구현을 위해 외부 기술이 필요할 경우 application-output-port 에 위치한 ~~~~Port 들을 사용하여 외부 기능을 사용한다.
application-output-port 의 포트 인터페이스를 database-dapter, redis-adapter 와 같은 외부 어댑터에서 구현한다.