애플리케이션 내부 아키텍처 결정(with. 멀티모듈) - ttasjwi/board-system GitHub Wiki

개요

  • 애플리케이션을 설계 할 때 내부 코드를 어떤식으로 배치할 지, 전체적인 큰 틀을 결정해야한다.

아키텍처 후보

  • 레이어드 아키텍처
    2010s-layered-architecture
    • Presentation → Application → Domain → Persistence
    • 단순하고 간단하며, 실무에서도 이 구조를 많이 사용함.
    • 의존성 방향의 끝에 영속성 계층이 위치해있고, 영속성 기술에 강하게 결합된 애플리케이션 로직이 구현되는 문제가 있음
  • 의존성 역전을 적용한 레이어드 아키텍처
    1_SYDIrH4ctHDt3N4M6dgMrw
    • Presentation -> Application / Domain <----------------- Persistence
    • 애플리케이션의 핵심 로직을 담당하는 Application 계층에서 특정 기술을 의존하지 않도록 의존관계를 끊어냄.
    • 서비스 계층에서는 내부 인터페이스 통해 기능을 호출하고, 실제 기능 구현은 영속성 계층에서 구현함.
    • 별도의 인터페이스를 두어야하기 때문에 구조가 복잡해지는 단점이 존재한다.
  • 그 외 아키텍처
    hexagonal-architecture-vs-clean-architecture-1 v4-800x312
    • 특정 기술을 끊어내고자 하는 관점은 클린 아키텍처, 헥사고날 아키텍처 등의 아키텍처에도 주장하는 핵심 요지이다.
    • 내부에서 계층을 어떻게 부르느냐, 어느 단위로 쪼개느냐의 차이가 있는 정도이다.
    • 이들의 본질은 결국 의존성 역전을 적용한 레이어드 아키텍처 와 일맥상통하다.

아키텍처 선택

  • 우리 서비스에서는 헥사고날 아키텍처의 아이디어를 적용해서 기능을 구현했다.
  • 다만 일부 간단하게 구현가능한 모듈단위에서는 헥사고날 아키텍처를 굳이 사용하지 않아도 될듯하여, 간소화하기도 했다.

단일모듈의 한계

  • 아키텍처를 결정하고 실제 코드로 구현하려고 해보면, 결국 맞닥들이게 되는 문제가 있다.
  • 계층의 의존 방향을 통제하기 어려운 점이다.
    • 단순히 패키지 기능만으로는 의존성의 방향을 완벽히 통제할 수 없다.
    • 기능 구현의 편의를 위해 애플리케이션 계층에 영속성 계층의 코드를 둔다거나 하는 문제 등...
  • 다른 맥락의 코드를 재활용하려는 유혹에 빠지기 쉽고, 다른 맥락의 의존을 가진 코드를 작성하게 되면서 기능 분리가 힘들어질 수 있다.
    • 게시글 개념이 게시글 좋아요 개념을 알게되고, 게시글 좋아요 개념이 게시글 개념을 안다고 생각해보자.
    • 이들 기능이 서로 강하게 결합되게 되면, 이후 좋아요 기능만을 따로 빼서 서비스를 분리하기 어려워진다.
  • 단일 모듈은 이런 계층방향, 개념 맥락 등에 대해서 제약을 두지 못 하는 한계가 있다.
    • 느슨한 제약은 오히려 모호한 코드를 만들 수 있고, 향후 기능을 독립적으로 발전시키는데 장애를 만들 수 있다.
  • 빌드 테스트를 위해 전혀 상관없는 기술도 끌어서 빌드해야한다.
    • 표현계층 기능만 테스트 해보고 싶으나, 데이터베이스를 작동시켜야 하거나.
    • 데이터베이스 테스트만 해보고 싶은데, 레디스도 따로 또 켜야하거나.

멀티모듈

  • 관련있는 계층끼리 모듈화시킬 수 있다.
  • 공통적으로 의존할 수 있는 기능은 따로 모듈을 분리하여 재사용할 수 있게 하고, 전혀 상관없는 맥락들은 의존을 시키지 않는다.
  • 계층의 의존방향을 통제한다.
    • 표현 계층 모듈에서는 도메인 계층의 지식을 모르게 함을 강제한다.
    • 애플리케이션 계층에서는 영속성 계층의 지식을 모르게 함을 강제한다.
    • 게시글 맥락은 게시글 좋아요에 대한 지식을 모르게 함을 강제한다.
    • 게시글 댓글 맥락은 게시글 좋아요에 대한 지식을 모르게 함을 강제한다.
  • 향후 서비스 규모가 커졌을 때, 모듈 단위로 서비스를 독립, 분리시키기 쉬워진다.

모듈 구성

  • board-system-app : 실행 모듈 (설정 구성)
    image
  • board-system-common
    image
    • core : 공통 코어 지식 및 기능(전 계층 공용), 외부 기술 연결 포트
    • data-serializer : 데이터 직렬화(JSON)
    • id-generator: 식별자 생성기(snowflake)
    • logger : 로깅
    • token : 액세스토큰/리프레시토큰 도메인 지식, 외부 기술 연결 포트
  • board-system-user: 사용자
    image
    • 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: 게시판
    image
    • board-web-adapter : 웹 API 진입점 (표현계층)
    • board-application-input-port : 애플리케이션 서비스 진입점(인터페이스)
    • board-application-service : 애플리케이션 서비스 구현
    • board-application-output-port : 외부기술 연결 포트
    • board-domain : 도메인 지식, 정책
  • board-system-article: 게시글
    image
    • article-web-adapter : 웹 API 진입점 (표현계층)
    • article-application-input-port : 애플리케이션 서비스 진입점(인터페이스)
    • article-application-service : 애플리케이션 서비스 구현
    • article-application-output-port : 외부기술 연결 포트
    • article-domain : 도메인 지식, 정책
  • board-system-article-comment: 게시글 댓글
    image
    • 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 : 게시글 좋아요
    image
    • 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 : 게시글 조회수 처리
    image
    • 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 : 게시글 조회 특화
    image
    • 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: 이메일 발송처리 (이벤트 구독, 이메일 발송 외부 기술)
    image
  • board-system-infrastructure: 외부기술
    image
    • database-adapter: 관계형 데이터베이스 접근기술
    • event-publisher : 애플리케이션 내부 이벤트 발행기
    • jwt : 액세스토큰/리프레시토큰 JWT 기술 처리
    • redis-adapter: Redis 접근기술
    • web-support: 웹 관련 공통 기술(인증/인가, 예외 API, 로케일, 메시지)
  • board-system-test : 테스트 관련
    image
    • rest-docs-support : Rest Docs 문서화테스트 관련 공통 기능, 설정

모듈간 관계

image

  • web-adapter 에 위치한 ~~~Controllerapplication-input-port 에 위치한 ~~UseCase 를 호출한다.
  • application-service 에 위치한 ~~~ApplicationService~~~UseCase 를 구현했다.
  • ~~~ApplicationService 는 기본적으로 요청을 애플리케이션 명령으로 변환하는 ~~~CommandMapper, 명령을 처리하는 ~~~Processor 를 통해 요청을 처리한다.
  • application-service 의 기능들은 domain 에 위치한 도메인 개념, 정책에 기반하여 동작하고, 애플리케이션 기능 구현을 위해 외부 기술이 필요할 경우 application-output-port 에 위치한 ~~~~Port 들을 사용하여 외부 기능을 사용한다.
  • application-output-port 의 포트 인터페이스를 database-dapter, redis-adapter 와 같은 외부 어댑터에서 구현한다.