-
AGGREGATE와 REPOSITORY 2부JAVA/DDD 2020. 12. 29. 18:21
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 Evans는 AGGREGATE 패턴에 대한 규칙을 다음과 같이 정리하고 있다.
-
ENTRY POINT는 전역 식별자(global identity)를 가지며 궁극적으로 불변식(invariant)을 검증하는 책임을 가진다.
-
ENTRY POINT는 전역 식별자(global identity)를 가진다. AGGREGATE 내부에 속한 REFERENCE OBJECT들은 지역 식별자(local identity)를 가지며, 지역 식별자는 AGGREGATE 내부에서만 유일하다.
-
AGGREGATE 경계 외부에 있는 어떤 객체도 ENTRY POINT 이외의 AGGREGATE 내부 객체를 참조할 수 없다. ENTRY POINT는 내부에 속한 REFERENCE OBJECT를 외부에 전달할 수는 있지만 이를 전달받은 객체는 일시적으로만 사용할 뿐 이에 대한 참조를 유지하지 않는다. ENTRY POINT는 VALUE OBJECT에 대한 복사본을 다른 객체에게 전달할 수 있다. VALUE OBJECT는 단지 값일 뿐이며, VALUE OBJECT는 AGGREGATE와 연관관계를 가지지 않기 때문에 VALUE OBJECT에 어떤 일이 발생하는지에 대해서는 신경 쓰지 않는다.
-
위 규칙으로부터 오직 ENTRY POINT만이 REPOSITORY로부터 직접 얻어질 수 있다는 사실을 유추할 수 있다. 모든 다른 객체들은 ENTRY POINT로부터의 연관 관계 항해를 통해서만 접근 가능하다.
-
AGGREATE 내부의 객체들은 다른 AGGREGATE의 ENTRY POINT를 참조할 수 있다.
-
삭제 오퍼레이션은 AGGREGATE 내부의 모든 객체를 제거해야 한다.(가비지 컬렉션을 가진 언어의 경우 이 규칙을 준수하는 것이 용이하다. AGGREGATE 외부의 어떤 객체도 ENTRY POINT를 제외한 내부 객체를 참조하지 않기 때문에 ENTRY POINT를 제거하면 이에 수반된 모든 내부 객체가 제거될 것이다.)
-
AGGREGATE 내부의 어떤 객체에 대한 변경이 확약되면, 전체 AGGREGATE에 관한 모든 불변 식이 만족되어야 한다.
- 눈 여겨봐야 할 규칙은 네 번째로 AGGREGATE의 ENTRY 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가 필요하다.
- AGGREGATE와 ENTRY POINT 역시 시스템의 복잡도를 낮춰주는 유용한 기법이다.
- AGGREGATE를 정의함으로써 자칫 자잘한 도메인 클래스 더미에 빠져 허우적댈 수도 있는 상황을 피해 불변식(invariant)을 공유하는 도메인 클래스들의 클러스터에 집중할 수 있다.
- 선택과 집중은 도메인 모델링 영역에서도 어김없이 적용된다.
- REPOSITORY는 AGGREGATE의 ENTRY POINT에 대해서만 할당한다.
- REPOSITORY는 객체 그래프에 대한 무분별한 접근을 지양하고 통제되고 제어된 방식으로 객체에 접근하고 항해할 수 있도록 한다.
- 이처럼 AGGREGATE는 REPOSITORY를 통해 접근해야 할 도메인 객체와 연관 관계 항해를 통해 접근해야 할 도메인 객체를 명확히 구분함으로써 효율적인 객체 항해를 위한 지침을 제공한다.
- AGGREGATE, ENTRY POINT, REPOSITORY는 유용한 분석 기법인 동시에 도메인 객체에 대한 메모리 컬렉션 관점을 데이터베이스와 동시 실행 콘텍스트를 기반으로 한 엔터프라이즈 애플리케이션 환경으로 자연스럽게 이어주는 구현 기법이기도 하다.
- 다음은 AGGREGATE와 ENTRY POINT를 결정한 후 REPOSITORY를 추가한 주문 도메인 모델을 도시한 것이다.
- 주문에 대한 불변식을 AGGREGATE에 추가했음에 주목하자.
참조
이터니티 - Domain-Driven Design의 적용
'JAVA > DDD' 카테고리의 다른 글
AGGREGATE와 REPOSITORY 4부 (0) 2021.01.05 Aggregate와 Repository 3부 (0) 2020.12.30 AGGREGATE와 REPOSITORY 1부 (0) 2020.12.28 DDD - Value Object와 Reference Object 4부 (0) 2020.12.24 DDD Value Object와 Reference Object 3부 (0) 2020.12.23