헥사고날 아키텍처는 비즈니스 로직(핵심 도메인)을 외부의 관심사(DB, 연동 서비스)등으로 부터 분리하는 것을 목표로 하는 아키텍처다. 애플리케이션 핵심 비즈니스 로직을 육각형(hexagon)안에 두고, 외부 세계와의 상호작용은 포트와 어댑터라는 인터페이스를 통해 이루어지도록 설계하는 것이다. 육각형이라는 것은 그림을 보면 좀 더 이해가 쉽다

그림과 같이 IN, OUT이라는 개념이 존재하고 어댑터와 어플리케이션을 연결하는 포트를 통해서 연결되고 있음을 볼 수 있다.
도메인(Domain)
포트(Port)
Usecase로 정의한다.Port로 정의한다.어댑터(Adapter)
controller가 이에 해당한다.repository가 이에 해당한다.MVC 패턴과 비교해서 헥사고날은 어떤 구조를 가지는 차이점을 알아보자.
com.example.app
├── controller/
│ ├── UserController.java
│ └── ProductController.java
├── model/
│ ├── User.java
│ └── Product.java
├── service/
│ ├── UserService.java
│ └── ProductService.java
├── repository/
│ ├── UserRepository.java
│ └── ProductRepository.java
└── ...
보통은 이런식으로 controller / model / service / reposiotry로 분리하여 패키지 구조를 구성할 것이다. 도메인별로 구성하는 경우도 있는데 어쨋든, 여기에는 외부시스템과의 구별은 없다. 요즘은 MSA처럼 도메인마다 어플리케이션이 분리되는 구조에다가, 다양한 외부 시스템을 이용해서 어플리케이션을 개발하는데 변경되는 부분들이 많다면 이러한 구조는 결합도가 높다고 볼 수 있다.
com.example.app
├── domain/ // 핵심 비즈니스 로직
│ ├── model/ // 엔티티, 값 객체 등
│ │ ├── User.java
│ │ └── Product.java
│ ├── usecase/ // 비즈니스 행위
│ │ ├── CreateUserUseCase.java
│ │ └── PlaceOrderUseCase.java
│ ├── port/ // 외부 시스템과의 상호작용
│ │ ├── UserRepositoryPort.java
│ │ └── PaymentGatewayPort.java
│ └ service/
│ └── OrderService.java
├── adapter/ // 외부 시스템과의 상호작용을 처리하는 어댑터
│ ├── in/ // 외부 요청을 핵심 도메인으로 전달
│ │ ├── rest/
│ │ │ └── UserRestController.java
│ │ └── cli/
│ │ └── UserCommandLineAdapter.java
│ ├── out/ // 핵심 도메인의 요청을 외부 시스템으로 전달
│ │ ├── persistence/
│ │ │ └── UserRepositoryJpaAdapter.java
└── ...
헥사고날 아키텍처는 JPA나 외부 시스템에 대한 상호작용은 adapter로 분리해놓은 것을 볼 수 있다. 만약 JPA를 쓰지 않고 다른 방식으로 DB 요청을 해야한다면 domain 부분은 건드릴 필요가 없다. usercase와 port라는 인터페이스로 이루어져 구현체인 adpater만 바꿔 개발하면 되기 때문이다.
모든 아키텍처는 항상 좋을 수는 없다. 결론적으로는 나의 어플리케이션의 상황에 맞춰 선택하는것이 중요하다. 내 어플리케이션이 헥사고날 아키텍처에 적합한지 알아보는 것은 중요하다.
1) 장점
2) 단점
그렇기 때문에 헥사고날 아키텍처는 애플리케이션이 다양한 외부시스템과 상호작용해야하는 경우, 데이터베이스 기술이 변경될 가능성이 있는경우, MSA와 같이 다양한 서비스가 존재하고, 또 확장되면서 비즈니스 로직 복잡성이 높아지고 안정적인 테스트가 필요한 경우에 적합하다고 할 수 있다.
다음은 실제 Springboot 와 JPA를 사용해서 어떤식으로 이루어지는지 코드로 알아보려고 한다.