헥사고날 아키텍처의 핵심은 **”다양한 외부 기술(어댑터)을 포트를 통해 연결할 수 있다”**는 유연성에 있습니다. 따라서 어떤 외부 기술과 연동하느냐에 따라 어댑터 폴더의 이름과 종류는 다양해집니다.
adapter/in 하위 폴더의 다른 예시들
in 어댑터는 외부에서 우리 애플리케이션의 비즈니스 로직을 호출(주도, Drive)하는 모든 종류의 기술을 포함합니다.
|
1 2 3 4 5 6 7 8 |
adapter/ └── in/ ├── web/ // ✅ 가장 흔함: HTTP 요청을 처리 (REST Controller, GraphQL Resolver 등) ├── cli/ // Command-Line Interface. 터미널 명령어로 기능을 실행 ├── scheduler/ // 특정 시간에 자동으로 실행되는 스케줄러 (예: Spring @Scheduled) └── messaging/ // 메시지 큐(Kafka, RabbitMQ 등)로부터 메시지를 수신하여 처리하는 Consumer |
cli(Command-Line Interface):- 예시:
java -jar app.jar create-user --name "John"과 같은 터미널 명령어를 처리하는 어댑터입니다. 이 어댑터는 커맨드라인 인자를 파싱하여CreateUserUseCase를 호출합니다.
- 예시:
scheduler:- 예시: 매일 자정에 휴면 계정을 처리하는 배치 작업을 실행하는 스케줄러입니다.
@Scheduled어노테이션이 붙은 클래스가 여기에 위치하며, 정해진 시간에DeactivateUserUseCase를 호출합니다.
- 예시: 매일 자정에 휴면 계정을 처리하는 배치 작업을 실행하는 스케줄러입니다.
messaging:- 예시: 다른 마이크로서비스로부터 ‘결제 완료’ 이벤트를 Kafka 메시지로 수신하는 컨슈머입니다.
@KafkaListener가 붙은 클래스가 여기에 위치하며, 수신한 메시지 데이터를 가지고UpdateOrderStatusUseCase를 호출합니다.
- 예시: 다른 마이크로서비스로부터 ‘결제 완료’ 이벤트를 Kafka 메시지로 수신하는 컨슈머입니다.
adapter/out 하위 폴더의 다른 예시들
out 어댑터는 우리 애플리케이션이 외부 시스템의 기능을 사용하기 위해 호출(주도받는, Driven)하는 모든 종류의 기술을 포함합니다.
|
1 2 3 4 5 6 7 8 9 |
adapter/ └── out/ ├── persistence/ // ✅ 가장 흔함: 데이터베이스에 데이터를 저장하고 조회 (JPA, MyBatis, JDBC 등) ├── notification/ // 이메일(SMTP), SMS, 푸시 알림 등을 발송 ├── restclient/ // 외부 서비스의 REST API를 호출하는 클라이언트 (RestTemplate, WebClient 등) ├── storage/ // 파일 스토리지(Amazon S3, 로컬 파일 시스템 등)에 파일을 업로드/다운로드 └── messaging/ // 메시지 큐(Kafka, RabbitMQ 등)에 메시지를 발행(Produce) |
notification:- 예시:
SendEmailPort인터페이스를 구현한SmtpEmailAdapter가 여기에 위치합니다. 이 어댑터는 실제 SMTP 서버와 통신하여 이메일을 발송합니다.
- 예시:
restclient:- 예시:
GetExchangeRatePort인터페이스를 구현한ExternalApiAdapter가 여기에 위치합니다. 이 어댑터는RestTemplate이나WebClient를 사용하여 외부 환율 정보 API를 호출하고 결과를 반환합니다.
- 예시:
storage:- 예시:
UploadFilePort인터페이스를 구현한S3StorageAdapter가 여기에 위치합니다. 이 어댑터는 AWS SDK를 사용하여 파일을 S3 버킷에 업로드합니다.
- 예시:
messaging:- 예시:
PublishEventPort인터A페이스를 구현한KafkaProducerAdapter가 여기에 위치합니다.KafkaTemplate을 사용하여 ‘주문 생성’ 이벤트를 Kafka 토픽으로 발행합니다.
- 예시:
종합적인 폴더 구조 예시
온라인 쇼핑몰의 “주문(order)”과 “사용자(user)” 도메인을 함께 보여주는 종합적인 예시입니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
com/example/shoppingmall/ ├── order/ │ ├── domain/ │ ├── application/ │ └── adapter/ │ ├── in/ │ │ └── web/ (PlaceOrderController) │ └── out/ │ ├── persistence/ (OrderPersistenceAdapter for DB) │ └── notification/ (SmsAdapter for order confirmation SMS) │ └── user/ ├── domain/ ├── application/ └── adapter/ ├── in/ │ ├── web/ (UserController) │ └── scheduler/ (DormantUserScheduler) └── out/ ├── persistence/ (UserPersistenceAdapter for DB) └── restclient/ (SocialLoginAdapter for Kakao/Google API) |
이처럼 애플리케이션이 어떤 외부 기술과 상호작용하는지에 따라 adapter 폴더는 매우 다채롭게 구성될 수 있습니다. 중요한 것은 각 폴더의 이름이 그 어댑터가 어떤 ‘기술’을 담당하는지 명확하게 드러내야 한다는 것입니다.
이렇게 구성하면, 예를 들어 “SMS 발송 시스템을 바꾸고 싶다”는 요구사항이 생겼을 때, 우리는 order/adapter/out/notification/ 폴더만 수정하면 된다는 것을 즉시 알 수 있습니다. 이것이 바로 헥사고날 아키텍처가 제공하는 유지보수의 용이성입니다.