# (🇰🇷 Kor) 헥사고날 아키텍처 시놉시스 Hexagonal Architecture Synopsis

# ⬡ 왜 육각인가 ⬡

🛰 일상에서 보는 제품에선 흔치 않게도 인공위성 중에는 6개의 측면 패널을 갖고 있는 경우가 있는데, 이 경우를 잘 보면 육각 구조를 띤 제품들이 몸체에 많은 모듈을 연결할 수 있다는 것을 알 수 있습니다. 이런 구조가 일반적인 사각 단면 구조에 비해 공간 효율이 좋기 때문입니다!

![아리랑 3호 위성의 주요 구성에 대한 러시안스페이스웹닷컴의 설명 자료. 이 위성의 곳곳에는 서비스 모듈, 태양광 패널, 지피에스 안테나, 스타 트래커, 이미지 시스템, 통신용 엑스밴드 안테나와 에스밴드 안테나 등이 장착되어 있습니다. 위성 사진과 위성 삼차원 설계도면이 양쪽으로 각각 배치되어 있습니다. 사진에서는 위성의 표면이 금박으로 싸여 있고 오른쪽 삼차원 모델에서는 표면을 가리는 구성요소 없이 각 구성품마다 포트와 내외부 구성품 등이 부품마다 다양한 색으로 채색되어 구분할 수 있게 표현되어 있습니다.](https://www.russianspaceweb.com/images/spacecraft/application/remote_sensing/kompsat/kompsat3a_design_1.jpg align="left")

📷 사진 출처: [아이랑 3호(KOMSAT-3A)에 대한 Russian Space Web 닷컴의 설명 자료](https://www.russianspaceweb.com/dnepr-kompsat-3a-arirang-3a.html)

---

이런 육각 구조물에서 "**<mark>하나의 본체에 다양한 모듈을 연결할 수 있다.</mark>**"라는 특징이 헥사고날 아키텍처(Hexagonal Architecture)의 명명 배경이라고 추측하고 있어요. 육각형과 다른 연관이 없는 편인데, 이렇게 **다양한 모듈을 연결하여 사용하는** 콘셉트가 닮아 있거든요.

헥사고날 아키텍처의 핵심은, 바로 이 '모듈'들입니다. 자바 등에서 모듈화 개념과 구분하기 위해서인지, 아니면 어차피 연결부에 초점을 두고 설명해야 해서인지, 보통은 모듈보다 '포트'와 '어댑터'로 설명하는 편입니다. 그래서 이 아키텍처를 '**<mark>포트 어댑터 패턴</mark>**'이라고도 부르죠.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1700525807574/62f9f31d-6ee2-4b22-804c-10c62ff60531.png align="center")

이 아키텍처는 본체와 모듈들을 각각 구분해 두는데, **마치 위성의 다양한 모듈들처럼 <mark>각 모듈이 그 임무를 세세하게 수행</mark>하고, 본체와는 관련 I/O만 주고 받는 콘셉트입니다**. 각 세부 동작을 본체 내부에서 자세히 관리하기보다, **그것만 담당하는 파트를 따로 운용하는 것이죠**. (헉! 늘상 하던 것과 비슷한가요?)

기존의 방법론(주로 레이어드 아키텍처)에서 하던 것과 차이는 "**<mark>본체의 포트가 I/O 스펙을 결정</mark>하고, 각 모듈에서는 그 스펙대로 어댑터를 구성한다**."라는 것입니다.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1700563804734/d3021b0a-c130-415b-907d-8477b34adcc9.png align="center")

이렇게 하면 본체 포트 스펙을 따르는 모든 어댑터를 사용할 수 있거든요. 교체가 수월하죠. RDB를 빼고 MongoDB를 사용하겠다고 해서, 또는 갑자기 이벤트 기반으로 변경한다고 해서, 우리 프로그램의 모든 영역을 전면 개편할 필요가 없게 될 테니, 이 글 꼭 읽어 보세요!

---

# ⬡ 헥사고날 아키텍처, 무엇일까? ⬡

아마존 CEO 제프 베조스의 영향을 받아, MSA 진영에서 권장하는 여러 규칙에는 다음 내용이 포함되어 있습니다.

* (팀 간의) 커뮤니케이션은 서비스 ***<mark>인터페이스로</mark>만*** 수행해야 합니다.
    
* 모든 서비스 인터페이스는 예외없이 <mark>외부에서 이용 가능</mark>해야 합니다.
    

이는 MSA에 관한 설명이고, 원자화된 여러 마이크로 서비스 간의 소통에 적용되었죠. 그런데 위 특징은 단위단위로 작업을 처리하는 **<mark>헥사고날 아키텍처</mark>에서도** 잘 묻어납니다.

## 기존 아키텍처와 비교

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1701142553779/4fc64703-d9d7-4fa4-ab20-e3e645eaca64.png align="center")

기존에 많이 사용하던 레이어드 아키텍처에서는 <mark>컨트롤러 → 서비스 → 레포지터리</mark> 방향으로 <mark>의존성</mark>을 이루었습니다. 레포지터리를 변경하면 서비스 로직이 영향을 받고, 서비스 로직을 변경하면 컨트롤러가 영향을 받았죠.

* 컨트롤러는 서비스가 제공하는 대로 기능을 사용합니다.
    
* 서비스는 레포지터리가 제공하는 대로 기능을 사용합니다.
    

여기에서 문제는 <mark>하위 계층이 자기가 제공할 기능을 결정</mark>하기 때문에, 하위 계층을 변경하는 것이 부담이 된다는 것이었습니다.

**<mark>헥사고날 아키텍처</mark>는** 여기서 '기능의 스펙을 레포지터리가 결정할 수 없도록' 변경합니다. 변경이 덜하면 좋겠는 것을 '본체'로 두고, 본체 주변으로 <mark>컨트롤러나 레포지터리가 어댑터</mark> 형식으로 붙게 했습니다.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1701142854082/500eff4b-0712-45c1-a0c5-c387f199246f.png align="center")

본체가 모든 스펙('포트'라고 부릅니다.)을 제공하고, 컨트롤러나 레포지터리는 이 본체가 제공하는 포트(주로 인터페이스)에만 맞추는 식입니다.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1700523904194/fda0ad57-b3e6-4694-819e-b4812e617bcb.png align="center")

그래서 관계가 다음처럼 변경되죠.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1701143292370/1644e7c5-b134-45df-adc8-baf91522bee3.png align="center")

본체에서는 '**<mark>포트</mark>**<mark>(port)</mark>'라는 이름으로 외부에 **인터페이스를 제공합니다**. 외부에 있던 모듈은 '**<mark>어댑터</mark>**<mark>(adapter)</mark>'라는 이름으로, 본체의 포트(인터페이스)를 구현하거나 또는 사용하는 클래스를 만듭니다. 이 포트와 어댑터가 모듈과 본체 간 데이터를 주고 받는(I/O) 일종의 소통 창구인 셈이죠. 이것을 하나의 프로젝트 안에서 구성할 수 있습니다.

## 계층의 구성

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1700749525761/8fd86fd1-9146-4bed-969e-78e566851fa2.png align="center")

우리가 앞서 이야기한 본체를 **<mark>Application 계층</mark>이라고 부릅니다**. 비즈니스 로직의 주요 부분을 작성할 계층이기도 하죠. 그래서 서비스 클래스도 이곳에 있고, 서비스 클래스가 사용할 '인터페이스'도 이곳에 존재합니다. 이 인터페이스 중 일부가 바로 '포트'이기도 하죠.

애플리케이션 계층의 내부에는 **<mark>Domain 계층</mark>이 있고**, 이건 우리가 생각하는 그 도메인 모델, 그러니까 취급할 관심사 데이터 및 그 스펙에 대한 것입니다. 이번 설명에선 비중이 덜한 편이죠.

그리고 '외부'라고 표현되기도 하는 각각의 **<mark>Adapter 모듈</mark>에**, 포트를 사용하거나 포트를 구현한 어댑터 클래스를 작성합니다. 예를 들어, 애플리케이션 계층의 Repository 포트(인터페이스)를 RDB Adapter라는 모듈에서 구현할 수도 있죠. 또 Web API 어댑터에서 Controller를 구현하고 서비스를 사용할 수도 있습니다.

### 의존성의 방향?!

헥사고날 아키텍처의 중요 키워드 중 하나는, <mark>의존 또는 구현의 방향이 내부를 향해야 한다</mark>는 것이에요. '내부'는 애플리케이션 계층과 도메인 계층을 말하고, 가장 안쪽은 도메인 계층입니다. '외부'는 각 어댑터 모듈들을 이야기할 수 있구요.

그리고 내부의 소스 코드가 외부의 소스 코드에 의존하고 있다면, 이것은 지적 사항이 될 수 있어요. 좋은 아키텍처는 언제든 떼어낼 수 있게 단위가 잘 구성되어야 하는데, 내부가 외부에 종속성을 갖는다면(즉 외부의 것을 사용해야 자신을 완성할 수 있다면), 외부 모듈을 교체할 때마다 내부의 소스 코드를 고쳐야 해서 교체가 번거롭겠죠.

**의존성 방향은 실제 헥사고날 아키텍처의 세부 구현에서 생각보다 많이들 실수하는 고려 대상이에요**.

## 드라이빙과 드리븐

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1700622983738/10148acd-a312-4357-b05b-08c368012640.png align="center")

앞서 헥사고날 아키텍처는 각 어댑터가 본체의 각 포트를 '사용'하거나 '구현'한다고 했어요. 이때 본체의 기능을 '사용'하느냐 '구현'하느냐에 따라 드라이빙 어댑터와 드리븐 어댑터로 구분해요.

예를 들어 컨트롤러는 본체가 제공하는 서비스를 사용하는 관계죠. 이를 드라이빙 어댑터로 분류합니다. JPA 레포지터리는 본체가 요구하는 세부 기능을 구현해 본체에 제공하는 관계죠. 이를 드리븐 어댑터로 부릅니다.

---

출처를 작성 안 한 자료는 DALL·E, excalidraw, Power Point 등을 통해 스스로 만들었습니다. (그래서 영어가 어색할 수 있습니다.) 어색한 영어 문장은 남대문 열렸다고 알려 주듯 살짝 말씀해 주시면 얼른 고쳐 보겠습니다. 그러면 다들 모쪼록 착한 개발 하세요.
