kongkong.note
[도메인 주도 개발 시작하기] 3. 애그리거트 본문
3.1 애그리거트
- 복잡한 도메인을 이해하고 관리하기 쉬운 단위로 만들기 위해 상위 수준에서 모델을 조망하는 방법
- 관련된 객체를 하나의 군으로 묶는 것
- 상위 수준에서 도메인 모델 간의 관계 쉽게 파악 가능
- 한 애그리거트에 속한 구성요소는 대부분 함께 생성, 제거(다른 애그리거트는 관리 x)
- 애그리거트 설정하는 기본 : 도메인 규칙, 요구사항 → ex) product, review 는 서로 다른 애그리거트
- 한 애그리거트는 일반적으로 1개의 엔티티 객체를 갖는다.
3.2 애그리거트 루트
- 한 애그리거트에 속한 모든 객체가 일관된 상태를 유지하기 위한 관리 주체 → ex) 주문 애그리거트 - Order
- 애그리거트 일관성이 깨지지 않도록 도메인 기능을 구현
- 애그리거트 외부에서 객체를 직접 변경하면 안됨. 불변 중요
→ setter 메서드를 public 으로 생성 x
→ value 타입은 불변으로 생성
3.3 리포지터리와 애그리거트
- 리포지터리는 애그리거트 단위로 존재
- 어떤 기술(ORM...)을 이용해서 리포지터리를 구현하느냐에 따라 애그리거트의 구현도 영향을 받는다.
ex) JAP → class {~~} 에서 value "Type" 으로 사용하던 밸류타입을 @Entity로 구현 - 리포지터리 조회 메서드는 완전한 애그리거트 제공 필요(한 애그리거트의 모든 구성요소 포함 필요)
- 애그리거트의 상태가 변경되면 모든 변경을 원자적으로 저장소에 반영 필요
3.4 ID를 이용한 애그리거트 참조
애그리거트 간 참조가 가능하고, 다른 애그리거트의 루트를 참조
다른 애그리거트 참조는 ID를 이용해서 간접 참조 해야 한다. 같은 애그리거트는 직접 참조 가능.
# 직접 참조
public class Orderer {
private Member member;
}
- 객체 그래프 : Orderer - Member - Address - City - ... → 다른 애그리거트까지 모두 연결
# 간접 참조
public class Orderer {
private MmeberId memberId;
}
- 객체 그래프 : Orderer - Member → 한 애그리거트에 속한 객체만 참조
3.4.1 ID를 이용한 참조와 조회 성능
ID 참조를 하게 되면 N+1 조회 발생 : 조회 전용 쿼리 사용 → 데이터 조회를 위한 별도 DAO 사용 (5장)
3.5 애그리거트 간 집합 연관
1:N 관계
- ex) 카테고리 : 상품(단일 카테고리)
- Set 컬렉션 이용
- N 쪽에서 실제 구현. N:1로 특정 카테고리에 속한 상품 목록을 구현.
N:M 관계
- ex) 카테고리 : 상품(다수 카테고리)
- 요구사항에 기반한 단일 N:M 연관만 구현 : 조인 테이블 사용(4장)
3.6 애그리거트를 팩토리로 사용
case) 상점이 신고당했는지 여부에 따라 물건 등록
AS-IS : 중요한 도메인 로직 처리가 응용 서비스에 노출
public class RegisterProductService {
public ProductId registerNewProduce (NewProductRequest request) {
Store store = storeRepository.findById(request.storeId);
checkNull(store);
if (store.isBlocked()){
throw new StoreBlockedException("Store is blocked");
}
ProductId id = productRepository.nextId();
Product product = new Product(id, store.getId());
productRepository.save(product);
return id;
}
}
TO-BE : Store 애그리거트에 팩토리 메서드 구현
→ "Store 상태"에 따른 Product 생성이므로, 이미 본인 상태를 알고 있는 "Store 애그리거트"에 팩토리 메서드 구현
public class Store {
public Product createProduct(ProductId newProductId){
if(isBlocked){
throw new StoreBlockedException("Store is blocked");
}
return new Product(newProductId, this.id);
}
}
public class RegisterProductService {
public ProductId registerNewProduce (NewProductRequest request) {
Store store = storeRepository.findById(request.storeId);
checkNull(store);
if (store.isBlocked()){
throw new StoreBlockedException("Store is blocked");
}
ProductId id = productRepository.nextId();
Product product = store.createProduct(id);
productRepository.save(product);
return id;
}
}
팩토리 메서드 : 외부에서 new 직접 사용을 방지하고 객체 생성 로직 숨겨둔 메서드
'DDD' 카테고리의 다른 글
| [도메인 주도 개발 시작하기] 5. 스프링 데이터 JPA를 이용한 조회 기능 (0) | 2025.12.25 |
|---|---|
| [도메인 주도 개발 시작하기] 4. 리포지터리와 모델 구현 (0) | 2025.12.25 |
| [도메인 주도 개발 시작하기] 2. 아키텍처 개요 (0) | 2025.12.15 |
| [도메인 주도 개발 시작하기] 1. 도메인 모델 시작하기 (0) | 2025.11.16 |
| [도메인 주도 개발 시작하기] 0. 세팅 (0) | 2025.11.15 |