35장. 헥사고날 아키텍처
34장에서 우리는
의존성의 문제를 살펴봤다.
- 변하지 않아야 하는 것이
- 변하는 것에 의존하면
- 시스템은 계속 흔들린다
그래서 우리는 결론을 얻었다.
외부 기술이 비즈니스 로직에 의존해야 한다
그렇다면 질문이 남는다.
이 개념을 시스템 구조로 만들 수 있을까?
그 답이
헥사고날 아키텍처 (Hexagonal Architecture)
이다.
헥사고날 아키텍처란 무엇인가
헥사고날 아키텍처는
시스템을 다음과 같이 구성한다.
[외부] → [Adapter] → [Port] → [Domain]
핵심은 이것이다.
도메인은 외부를 모른다
왜 “헥사고날”인가
이 구조는
여러 방향으로 연결될 수 있는 형태를 가진다.
즉,
- DB
- Kafka
- 외부 API
- 테스트 코드
모두 동일한 방식으로
도메인에 연결된다.
기존 구조와 비교
레이어 아키텍처
Controller → Service → Repository
문제:
- Service가 모든 것을 안다
- DB, Kafka, API가 섞인다
헥사고날 아키텍처
외부 → Adapter → Port → Domain
특징:
- 외부는 Adapter에서 처리
- Domain은 순수하게 유지
핵심 구성 요소
1️⃣ Domain (도메인)
비즈니스 로직이 존재하는 곳이다.
예:
- 주문 생성
- 결제 처리
- 상태 전이
도메인은
- DB를 모르고
- Kafka를 모르고
- API도 모른다
비즈니스 규칙만 가진다
2️⃣ Port (포트)
도메인이 외부와 통신하기 위한 인터페이스다.
예:
- 저장 포트
- 이벤트 발행 포트
- 외부 서비스 호출 포트
포트는
무엇을 할 것인가만 정의한다
3️⃣ Adapter (어댑터)
포트를 실제로 구현하는 영역이다.
예:
- DB Repository
- Kafka Producer
- HTTP Client
- Outbox / Inbox 처리
어댑터는
어떻게 할 것인가를 담당한다
의존성 방향
헥사고날에서 가장 중요한 규칙이다.
Adapter → Port → Domain
의존성은 항상 도메인 방향으로 향한다
이벤트 시스템에 적용하면
지금까지 배운 내용을
헥사고날로 보면 이렇게 정리된다.
이벤트 발행 (Outbox)
Domain → EventPort → OutboxAdapter
- Domain은 이벤트 발행을 요청한다
- 실제 저장은 Outbox Adapter가 수행한다
이벤트 소비 (Inbox)
ConsumerAdapter → Domain
- Kafka Consumer는 Adapter
- Domain은 처리만 수행한다
중요한 변화
이 구조에서 가장 중요한 변화는 이것이다.
도메인은 외부 기술을 전혀 모른다
이 구조가 주는 장점
1️⃣ 비즈니스 로직 보호
도메인은
- DB 변경
- 메시지 시스템 변경
에 영향을 받지 않는다
2️⃣ 테스트 용이성
외부 의존 없이
도메인을 단독으로 테스트할 수 있다
3️⃣ 기술 교체 가능
- Kafka → SQS
- MySQL → DynamoDB
→ Adapter만 교체하면 된다
4️⃣ 확장성
새로운 기능은
Adapter 추가로 해결 가능
단점
1️⃣ 초기 복잡도
구조를 나누는 데 시간이 필요하다
2️⃣ 코드 증가
포트와 어댑터로 인해 코드가 늘어난다
3️⃣ 과도한 설계 위험
작은 서비스에서는
오히려 과한 구조가 될 수 있다
언제 사용하는가
다음과 같은 경우에 적합하다.
- 이벤트 기반 시스템
- 외부 의존성이 많은 서비스
- 장기적으로 유지보수해야 하는 시스템
전체 흐름을 다시 보면
지금까지 우리는
다음 단계를 거쳐왔다.
문제 (중복, 순서, 유실)
→ 해결 (Outbox, Inbox, 멱등성)
→ 구조 (헥사고날)
핵심 메시지
헥사고날 아키텍처의 본질은 이것이다.
비즈니스 로직을 외부로부터 보호하는 구조
이 장의 핵심
- 의존성 방향을 통제해야 한다
- 도메인은 외부 기술을 몰라야 한다
- 포트는 역할을 정의한다
- 어댑터는 구현을 담당한다
- 헥사고날은 이 구조를 만드는 방법이다