주문이라는 도메인 개념은 주문, 배송지 정보, 주문자, 주문 목록, 총 결제 금액의 하위 모델로 구성된다. 이 하위 개념을 표현한 모델을 하나로 묶어서 주문이라는 상위 개념으로 표현할 수 있다.
개별 객체가 아닌 관련 객체를 묶어서 바라 볼 수 있게되고, 도메인 일관성을 지킬 수 있다.
이 일관성을 트랜잭션 경계 내에서 어떻게 보장할 것 인가? 에 대한 해답이 바로 애그리거트다.
도메인 객체 모델이 복잡해지면 개별 구성요소 위주로 모델을 이해하게 되고, 전반적인 구조나 큰 수준에서 도메인 간의 관계를 파악하기 어려워진다. 이 말은 곧 코드를 변경하고 확장하는 것이 어렵다는 것을 의미하며 전체 모델을 망가뜨리지 않으면서 추가 요구사항을 모델에 반영해야 하는데 세부적인 모델만 이해한 상태로는 코드 수정이 꺼려지기 때문에 코드 변경을 회피하는 쪽으로 요구사항을 협의하게 되므로 이러한 방법은 장기적으로 더 수정하기 어렵게 만든다.
따라서 복잡한 도메인을 이해하고 관리하기 쉬운 단위로 만들려면 상위 수준에서 모델을 조망할 수 있는 방법이 필요한데 이게 바로 애그리거트다. 수많은 객체를 애그리거트로 묶어서 바라보면 상위 수준에서 도메인 모델 간의 관계를 파악할 수 있다.
(Order) (애그리거트 루트)
├── (OrderLine) (엔티티)
└── (ShippingInfo) (밸류 객체)
shippingInfo를 변경하려면 루트 entity인 Order를 통해서만 변경해야만 한다.
애그리거트는 도메인의 안전한 울타리다.
그 안에서만 마음대로 놀고, 밖에서 접근할 땐 문지기(루트)를 통해야 한다.
트랜잭션 범위는 작을수록 좋다.
한 트랜잭션 안에서 수정하는 테이블 대상이 많아진다는 것은 그만큼 잠금 대상이 늘어나는 것이고 그만큼 동시에 처리할 수 있는 트랜잭션 개수가 줄어들고 이것은 전체적인 성능을 떨어뜨린다.
애그리거트는 최대한 서로 독립적이어야 하는데 한 애그리거트가 다른 애그리거트의 기능에 의존하기 시작하면 애그리거트 간 결합도가 높아진다. 결합도가 높아지면 높아질수록 향후 수정에 대한 비용이 증가하므로 애그리거트에서 다른 애그리거트의 상태를 변경하지 말아야 한다.
부득이하게 변경이 필요한 상황이라면 직접 수정하지 말고 서비스에서 두 애그리거트를 수정하도록 구현하는게 낫다.