함께 일관성을 지켜야 하는 도메인 객체들의 묶음. 바깥에서는 묶음의 대표인 애그리거트 루트(Aggregate Root)를 통해서만 접근하고 변경한다. 도메인 주도 설계 (DDD)의 핵심 개념 중 하나다.
class Order { // 애그리거트 루트
private items: OrderItem[] = []
addItem(product: Product, qty: number) {
if (this.status !== 'pending') throw new Error('확정된 주문은 바꿀 수 없다')
this.items.push(new OrderItem(product, qty))
}
}
// order.items[0].qty = 99 처럼 내부를 직접 고치지 않는다- 일관성 경계: "주문 총액은 항목 합계와 같다" 같은 불변식(invariant)은 애그리거트 안에서 항상 지켜진다. 루트가 모든 변경을 통제하기 때문이다
- 트랜잭션 단위: 한 트랜잭션에서는 대개 한 애그리거트만 바꾼다. 여러 애그리거트에 걸친 변경은 이벤트로 이어 붙이고 최종 일관성(Eventual Consistency)을 받아들이는 경우가 많다(트랜잭셔널 아웃박스 패턴)
- 다른 애그리거트는 식별자로 참조한다. 객체를 직접 물고 있으면 경계가 흐려진다
- 리포지터리(Repository)도 애그리거트 단위로 둔다
JPA로 구현할 때는 루트에서 하위 엔티티로 영속성 전이(Cascade)를 거는 것이 자연스럽다. 묶음이 너무 크면 동시 수정 충돌과 조회 비용이 커지니 작게 유지한다. 내부를 숨긴다는 점에서 디미터 법칙, 컬렉션 캡슐화와 같은 생각이다.