#03장 애그리거트

최범균 저「DDD START!, 2016」를 읽고 정리하였습니다.

다룰 내용

  • 애그리거트

  • 애그리거트 루트와 역할

  • 애그리거트와 리포지터리

  • ID를 이용한 애그리거트 참조

애그리거트

  • 복잡한 객체관계에 대한 이해보다, 상위 수준에서 도메인 모델 관계를 이해해야 된다.

  • 그게 바로 애그리거트

  • 동일한 애그리거트에 있는 객체는 동일한 라이프사이클을 갖는다.

  • Order, OrderLine, Orderer은 함께 생성된다.

    • ShippingInfo에서 주문자를 생성하지 않는다.

    • 주문 애그리거트에서 회원 비밀번호를 변경하거나 상품의 가격을 변경하지 않는다.

  • 경계 설정에는, 도메인 규칙과 요구사항이 기본이다.

    • 주문시점 생성되는 애그리거트 = 주문 상품 개수, 배송지 정보, 주문자 정보

  • A가 B를 갖는다고 한 애그리거트가 아니다

    • 예, 상품 - 리뷰 (상품이 생성된다고 리뷰가 생성되는 것은 아니다)

  • 경험상, (대부분) 한 애그리거트에는 한개의 엔티티 객체만 갖는다.

애그리거트 루트와 역할

  • 모든 객체가 일관된 상태를 유지하기 위해, 전체를 관리할 주체 “애그리거트 루트 엔티티”가 있다.

  • 루트 역할: 일관성이 깨지지 않게, 중앙적으로 관리한다.

    • 예, 주문 애그리거트는 배송지 변경, 주문 상품 변경 기능 제공

  • 이를 달성하기 위한 팁

    • set 메서드는 public 범위로 만들지 않는다.

    • 밸류타입은 불변으로 구현한다.

      • 외부에서 밸류 객체의 상태를 변경할 수 없게 된다. (루트에서만 관리)

  • 트랜잭션 범위는 작게하자. ( 성능적으로, 테이블 3개를 잠그는 것보다 1개만 잠그는게 훨씬 좋음)

    • 한 트랜잭션에서 한 개의 애그리거트만 수정한다. (충돌 낮춤)

    • 다른 말로, 2개의 애그리거트 함께 수정되는 트랜잭션 자제

    • 예, 주문 중에서 배송지를 변경했다고, 회원 자체의 배송지 정보를 변경하지 말자. (주문, 회원 애그리거트 손대는 행위) 결합도는 최대한 낮추자.

    • 그러나, 책에선 3가지 제약의 이유로 두개 애그리거트 변경이 발생할 수 있다고 이야기한다.

    • 2개의 애그리거트를 건들시, 한 애그리거트에서 다른 애그리거트를 건드리는게 아니라, 응용 서비스에서 처리하자.

애그리거트와 리포지터리

  • 리포지터리는 애그리거트 단위로 존재한다.

  • 애그리거트는 개념적으로 하나이므로, 전체를 저장소에 영속화 한다.

ID를 이용한 애그리거트 참조

  • 다른 애그리거트를 참조한다는 것은 애그리거트 루트를 참조한다는 의미이다.

    • 예, 주문 애그리거트의 Orderer에서 회원은 멤버 애그리거트 루트인 Member를 참조한다.

  • ORM 덕에, 애그리거트 루트 참조 쉽다.

    • 하지만 3가지 문제점

      • 편한 탐색 오용, 성능에 대한 고민점, 확장 어려움

    • 해결방법: ID를 이용한 다른 애그리거트 참조

해결방법 예시 - Member를 MeberId로 바꾸자.

  • 변경 전

  • 변경후

    • 주문이랑 멤버가 아니라도, 다른 도메인이 있다고 가정하면, 다른 DB를 사용할 수 있기 때문에 이렇게 하면 ~

다음과 같이 사용할 수 있따.

  • 하지만... 조회성능에서 문제가 찾아올 수 있다. (예, N+1 문제)

  • 이를 해결하기 위해, 전용 조회 쿼리 사용하자.

    • 별도의 조회용 DAO 를 만든다.

    • 아래는 사용자 주문내역인 OrderView를 만든다. 주문, 멤버, 상품 애그리거트를 세타조인 했다.

    • 자세한 조회전용 쿼리는 5장에서

애그리거트 간 집합 연관

  • 애그리거트 간의 1:N 연관을 실제 구현에 반영하는 경우는 드물다.

    • 솔직히 아래 사례, 무슨말인지 잘 모르겠다.. 카테고리 객체 코드에서 상품 가져오는 코드가 페이징 처리를 상품을 다 가져오고 나서 해서... 비교가 되는 코드인지 모르겠다.

    • 예, 카테고리 - 상품 (상품은 하나의 카테고리에만 들어간다 가정)

      • 카테고리 객체에 Set으로 상품들 담아두면, 특정 카테고리의 상품들을 조회시 성능 문제 발생

    • 해결을 위해, 1:N이 아닌 N:1의 입장에서 생각하자.

      • 상품에 카테고리 ID를 넣어두고, 페이징처리하면서 부분만 가져오자.

  • M:N 의 경우, 단방향으로만 적용하면 된다.

애그리거트를 팩토리로 사용하기

  • 도메인 로직을 응용서비스에 노출하지 말자.

Last updated