소프트웨어 아키텍처 시리즈 9화 – 헥사고날 아키텍처와 DDD의 통합 전략: 아키텍처와 도메인이 만나는 지점
헥사고날 아키텍처와 도메인 주도 설계(DDD)는 설계 철학과 기술적 구현에서 밀접하게 연결됩니다. 이 글에서는 두 개념이 어떻게 만나고, 실제 아키텍처에서 어떤 방식으로 통합될 수 있는지를 실무 사례 중심으로 설명합니다.
왜 DDD와 헥사고날 아키텍처는 궁합이 좋을까?
이유는 간단합니다.
두 구조 모두 ‘도메인’을 중심에 두고, 외부 기술 요소들을 경계 밖으로 밀어내는 철학을 공유하기 때문입니다.
개념핵심 가치
DDD | 도메인을 현실 모델에 가깝게 표현하고, 유비쿼터스 언어로 통합 |
헥사고날 아키텍처 | 도메인을 외부 기술로부터 분리하고, 포트/어댑터로 유연성 확보 |
즉, DDD는 도메인의 ‘내용’을 다루고,
헥사고날은 도메인의 ‘위치’와 ‘연결 방식’을 다루는 구조적 틀이라고 보면 됩니다.
통합 구조: 계층 vs 동심원 vs 헥사고날
DDD를 실제 아키텍처에 녹여낼 때는 다음 3가지 아키텍처 스타일이 많이 사용됩니다.
- 계층형 DDD – Domain, Application, Infrastructure로 나누는 3계층 구조
- Onion 아키텍처 기반 DDD – 도메인을 중심으로 안쪽에서 바깥으로 의존성이 향하는 구조
- 헥사고날 기반 DDD – 포트를 통해 외부와 단절하고 도메인을 보호
세 방식 모두 동일한 도메인 설계 철학을 따르지만, 헥사고날 구조는 도메인과 외부의 연결을 더욱 유연하고 명시적으로 표현할 수 있다는 점에서 큰 장점이 있습니다.
포트와 도메인 서비스의 역할 정립
헥사고날 구조 안에서 DDD의 주요 컴포넌트를 어떻게 배치할 수 있는지 살펴보겠습니다.
DDD 요소헥사고날 내 위치설명
Entity / Value Object | Domain Core | 비즈니스 핵심 개념을 캡슐화 |
Domain Service | Domain Core | 복잡한 도메인 로직을 모델 외부에 위치 |
Repository Interface | Outbound Port | 도메인이 의존하는 저장소 인터페이스 |
Application Service | Inbound Port 구현 | 유즈케이스 흐름, 트랜잭션 제어 담당 |
Adapter (JPA, REST 등) | 어댑터 | 외부 기술과 포트를 연결하는 구현체 |
여기서 핵심은, 도메인 로직은 절대 기술 의존성을 갖지 않아야 하며, 포트를 통해 외부와 통신해야 한다는 점입니다.
유스케이스 기반 설계와 Aggregate 중심 도메인
실제 시스템을 설계할 때는 도메인 모델을 먼저 설계하고, 그 위에 유스케이스를 구성합니다.
- 유스케이스는 Inbound Port로 인터페이스화되어 Application Layer에 위치
- 도메인 모델은 Aggregate를 중심으로 구성되고, 변경 불가능한 값(Value Object)과 명확한 경계(Bounded Context)를 지님
- Application Service는 트랜잭션 단위로 도메인 로직을 호출하며, 필요한 외부 연동은 Outbound Port를 통해 수행
이러한 흐름은 업무 흐름(Use Case) 중심 + 도메인 모델 중심의 결합으로, 복잡한 비즈니스 로직을 안정적으로 다룰 수 있게 합니다.
통합 전략의 실전 예시 – ‘주문 생성’ 유스케이스
도메인 모델:
- Order (Aggregate Root)
- OrderLine, Product, ShippingInfo (Value Object)
포트 정의:
// Inbound Port
public interface PlaceOrderUseCase {
void placeOrder(OrderRequestDto dto);
}
// Outbound Port
public interface PaymentProcessor {
PaymentResult requestPayment(PaymentInfo info);
}
Application Service (Inbound Adapter):
public class PlaceOrderService implements PlaceOrderUseCase {
private final OrderRepository orderRepository;
private final PaymentProcessor paymentProcessor;
public void placeOrder(OrderRequestDto dto) {
Order order = Order.create(dto); // 도메인 로직
PaymentResult result = paymentProcessor.requestPayment(order.getPaymentInfo());
if (result.isSuccess()) {
order.markAsPaid();
}
orderRepository.save(order);
}
}
도메인은 기술과 전혀 연결되지 않으며, 필요한 외부 기능은 전부 포트로 추상화되어 Application이 연결합니다.
마이크로서비스와의 연결점
헥사고날 + DDD 구조는 바운디드 컨텍스트를 마이크로서비스의 경계로 정의하기에 매우 적합합니다.
- 각 서비스는 자신만의 도메인 모델, 포트, 어댑터를 가짐
- 서비스 간 통신은 Event나 API를 통해 비동기/동기로 수행
- DDD의 언어적 통일성과 헥사고날의 구조적 명확성이 독립성과 유연성을 동시에 확보함
오해와 위험 요소
- 헥사고날 구조를 도입했다고 해서 DDD가 자동으로 구현되는 건 아닙니다.
- 많은 팀이 **‘포트/어댑터만 나누고, 도메인은 여전히 CRUD 중심’**으로 남아 있는 경우가 있습니다.
- 진짜 DDD는 업무 개념을 코드로 설계하는 과정입니다. 헥사고날은 이를 도울 수 있는 ‘그릇’일 뿐입니다.
도메인을 중심에 둘 수 있는 아키텍처
헥사고날 아키텍처는 단순히 포트를 나누는 기술적 구조가 아닙니다.
도메인을 외부 기술로부터 지켜내고, 오직 비즈니스의 흐름과 책임만으로 시스템을 설계할 수 있게 도와주는 강력한 틀입니다.
도메인 주도 설계는 복잡한 비즈니스 문제를 소프트웨어 모델로 표현하기 위한 방법론이며,
헥사고날 아키텍처는 그 표현을 깔끔하게 현실 시스템에 구현하는 방법론입니다.
두 철학이 만나면, 시스템은 훨씬 더 강건하고 변화에 유연해집니다.