Backend/SpringBoot

Hexagonal Architecture 일부적용 및 느낀점

Dean83 2026. 1. 30. 15:21

스프링부트를 하면서, Hexagonal Architecture 에 대한 고민을 했던 기억이 있어 내용을 정리해 둔다. 

 

고민시점

  • 도메인 위주로 패키지를 나누어 둠 (혹시 모를, 추후 MSA 전환을 대비)
  • 도메인 A 에서 도메인 B의 Service나 Repository를 주입받아 이용하는곳이 있었음. 
  • 이 연관관계를 깨고 싶었음. 

이 시점에 고민을 했었고, 실제 완전한 Hexagonal 은 아니어도, 어느정도 의미있게 분리를 했다고 생각한다. 

 

서버 이벤트 방식 고민

  • 자료를 리턴받는 콜백 개념이 필요했으므로, fire-forget인 이벤트와는 맞지않다고 생각했다.
  • 충분히 큰 규모였다면 kafka 나 MQ 처럼 외부 서비스를 구성해 볼수도 있겠지만, 현재는 시작단계여서 오버스펙이었다.
  • 또한 백앤드는 클라이언트와 다르게 수많은 클라이언트를 대상으로 하기도 하고, 역할 분리 등이 엄격하다고 느꼈다.
  • 그러나 사실 서버 이벤트 방식도 고민을 했었고, 충분히 적용해볼 만 하다고도 생각된다. 
  • 대략적으로 구상한 방법은,
    • 도메인 A 에서 "나 이 자료 필요해" 라고 이벤트 발생
    • 도메인 B 에서 해당 이벤트 수신 후 DB 조회 등 작업 수행
    • 도메인 B 에서 "자료 여기있어" 라고 이벤트 발생
    • 도메인 A 에서 이 이벤트를 수신하여 실제 비즈니스 로직 수행
  • 실제 이 방식은 C#을 이용했을때 많이들 사용했던 방식이고, 사실 delegate를 이용하여 조금 모습이 다르긴 하다만, 충분히 반영해봐도 좋다고 생각한다.

 

다시 돌아와서, 내가 적용했던 Hexagonal 내용을 정리하자면, 

  • 도메인 A에서만 사용할 Dto 생성
  • Port 인터페이스 생성
  • Adapter 클래스 생성

이 정도로만 구성을 끝냈다. 원래대로라면 좀 더 복잡하지만, 어짜피 Springboot 라는 조건하에 굳이 순수 Java 코딩을 해야 하는 부분들은 필요 없다고 생각 했다.

 

실제 각각 어떤것을 적용했냐 하면, 

 

Dto 생성

  • 도메인 A에서만 사용할 Dto로, 외부 데이터를 이용하여 구성한다.
  • 이를 통해 도메인 A 에서는 외부 자료형 등에 영향을 받지 않고, 내부 도메인 Dto만 바라볼 수 있어 결합도가 낮아진다.

 

Port 인터페이스 생성

  • 외부 통신을 정의한 인터페이스로, 위에서 정의한 Dto를 리턴하는 메서드를 정의만 해 둔다.

 

Adapter 클래스 생성

  • 사실상 핵심이라고 볼 수 있다. Port를 구현한 클래스로, 실제 외부 통신을 수행하게 된다.
  • 역할은, 비즈니스 로직을 제외하고 순수 외부 통신 -> Dto로 데이터를 변환하여 리턴만 한다.
  • 외부 통신 및 외부에서 쓰는 자료형을 리턴받기 때문에 더러워 질 수 밖에 없다. 
  • 그러나 외부의 영향을 받는 모든것들을 이곳에 모아둠으로서, 도메인 A에 있는 다른 모든 항목들은 영향을 받지 않고 분리된다.
  • 여기서 B 도메인의 Service를 주입받아, 메소드 호출 및 리턴 자료형을 도메인 A에 사용하는 Dto로 변환 하였다.
  • 도메인 A 에 있는 Service에서 이 Adapter를 주입받아 호출하여 사용한다. 

 

물론 도입 과정에서 Dto가 중복되는 점 (클래스는 다르나 내용은 같은점) 등 많은 고민이 있었으나 나름 좋은 경험이었다고 생각된다.