본문 바로가기

Spring

헥사고날 아키텍처(Hexagonal Architecture)

만들면서 배우는 클린 아키텍처라는 책을 읽고 정리한 내용입니다.

헥사고날 아키텍처란?

헥사고날 아키텍처알리스테어 콕번(Alistair Cockburn)이 만든 용어로 모듈 간 종속성을 외부에서 내부로만 향하게 하여 의존성을 역전시켜 객체 의존도를 낮추는데 목적을 둔 클린 아키텍처의 원칙들을 조금 더 구체적으로 정립한 개념이다.

아래 그림이 헥사고날 아키텍처가 어떤 구조로 이루어져 있는지 보여주는 좋은 예시이다.

 

 

헥사고날 아키텍처는 어플리케이션 계층이 각 어댑터와 상호작용하기 위해 특정 포트를 제공하기 때문에 포트와 어댑터(ports-and-adapters) 아키텍처라고도 불린다.

 

 

위와 같은 패키지 구조를 가지고 있으며 어댑터, 어플리케이션, 도메인으로 나눈 뒤 각 패키지간에 통신할 때는 어플리케이션 계층에서 제공하는 인터페이스 기반인 입출력 포트를 통해서 통신이 이루어진다.

 

각 패키지에 대해 조금 더 설명하자면

domain 패키지는 해당 패키지가 속한 Account 모델과 관련된 도메인 모델이 포함되어있다.

application 패키지는 도메인 모델을 둘러싼 서비스 계층(비즈니스 로직)을 포함하고 있으며 웹 계층은 인커밍 포트 인터페이스(SendMoneyUseCase)를 통해 application 계층을 호출하고 application 계층은 아웃고잉 포트 인터페이스(LoadAccountPort, UpdateAccountStatePort)를 통해 영속성 계층을 호출한다.

adapter 패키지는 application 계층의 인커밍 포트를 호출하는 웹 어댑터와 아웃고잉 포트에 대한 구현을 제공하는 아웃고잉 어댑터를 포함하고 있다.

 

만들고 보니 굉장히 복잡해 보인다. 이렇게 패키지 구조를 구성함으로써 얻는 이득이 뭘까?? 오히려 패키지를 구조화하는데 더 많은 비용을 소모하게 되는건 아닐까??

 

책을 읽으면서 가장 공감이 됐던 부분은 새로운 코드를 작성할 때 이 코드가 어느 패키지에 속해야 하는지 항상 염두해 두어야 하고 이러한 과정이 클린 아키텍처를 구현하는 데 많은 도움이 된다는 점이다.

 

이 책을 읽기 전까지는 모든 프로젝트를 계층형 아키텍처로 개발을 해왔다.

계층형 아키텍처는 단순하다. 웹에서 클라이언트의 요청을 받아 도메인이나 비즈니스 계층에서 서비스 로직을 수행하고 영속성 계층에서 도메인 엔티티의 현재 상태를 조회하거나 변경하기 위한 작업을 수행한다. 패키지 구조도 Controller, Service, Repository로 나눈 뒤 단순한 구조로 개발을 해왔다. 아마 웹 애플리케이션 개발 공부를 하는 사람이라면 모두 위와 같은 계층형 구조로 개발을 해봤을텐데 계층형 구조는 다음과 같은 단점이 존재한다.

1. 데이터베이스 주도 설계를 유도한다.

그동안 만들어 왔던 애플리케이션을 되돌아 보면 항상 DB 설계를 먼저 하고 엔티티를 정의한 후 비즈니스 로직을 구현해왔다. 이는 비즈니스 관점에서는 맞지 않으며 비즈니스 관점에서 봤을때 가장 중요한 비즈니스 로직을 먼저 구현한 후 영속성 계층과 웹 계층을 만들어야 한다. 

2. 지름길을 택하기 쉬워진다.

계층형 아키텍처에서는 같은 계층에 있는 컴포넌트나 아래에 있는 계층에만 접근이 가능하다. 만약 상위 계층에 있는 컴포넌트에 접근하고 싶다면 해당 컴포넌트를 아래로 내리면 가능하다. 하지만 이와 같은 일이 반복된다면 하위 계층의 규모는 점점 복잡하고 비대해지며 계층형 구조에서는 이런일이 자주 발생한다.

3. 테스트하기 어려워진다.

계층형 아키텍처에서 발생하는 또 다른 문제는 중간계층을 건너 뛰는 것이다. 만약 영속성 계층에서 단 하나의 엔티티의 필드만 조작하면 되는 경우 도메인 계층을 건너뛰어 바로 영속성 계층에 접근하는 행위를 하게 된다.

 

이 경우에는 웹 계층에서 도메인 로직을 구현하게 되고 이와 같은 일이 반복되면 책임이 섞이고 핵심 도메인 로직이 퍼져 나가게 된다. 뿐만 아니라 테스트 코드를 작성할 때 의존하는 객체가 많아져 단위 테스트의 복잡도가 올라가게 되고 테스트 코드를 작성하는 시간보다 mock 객체를 만드는 시간이 더 들어가게 된다.

4. 동시 작업이 어려워진다.

앞서 언급했듯이 계층형 아키텍처는 영속성 계층 -> 도메인 계층 -> 웹 계층 순으로 개발이 이루어 진다. 그렇기 때문에 개발자들은 계층 단위가 아닌 기능단위로 작업을 수행하는데 서로 다른 기능을 작업하더라도 계층형 구조에서는 컴포넌트간에 로직이 복잡하게 얽혀있어 같은 서비스를 동시에 작업하는 상황이 발생한다. 이렇게 되면 충돌이 발생할 수 있기 때문에 동시 작업이 어려워진다.

 

위와 같은 단점들을 헥사고날 아키텍처를 사용함으로써 한번 더 고민하게 되고 유지보수하기 쉬운 클린한 아키텍처를 만듬으로써 해결할 수 있게 된다.