DDD 3. 애그리거트 Aggregate
⌜애그리거트⌟
1. 애그리거트(Aggregate)
< 애그리거트 개념이 필요한 이유 > 도메인 객체 모델이 복잡해지면 개별 구성요소 위주로 모델을 이해하게 되고 전반적인 구조나 큰 수준에서 도메인 간의 관계를 파악하기 어려워진다.
- 복잡한 도메인을 이해하고 관리하기 쉬운 단위로 만들려면 상위 수준에서 모델을 조망할 수 있어야한다.
- 그 방법이 바로 애그리거트다.
- 애그리거트는 관련된 객체를 하나의 군으로 묶어 준다.
- 수많은 객체를 애그리거트 단위로 묶어서 바라보면 상위 수준에서 도메일 모델간의 관계를 파악할 수 있다.
- 애그리거트 단위는 보통 도메인 모델 1개 많으면 2개 정도로 구성된다.
2. 애그리거트 루트와 역할
- 애그리거트는 여러 객체로 구성되기 때문에 한 객체만 상태가 정상이면 안된다.
- 도메인 규칙을 지키려면 애그리거트에 속한 모든 객체가 정장 상태를 가져야한다.
- 애그리거트에 속한 모든 객체가 일관된 상태를 유지하려면 애그리거트 전체를 관리할 주체가 필요한데, 이 책임을 치는 것이 바로 애그리거트의 루트 엔티티이다.
3. 애그리거트와 리포지터리
- 애그리거트는 개념상 완전한 한 개의 도메인모델을 표현하므로 객체의 영속성을 처리하는 리포지터리는 애그리거트 단위로 존재한다.
- 애그리거트 내부 객체들이 물리적으로 각각 별도의 DB 테이블에 존재한다고 해서 각각의 객체를 위한 리포지터리를 만들지 않는다.
4. ID를 이용한 애그리거트 참조
- 한 객체가 다른 객체를 참조하는 것처럼 애그리거트도 다른 애그리거트를 참조한다.
- 애그리거트 관리 주체는 애그리거트 루트이므로 애그리거트에서 다른 애그리거트를 참조한다는 것은 다른 애그리거트의 루트를 참조한다는 것과 같다.
- < 애그리거트 간의 필드를 이용한 참조 >
- ORM 의 매핑 기능을 이용해 필드를 통한 다른 애그리거트 참조를 쉽게 구현할 수 있다.
-
하지만 필드를 이용한 애그리거트 참조는 다음 문제를 야기할 수 있다.
[ 편한 탐색 오용 ]
애그리거트 내부에서 다른 애그리거트 객체에 접근할 수 있으면 다른 애그리거트의 상태를 쉽게 변경할 수 있게 된다. 이는 애그리거트 간의 의존 결합도를 높여서 결과적으로 애그리거트의 변경을 어렵게 만든다.
[ 성능에 대한 고민 ]
ORM 의 기능중 지연로딩과 즉시로딩 같은 로딩 전략을 경우에 따라 다르게 정해야 한다.
[ 확장의 어려움 ]
하위 도메인 별로 시스템이 분리되고 DBMS의 종류, 물리적인 저장소가 달라질 때 단일 기술을 사용할 수 없으므로 확장에 어려워진다.
- 이런 세 가지 문제를 완화할 때 사용할 수 있는 것이 ID를 이용해서 다른 애그리거트를 참조하는 것이다. DB 테이블에서 외래키로 참조하는 것과 비슷하게 ID를 이용한 참조는 다른 애그리거트를 참조할 때 ID를 사용한다.
<aside> 💡 <ID 참조 사용의 장점 > 1) 한 애그리거트에 속한 객체들만 참조로 연결된다. - 이는 애그리거트의 경계를 명확히 하고 애그리거트간의 물리적인 연결을 제거하기 때문에 모델의 복잡도를 낮춰준다. - 또한 애그리거트 간의 의존을 제거하므로 응집도를 높여주는 효과도 있다. 2) 구현 복잡도도 낮아진다. - 다른 애그리거트를 직접 참조하지 않으므로 애그리거트 간 참조를 지연 로딩으로 할지 즉시 로딩으로 할지 고민하지 않아도 된다. - 참조하는 애그리거트가 필요하면 응용 서비스에서 ID를 이용해서 로딩하면 된다. </aside>
5. 애그리거트 간 집합 연관
- 1 : N, N : 1 의 경우 N : 1 관계만 매핑하여 구현하는게 성능상의 이점이있다. ( 예시 : 카테고리와 상품의 관계에서 카테고리에 속한 상품의 갯수가 많을 경우 )
- M : N 의 경우 요구사항을 고려하여 특정 방향 즉 단방향 M : N 연관만 적용하면 된다.
6. 애그리거트를 팩토리로 사용하기
- 애그리거트 생성시에 해당 생성 기능이 논리적으로 하나의 도메인 기능인지 판단하고 맞다면 응용서비스에서 구현하기 보다 애그리거트에서 구현하는것이 개념상 더 바람직하다. 응용 서비스에서 애그리거트의 데이터로 생성 여부를 판단한다면 이는 응용 서비스와 도메인간의 결합도가 높아지고 애그리거트의 응집도가 낮아지는것이다. ( 에시 : 특정 상점의 상태에 따라 해당 상점에 상품등록 가능여부를 판단하는 로직 )
- 특정 애그리거트가 갖고 있는 데이터를 이용해서 다른 애그리거트를 생성해야 한다면 애그리거트에 팩토리 함수를 구현하는 것을 고려해보자.
- 차단 상태의 상점은 상품을 만들 수 없다는 도메인 로직은 한곳에 계속 위치하게 된다.
Comments