Skip to the content.

Domain Layer — DDD Aggregate & Pure Java

이 문서는 domain-layer에 대한 요약 가이드

핵심 원칙, 패키징 구조, 그리고 각 영역별 상세 가이드 링크를 제공합니다.

📌 V2 컨벤션: Domain Layer Convention V2 참조


1) 핵심 원칙 (한눈에)

금지사항

허용 범위

허용 설명
java.* Java Standard Library
javax.annotation.* 표준 어노테이션 (@Nullable 등)
// domain 모듈 build.gradle
dependencies {
    // ✅ Domain Layer는 외부 의존성 없음 (순수 Java만 허용)
    // Java Standard Library만 사용

    // ❌ 금지: 모든 외부 라이브러리
    // implementation 'org.projectlombok:lombok'
    // implementation 'org.springframework:spring-context'
    // implementation 'com.github.f4b6a3:uuid-creator'
}

허용 기준:


2) 패키징 구조 (Bounded Context 예)

domain/
├─ common/                        # 공통 인터페이스 (DIP 준수)
│  ├─ event/
│  │  └─ DomainEvent.java         # 도메인 이벤트 인터페이스
│  ├─ exception/
│  │  ├─ DomainException.java     # 기본 도메인 예외
│  │  └─ ErrorCode.java           # 공통 에러 코드 인터페이스
│  └─ util/
│     └─ ClockHolder.java         # Clock 인터페이스 (구현은 Application Layer)
│
└─ [boundedContext]/              # 예: order
   ├─ aggregate/
   │  └─ [aggregateName]/         # 예: order (Aggregate Root 이름 소문자)
   │     ├─ Order.java            # ← Aggregate Root (forNew, of, reconstitute 포함)
   │     └─ OrderLineItem.java    # ← Entity (Root에 종속)
   │
   ├─ vo/                          # Value Object
   │  ├─ OrderId.java
   │  ├─ Money.java
   │  └─ OrderStatus.java
   │
   ├─ event/                       # Domain Event (옵션)
   │  └─ OrderCreatedEvent.java
   │
   └─ exception/                   # BC 전용 예외
      ├─ OrderNotFoundException.java
      └─ InvalidOrderStateException.java

패키지 네이밍 규칙:

패키지 배치 원칙:

domain.common (공통 인터페이스):

domain.[boundedContext] (Bounded Context):


3) 영역별 상세 가이드 링크

📦 Aggregate 설계

🎁 Value Object 설계

🚨 Exception 설계

📢 도메인 이벤트

핵심 패턴:

// Aggregate 내부에서 Event 생성 및 등록
public class Order {
    private final List<DomainEvent> domainEvents = new ArrayList<>();

    public static Order forNew(...) {
        Order order = new Order(...);
        order.registerEvent(OrderCreatedEvent.from(order));  // Event 등록
        return order;
    }

    public List<DomainEvent> pullDomainEvents() {
        List<DomainEvent> events = List.copyOf(domainEvents);  // 불변 리스트 반환
        domainEvents.clear();
        return events;
    }
}