이번에 진행 중인 DDD+헥사고날 프로젝트를 하며 아래 서적을 읽었다.
- 만들면서 배우는 헥사고날 아키텍처 설계와 구현
책에 정의된 헥사고날 아키텍처의 구조 및 사용이유에 대해 정리해두면 추후 요긴하게 사용할 것 같아, 해당 문서에 기술해둔다.
헥사고날 아키텍처
- 비즈니스 코드를 기술 코드로부터 분리
- 기술 측면이 비즈니스 측면에 의존하는지도 확인하여, 비즈니스 측면이 비즈니스 목표를 달성하는 데 사용되는 기술에 대한 우려 없이도 발전할 수 있게 함
- 관련된 비즈니스 코드에 피해를 주지않고도 기술 코드를 변경할 수 있게 함
⇒ 이를 위해 도메인 헥사곤을 생성 (엔티티 + 값 객체)
⇒ 엔티티 >> 식별자를 할당할 수 있는 것을 의미
⇒ 값 객체 >> 엔티티들을 합성하기 위해 사용하는 불변 컴포넌트
도메인 헥사곤
- 실 세계 문제를 이해하고 모델링하는 활동을 나타냄
- 중요한 비즈니스 데이터와 규칙에 관련된 엔티티 및 값 객체들이 있음 (이것들은 실제 문제에 대한 모델을 나타내기 때문에 중요함)
엔티티
- 연속성과 정체성을 가지는 객체
- 연속성 객체의 수명주기 및 변경 가능한 특성이 관련있음. (시간이 지나면서 속성이 변할 수 있다는 의미이며, 수명주기를 가진다는 뜻)
- 정체성 엔티티는 고유해야하므로 식별자를 가져야함. 이게 정체성에 대한 의미
값 객체
- 무언가 고유하게 식별할 필요가 없는 경우는 물론이고, 정체성보다는 속성에 관심을 갖는 객체
- 도메인 전체에서 예상치 못한 불일치를 방지하기 위해 값 객체는 변경할 수 없게 해야함
애플리케이션 헥사곤
- 애플리케이션 특화 작업을 추상적으로 처리하는 곳
- 아직 기술 관심사를 직접 다루지 않기 때문에 추상적인 것을 이야기함
- 도메인 비즈니스 규칙에 기반한 소프트웨어 사용자의 의도와 기능을 표현함
- 구성요소
- 유스케이스
- 유스케이스는 엔티티 및 다른 유스케이스와 직접 상호작용하고 그것들을 유연한 컴포넌트로 만듦
- 자바에서 유스케이스는 소프트웨어가 할 수 있는 것을 표현하는 인터페이스로 정의된 추상화로 보여줌
- 입력포트
- 유스케이스가 소프트웨어가 하는 일을 설명하는 인터페이스라면, 해당 인터페이스를 구현하는 곳
- 출력포트
- 유스케이스가 목표를 달성하기 위해 외부 리소스에서 데이터를 가져와야하는 상황이 있을 것임. 그리고 이때 사용하는 것이 출력 포트의 역할임.
- 유스케이스
- input
- 수동적으로 요청받는 것
- output
- 능동적으로 요청하는 것
프레임워크 헥사곤
- 소프트웨어와 통신할 수 있는 기술을 결정하는 곳
- 통신은 아래 2가지 형태로 발생할 수 있음
- 드라이빙 (입력 어뎁터 == Input Adapter)
- 드리븐 (출력 어뎁터 == Output Adapter)
- 드라이빙 오퍼레이션
- 소트프웨어(애플리케이션)에 동작을 요청하는 것
- 입력 어뎁터
- 요청이 들어오는 곳 (API를 기준으로 보았을 때, 프로토콜을 정의할 수 있는 곳임)
- 사용자의 요청을 받아들일 때 사용되는 Adapter
- 드리븐 오퍼레이션
- 애플리케이션에서 트리거되고, 외부에서 소트프웨어 요구사항을 충족시키는 데 필요한 데이터를 가져오는 것
- 출력 어뎁터
- 데이터를 어떻게 가져올지에 대해 정의하는 곳
- 도메인 모델의 처리에 사용되는 Adapter
위 구조 및 내용들을 정리하면, 헥사고날 아키텍처의 핵심을 아래와 같이 한 마디로 정리할 수 있을 것 같다.
외부와의 통신을 인터페이스로 추상화하여 비즈니스 로직 안에 외부 코드나 로직의 주입을 막는다.
왜 헥사고날을 쓰는가?
- 변경 허용
- 포트와 어뎁터라는 특성을 이용하여 마찰이 적고 기술 변화를 흡수할 준비를 해두었기 때문에, 기술 변화가 빠르게 일어나는 현재 시점상 변경에 강함
- 유지보수성
- 비즈니스 규칙을 변경해야 하는 경우, 유일하게 변경해야하는 곳은 도메인 헥사곤임.
- 아직 애플리케이션에서 지원하지 않는 특정 기술이나 프로토콜을 사용하는 기존 기능을 고객이 트리거할 수 있게 허용해야 하는 경우 프레임워크 헥사곤에서 실행할 수 있는 새로운 어뎁터를 만들면 됨
- 테스트 용이성
- 외부 의존성이 없더라도 개발자가 애플리케이션을 테스트 할 수 있는 구조임
- 외부 의존성이 없더라도 개발자가 애플리케이션을 테스트 할 수 있는 구조임
DIP (의존성 역전 원칙)
- 상위수준 컴포넌트는 하위수준 컴포넌트에 의존해서는 안 된다. 대신 이들 모두는 추상화에 의존해야 한다.
- 상위수준 컴포넌트
- 주요 시스템 동작을 제공하기 위해 조정된 일련의 오퍼레이션을 가짐
- 구체적이거나 추상적인 요소일 수 있음
- 하위수준 컴포넌트
- 상위수준 컴포넌트의 목표를 지원하기 위해 특별한 동작을 사용할 수 있음
- 항상 구현 세부사항을 제공해야하기 때문에 구체적이여야 함
- 상위수준 컴포넌트
'★ 프로젝트 + 트러블 슈팅 ★' 카테고리의 다른 글
[이미지 렌더링 최적화] CloudFront 비용절감 트러블 슈팅 (설계 및 플로우) (0) | 2025.01.07 |
---|---|
[이미지 렌더링 최적화] CloudFront 비용절감 트러블 슈팅 (0) | 2024.12.17 |
[DDD] 도메인, 바운디드 컨텍스트, 애그리거트 개념 정의 (3) | 2024.11.05 |
[FCM] AOS / IOS 푸시 메시지 미수신 및 액션링크 미작동 이슈 (3) | 2024.09.14 |
[FCM] Firebase Cloud Messaging deprecated API 이슈 (0) | 2024.09.13 |
댓글