WebFlux와 헥사고날 아키텍처가 잘 어울리는 이유는 두 기술의 핵심 철학이 유사하기 때문이다. 둘 다 분리와 유연성을 추구하기 때문이다.
헥사고날 아키텍처는 비즈니스 로직을 데이터베이스, 메시징 시스템, 외부 API 등과 같은 외부 기술로부터 분리한다.
이 분리 작업은 포트(Port)와 어댑터(Adapter)라는 개념을 통해 이루어진다.
WebFlux의 논블로킹 특성 역시 외부 I/O 작업을 블로킹하지 않고 처리하는 것을 목표로 한다. 헥사고날 아키텍처는 이러한 외부 I/O 로직을 어댑터에 격리시켜, 비즈니스 로직이 WebFlux의 핵심인
Mono와 Flux를 활용하는 데 집중할 수 있게 해준다.
WebFlux는 논블로킹 I/O를 통해 시스템의 동시성을 높인다. 헥사고날 아키텍처를 적용하면 이 논블로킹 패러다임을 애플리케이션의 모든 계층으로 확장할 수 있다.
예를 들어, 데이터베이스를 R2DBC 어댑터로, 외부 API를 WebClient 어댑터로 구현하면, 비즈니스 로직은 Mono나 Flux같이 반응형 타입에만 의존하게 된다. 이렇게 되면 비즈니스 로직 자체는
특정 I/O 기술에 묶이기 않고 순수하게 논리적인 흐름에만 집중할 수 있다.
헥사고날 아키텍처는 테스트 용이성을 크게 향상시킨다. 외부 의존성(데이터베이스, 외부 API)을 어댑터로 분리했기 때문에, 비즈니스 로직을 테스트할 때는 실제 어댑터 대신 목(Mock) 객체를 사용해
포트를 구현하면 된다.
이는 WebFlux 프로젝트에서도 마찬가지이다. 비즈니스 로직을 테스트할 때 실제 WebClient 호출 없이 XXXApiPort같은 가짜 구현체를 사용하면 된다. 이는 테스트를 빠르고 안정적으로 만들어준다.
헥사고날 아키텍처는 변경에 대한 영향을 최소화한다. 예를 들어, 현재 사용 중인 외부 AI API 제공업체를 다른 곳으로 변경해야 할 때, 수정이 필요한 XXXApiAdapter만 수정하면 된다.
비즈니스 로직이나 WebFlux 컨트롤러는 전혀 변경할 필요가 없다. 이는 WebFlux의 논블로킹 스트림을 유지하면서도 기술적 변화에 유연하게 대응할 수 있게 해준다.
헥사고날 아키텍처는 포트와 어댑터라는 두 가지 주요 구성 요소로 이루어져있다. 이들을 통해 내부 비즈니스 로직과 외부 기술을 분리한다.
포트는 애플리케이션의 내부와 외부를 연결하는 인터페이스 역할을 한다. 비즈니스 로직이 외부 세계와 통신하기 위한 규칙과 계약을 정의한다. 포트는 두 가지 유형으로 나뉜다.
어댑터는 포트가 정의한 인터페이스를 구현하는 구현체이다. 외부 시스템과 실제 통신하는 역할을 맡는다. 어댑터도 포트처럼 두 가지 유형으로 나뉜다.
핵사고날의 핵심 영역으로 비즈니스 로직이 위치한다. 이 영역은 외부의 어떤 기술에도 의존하지 않는 순수한 비즈니스 규칙과 도메인 모델로 구성된다. 포트를 통해 외부와 통신하며, 어댑터의 구현 기술과는 완전히
분리되어있다.
헥사고날 아키텍처의 구성 요소인 도메인, 어댑터, 포트를 중심으로 프로젝트의 최상위 패키지를 구성하는 것이 좋다.
핵심 비즈니스 로직을 포함하는 패키지. 외부 의존성 없이 순수한 비즈니스 규칙과 엔티티를 담는다.
외부 세계외 통신하는 구체적인 기술 구현체들을 모아두는 패키지이다.
도메인과 어댑터 사이의 계약을 정의하는 인터페이스들을 모아두는 패키지이다.
src/main/java/com/your-project-name
├── domain // 핵심 비즈니스 로직
│ ├── model // 엔티티, 값 객체 등
│ └── service // 핵심 비즈니스 서비스
│
├── adapter // 외부와의 통신 기술 구현체
│ ├── in // 인바운드 어댑터 (ex: controllers)
│ └── out // 아웃바운드 어댑터 (ex: repositories, api clients)
│
├── port // 내부와 외부를 연결하는 인터페이스
│ ├── in // 인바운드 포트
│ └── out // 아웃바운드 포트
│
└── Application.java // 메인 애플리케이션 클래스
이러한 구조를 따르면 각 패키지의 역할이 명확해져 유지보수와 확장이 용이해진다.