Eternity's Chit-Chat

aeternum.egloos.com



Domain-Driven Design의 적용-2.AGGREGATE와 REPOSITORY 2부 Domain-Driven Design

AGGREGATE

AGGREGATE는 데이터 변경 시 하나의 단위로 취급할 수 있는 연관된 객체들의 클러스터이다. AGGREATE는 루트(root)와 경계(boundary)를 가진다. 경계는 AGRREGATE 내부에 무엇이 포함되어야 하는지를 정의한다. 루트는 AGGREGATE 내에 포함된 하나의 REFERENCE OBJECT이다. 루트는 외부에서 참조 가능한 유일한 AGGREGATE의 내부 객체이다. 외부에서는 루트 객체만이 참조 가능하지만 AGGREGATE 내부의 객체는 외부 객체를 자유롭게 참조할 수 있다. 루트를 제외한 나머지 REFERENCE OBJECT들은 외부로부터 접근이 불가능하기 때문에 지역 식별자(local identity)를 가진다. 지역 식별자는 AGGREGATE 내부에서 REFERENCE OBJECT를 식별하기 위한 용도로만 사용된다. 반면 루트는 전역 식별자(global identity)를 가진다.

 

루트(root)AGGREGATE 내에 포함된 객체 그룹을 항해하기 위해 필요한 시작 위치를 제공한다. 루트라는 용어는 Eric Evans가 그의 저서 “Domain-Driven Design”에서 AGGREGATE의 개념을 설명하면서 사용한 것으로 지난 아티클에서 소개한 ENTRY POINT와 동일하다. ENTRY POINT Martin Fowler“Analysis Patterns”에서 사용한 용어로서 ENTRY POINT라는 용어가 객체 그룹 내의 항해를 위한 시작 위치라는 본연의 역할을 더 잘 전달하기 때문에 본 아티클에서는 루트 대신 ENTRY POINT를 사용하기로 한다.

 

본 아티클에서는 ENTRY POINT를 다음과 같은 의미로 사용한다.

 

ENTRY POINT AGGREGATE를 대표하는 REFERENCE OBJECT AGGREGATE에 속한 객체 그룹을 항해하기 위한 시작 위치를 제공한다. ENTRY POINT는 전역 식별자(identity)를 가진다. 외부에서는 ENTRY POINT 이외의 다른 객체들에 직접 접근할 수 없으며 오직 ENTRY POINT로부터의 항해를 통해서만 접근 가능하다.

 

Eric EvansAGGREGATE 패턴에 대한 규칙을 다음과 같이 정리하고 있다.

  • ENTRY POINT는 전역 식별자(global identity)를 가지며 궁극적으로 불변식(invariant)을 검증하는 책임을 가진다.
  • ENTRY POINT는 전역 식별자(global identity)를 가진다. AGGREGATE 내부에 속한 REFERENCE OBJECT들은 지역 식별자(local identity)를 가지며, 지역 식별자는 AGGREGATE 내부에서만 유일하다.
  • AGGREGATE 경계 외부에 있는 어떤 객체도 ENTRY POINT 이외의 AGGREGATE 내부 객체를 참조할 수 없다. ENTRY POINT는 내부에 속한 REFERENCE OBJECT를 외부에 전달할 수는 있지만 이를 전달 받은 객체는 일시적으로만 사용할 뿐 이에 대한 참조를 유지하지 않는다. ENTRY POINTVALUE OBJECT에 대한 복사본을 다른 객체에게 전달할 수 있다. VALUE OBJECT는 단지 값일 뿐이며, VALUE OBJECT AGGREGATE와 연관관계를 가지지 않기 때문에 VALUE OBJECT에 어떤 일이 발생하는지에 대해서는 신경 쓰지 않는다.
  • 위 규칙으로부터 오직 ENTRY POINT만이 REPOSITORY로부터 직접 얻어질 수 있다는 사실을 유추할 수 있다. 모든 다른 객체들은 ENTRY POINT로부터의 연관 관계 항해를 통해서만 접근 가능하다.
  • AGGREATE 내부의 객체들은 다른 AGGREGATEENTRY POINT를 참조할 수 있다.
  • 삭제 오퍼레이션은 AGGREGATE 내부의 모든 객체를 제거해야 한다.(가비지 컬렉션을 가진 언어의 경우 이 규칙을 준수하는 것이 용이하다. AGGREGATE 외부의 어떤 객체도 ENTRY POINT를 제외한 내부 객체를 참조하지 않기 때문에 ENTRY POINT를 제거하면 이에 수반된 모든 내부 객체가 제거될 것이다.)
  • AGGREGATE 내부의 어떤 객체에 대한 변경이 확약되면, 전체 AGGREGATE에 관한 모든 불변식이 만족되어야 한다.

 

여기에서 눈 여겨봐야 할 규칙은 네 번째로 AGGREGATEENTRY POINT 만이 REPOSITORY를 통해 얻어질 수 있으며, AGGREGATE 내부의 다른 객체들은 ENTRY POINT로부터의 연관 관계를 통해서만 접근 가능하다는 부분이다. 이 규칙은 주문 도메인 예에서 살펴본 AGGREGATE 식별 규칙에 다음과 같은 한 가지 규칙을 추가한다.

 

어떤 REFERENCE OBJECT가 다른 객체에 대해 독립적으로 얻어져야 한다면 이 REFERENCE OBJECT를 중심으로 AGGREGATE 경계를 식별하고 해당 REFERENCE OBJECT ENTRY POINT로 정한다.

 

다시 주문 도메인을 살펴 보자. 만약 시스템 내의 모든 주문이 특정 고객 객체를 얻은 후에만 접근할 수 있다면 주문과 주문 항목은 고객 객체를 ENTRY POINT로 하는 AGGREGATE의 일부가 되어야 한다. , 고객 객체를 REPOSITORY로부터 얻은 후 해당 고객 객체로부터 연관 관계를 통해 해당하는 주문들을 항해하면서 작업을 처리한다. 그러나 고객과 무관하게 주문에 직접 접근해야 할 필요가 있다면 주문을 ENTRY POINT로 하는 AGGREGATE를 만드는 것이 좋다. 따라서 특정 일자에 발생한 모든 주문을 조회해야 한다는 요구사항이 존재한다면 주문을 ENTRY POINT로 하는 AGGREGATE가 필요하다.

 

AGGREGATEENTRY POINT 역시 시스템의 복잡도를 낮춰주는 유용한 기법이다. AGGREGATE를 정의함으로써 자칫 자잘한 도메인 클래스 더미에 빠져 허우적댈 수도 있는 상황을 피해 불변식(invariant)을 공유하는 도메인 클래스들의 클러스터에 집중할 수 있다. 선택과 집중은 도메인 모델링 영역에서도 어김없이 적용되는 캐치프레이즈인 것이다.

 

구현과 관련해서는 미묘한 동시성 컨텍스트 하에서 일관성을 유지하기 위해 도메인 클래스의 잠금 전략을 적용할 수 있는 위치를 제공하며, 높은 경합 지점의 식별을 통해 전반적인 성능 향상을 꾀할 수 있는 기초 자료가 된다.

 

REPOSITORY AGGREGATEENTRY POINT에 대해서만 할당한다. REPOSITORY는 객체 그래프에 대한 무분별한 접근을 지양하고 통제되고 제어된 방식으로 객체에 접근하고 항해할 수 있도록 한다. 이처럼 AGGREGATEREPOSITORY를 통해 접근해야 할 도메인 객체와 연관 관계 항해를 통해 접근해야 할 도메인 객체를 명확히 구분함으로써 효율적인 객체 항해를 위한 지침을 제공한다.

 

AGGREGATE, ENTRY POINT, REPOSITORY는 유용한 분석 기법인 동시에 도메인 객체에 대한 메모리 컬렉션 관점을 데이터베이스와 동시 실행 컨텍스트를 기반으로 한 엔터프라이즈 어플리케이션 환경으로 자연스럽게 이어주는 구현 기법이기도 하다. 이에 관해서는 ORM(Object-Relational Mapping)을 소개하는 부분에서 자세히 살펴보기로 한다.

 

다음은 AGGREGATEENTRY POINT를 결정한 후 REPOSITORY를 추가한 주문 도메인 모델을 도시한 것이다. 주문에 대한 불변식을 AGGREGATE에 추가했음에 주목하라.


그림 9 Order, Customer, Product에 대한 REPOSITORY 추가


핑백

  • Domain-Driven Design | Jongmin Kim's Blog 2014-09-02 01:18:33 #

    ... -Driven Design의 적용-2.AGGREGATE와 REPOSITORY 3부 [2] 2008/11/23 Domain-Driven Design의 적용-2.AGGREGATE와 REPOSITORY 2부 2008/11/20 Domain-Driven Design의 적용-2.AGGREGATE와 REPOSIT ... more