3.1 애그리거트
- 모델을 이해하는 데 도움을 준다.
- 일관성을 관리하는 기준이 된다.
- 일반적으로 애그리거트에는 하나의 엔티티 객체가 있다.
3.2 애그리거트 루트
- 애그리거트의 일관성을 관리하기 위해 애그리거트 전체를 관리할 주체
- 도메인 규칙과 일관성을 담당한다
- 애그리거트 루트의 기능은
- 애그리거트 내부의 다른 객체 (vo 등)를 조합해서 기능을 완성한다.
- vo는 불변으로 구현하고 vo의 (상태변경) 기능을 외부에서 실행할 수 없도록 제약하자
- 트랜잭션이 담당하는 범위로 삼는다.
- 한 트랜잭션에서 한 개의 애그리거트를 변경하는 것이 디폴트
3.3 리포지토리와 애그리거트
- 리포지터리는 애그리거트 단위로 존재한다.
- 데이터 일관성을 위해!
- 참고) - 유영모 - 애그리게잇 하나에 리파지토리 하나
- 보통 다음의 두 메서드를 기본으로 제공한다.
- save
- findById
3.4 ID를 이용한 애그리거트 참조
애그리거트에서 다른 애그리거트를 참조한다는 것은 다른 애그리거트의 루트를 참조한다는 것과 같다.
애그리거트를 참조하는 두가지 방식
- 직접 참조
- id를 이용한 간접 참조
애그리거트를 직접 참조하는 방식 예시
package com.meoguri.linkocean.domain.bookmark.entity; ... import com.meoguri.linkocean.domain.linkmetadata.entity.LinkMetadata; import com.meoguri.linkocean.domain.profile.command.entity.Profile; import com.meoguri.linkocean.domain.tag.entity.Tags; ... @Entity public class Bookmark { private Profile writer; private LinkMetadata linkMetadata; private Tags tags; }
애그리거트를 직접 참조하는 방식의 문제점
- 편한 탐색 오용
- 성능에 대한 고민
- 참조를 마구 때려 넣는 방식으로 구현하다보면 무조건 만나는 문제중 하나이다.
참조한 객체를 lazy loading과 eager loading 두 가지 방식으로 로딩할 수 있다. 단순히 연관된 객체의 데이터를 함께 화면에 보여줘야 하면 eager loading이 조회 성능에 유리하지만 aggregate의 상태를 변경하는 기능을 실행하는 경우에는 불필요한 객체를 함께 로딩할 필요가 없으므로 지연 로딩이 유리하다. 이런 다양한 경우의 수를 고려하여 로딩 전략을 결정해야 한다.
- 확장 어려움
한 애그리거트 내에서만 객체 참조를 사용하고 외부 객체에 대해서는 ID를 참조하여 애그리거트의 경계를 명확히 할 수 있다.
3.4.1 ID를 이용한 참조와 조회 성능
다른 애그리거트를 ID로 참조하면 참조하면 여러 애그리거트를 읽을 때 조회 속도가 문제 될 수 있다. -p.118
ID를 사용한 조회가 오히려 성능에 유리 할 수도 있다.
- Application/DB 관점에서 분리된 쿼리의 캐시가 validate할 가능성이 될 가능성이 높다.
해결 방법 1. 객체 참조로 바꾼다 → 조삼모사
해결 방법 2. 서비스 레이어에서 조합 한다.
이때 N+1 문제에 주의한다.

해결 방법 3. Join이 필수적이라면
- DAO를 사용한다. - aggregate간의 경계를 넘어선 조회가 필요한 경우 활용

3.5 애그리거트간 집합 연관
@OnetoMany
@ManyToMany
양방향 참조가 필요한지, ID 참조로 충분한지 판단한다.
참조 대상 집합의 숫자가 수만건이 됬을때 발생하는 쿼리를 예상해보자
3.6 애그리거트를 팩토리로 사용하기
- 애그리거트가 갖고 있는 데이터를 이용해 다른 애그리거트를 생성해야 한다면 애그리거트에 팩토리 메서드를 구현하는 것을 고려해보자.
- 알림, 링크 메타 데이터 생성시 고려해보자