헥사고날 아키텍처란?
- 핵심 로직(도메인)과 외부 세계(DB, 웹, 메시징 등)를 깔끔하게 분리하려는 목적을 가지는 소프트웨어 아키텍처 패턴
- 중심에는 비즈니스 로직이 있고 외부와 어댑터로 연결됨
이름이 왜 헥사고날 아키텍처?
- 육각형 자체에 기술적인 의미는 없다.
- 개념을 제안한 개발자 Alistair Cockburn가 중심의 도메인을 둘러싼 어댑터라는 개념을 설명하며 그린 그림이 육각형이라서..🤔
- 개념적으론 포트 앤 어댑터(Ports and Adapters) 아키텍처라는 다른 명칭이 더 알맞다.
왜 헥사고날 아키텍처를 쓸까?
- 기존 구조에서 일어나기 쉬운 문제들
- 웹 요청이 들어오면 컨트롤러 → 서비스 → DB까지 다 엮여있는 경우
- 도메인과 웹이 얽혀 있어서 웹 요청 없이 테스트하기 힘든 경우
- DB를 바꾸려면 비즈니스 로직까지 수정해야 하는 경우
👉 그럼 핵심 로직을 외부 기술에 의존하지 않게 만들면 되지 않나?
헥사고날 아키텍처의 핵심 용어
- Port
- 핵심 로직이 외부와 연결되기 위한 방식을 정리한 인터페이스
- Adapter
- Port의 실제 구현체(DB 가져오기, 외부 API 호출 등)의 역할
- Application Core
- 핵심 로직인 도메인 모델 + 유스케이스
- 외부에 의존하지 않음
🙈이해하기 쉬운 간단 예시
사용자가 포스트를 작성하는 기능이 있다고 했을 때
- PostRepository는 인터페이스 ⇒ Port
- JpaPostRepository는 Spring Data JPA를 사용하는 실제 구현체 ⇒ Adapter
- PostService는 유즈케이스에 해당하는 서비스로 ⇒ Application Core
👉 이 구조 하에서 PostService는 무슨 DB와 연결되었는지 몰라도 동작 가능
😅사실은..
위 예시는 헥사고날 아키텍처의 개념을 간단히 설명하기 위해 레이어드 아키텍처를 빌린 것.
- 우리가 사용하는 기존의 레이어드 아키텍처는 구조적으로 나뉘어져 있지만, 실제로는 도메인 로직이 프레임워크(스프링)에 종속되어 있다.
- 예: @Service, @Repository, @Transactional 같은 Spring 어노테이션이 도메인 로직 곳곳에 박혀 있음
🔥진짜 헥사고날 아키텍처는 더 분리한다!🔥
- 비즈니스 로직을 가장 중요하게 보고, 이를 외부 기술로부터 철저히 보호한다.
- 핵심 로직은 Spring도, JPA도 몰라야 한다. 그냥 자바 객체로만 존재해야 한다.
- 예: 도메인 영역에 속한 엔티티들은 어노테이션 사용 없는 순수한 자바 객체로 존재
- Spring은 단지 접착제 역할만 한다. 즉, 실제 동작은 Adapter에서 일어나고, Core는 완전히 독립적이다.
- @Transaction같은 어노테이션도 Adapter에서만 사용한다
😩이걸 어디까지 분리해야
레이어드 아키텍처가 아니라 헥사고날 아키텍처인가?
항목 어디까지?
도메인 코드 | 어떤 프레임워크도 몰라야 한다. @Service, @Repository 없어야 함 |
유즈케이스 | 인터페이스(Port)에만 의존해야 함. 구현체를 몰라야 함 |
어댑터 | Spring, JPA, 외부 API 등 기술 구체사항은 모두 여기서 처리 |
어노테이션 | @Transactional, @RestController, @Repository 등은 어댑터에만 위치 |
헥사고날 아키텍처의 장점
- 역할이 명확함
- 비즈니스 로직과 구현 세부가 분리됨
- 기술 교체 유연함
- 예: MySQL → MongoDB로 바꿔도 도메인은 그대로
- 코드 구조가 명확해짐
- 어디서 비즈니스가 처리되고 어디서 외부와 연결되는지 쉽게 파악 가능
- 테스트하기 쉬워짐
- 외부 의존성을 신경쓰지 않고 유닛 테스트가 가능해짐
헥사고날 아키텍처의 단점
- 초반엔 개발 속도가 떨어짐
- 계층 분리 비용
- 인터페이스 설계 비용
- 위의 단점으로 인해 작은 규모 프로젝트에서는 오버 엔지니어링
- 도메인 중심 설계에 익숙하지 않으면 너무 난해하게 받아들일 수 있음