스프링부트를 하면서, 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가 중복되는 점 (클래스는 다르나 내용은 같은점) 등 많은 고민이 있었으나 나름 좋은 경험이었다고 생각된다.
'Backend > SpringBoot' 카테고리의 다른 글
| Cursor 기반 Paging 추가 정리(QueryDsl 기준) (0) | 2026.02.03 |
|---|---|
| 임시 비번 발급 후 비교할때 주의점(PasswordEncoder) (0) | 2026.02.02 |
| Application.yaml 값 불러오기 (Class에 매핑) (0) | 2026.01.29 |
| Cache, RefreshToken 용 Redis를 쓸 경우. (0) | 2026.01.29 |
| Security 에서 Role 적용시 헷갈리는 부분 정리 (0) | 2026.01.28 |