Skip to content

[Architecture] 헥사고날 아키텍쳐를 적용 후기

한규범 (Ryan) edited this page Aug 18, 2024 · 1 revision
헥사고날 아키텍처 자세히 보기

헥사고날 아키텍처

헥사고날 아키텍처(Hexagonal(육각형) Architecture)는 포트와 어댑터 아키텍처(Ports And Adapters Architecture)라는 이야기도 한다. 컴퓨터 과학자인 Alistair Cockburn의 제안으로 알려진 아키텍처이다.

image

위의 그림처럼 어댑터는 포트를 통해 애플리케이션의 도메인 영역과 통신을 하는데 통신에 대한 규격을 Port로 규정하고 내부에서는 Use Case를 통해 비즈니스 로직을 실행하여 엔티티에 접근한다. 이와 같이 구성을 하게 된다면 응용 프로그램의 비즈니스 로직을 외부 세계로부터 격리시켜 유연하고 테스트하기 쉬운 구조를 만드는 것이다.

주요개념

  1. 중심 비즈니스 로직
  • 애플리케이션의 핵심 도메인 로직을 중앙에 배치한다.
  • 이 로직은 외부의기술적 세부 사항과 독립적이며 비즈니스 요구사항에만 집중한다.
  1. 포트
  • 포트는 애플리케이션의 도메인 로직과 외부 시스템 간의 인터페이스를 정의한다.
  • 포트는 도메인 로직을 외부에서 접근하는 방법을 결정하며 도메인 로직을 노출하거나 외부 요청을 처리하는 역할을 한다.
  • 포트는 인터페이스를 정의하며 어댑터는 이 인터페이스를 구현하는 구조이다. 이렇기에 새로움 어댑터를 추가할 때, 기존 포트를 준수하면서도 다른 방식으로 구현할 수 있어야한다. 이는 리스코프 치환 원칙에 부합한다.
  1. 어댑터
  • 어댑터는 포트에 연결되어 실제로 외부 시스템과의 상호작용을 처리한다.
  • 포트와 어댑터를 통해 시스템의 확장을 가능하게 한다. 이는 개방 폐쇄 원칙이 잘 이루어졌다.
  • 각 어댑터는 자신이 필요한 포트에만 의존하며, 다른 불필요한 포트나 기능에 의존하지 않는다. 이는 인터페이스 분리 원칙에 부합한다.
  1. 애플리케이션의 외부와 내부 분리
  • 핵사고날 아키텍처의 핵심은 애플리케이션의 내부와 외부를 분명히 분리하는 것이다.
  • 이를 통해 내부 로직은 외부 변화에 영향을 받지 않고, 외부 시스템과 상호작용 방법도 쉽게 교체하거나 확장할 수 있어야한다.

결론

개인적으로 헥사고날 아키텍쳐를 보면서 SOLID 규칙이 잘 지켜진 아키텍쳐라고 생각한다. 특히 마지막에 persistence(JPA) 부분만 분리해서 모듈화 할 수 있는 것이 거의 10분 내에 이루어질 정도로 분리가 잘 이루어져 확장성과 테스트 용이성이 돋보였다.


사용후기 및 (핵심)

헥사고날 아키텍처는 레이어드 아키텍처와 달리 도메인 로직을 외부 의존성으로부터 완전히 분리하는 것을 목표로 합니다. 이번 프로젝트에서 헥사고날 아키텍처를 처음 적용하면서, 멀티모듈 구조와 코틀린을 함께 사용해야 했기 때문에 많은 도전에 직면했다. 그 과정을 통해 겪은 주요 고민과 결정을 공유하고자 한다.

헥사고날 아키텍쳐의 코드 구현에 대해서는 해당 리포를 참고했다. LINK


첫째, Adapter의 DTO와 application의 DTO를 공유할까...? NO

새로운 API를 개발할 때마다 Adapter와 Application 층에 각각 DTO가 생성되었고, 이로 인해 객체 매핑에 대한 복잡성이 크게 증가했다. 특히, 각 DTO가 서로 다른 목적을 가지고 있기 때문에 하나의 DTO를 공유하는 것은 부적절하다고 판단했다. 최종적으로, Adapter와 Application의 DTO는 별도로 유지하고, 매핑 작업은 Adapter 쪽에서 처리하도록 결정했다. 만약 매핑 로직이 더욱 복잡해지면, 별도의 매핑 객체를 도입하는 것도 고려할 예정이다.

고민의 PR 리뷰 LINK

결국 각각 다른 dto를 가지며 mapping에 대한 작업을 가지기로 하였다. 이것도 application의 dto보다는 adapter의 dto가 적합하다고 판단되어 dapter에서 진행하였다. 추후에 개발 불륨이 커지면서 매핑에 대한 작업이 많아진다면 별도의 Mapping 역할을 가지는 객체를 생성하는 것도 고려하고 있다.


둘째, Persistence의 Entity와 domain의 Model과 공유할까..? NO

JPA Entity와 도메인 모델을 공유할지 고민했으나, 이를 공유할 경우 비즈니스 로직이 JPA에 의존하게 되어 헥사고날 아키텍처의 원칙에 위배될 수 있다고 판단했다. 도메인 모델은 비즈니스 로직의 순수성을 유지하기 위해 JPA와 독립적으로 설계되었으며, 이렇게 함으로써 추후 JPA를 다른 퍼시스턴스 메커니즘으로 대체할 때도 유연성을 유지할 수 있다.

결국 공유하지 않고 Model을 따로 선언하여 애플리케이션의 내부 모듈은 JPA에 의존적이지 않은 코드이며 실제로 막판에 JPA 또한 멀티 모듈로 분리하였다.


셋째, 헥사고날 아키텍처 여기에 적합해..? I don't know yet

사실 아키텍처를 구성하면서 정말 많은 고민을 했다. 지금이라도 레이어드로 할까, 다 공유를 하는 형태로 갈까에 대한 고민을 했다. 하지만, 해당 프로젝트는 사이드 프로젝트이며 공부의 목적이 강한 프로젝트이기에 몸에 좋은 약일 것이라고 생각하며 쓰더라도 삼키며 구성을 하였다. 구성을 마치고도 너무 과한 구성인가 싶다가도 하나의 단어에 통했다. 공부를 붙이면 모두가 수긍되었다. 오히려 더 과하게 하지 못한 아쉬움이 있을 정도였다. 이 아키텍쳐가 좋을지 안좋은지는 프로젝트마다 다르겠지만 나는 명식이에 적용해보고 이게 좋다 나쁘다 보다는 어디에 적합한지에 대한 잣대가 생기길 바란다. 따라서, 지금은 이 아키텍처가 좋은지 나쁜지 모른다.


관련 이슈 https://github.com/MYONGSIK/Server-v2/issues/2
관련 PR https://github.com/MYONGSIK/Server-v2/pull/3

Reference. https://reflectoring.io/spring-hexagonal/