photocard backend server 개발일기

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

한둥둥 2023. 11. 18. 12:38

헥사고날 아키텍쳐란 무엇인가?

- 헥사고날 아키텍처는 Layered Architecture 계층형 아키텍처의 단점을 해결하기 나왔음. 

단점)

1. 계층형 아키텍처는 데이터베이스 주도 설계를 유도함

웹 - 도메인 - 영속성 계층으로 이루어진 계층형 아키텍처에서는 결국 웹 계층은 도메인에, 도메인 계층은 영속성에 의존하기 때문에 

결국 데이터베이스에 의존

데이터베이스를 중심으로 아키텍처를 만드는 방식은 전통적인 아키텍처에서는 합리적인 방법 but 비지니스적인 관점 맞지않음

 

객체지향 설계를 위해서는 도메인 로직 중심으로 설계 진행해야함. 도메인 로직을 만들고 검증한 뒤에, 이를 기반으로 영속성 계층과 웹계층을 만드는 것이 올바른 성향 

 

ORM(Object-Relational mapping) 기술을 활용하다보면, 데이터베이스 중심의 아키텍처가 더 쉽게 만들어진다.

ORM 프레임워크가 계층형 아키텍처에서 영속성관점과 비즈니스 규칙을 섞기 좋게 기능들을 제공한다.

 

아래는 계층형 아키텍처의 구조이다.

 

 

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

계층형 아키텍처에서는 같은 계층이나 아래 계층에만 접근이 가능하다. 개발을 하다보면 상위계층에 위치한 컴포넌트에 접근해야할 때가 있다. 이때 흔히 개발자들이 하는 실수는 상위 계층에 위치한 컴포넌트를 아래로 내려버린다. 

 

헬퍼 컴포넌트나 유틸리티 컴포넌트는 객체지향 진영에서는 피해야할 방식중 하나이다. 

심지어 각 계층에 전혀 포함되지 않을 것처럼 보이는 이러한 컴포넌트들이 영속성 계층에 포함되어 있으니 계층이 점점 비대해지고 비효율적으로 변해간다.

 

3. 테스트가 어려워진다.

계층형 아키텍처에서 개발하다보면 웹 계층에서 영속성 계층의 엔티티에 접근해서 조작하면 되지 않을까하는 생각이듬. 

엔티티 필드 한두개만 조작하면 되는 경우라면 굳이 도메인 계층을 통해서 할 필요가 없다는 생각이 든다.

하지만 한번이 어렵지 이렇게 반복되면 구조가 완전히 깨져버린다.

첫째, 도메인 로직이 웹 계층에 구현되게 된다는 것이다. 아주 작은 단위의 프로젝트에서는 괜찮지만 점점 더 서비스를 확장하게 될 것이라면 이렇게 짜놓으면 어플리케이션 전반에 책임이 뒤섞인다. 

 

둘째, 테스트 시 도메인 계층 뿐만아니라 영속성 계층의 컴포넌트들도 모킹해줘야함

이렇게 되면 테스트의 복잡도가 올라가게 되어 정상적인 단위 테스트가 어려움

 

4. 유즈케이스를 숨긴다.

프로젝트 시 설계를 제대로 진행하는 이유는 추후에 기능을 추가하기 위해서인데 계층형 아키텍처는 여러 계층에 도메인 로직이 흩어져 있을 가능성이 굉장히 높다. 

 

이러한 위에있는 단점들을 개선하고자 헥사고날 아키텍처가 나오게되었다.

 

이제부터 본격적으로 헥사고날 아키텍처에 대해 알아보자

- 사전적 의미로 "육각형 건출물" 의미

- 소프트웨어 설계에 사용되는 아키텍처 패턴중 하나로 여러 소프트웨어 환경에 쉽게 연결할 수 있도록, 느슨하게 결합된 어플리케이션 구성요소를 만드는게 목표이다. 

- 도메인의 비즈니스 로직을 외부 라이브러리 및 툴로부터 분리 할 때 포트와 어댑터라고 부르는 인터페이스를 사용하기 때문에 포트&어댑터 아키텍처라고 부른다. 

위 사진을 보면 내부 인터페이스로부터 데이터를 주고 받을 때 내부 인터페이스의 구현에 외부 인터페이스의 존재가 영향을 주면 안되고 외부 인터페이스의 구현 형태에 상관 없이 서비스를 구축해 나갈 수 있도록 하는 것이 클린 아키텍처 목표이다. 

 

 

헥사고날 아키텍처는 위에 그림과 같은 형태를 가지고 있다.

육각형 안에는 도메인 엔티티와 상호작용하는 유즈케이스가 있고, 모든 의존성을 엔티티를 향해 있다.

 

헥사고날 아키텍처의 핵심

도메인 비즈니스 로직이 외부요소에 의존하지 않게 만들고, 프레젠테이션 계층(controller)과 데이터 소스 계층(persistence)같은 외부 요소들이 도메인 계층에 의존하도록한다.

-> 외부와의 접축을 인터페이스로 추상화하여 비즈니스 로직안에 외부 코드나 로직의 주입을 막는다. 외부 라이브러리 및 툴로부터 분리시키는 것이 아키텍처의 핵심이다. 

 

헥사고날 아키텍처의 구성

헥사고날 아키텍처는 내부(도메인) 외부 (인프라)로 구분된다.

내부 영역 - 순수한 비즈니스 로직을 표현하며 캡슐화된 영역이고 기능적 요구사항에 따라 먼저 설계

외 부 영역 - 내부 영역에서 기술을 분리하여 구성한 영역이고 내부 영역 설계 이후 설계

 

 

포트와 어댑터

개발을 시작할 때 포트와 어댑터의 역할, 두 어댑터간의 차이점을 제대로 인지한다면 개발이 수월하다. 

(도메인 + application layer까지 비즈니스 로직입니다.)

 

포트

Port는 application 입장에서 consumer, 또는 application에서 나가거나/ 들어오는 end point라고 볼 수 있다.

포트는 내부 비즈니스 영역을 외부 영역에 노출한 API이고 인바운드(Inbound)/ 아웃바운드(Outbound) 포트로 구분

인바운드 포트 - 내부 영역 사용을 위해 노출된 API

아웃바운드 포트- 내부 영역이 외부 영역을 사용하기 위한 API

 

어댑터

어댑터는 인프라나 web과 같은 저수준 layer들이 도메인 로직에 접근할 수 있는 포트를 사용할 수 있도록 한다. 

 

Primary (Driving) Adapters - 위의 다이어그램에서 왼쪽에 있는 adapter, application을 동작시키는(Driving) 역할을 한다. Driving Adapter에는 주로 UI 쪽이 들어간다. 인바운드 포트 사용
 
Secondary (Driven) Adapters - 오른쪽에 있는 adapter, application에 의해 동작되는(Driven) 역할을 가진 부분이다. 주로 인프라와 연결되는 부분이 들어간다. 아웃바운드 포트 사용
 
Primary adapter에 의해 Secondary adapter들이 호출된다. (인바운드 adapter, 아웃바운드 adapter로 부르기도 한다)
 
또한 두 종류의 adapter에서 어떻게 port와 adapter가 쓰이는지도 차이점이 있다:
Primary adapter는 port에 의존하고 있다. 실제로 사용될 때는 구체적인 port의 구현체가 adapter에 주입된다. 이 때 왼쪽에서 port와 그 구현체는 application 내부에 속하게 된다.
 
Secondary adapter는 port의 구현체가 되고 application의 비즈니스 로직에 주입된다. 그렇기 때문에 Application 비즈니스 로직의 입장에서는 port의 interface만 알고 있다. 이 때 port는 application 내부에 속하지만 port의 구체적인 구현체는 application 외부에 속하게 된다. 그리고 그 구현체는 외부 tool(SMS 라이브러리, ORM 등)을 감싸고 있다.

 

지금부터 Photocard프로젝트는 헥사고날 아키텍처로 구성하여 개발할 계획이다.

헥사고날 아키텍처를 채택한 이유)

1. 테스트 코드의 작성을 조금 더 편리하게 하기위하여 

2. 기존의 Service로직에 너무 많은 역할이 생긴다고 판단하였음

3. 프로젝트를 진행하다보면 최상위 Component를 나도 모르게 쉽게 개발하기 위하여 아래로 내려서 사용하는 경우가 많았다.

4. 해당 아키텍처의 컨셉을 보았을 때, ORM이 추구하는 방향과 어느정도 맞아떨어진다고 생각하여 채택하게됨

 

참고 블로그들

https://happy-coding-day.tistory.com/entry/헥사고날-아키텍처Hexagonal-Architecture-코드로-이해해보기-미완성

 

헥사고날 아키텍처(Hexagonal Architecture) 코드로 이해 해보기

EventsJdbcEntityRecordPublishedEventService 이 부분은 '만들면서 배우는 클린 아키텍쳐' 의 책을 보고 배운점과 느낌점을 설명합니다. 헥사고날 아키텍쳐란 무엇인까요? 헥사고날 아키텍쳐는 레이어드 아

happy-coding-day.tistory.com

https://devkingdom.tistory.com/340

 

http://covenant.tistory.com