DDD에 대해 이해하고 프로젝트에 적용해보자
DDD의 개념과 등장 배경
- 소프트웨어를 설계할 때 가장 중요한 것 = 고객의 요구사항을 정확히 이해하는 것
- 과거 : 기술 중심 개발 방법론 → 비즈니스 측면에서 발생하는 요구사항 반영에 한계
DDD의 핵심 가치
- 소프트웨어 설계에서 도메인 지식이 가장 중요한 요소임을 인식하고 이를 중심으로 소프트웨어 설계
- 유비쿼터스 언어 : 모든 곳에서 동일하게 사용하는 언어
- 용어의 모호함을 줄이고 도메인과 코드 사이 불필요한 해석 과정 감소
도메인 모델
- DDD에서 핵심 개념을 포현하는 방법
- 특정 도메인에 대한 지식, 규칙, 로직을 추상화하여 개념적으로 표헌한 것
DDD의 구조와 용어
Entity
- 고유의 식별자를 갖는 객체로 자신의 라이프 사이클을 가짐
- 데이터와 함께 기능을 제공하는 객체
- 도메인 관점에서 기능을 구현하고 기능 구현을 캡슐화해서 데이터가 임의로 변경되는 것 방지
Value
- 고유의 식별자를 갖지 않는 객체로 개념적인 하나의 값을 표현
Domain Service
- 특정 엔티티에 속하지 않는 도메인 로직

Aggregate
- 관련된 객체들을 모아 하나의 단위로 취급하는 개념
- 연관 도메인을 애그리거트로 묶어 하나의 군집으로 이해
- 상위 수준에서 도메인 모델 간의 관계 파악 가능
- 특정 도메인 군집에 속한 객체들을 관리하는 루트 엔티티를 가짐
- 하나의 애거리거트에는 반드시 하나의 루트 엔티티가 존재

JPA에서의 DDD
- 비즈니스 로직과 도메인 모델 간의 결합도를 낮추기 위해 repository 패턴 권장
- JpaRepository, @Entity
- 도메인 모델이 애플리케이션의 핵심
- 데이터베이스 테이블에 대한 매핑을 하면서도 도메인 모델의 순수성 유지 가능
그럼 mybatis로 DDD 개발은 어렵나…? 똑같이 repository로 하는거라 상관없나..? 흠
- JpaRepository를 루트 애그리거트에만 구현
- 루트 애그리거트가 하위 애그리거트 관리
- 영속성 로직도 루트 애그리거트에 집중
- ex) Order(root) → OrderProduct → Receipt 가격 정보 수정
@Transactional
public void updateOrderProductReceiptPrice(Long id, Long orderProductId, Long receiptId, Long price) {
orderRepository.findById(id)
.flatMap(order -> order.getProduct(orderProductId))
.flatMap(orderProduct -> orderProduct.findReceipt(receiptId))
.ifPresent(receipt -> receipt.update(price));
}OrderProduct는 Order에 의해 변경 되고, Receipt는 OrderProduct에 의해 변경됨 → 캡슐화가 깨지지 않음!
MSA 에서의 DDD
- 모놀리식 애플리케이션을 MSA로 전환할 때 중요한 것 : 서비스의 경계를 명확히 나누는 것
- 도메인 개념을 기준으로 마이크로서비스 구축(주문, 상품, 리뷰 등)
