Toby 's hexagonal architecture

·2026년 2월 7일

1. 도메인 모델과 DDD

1. Domain?

  • 본래의 정의 : 영역, 영토, 소유지
  • 지식, 영향, 활동 영역

2. SW 개발에서의 도메인

  • SW는 이를 사용하는 사용자들의 활동이나 관심사와 관련이 있다.
  • 사용자가 프로그래, 또는 SW service를 적용하는 주제 영역을 도메인 이라 한다.
  • SW가 도메인을 반영 하도록 만들어야 한다.

3. Domain Model (중요)

  • SW는 Domain의 핵심 개념과 요소들을 통합하고, 그 관계를 구현해야한다.
  • SW는 도메인을 모델링 해야한다.
    • Domain은 현실 세계의 일부이고, 단순히 코드로 직접 옮길 수 없다. 따라서 도메인의 추상화인 도메인 모델을 만들어야 한다.
    • Domain의 추상화된 상태, 단순화된 상태라 생각하기.
  • Domain Model은 SW가 해결하려는 특정 문제 영역(도메인)의 핵심지도
  • Domain에 존재하는 중요한 개념과 이들 사이의 관계, 그리고 규칙을 표현

4. 도메인 주도 설계 (DDD, Domain Driven Design)

  • 도메인의 복잡성이 주는 문제를 해결하기 위한 접근 방법
  • 도메인 모델을 개발 과정의 중심에 두는 방법
  • 개발자 뿐만 아니라 도메인을 가장 잘 아는 현업 전문가, 이해 관계자가 모두 참여해 함께 도메인 모델을 만들고 계속 발전 시켜야 한다.
  • 도메인 모델이 설계와 코드까지 이어져야 한다. (분석 -> 설계 -> 구현)
  • 팀 안에서 도메인 모델에 기반한 단일 어휘체계를 만들고, 이를 문서, 회의, 대화 그리고 코드까지 일관되게 사용 (보편 언어)

DDD의 실천 방법
1. 도메인과 보편 언어를 프로젝트에 기록하기
2. 용어 사전.md
3. 도메인 모델.md
3. 도메인 모델.drawio

2. Splearn 모델 만들기

1. 도메인 모델 만들기

  • 듣고 배우기
  • '중요한 것' 찾기 (개념 식별)
  • '연결 고리 찾기' (관계 정의)
  • '것'들을 설명하기 (속성 및 기본 행위 명시)
  • 그려보기 (시각화)
  • 이야기 하고 다듬기(반복)

2. 도메인 전문가가 없을 때

  • 창업자, 기획자, PO를 가상의 도메인 전문가로 활용
  • 다양한 탐색과 집단적인 학습 (이벤트 스토밍)
  • 가설 기반의 점진적인 모델링
  • 보편 언어의 의식적인 구축과 진화
  • 베타 테스터, 초기 사용자와의 적극적인 소통
  • 도메인 모델의 발전과 진화, 공유를 더욱 적극적으로 하여야
  • 경쟁업체 서비스 분석

3. Splearn 예시

1. 도메인 모델.md

# Splearn 도메인 모델

## 도메인 모델 만들기
1. 듣고 배우기
2. '중요한 것'들 찾기 (개념 식별)
3. '연결 고리' 찾기 (관계 정의)
4. '것'들을 설명하기 (속성 및 기본 행위 명시)
5. 그려보기 (시각화)
6. 이야기 하고 다듬기 (반복)  

## Splearn 도메인
- 스프런은 회원이 강의를 수강하는 온라인 서비스이다.
- 스프런은 스프링 프레임워크의 철학을 바탕으로 개발되고 운영되며 발전하는 학습 생태계를 목표로 한다.  
  이 생태계를 구성하는 핵심 구성 요소는 학습(성장)하는 회원이다.
    - 그래서 이름이 Spring + Learner = Splearn
    - 유사한 이름으로 인프런이 있다.
- 스프런에서 활동하기 위해서는 회원으로 등록해야 한다.
    - 다만, 회원이 되기 전에도 스프런에 대한 소개와 강의 정보를 살펴볼 수 있다.
    - 강의를 수강하기 위해서는 등록을 완료하고 활동 가능한 회원이 되어야 한다.
    - 등록 신청을 한 뒤 정해진 요건을 충족하면 등록이 완료된다.
    - 등록을 완료한 경우에 프로필 주소, 자기 소개를 등록하거나 수정할 수 있다. 
      - 프로필 주소는 알파벳과 숫자로 구성된 15자리 이내의 중복되지 않은 값
      - 탈퇴한 회원의 프로필 주소와 자기 소개는 수정할 수 없다. 
    - 등록 시간, 등록 완료 시간, 탈퇴 시간을 저장한다. 
- 원하는 회원은 자신이 가진 지식과 경험을 강의라는 형태로 다른 회원에게 제공하는 강사가 될 수도 있다.
    - 회원이 최초로 강사가 되려면 강사 신청과 승인 과정을 거치도록 한다.
    - 승인된 강사는 강의를 생성하고 검수를 거쳐 강의를 공개할 수 있다.
    - 공개된 강의는 회원에게 노출되고, 회원은 이 강의를 수강할 수 있다.
- 수강은 강의를 학습하는 것을 말한다. "내가 수강한 강의는 a이다. 나는 b 강의 수강중이다."
    - 수강을 위해서는 먼저 수강 신청이 필요하다.
    - 수강 신청은 강의의 수강 요건에 따라서 신청을 해야 하고 이후 추가 절차가 요구될 수 있다.
    - 일부 강의는 수강 신청과 동시에 수강이 가능하다.
    - 어떤 강의는 수강 신청후 강의비 결제를 완료해야 수강이 가능하다.
    - 강사는 강의 수강 기간의 제한을 둘 수도 있다.
- 강의는 영상, 문서와 같은 컨텐츠를 가진 하나 이상의 수업으로 구성 된다.
    - 수업은 갯수가 많을 수 있다. 그래서 수업은 다시 섹션으로 구분한다.
    - 하나의 강의는 여러 개의 섹션과 각 섹션에 속한 수업으로 구성된다.
    - 수업과 섹션은 학습 순서를 가진다.
    - 학습 진도는 매 수업 단위로 기록된다.
    - 강의의 모든 수업의 학습을 마치고 수업 진도가 100%에 도달하면 강의 수강을 완료한 것이다.

## 도메인 모델

---
### [회원 애그리거트]

### 회원(Member)

#### 행위

#### 규칙
- 회원 생성후 상태는 등록 대기
- 일정조건을 만족하면 등록 완료가 된다
- 등록 대기 상태에서만 등록 완료가 될 수 있다
- 등록 완료 상태에서는 탈퇴할 수 있다
- 등록 완료 상태에서만 회원 정보를 수정할 수 있다 
- 회원의 비밀번호는 해시를 만들어서 저장한다
- 프로필 주소는 중복을 허용하지 않는다. 기존 프로필 주소를 제거할 수는 있다

#### 행위

---

### Email
_Value Object_
#### 속성
- `address`: 이메일 주소
---


### 강사

### 강의

### 수업

### 섹션

### 수강

### 진도


2. Splearn 용어 사전
# Splearn 용어 사전

| **한국어** | **영어**         | **설명**                                     |
| ------- | -------------- | ------------------------------------------ |
| 회원      | Member         | 스프런 서비스를 이용하는 사용자로 강의를 수강할 수 있다            |
| 강사      | Instructor     | 강의를 만들고 제공하는 회원. 회원은 신청 과정을 통해서 강사가 될 수 있다 |
| 강의      | Course         | 특정한 주제를 학습하도록 설계된 교육과정. 여러 개의 수업으로 구성.     |
| 수업      | Lesson         | 강의를 구성하는 학습 단위. 영상과 문서 등으로 구성된다.           |
| 수강      | Enrollment     | 회원이 강의를 학습하는 것. 수강 신청을 통해서 수강할 수 있다.       |
| 섹션      | Section        | 강의를 세부 주제별로 나눈 중간 단위                       |
| 진도      | Progress       | 하나의 강의 내에서 얼마나 학습을 완료했는지를 나타내는 학습 상태 정보    |


3. 개발 가이드
# Splearn

## 아키텍쳐
- 헥사고날 아키텍쳐
- 도메인 패턴 모델

### 계층
- Domain Layer
- Application Layer
- Adapter Layer

> 외부(액터)->어댑터 -> 애플리케이션 -> 도메인

## 패키지
- domain
- application
  - required
  - provided
- adapter
  - webapi
  - persistence
  - integration
  - security



3. 도메인 모델 패턴으로 회원 도메인 개발

1. Entity

  • 도메인 모델을 만들 때 사용하는 패턴
  • 도메인 안에 있는 대상이나 개념
  • 고유한 식별자 (identity)를 가지고, 일를 통해서 개별적으로 구별
  • 생명주기 (Life cycle)를 가진다. 시간의 흐름에 따라 상태가 변경 될 수 있다.
## 도메인 모델

---
### [회원 애그리거트]

### 회원(Member)
_Aggregate Root_
#### 속성
- `id`: `Long`
- `email`: 이메일 - Natural ID
- `nickname`: 닉네임
- `passwordHash`: 비밀번호 해시
- `status`: `MemberStatus` 회원 상태
- `detail`: `MemberDetail` 1:1
#### 행위
- `static register()`: 회원 등록: email, nickname, password, passwordEncoder
- `activate()`: 등록을 완료시킨다
- `deactivate()`: 탈퇴시킨다
- `verifyPassword()` : 비밀번호를 검증한다
- `changePassword()`
- `updateInfo()`: 회원 정보 수정. 회원의 닉네임, 프로필 주소, 자기 소개를 수정하다
#### 규칙
- 회원 생성후 상태는 등록 대기
- 일정조건을 만족하면 등록 완료가 된다
- 등록 대기 상태에서만 등록 완료가 될 수 있다
- 등록 완료 상태에서는 탈퇴할 수 있다
- 등록 완료 상태에서만 회원 정보를 수정할 수 있다 
- 회원의 비밀번호는 해시를 만들어서 저장한다
- 프로필 주소는 중복을 허용하지 않는다. 기존 프로필 주소를 제거할 수는 있다

### 회원 상세(MemberDetail)
_Entity_
- `id`: `Long`
- `profile`: 프로필 주소. 모든 회원이 고유한 프로필 주소를 가져야 한다
- `introduction`: 자기 소개
- `registeredAt`: 등록 일시
- `activatedAt`: 등록 완료 일시
- `deactivatedAt`: 탈퇴 일시
#### 행위
- `static create()`: 회원 등록. 현재 시간을 등록 일시로 저장한다.
- `activate()`: 등록 완료와 관련된 작업 수행. 등록 완료 일시 저장.
- `deactivate()`: 탈퇴와 관련된 작업 수정. 탈퇴 일시 저장.
- `updateInfo()`: 상세 정보 수정

### 회원 상태(MemberStatus)
_Enum_
#### 상수
- `PENDING`: 등록 대기
- `ACTIVE`: 등록 완료
- `DEACTIVATED`: 탈퇴

### DuplicateEmailException
_Exception_

### 비밀번호 인코더(PasswordEncoder)
_Domain Service_
#### 행위
- `encode()`: 비밀번호 암호화하기
- `matches()`: 비밀번호가 일치하는지 확인

### 프로필 주소(Profile)
_Value Object_
#### 속성
- `address`: 프로필 주소

---

### Email
_Value Object_
#### 속성
- `address`: 이메일 주소
---

2. 도메인 모델 패턴

  • 도메인 / 비즈니스 로직을 구성하는 아키텍쳐 패턴의 한 가지
  • 도메인 모델의 속성과 행위를 모두 포함하는 도메인의 Object Model이다.
  • Object Model 이기 때문에 복잡한 연관 관계, 커스텀 속성, 상속등을 사용 할 수 있다.
  • 트랜잭션 스크립트는 하나의 업무 절차를 처리하기 위한 스크립트(Method)를 만들고 비즈니스 로직을 순서대로 코드로 작성하는 방법

3. 값 객체의 도입

  • 도메인 모델에서 식별자가 필요하지 않고 , 속성/ 값으로만 구별되는 Object
  • 엔터티가 너무 많은 책임을 가지는 것을 방지하고, 특정 속성 관련 행위를 분리해 엔터티를 더 집중된 상태로 유지
  • 원시 타입보다는 도메인 개념을 더 명시적으로 나타내 모델의 명확성을 높인다.
  • 생성된 이후 상태가 변하지 않고, 변경이 필요하면 새로운 객체로 교체
  • 풍부한 기능을 가짐
  • 자체 유효성 검사도 가능하다.

4. 원시 타입을 개체로 교체 (리펙토링)

  • 원시 타입의 남용을 개선하고, 코드의 명시성과 안정성을 높이는 방법
  • 값 객체는 도메인 모델의 핵심 구성요소로 값. 그자체의 의미는 담아내고, 불변성, 동등성 등의 도메인 로직을 포함해 설계하는 방식
기존 String email;

@Embeddable
public record Email(String address) {
  private static final Pattern EMAIL_PATTERN =
      Pattern.compile("^[a-zA-Z0-9]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$");

  public Email{
    if (!EMAIL_PATTERN.matcher(address).matches()) {
      throw new IllegalArgumentException("Invalid email address" + address);
    }

  }

5. 도메인 모델 패턴의 두가지 스타일

  • 단순 도메인 패턴(Simple Domain Model)

    • DB설계와 유사. 테이블에 대해 하나의 도메인 프로젝트
  • 풍성한 도메인 모델 (Rich Domain Model)

    • 상속, 전략 GoF디자인 패턴, 연관 관계. 복잡한 로직에 적합하지만 DB매핑이 어려울 수 있다.

6. 도메인 로직의 API 개발

  • 도메인 모델 패턴은 트랜잭션 스크립트처럼 작업 단위의 절차형 API를 만들기가 어렵다.

  • 도메인 로직의 명확한 작업 단위 API를 제공하는 애플리케이션 서비스가 필요.

profile
# h

0개의 댓글