본문 바로가기

[DDD START!] 3장 애그리거트

- 애그리거트

- 애그리거트 루트와 역할

- 애그리거트와 리포지터리

- ID를 이용한 애그리거트 참조

 

애그리거트

관련된 객체를 하나의 군으로 묶어준다. 

-> 좀 더 상위 수준에서 도메인 모델 간의 관계를 파악할 수 있다. 

애그리거트는 모델을 이해하는 데 도움을 줄 뿐만 아니라 일관성을 관리하는 기준이 된다. 

애그리거트에 속한 객체는 유사하거나 동일한 라이프사이클을 가진다. 

애그리거트는 독립된 객체군이며, 각 애그리거트는 자기 자신을 관리할 뿐 다른 애그리거트를 관리하지 않는다. 

A가 B를 갖는다고 한 애그리거트에 있지는 않음

-> 상품 리뷰와 상품 상세가 그러함.

-> 라이프사이클이 다름, 변경의 주체가 다름.

다수의 애그리거트가 한 개의 엔티티 객체만 갖는 경우가 많음 드물게 2개 이상의 엔티티로 구성된 애그리거트도 있음.

 

애그리거트 루트 

애그리거트 루트의 핵심 역할은 애그리거트의 일관성이 깨지지 않도록 하는 것.

불필요한 중복을 피하고 애그리거트 루트를 통해서만 도메인 로직을 구현하게 만들려면

도메인 모델에 대해 

1. 단순히 필드를 변경하는 set 메서드를 공개(public) 범위로 만들지 않는다.

- 중요 도메인의 의미나 의도를 표현하지 못하고

- 도메인 로직이 도메인 객체가 아닌 응용 영역이나 표현 영역으로 분산되게 만드는 원인.

2. 밸류 타입은 불변으로 구현한다. 

-  애그리거트 외부에서 변경할 수 있는 가능성이 줄어든다. 

- 밸류 타입의 내부 상태를 변경하려면 애그리거트 루트를 통해서만 가능함.

 

애그리거트 루트의 기능 구현

 

트랜잭션 범위 

트랜잭션 범위는 작을수록 좋다. 

한 트랜잭션에서 한 애그리거트만 수정한다는 것은 애그리거트에서 다른 애그리거트를 변경하지 않는다는 것을 뜻한다. 

 

리포지터리와 애그리거트

애그리거트는 개념상 완전한 한 개의 도메인 모델을 표현하므로 객체의 영속성을 처리하는 리포지터리는 애그리거트 단위로 존재한다. 

- save : 애그리거트 저장

리포지터리에 애그리거트를 저장하면 애그리거트 전체를 영속화 해야 한다. 

- fineById : ID로 애그리거트를 구함.

 

ID를 이용한 애그리거트 참조

Order안에 Member 객체 직접 참조의 경우

1. 편한 탐색 오용

한 애그리거트 내부에서 다른 애그리거트 객체에 접근할 수 있으면 다른 애그리거트의 상태를 쉽게 변경할 수 있다.

애그리거트가 관리하는 범위는 자기 자신으로 한정해야 한다. -> 다른 애그리거트를 수정하고자 하는 유혹에 빠짐.

2. 성능에 대한 고민

객체 지연로딩, 즉시 로딩, 조회는 즉시로딩, 수정은 지연로딩이 유리하다.

3. 확장 어려움 

사용자가 몰리면 하위 도메인 별로 시스템 분리, 하위 도메인마다 다른 DBMS를 사용할 가능성이 있다. -> 다른 애그리거트 루트를 참조하기 위해 JPA와 같은 단일 기술을 사용할 수 없음을 의미한다.

->>>>> 해결 : ID를 이용해서 다른 애그리거트 참조   (외래키 사용과 비슷)

지연로딩을 하는것과 동일한 결과, 한 애그리거트에서 다른 애그리거트 수정하는 문제를 원척적으로 방지, 다른 구현 기술 가능

 

ID를 이용한 참조와 조회 성능

조회 대상이 N개일 때 N개를 읽어오는 한 번의 쿼리와 연관된 데이터를 읽어오는 쿼리를 N번 실행한다 해서 N+1 조회 문제

-> 지연로딩이 문제라서 객체 참조로 바꾸면 됨 -> 그럼 위의 3가지 문제가 다시 발생.

ID참조 방식을 사용하면서 N+1 조회 와 같은 문제가 발생하지 않도록 하려면 조회 쿼리를 따로 만든다. 

 

애그리거트간 집합 연관

애그리거트를 팩토리로 사용하기