각진 세상에 둥근 춤을 추자

DDD (Domain-Driven Design) 란? 본문

Java

DDD (Domain-Driven Design) 란?

circle.j 2024. 11. 26. 17:29

📌 DDD란? 

 

DDD (Domain-Driven Design, 도메인 주도 설계): 도메인을 중심으로 설계를 진행하는 방법론이다

(도메인: 소프트웨어가 해결하려고 하는 특정 문제 영역이나 비즈니스 컨텍스트를 의미한다.)

DDD는 개발팀과 도메인 전문가 간의 협업을 강조하고, 비즈니스 로직을 정확히 반영한 시스템을 만드는 데 초점을 맞춘다. 

 

기존의 전통적인 소프트웨어 설계 방식인 '계층적 구조'와의 차이 

  계층적 구조 DDD 구조
초점 데이터 중심 설계  도메인 중심 설계 
확장성 간단하고 빠르나 확장에는 취약  최초 구현 시, 시간은 많이 소요되나 유연하고 확장에 용이
복잡성 구조가 단순 구조가 복잡 
적합한 프로젝트 단순 CRUD 중심 복잡한 비즈니스 로직 

 


📌 DDD의 주요 개념 

 

1. 유비쿼터스 언어 (Ubiquitous Language)

도메인 전문가와 개발자가 공통적으로 사용하는 언어로 정의하고, 이 언어로 의사소통을 하며 도메인을 정확히 이해하고 설계한다. 

코드와 문서에서도 이 언어를 사용해 도메인 개념을 일관되게 표현한다. 

 

 

2. 도메인 이벤트 (Domain Event)

도메인에서 중요한 상태 변화나 사건을 모델링한 객체

예: 주문이 생성됨, 결제가 완료됨, 상품이 배송됨 ... 

 

 

📌 이벤트 스토밍 (Event Stroming) 

DDD에서 사용하는 워크숍 기법으로, 시스템에서 일어나는 주요 이벤트를 중심으로 도메인을 설계하는 방법이다. 

(1) 준비물: 큰 화이트보드 또는 긴 벽 공간, 포스트잇과 마커

(예: 색깔별 포스트잇) 

  • 도메인 이벤트: 주황색
  • 커맨드: 파랑색
  • 정책(비즈니스 규칙): 노란색
  • 외부 시스템: 보라색 

 

(2) 참여자 구성

  • 도메인 전문가: 비즈니스 프로세스와 요구사항을 잘 아는 사람
  • 개발자: 기술적인 구현 가능성을 논의할 사람
  • 디자이너/기획자: 사용성과 프로세스를 이해하는 사람
  • 중재자: 워크숍을 진행하고 의견을 조율할 사람 

 

(3) 진행 단계

Step1: 도메인 이벤트 나열 "이 시스템에는 어떤 일이 발생하나요?"

- 시스템에서 일어나는 이벤트를 포스트잇에 작성하고, 시간의 흐름에 따라 나열

(예: 주문이 생성됨, 결제가 완료됨, 상품이 배송됨 ... )

 

Step2: 이벤트 간 관계 정리

- 이벤트가 발생하는 순서를 연결하며 비즈니스 프로세스를 시각화 

(예: 주문이 생성됨 → 결제가 완료됨 → 배송이 시작됨)

 

Step3: 커맨트 추가  "이벤트가 발생하려면 어떤 행동이 필요하죠?"

- 이벤트를 트리거 하는 커맨드(사용자 요청 또는 시스템 명령)를 추가

(예: 주문하기, 결제 요청)

 

Step4: 정책(비즈니스 규칙) 추가 "어떤 조건이 충족될 때 이벤트가 발생하나요?"

- 정책(조건)과 관련된 규칙을 이벤트와 커맨드 사이에 추가 

(예: 결제가 완료되면 배송을 시작한다.)

 

Step5: 외부 시스템 추가 "프로세스에 외부 시스템이 관여하나요?"

- 외부 시스템과 관련된 이벤트, 커맨드를 연결

(예: 결제 게이트웨이, 물류 시스템 등 외부 시스템을 포스티잇으로 추가)

 

Step6: 바운디드 컨텍스트 도출

- 도메인 간의 경계(Bounded Context)를 설정하고 서브 도메인 간의 컨텍스트 매핑을 통해 바운디드 컨텍스트 간의 정보 참조 릴레이션을 정의

 

 


📌 DIP (Dependency Inversion Principle) 

DIP는 의존성 역전 원칙으로 객체 지향 설계 원칙 중 하나이다. 

A객체에서 B객체를 참조해야 하는 경우 (다른 클래스의 메소드를 사용해야 하는 경우) 클래스를 직접 참조하는 것이 아니라 상위 요소 (추상 클래스 또는 인터페이스)를 참조하는 원칙을 말한다. 

 

DIP 기반 프로젝트의 주요 영역 

 

 

1. 도메인 영역 (Domain Layer)

(1) 역할: 시스템의 핵심 비즈니스 로직과 규칙을 정의하는 영역 

(2) 구성 요소

  • 엔티티 (Entity): 고유한 식별자를 가지며, 상태와 행동을 포함
  • 값 객체(Value Object): 불변성을 가지며, 동일한 속성값은 동일한 객체로 간주 
  • 애그리게이트(Aggregate): 연관된 엔티티와 값 객체를 그룹으로 묶고, 트랜잭션의 경계를 정의
  • 도메인 이벤트(Domain Event): 도메인에서 중요한 상태 변화나 이벤트를 나타냄
  • 리포지토리 인터페이스(Repository Interface): 데이터 접근을 추상화하여 도메인이 구체적인 구현에 의존되지 않도록 함 

 

(3) DIP 원칙: 도메인 영역은 기술적 세부사항(데이터베이스, API 등)에 의존하지 않고, 추상화(인터페이스)를 통해 필요한 동작만 정의

 

 

2. 애플리케이션 영역 (Application Layer)

(1) 역할: 도메인 로직을 활용하여 유스케이스(Use Case)와 워크플로를 정의하는 영역, 비즈니스 로직은 없고 단순히 도메인의 기능을 조합하거나 호출

(2) 구성 요소

  • 서비스(Service): 비즈니스 규칙을 기반으로 애플리케이션의 주요 동작을 정의
  • DTO (Data Transfer Object): 계층 간 데이터를 주고받기 위해 사용되는 객체
  • 유스케이스 (Use Case): 사용자가 시스템과 상호작용하는 특정 시나리오를 정의

 

(3) DIP 원칙: 애플리케이션 영역은 도메인 영역에 의존하지만 인프라스트럭처 영역에 직접 의존하지 않는다. 

 

 

3. 인터페이스/프레젠테이션 영역 (Interface/Presentaion Layer)

(1) 역할: 사용자와 시스템 간의 상호작용을 담당하는 영역, 시스템의 진입점 역할을 담당 (UI, API, CLI 등)

(2) 구성 요소

  • 웹 API 또는 UI 컨트롤러: 사용자의 요청을 받아 애플리케이션 영역으로 전달
  • 뷰(View): 사용자에게 데이터를 출력 
  • 폼 또는 입력 처리: 사용자의 입력 데이터를 검증하고 전달 

 

(3) DIP 원칙: 프레젠테이션 영역은 애플리케이션 서비스에 의존하지만 도메인이나 인프라스트럭처의 구현 세부사항을 직접 참조하지 않는다. 요청과 응답은 DTO를 사용해 전달한다. 

 

 

4.  인프라스트럭처 영역 (Infrastructure Layer)

(1) 역할: 기술적인 세부사항을 처리하는 영역으로 데이터베이스, 메시지 큐, 외부 API 통신 등을 담당

(2) 구성 요소

  • 리포지토리 구현체 (Respository Implementation): 도메인 영역에서 정의된 리포지토리 인터페이스를 구현
  • 외부 API 클라이언트: 외부 시스템과의 통신을 담당 

 

(3) DIP 원칙: 도메인에서 정의한 인터페이스를 구현하고 상위 계층에 필요한 구체적인 기능을 제공한다. 상위 계층에서 직접 호출되지 않고, 인터페이스를 통해 연결된다 

 

 

DIP 구조 예시는 다음과 같다.

src/
├── domain/
│   ├── model/
│   │   ├── Entity.java
│   │   ├── ValueObject.java
│   │   └── AggregateRoot.java
│   ├── repository/
│   │   └── CustomerRepository.java
│   └── event/
│       └── OrderCreatedEvent.java
├── application/
│   ├── service/
│   │   └── CustomerService.java
│   ├── usecase/
│   │   └── CreateOrderUseCase.java
│   └── dto/
│       └── OrderDTO.java
├── infrastructure/
│   ├── persistence/
│   │   └── JpaCustomerRepository.java
│   ├── messaging/
│   │   └── KafkaEventPublisher.java
│   └── external/
│       └── PaymentApiClient.java
└── presentation/
    ├── controller/
    │   └── OrderController.java
    ├── view/
    │   └── OrderView.html
    └── form/
        └── OrderRequestForm.java