본문 바로가기
디프만

헥사고날 아키텍처(Hexagonal Architecture)

by 위대한초밥V 2023. 11. 30.

디프만 프로젝트를 하면서 패키지 구조에 대한 고민이 시작되었다. 우리 팀은 헥사고날 아키텍처 구조를 사용해서 프로젝트를 진행하기로 하였다.

프로젝트 시작전에 아키텍처에 대한 이해를 먼저 하기로 해서 공부를 시작한다.

 

계층형 아키텍처란?

이전에 프로젝트할 때, 만들어본 예제를 헥사고날 아키텍처로 변경한다.

 

1. 패키지 구조

의존성 방향은 다음과 같다.

controller -> service -> repository

 

2. 계층형 아키텍처의 단점

  1. 데이터베이스 주도 설계를 유도한다
    • 객체지향 설계를 위해 도메인 중심으로 설계하는 것이 필요하다. 도메인 로직을 만들고, 영속성 계층과 웹계층을 만들어야 한다. ORM(Object-Relational Mapping)을 사용하다보면, 자연스럽게 데이터베이스 중심의 아키텍처를 만들게 된다.
    • 웹 - 도메인 - 영속성 계층으로 이루어진 구조에서 웹계층은 도메인에, 도메인은 영속성에 의존하여 결국 데이터베이스에 의존하게 된다.
  2. 지름길을 택하기 쉬워진다
    • helper, utility 컴포넌트가 영속성 계층에 자리잡게 된다.
  3. 테스트가 어려워진다
    영속성 계층에서 엔티티에 접근해서 조작하는 상황이 된다.
    이 경우에 다음의 문제점이 생긴다.
    • 간단한 로직이라도 도메인 로직이 웹 계층에 구현되게 된다.
    • 테스트 시에 도메인 계층 뿐만 아니라 영속성 계층을 함께 모킹해줘야 한다.
  4. 유즈케이스를 숨긴다
    계층형 아키텍처에서는 새로운 기능을 추가하거나, 변경할 때 적절한 위치를 빠르게 찾는데 위해서이다.
  5. 동시 작업이 어려워진다
    계층형 아키텍처에서는 웹 - 도메인 - 영속성 계층을 옮겨다니면서 개발할 일이 있다. 따라서 각 계층을 나누어 작업하는 것도 어렵고, 서로 다른 기능을 맡아서 하는 경우에도 같은 서비스를 동시에 편집하는 경우가 발생하기 때문에 어렵다.

헥사고날 아키텍처

1. 헥사고날 아키텍처 구성 요소
내부(in)와 외부(out)
헥사고날 아키텍처는 in(도메인)와 out(인프라)로 구분된다.

  • in: 비즈니스 로직만을 캡슐화된 영역으로 기능적 요구사항에 따라 먼저 설계된다(REST API)
  • out: 내부 영역에서 기술을 분리하여 구성한 영역으로 내부 영역 설계 이후 설계된다(RDB, Redis + ORM, JPA)

포트와 어댑터

  • 포트(port): 내부 비즈니스 영역을 외부에 노출시키는 API를 말한다.
    • 인바운드 포트: 내부 영역을 사용하기 위해 노출된 API
    • 아웃바운드 포트: 내부 영역이 외부 영역을 사용하기 위한 API
  • 어댑터(adapter): 인프라나 web과 같은 낮은 층들이 도메인 로직에 접근할 수 있는 포트를 사용할 수 있게 한다.

2. 헥사고날 아키텍처로 변경하기

만들면서 배우는 클린 아키텍처에 나와있는 예제 코드를 보면서 구조를 변경해보았다.
GitHub - wikibook/clean-architecture: 《만들면서 배우는 클린 아키텍처》 예제 코드

 

GitHub - wikibook/clean-architecture: 《만들면서 배우는 클린 아키텍처》 예제 코드

《만들면서 배우는 클린 아키텍처》 예제 코드. Contribute to wikibook/clean-architecture development by creating an account on GitHub.

github.com

 

adapter, application, domain 패키지 생성하기

main

ㄴ java.com.example.board
  ㄴ user
    ㄴ adapter
        ㄴ in
            ㄴ web
        ㄴ out
            ㄴ persistence
    ㄴ application
        ㄴ port
            ㄴ in
            ㄴ out
        ㄴ service
    ㄴ domain

 

adapter, application, domain 패키지를 갖는다.

adapter는 in/out 패키지를 갖고, application은 port, service를 갖는다.

 

application

- 입/출력

- 비즈니스 규칙 검증

- 모델 상태 조작

UseCase 인터페이스가 존재하고, 해당하는 구현체가 존재한다.

service는 port를 통해 입출력이 이루어진다. 이를 통해 adapter와 통신하게 된다.

 

adapter

  • 요청을 자바 객체로 매핑
  • 권한 및 입력 유효성 검증
  • 입력을 유스케이스 입력 모델로 매핑
  • 유스케이스 호출
  • 유스케이스 출력을 HTTP로 매핑
  • 응답 반환

 

domain
영속성 계층을 말한다.

  • 데이터베이스 형식으로 매핑한다.
  • 입력을 데이터베이스로 보낸다.
  • 데이터베이스 출력을 애플리케이션으로 매핑한다.
  • 출력을 반환한다.

 

의도적으로 계층형 아키텍처에서 벗어나 port, adapter 개념을 이용해 분리한다는 점이 인상깊었다. 또 패키지명과 클래스명이 이해하기 편했다.

다만 코드가 너무 늘어나서 오히려 관리해야 하는 포인트가 늘어날 것 같다는 생각이 들었다. 어떤 것이 더 좋다 라는 것은 없지만, 잘 이해하고 사용을 결정하면 좋을 것 같다.

반응형