아키텍처

헥사고날(포트/어댑터) 아키텍처 맛보기

infitry 2023. 2. 26. 18:46
반응형

헥사고날 아키텍처

헥사고날 아키텍처에 대해 정리해 보겠습니다.

순서는 다음과 같습니다.

  1. 용어정리
  2. 헥사고날 아키텍처 장/단점
  3. 패키지 구조
  4. 개발 순서 및 각 계층별 개발방법

학습 후 생각이 곁들여져 있기 때문에 부족한 부분이나 다른 점이 있을 수 있다는 점 참고 부탁드립니다.😅

1. 용어 정리

  • Port : 어플리케이션과 어댑터를 연결해주는 인터페이스
  • Adapter : 포트를 통해 어플리케이션에 접근하거나 동작하는 외부 시스템 ( 웹, 영속성, 외부 API 등)
  • 주요소 (Primary) : 외부에서 요청해야 동작하는 포트와 어댑터, 주 포트, 주 어댑터라고 부릅니다.
  • 부요소 (Secondary) : 어플리케이션에 의해 동작하는 포트와 어댑터, 부 포트, 부 어댑터라고 부릅니다.

2. 헥사고날 아키텍처 장/단점

  • 장점
    결합도를 낮추고 응집도를 높인다.
    각 유스케이스 별로 모델을 생성하여 유스케이스를 명확히 이해하고 유스케이스 별로 결합도가 낮기 때문에 유지보수를 쉽게 한다.
    추후 어댑터가 변경되어도 어플리케이션을 수정할 필요가 없고 어댑터는 포트만 알고 있으면 된다.
    해당 도메인을 모르는 개발자가 보더라도 UseCase 파일로 해당 도메인이 어떤 일을 하는지 파악할 수 있다.
  • 단점
    초기 개발 시 생산성이 떨어질 수 있다. ( 각 유스케이스 별 클래스 생성 및 유스케이스 별 모델 생성 )
    기존 3계층 구조에 익숙한 개발자가 많다.
    계층 간 결합도가 낮기 때문에 모델 매핑 작업이 많다. (매핑 전략 정하는 것도 힘들어 보인다.)

3. 도메인 별 패키지 구조 한눈에 보기

adapter의 in / out 에는 항상 웹 어댑터 혹은 영속성 어댑터만 오는 게 아니라 
상황에 따라 유동적으로 변경 될 수 있습니다.
패키지 구조는 꼭 하단과 같이 맞춰야 하는 것은 아닙니다.
헥사고날 아키텍처를 강제할 수 있는 다른 패키지 모습 또는 명칭이 있다면 변경 가능합니다.

- adapter
	ㄴ in (주 어댑터)
		ㄴ web ( 컨트롤러 )
	ㄴ out (부 어댑터)
		ㄴ persistence ( 영속성 )

- application
	ㄴ port ( 어플리케이션 in / out 포트 )
		ㄴ in (유스케이스, 커맨드 )
		ㄴ out ( 어플리케이션에서 영속성 or 외부 시스템으로 나가는 인터페이스 )
	ㄴ service ( 유스케이스 구현체 )

- domain ( 엔티티, VO, 정책 등 도메인 관련 )

 

4. 개발 순서

3 계층 아키텍처와는 달리 헥사고날 아키텍처에서의 개발은 도메인 모델링부터 시작됩니다.
3 계층 아키텍처에서는 테이블부터 설계한 후 개발을 진행하지만, 헥사고날 아키텍처에서는 도메인부터 모델링한 후
애플리케이션 계층 (3 계층 에서의 도메인[서비스] 계층과 유사합니다.)을 먼저 개발합니다. 
의존성 역전의 법칙으로 인해 애플리케이션을 호출하는 어댑터나 애플리케이션에 의해 호출되는 어댑터를 몰라도 개발할 수 있습니다.
(인터페이스로 생성하면 되기 때문)
따라서 도메인 모델링 -> 유스케이스 작성 -> 영속성 / 웹 어댑터 작성 순으로 이루어집니다.
아직은 도메인 모델링에 대한 확신이 없고 모든 도메인 상황에 맞춰 모델링할 자신이 없어 해당 글에서는 도메인 모델링은 다루지 않습니다. ( 추후 업데이트 하겠습니다. 😅)

 

5. 유스케이스 구현하기

  • 기본적인 유스케이스의 책임
    → 입력을 받는다. → 비즈니스 규칙을 검증한다. → 모델 상태를 조작한다. → 출력을 반환한다.

  • 입력 유효성 검증
    모든 어댑터(웹 또는 다른 주도하는 어댑터)가 유효성검증을 했다고 믿을 수 없기 때문에 유효성검증은 어플리케이션 계층
    UseCase의 Command  에서 진행합니다. ( 매핑 전략에 따라 달라질 수 있습니다. )
    매핑 전략은 매핑하지않기, 단방향, 양방향, 완전 매핑 등이 있습니다.
    헥사고날 아키텍처 맛보기 이기도하고, 상황에 맞추어 전략을 다르게 가져가야 하는 모호한 부분이라
    해당 글에서는 다루지 않겠습니다.

  • 비지니스 규칙 검증하기
    비즈니스 규칙은 모델에 접근해야 검증할 수 있는 것들 입니다.
    예를 들어 “주문의 재고는 0 미만이 될 수 없다.” 라는 규칙은 모델의 현재 상태에 접근해야 알 수 있습니다.
    하지만 “주문의 최소 주문 개수는 1개 이상이어야 한다.” 라는 규칙은 모델에 접근하지 않고도 검증될 수 있습니다.
    비즈니스 규칙을 검증하는 방법에는 두 가지가 있습니다.
    비즈니스 규칙 검증을 각 유즈케이스에서 하는 방법 (빈약한 도메인 모델)
    또는 각 엔티티에서 하는 방법 (부유한 도메인 모델) 이 있습니다.

6. 웹 어댑터 구현하기

  • 웹 어댑터의 책임
    HTTP 요청 수신, 파라미터 콘텐츠 직렬화, 인증, 권한 부여, 에러 반환, 객체 유효성검증
    객체 유효성 검증의 경우 유스케이스와 동일한 유효성 검증이 아닌, 웹 어댑터의 입력 모델을 유스케이스 입력모델로 변환할 수 있다는 것을 검증해야 합니다.

  • 컨트롤러 나누기
    같은 패키지 수준에 놓고, 너무 적은 것보다는 많은 것이 좋습니다.
    각 컨트롤러가 가능한 한 좁고 다른 컨트롤러와 가능한 한 적게 공유하는 웹 어댑터 조각을 표현해야 합니다.

7. 영속성 어댑터 구현하기

  • 영속성 어댑터의 책임
    영속성 어댑터의 입/출력 모델은 어플리케이션에 존재하기 때문에 영속성 어댑터를 변경하는 것이 코어에 영향을 미치지 않는다.
    영속성 어댑터에 의해 어플리케이션의 입/출력 모델을 변경하는 일은 없어야 합니다.

  • 포트 인터페이스 나누기
    ISP(인터페이스 분리원칙) 에 의해 포트 당 하나의 메서드만 두고 역할을 포트의 이름으로 표현
    포트 하나당 하나의 메서드는 모든 상황에서 적용될 수 없습니다.
    필요하다면 여러 메서드의 집합을 만들어 사용할 수 있습니다.

  • 트랜잭션
    트랜잭션은 영속성 어댑터를 호출하는 서비스(유스케이스)에 위임해야 합니다.

8. 후기 및 정리

항상 3 계층 구조로만 개발을 하다 헥사고날 아키텍처를 처음 접했을 때는 정말 헷갈렸습니다.
포트와 어댑터 개념이 이해가 안 가기도 하고 각 계층 별 매핑 전략을 정하는 부분 그리고 3 계층 구조에 너무 익숙해져 버린 자신🥲과 데이터베이스부터 설계하는 것에 대한 익숙함 때문이었던 것 같습니다.
확실한 건 3 계층 구조보다는 좀 더 어댑터와 애플리케이션 간의 결합도를 낮출 수 있고 패키지 레벨 제한을 두어 어느 정도 강제할 수도 있는 것 같습니다.
또한 처음 보는 사람이 해당 도메인에 대한 프로젝트를 보더라도 유즈케이스 별로 파일을 나누어 해당 도메인에 대한 어떤 유즈케이스가 있는지도 한눈에 확인할 수 있을 것 같고, 각 유즈케이스 별로 영향을 받지 않는 것도 여러 개발자가 유지보수하기 편할 것 같습니다.

반응형