본문 바로가기
Programming/Architecture

[Hexagonal Architecture #1] 개념, 용어 정리부터 시작

by TinKerBellBass 2022. 5. 11.
728x90
반응형

개념과 용어가 헷갈리기 시작하면 핵심에 도달할 수 없기에 우선 개념과 용어부터 정리하려고 한다.
지극히 주관적인 정리가 될 것이기 때문에 잘못된 정보를 전달할 수도 있을 것이다.

헥사고날 아키텍처

DDD 를 잘 표현해 줄 수 있는 아키텍처 중 하나가 헥사고날 아키텍처이다.
포트 - 어댑터 아키텍처라고도 불리는 이 아키텍처의 핵심은
의존성의 방향이 외부로 향하지 않게 관리하여 외부 영역에 의한 도메인 영역의 오염을 막는 것이다.

헥사고날 아키텍처의 전반적인 개념은 아래와 같다.

  • 헥사고날의 가장 중심에는 도메인 영역이 자리한다.
  • 도메인 영역의 바깥쪽에는 도메인을 사용해서 어떠한 요구사항(시나리오, 비지니스 로직)을 충족시키는 애플리케이션 영역이 자리한다.
  • 외부 영역인 웹, 앱에서는 요구사항을 충족시키기 위해서 Usecase 를 사용한다.
  • Usecase 는 요구사항을 처리하기 위해 외부 영역인 MySQL, AWS S3 를 사용한다.
  • 의존성의 흐름이 외부 영역으로 나가지 않는다.
  • 도메인 영역은 의존하는 영역이 존재하지 않는다.

포트와 어댑터

포트와 어댑터는 들어오는 것과 나가는 것, 즉 인커밍과 아웃고잉으로 나눌 수 있는데
인커밍 포트는 Usecase, 인커밍 어댑터는 Web / App,
아웃고잉 포트는 Repository / Storage, 아웃고잉 어댑터는 MySQL / AWS S3 이다.
그리고 바깥 영역으로 나가고 있지 않는데 왜 아웃고잉이라는 이름이 붙은 이유는
의존성 역전을 통해 의존성의 방향이 뒤집혔기 때문으로 원래 방향은 바깥으로 향하는 것이다.

인커밍 포트, 인커밍 어댑터, 아웃고잉 포트, 아웃고잉 어댑터는 다음과 같이 정의할 수 있다.

Incoming Port 요구사항을 구현하기 위한 방법을
인터페이스로 제공
Incoming Adapter 요구사항을 충족시키기 위해 인커밍 포트에
요청을 보내는 외부 영역
Outgoing Port 요구사항을 충족시키기 위해 사용되는
외부 영역이 구현해야 하는 인터페이스를 제공
Outgoing Adapter 요구사항을 충족시키기 위한 외부 영역으로
아웃고잉 포트 인터페이스에 맞춰서 구현

간단히 시나리오를 하나 만들어 보면 다음과 같다.
1. 웹(인커밍 어댑터)에서 유저 생성 유즈케이스(인커밍 포트)에 유정 생성을 요청
2. 유저 생성 유즈케이스(인커밍 포트)는 유저 생성 도메인에게 비지니스 규칙 확인, 유저 생성 등의 작업을 요청
3. 유저 생성 유즈케이스(인커밍 포트)리포지토리(아웃고잉 포트)에 생성된 유저 정보의 영속화를 요청
4. 리포지토리(아웃고잉 포트)를 구현한 MySQL(아웃고잉 어댑터)가 생성된 유저 정보를 영속화

위 시나리오에 사용된 인커밍 어댑터는 웹이 아니어도 되고, 아웃고잉 어댑터는 MySQL 이 아니어도 된다.
인커밍 어댑터는 인커밍 포트 인터페이스에 맞춰서 요구사항을 요청하면 되고,
아웃고잉 어댑터는 아웃고잉 포트 인터페이스에 맞춰서 구현하면 되는 것이다.
그리고 여기서 인터페이스는 자바의 인터페이스를 지칭하기보다 무엇인가를 사용하기 위한 방법으로 이해해야 한다.

Domain 과 Usecase

도메인은 비지니스 또는 해결해야 할 문제로 정의할 수 있고
유즈케이스는 이러한 도메인을 이용해서 요청사항을 처리하는 시나리오로 정의할 수 있다.
예를 들어
유저 생성 도메인은 생성해야 할 유저 정보를 상태로 가지며 유저 정보를 생성하기 위한 업무 규칙을 정의하고 있으며
유저 생성 유즈케이스는 다음과 같은 시나리오를 정의하고 있다.
1. 유저 생성 요청을 받음
2. 유저 생성 도메인에게 유저 생성을 요청
3. 생성된 유저를 데이터베이스에 영속화
4. 유저 생성에 성공했다고 요청한 곳에 알림

Entity, Value Object

엔티티는 식별이 가능한 식별자를 가지는 의미 있는 값들의 집합을 의미하며
밸류 오브젝트는 단순히 의미 있는 값들의 집합을 의미하는데,
밸류 오브젝트는 엔티티가 가지는 값 중 연관이 있는 것들을 묶어 놓기 위해 사용된다.

// Entity
class User {
	private final String userID;
	private final Contact contact;
    
    ...userID 검증, contact 검증 메서드
    ...기타 비지니스 검증 메서드들
    ...생성자, 게터
}

// Value Object
class Contact {
	private final String phone;
	private final String address;
    
    ...생성자, 게터
}

개인적인 취향인데 밸류 오브젝트에 관련한 비지니스 검증 메서드는 밸류 오브젝트보다 사용하는 엔티티에 넣는 것을 좋아한다.

그리고 엔티티 하면 왠지 ORM 에 사용되는 객체가 떠오르는데
도메인 영역에서 비지니스를 정의한 것이 헥사고날 아키텍처의 핵심 엔티티라고 생각한다.
물론 식별자를 가지는 의미 있는 값들의 집합을 엔티티로 정의하기 때문에 ORM에 사용되는 객체도 엔티티이지만
이 엔티티는 퍼시스턴스를 위한 것이다.
@Entity 라는 어노테이션 하나로 엔티티는 퍼시스턴스 영역에 있다는 사고가 굳어진 것 같은데
@OrmObject, @OrmEntity 등으로 이름 지었으면 어땠을까 개인적으로 생각해본다.




728x90
반응형

댓글