본문 바로가기

도메인 주도 개발 시작하기

[도메인 주도 개발 시작하기] 애그리거트 루트

1) 애그리거트 루트란?

- 주문 애그리거트는 다음을 포함한다.

 

(1) 총 금액인 totalAmounts를 갖고 있는 Order 엔티티

(2) 개별 구매 상품의 개수인 quantity와 금액인 price를 갖고 있는 OrderLine 밸류

 

- 구매할 상품의 개수를 변경하면 한 OrderLine의 quantity를 변경하고

  더불 Order의 totalAmounts도 변경해야 한다.

  그렇지 않으면 다음 도메인의 규칙을 어기고 데이터 일관성이 깨진다

주문 총 금액은 개별 상품의 주문 개수 x 가격의 합이다.

 

- 애그리거트는 여러 객체로 구성되기 때문에 한 객체만 상태가 정상이면 안된다.

  도메인 규칙을 지키려면 애그리거트에 속한 모든 객체가 정상 상태를 가져야 한다.

  주문 애그리거트에서는 OrderLine을 변경하면 Order의 totalAmounts도 다시 계산해서 총 금액이 맞아야 한다.

 

- 애그리거트에 속한 모든 객체가 일관된 상태를 유지하려면 애그리거트 전체를 관리할 주체가 필요한데,

  이 책임을 지는 것이 바로 애그리거트의 루트 엔티티이다.

  애그리거트의 루트 엔티티는 애그리거트의 대표 엔티티다.

  애그리거트에 속한 객체는 애그리거트 루트 엔티티에 직접 또는 간접적으로 속하게 된다. 

 

- 주문 애그리거트에서 루트 역할을 하는 엔티티는 Order이다.

  OrderLine, ShippingInfo, Orderer 등 주문 애그리거트에 속한 모델은 Order에 직접 또는 간접적으로 속한다.

 

 

2) 도메인 규칙과 일관성

- 애그리거트 루트가 단순히 애그리거트에 속한 객체를 포함하는 것으로 끝나는 것은 아니다.

  애그리거트 루트의 핵심 역할은 애그리거트의 일관성이 깨지지 않도록 하는 것이다.

  이를 위해 애그리거트 루트는 애그리거트가 제공해야 할 도메인 기능을 구현한다.

 

- 예를 들면, 주문 애그리거트는 배송지 변경, 상품 변경과 같은 기능을 제공하고,

  애그리거트 루트인 Order가 이 기능을 구현한 메서드를 제공한다.

 

- 애그리거트 루트가 제공하는 메서드는 도메인 규칙에 따라 애그리거트에 속한 

  객체의 일관성이 깨지지 않도록 구현해야 한다.

 

- 배송이 시작되기 전까지만 배송지 정보를 변경할 수 있다는 규칙이 있다면,

  애그리거트 루트인 Order의 changeShippingInfo() 메서드는 이 규칙에 따라

  배송 시작 여부를 확인하고 규칙을 충족할 때만 배송지 정보를 변경해야 한다. 

 

public class Order {

    // 애그리거트 루트는 도메인 규칙을 구현한 기능을 제공한다.
    public void changeShippingInfo(ShippingInfo newShippingInfo) {
        verifyNotYetShipped();
        setShippingInfo(newShippingInfo);
    } 
    
    private void verifyNotYetShipped() {
       if (state != OrderState.PAYMENT_WAITING && state != OrderState.PREPARING){
          throw new IllegalStateException("already shipped");
       }
    }
    
    ...
 }

 

- 애그리거트 외부에서 애그리거트에 속한 객체를 직접 변경하면 안된다.

  이것은 애그리거트 루트가 강제하는 규칙을 적용할 수 없어 모델의 일관성을 깨는 원인이 된다.