DDD 의 Aggregate

정의

  • Entity들의 묶음. 데이터 변경의 단위로 다루는 연관 객체들의 묶음
  • 불변식이 존재한다.
    • ex) Option이 존재하면, OptionGroup 이 존재한다. Item 이 존재하면, Option이 없을 수 있다.

필요성

  • 모델 내에서 복잡한 연관관계를 맺는 객체를 대상으로 일관된 규칙을 보장하기는 쉽지 않다.
  • 개별 객체만이 아니라 서로 밀접한 관계에 있는 객체 집합에도 일관된 규칙(=불변식)이 유지되어야 하기 때문이다.
  • 이를 위해 Aggregate를 구성하고 Aggregate에 적용되는 불변식은 각 트랜잭션이 완료될 때 이행되도록 한다.

특징

  • 각 Aggregate 에는 Root 와 Boundary가 있다.
    • Boundary 에는 Aggregate 에 무엇이 포함되고 포함되지 않는지를 정의한다.
    • Root는 단 하나만 존재하며, Aggregate 에 포함된 특정 Entity를 가리킨다.
  • Aggregate 경계 밖에서는 루트 Entity를 제외한 Aggregate 내부의 구성요소를 참조할 수 없다.
  • Aggregate 경계 안의 어떤 객체를 변경하더라도 전체 Aggregate 의 불변식은 모두 지켜져야 한다.

예시

  • 상품 도메인에 대해서 DDD 를 적용시켜 본다.
    • 상품 도메인은 아래의 Entity로 구성된다
      • Item
      • ItemOptionGroup
      • ItemOption
    • 이 중 Item 은 Item 도메인 전체의 Aggregate Root 역할을 한다.
      • Item Aggregate 경계 밖에서는 Item 을 제외한 Aggregate 내부 구성요소를 참조할 수 없다.
        • 외부 서비스(e.g. Partner 도메인)은 Root(e.g. Item entity)와만 통신이 가능하다. 그 외(e.g. ItemOptionGroup, ItemOption entity) 와는 통신이 불가하다.
      • Item을 획득하면 Aggregate 내부의 객체를 탐색해서 획득할 수 있게 된다.
      • Item Aggregate 내부에서는 데이터가 변경될 때마다 유지돼야 하는 일관된 규칙이 지켜져야 한다.
        • 일관된 규칙은 Aggregate Root 에 적용되는 모든 트랜잭션 내에서 지켜져야 한다.
          -> 규칙이 깨진다면, 트랜잭션 롤백이 발생한다는 것!
    • Item Aggregate를 만들어내는 과정에서 Factory 사용을 검토한다.
      • Item 도메인의 경우 객체 생성 과정에서 Item 뿐만 아니라, OptionGroup, Option의 정합성이 일관되게 지켜져야 한다.
        • 각 클래스의 생성자만으로는 Item Aggregate 생성 과정의 복잡한 규칙을 표현하기 어렵다


Factory

필요성

  • 복잡한 객체를 생성하는 일은 도메인 계층의 책임이지만, 그것이 모델을 표현하는 객체에 속하는 것은 아니다.
    • 자동차를 조립하는 것과 자동차를 운전하는 것은 다른 영역의 것이다. 결코 동시에 일어날 수 없다.
  • 그렇다고 객체의 생성을 클라이언트에 두면, Aggregate의 캡슐화를 위반하고 클라이언트의 설계가 지저분해지게 된다.
  • 복잡한 객체와 Aggregate의 인스턴스 생성을 책임지는 별도의 객체를 선언하여 운영하는 것이 필요하다.

특징

  • 자신의 책임과 역할이 다른 객체를 생성하는 프로그램 요소를 Factory라고 한다.
    • 복잡한 객체와 Aggregate 인스턴스를 생성하는 책임을 맡기기 적합하다.
    • Factory 의 역할에서 객체를 데이터베이스와 같은 저장소에 영속화시키는 것은 포함되지 않는다! 이는 Repository 의 역할이다.
  • Factory 는 해당 Factory에서 만들어내는 객체와 매우 강하게 결합돼 있으므로, 자신이 생성하는 객체와 가장 가까이 있어야 한다.
  • Factory 는 Aggregate 에서 유지되어야 할 불변식 로직을 Factory 내에 둬서 Aggregate 내에 들어 있는 복잡한 요소를 줄일 수도 있다.
    • 특정 객체나 Aggregate를 생성하는 일이 복잡해지거나 내부 구조를 너무 많이 드러내는 경우, Factory를 사용하자!

예시

Item 을 생성할 때 ItemOptionGroup, ItemOption 을 둘 다 생성해주어야 하면, 이를 Factory 내부 로직으로 숨길 수 있다

1. Domain Layer 의 ItemServiceImpl 에서
2. Domain Layer 의 ItemOptionSeriesFactory 인터페이스를 참조하고
3. Infrastructure Layer 에서 이를 구현한 ItemOptionSeriesFactoryImpl 의 store() 에서 ItemOptionGroup, ItemOption 을 둘 다 생성


Reference

Leave a comment