
출처 : 도메인 주도 개발 시작하기
위와 같이 상위 도메인 개념의 연관관계를 나타내면 이해하기가 굉장히 쉽다.
하지만, 이를 개별 객체의 관계도로 디테일하게 그려보면 아래와 같이 연관관계를 한눈에 파악하기가 어렵다는 것을 알 수 있다.

출처 : 도메인 주도 개발 시작하기
그렇기 때문에, 연관관계를 볼 때, 상위 수준에서 바라보는 것이 굉장히 중요한 것이고, 이를 지키기 위해 개별 객체 수준과 상위 도메인 개념을 합쳐서 다음과 같이 볼 수 있다.

출처 : 도메인 주도 개발 시작하기
이를 통해서 모델을 이해하는데 도움을 받을 수 있고, 이로 인해 일관성을 관리하는 기준이 된다.
또한, 복잡한 도메인 구조를 단순한 구조로 만들어주기 때문에 도메인 기능을 확장하고 변경하는 데 필요한 노력이 줄어들게된다.
위의 그림에서 보듯이, 애그리거트는 경계를 갖게 된다. 한 애그리거트에 속한 객체는 다른 애그리거트에 속하게 되지 않는 것이다.
예를 들어서 주문 애그리거트는 배송지를 변경하거나 주문 상품 개수를 변경하는 등 자기 자신은 관리하지만, 회원의 비밀번호를 변경하거나 상품의 가격을 변경하지 않는 것처럼 말이다.
그래서 경계를 설정하는 것이 굉장히 중요하다.
가장 쉬운 방법으로는 도메인 규칙에 따라 함께 생성되는 구성요소는 한 애그리거트에 속할 가능성이 굉장히 높다.
하지만, 헷갈리면 안되는 부분이 있다. 흔히 A가 B를 갖는다로 해석할 수 있는 요구사항이 있다면? 포함관계로 표현하기가 쉬운데, 그렇지 않다.
그렇기 때문에, 서로 간의 생명주기를 확인하고 도메인을 설계하는 것은 굉장히 중요하다.

출처 : 도메인 주도 개발 시작하기
Product의 Review가 달리더라도, 서로 생명주기가 다르고, 서로의 변경이 서로에게 영향을 주지 않기 때문에 다른 애그리거트로 잡아야한다. Product가 Review를 포함하고 있는 것으로 보기 굉장히 쉽기에, 생명주기를 고려하는 것이 더더욱 중요한 것이다.
도메인 요구사항을 지키기 위해서는, 단 하나의 객체만이 도메인 요구사항을 지키는 상태이면 안된다. 모든 객체들이 그러한 상태를 유지해야 하기에, 이를 관리하는 주체가 필요한데, 이것이 애그리거트 루트이고, 루트에 다른 객체들은 속하게 된다.

출처 : 도메인 주도 개발 시작하기
위에서 설명하였듯이, 애그리거트에 속해있는 객체들이 도메인 요구사항을 지키는 일관성을 유지시켜주는 역할이 애그리거트 루트이다.
또한, 이는 애그리거트 외부에 있는 다른 객체들이 현 애그리거트 내부 객체들을 변경하면 안된다는 의미로 해석할 수도 있다.
만일 이가 지켜지지 않는다면, 정합성이 깨질 수 있는 위험요소가 곳곳에 존재할 것이고, 유지보수는 더 어려워지게 될 거싱다.

출처 : 도메인 주도 개발 시작하기
이를 자동적으로 지키기 위해서, 현재 본인이 가장 지키고 있는 부분 중에 하나이고, 가이드 하는 부분이기도 하다.
이는 중복코드를 발생시키지 않으며, 변경지점을 하나로 모아 유지보수도 쉽게 만들어준다.

또한 불변으로 만들었을 때에는 무조건 새로운 객체를 할당해서 값을 변경해야 한다는 장점도 존재한다. (side effect 줄임)
최대한 하위 애그리거트에 도메인 요구사항을 구현하도록 하고, 또한 외부에서 애그리거트 루트가 가지고 있는 요소들을 직접 변경할 수 없게 만들어 side effect를 줄이는 것이 좋다. 방법으로는 private 혹은 같은 패키지내에서만 사용할 수 있도록 protected를 추천한다.
트랜잭션의 범위는 좁을 수록 좋다.
이를 도메인적인 관점에서 보면 하나의 애그리거트가 다른 애그리거트를 수정하게 되면, 해당 애그리거트를 변경할 때, 다른 애그리거트까지 수정할 확률이 굉장히 높아진다는 것을 의미한다.
그렇기 때문에, 동시에 여러 애그리거트를 수정해야하는 일이 생긴다면, 서비스 측에서 이를 수정하는 것이 좋고, 그렇게 하기 위해서 애그리거트 간의 참조 관계를 직접 참조를 사용하는 것보다 간접 참조를 사용하는 것이 더 좋아보인다. (애그리거트 간의 관계를 최대한 느슨하게 하면서, 동시에 수정되는 일을 최대한 방지하고, 명시적으로 Service 계층에서 컨트롤)
이렇게 잘 분리해두면, 비동기로 처리하는 것도 조금 쉬워진다.

출처 : 도메인 주도 개발 시작하기
어쩄든, 하나의 트랜잭션에서 여러개의 애그리거트를 수정하는 것을 추천하지는 않지만 위와 같은 경우에는 어쩔 수 없이 진행해야 한다.
리포지토리는 애그리거트 전체를 영속시키거나 찾아온다.
그렇기 때문에, 완전한 애그리거트를 영속시켜야하고, 또한 기존의 데이터가 존재했다면 모든 내용을 바꿔주어야한다.

출처 : 도메인 주도 개발 시작하기
이런 식으로 직접참조를 사용하면, order.getOrderer().getMember().getId() 등처럼 쉽게 참조를 진행할 수 있다.
같은 애그리거트 내에서 이러한 것들은 굉장히 이득이 되지만, 그렇지 않다면 다음과 같은 단점이 존재하게 된다.

출처 : 도메인 주도 개발 시작하기
물론 좋은 점이 엄청나게 많지만, 나쁜점또한 이 좋은 점들에서 오는 것 같다.
다른 애그리거트를 너무나도 손쉽게 사용하고, 변경할 수 있으니 다음과 같은 문제점이 발생한다.
이러한 결과로 서로 다른 애그리거트 간의 결합도가 높아지게 되고, 이는 변경의 어려움을 발생시킨다.
성능에 대한 고민은 단순히 모든 것을 조회한다면 그냥 다 불러오는게(즉시 로딩) 성능상 이득이지만, 만일 애그리거트에 속해있는 다른 애그리거트를 조회하지 않는다거나 변경에 필요하지 않은 경우 지연로딩이 이득이다.
이런 식으로 고민을 발생시키게 된다.
확장도 문제인데, 현재 JPA이기 때문에, 가능하지만, 나중에 기능을 확장하면서 여러 DBMS를 사용하게 될 수 있기 때문에 변경이 어려운 것이다.
이를 해결하기 위한 방법은 ID로 참조하는 것이다.
애그리거트 간의 의존을 제거하므로 응집도를 높여주고, 구현 복잡도도 낮아진다 (위 3가지 고민을 하지 않아도 되기 때문에)
하지만, 단점도 생기게 된다.
기존에 메서드 하나만 호출하면 됐었는데, 이제는 서비스 측에서 이를 따로따로 호출해주어야 한다. 하지만, 이게 추후 결과적으로 봤을 때에는 더 좋은 방향임은 확실한 것 같다.

출처 : 도메인 주도 개발 시작하기
또한, 다음과 같이 도메인 별로 다른 DB를 사용할 수도 있다.
ID를 이용해서 처리하게 되는 경우, 마치 N+1문제가 발생하는 것과 동일한 현상이 발생하기도 한다. 기존에는 조인으로 처리했던 것을 각각 select 쿼리를 날리기 때문이다.
당연히 조인을 하면 해결이 되기 때문에 이를 해결해보자.


출처 : 도메인 주도 개발 시작하기
다음과 같은 형식으로 DAO를 만들어서 조인 쿼리를 날리는 형식으로 해결하면된다.
세련되지 않은 방식이라고 생각할 수 있지만, 조회성능을 개선시키기 위해 쿼리를 작성하는 능력과 그것을 적절하게 선택해 활용할 수 있는 능력은 꼭 필요한 능력 중 하나이다.
직접 참조하게 되면, 이전과 같이 @OneToMany List 로 관리하는 것이 불가능해진다. 하지만, 괜찮다. N 관계에 있던 애그리거트가 1을 참조하는 id 를 가지고 있다면 Repository로 Service딴에서 조회하면 되는 문제이다.

출처 : 도메인 주도 개발 시작하기
N-M 관계도 어렵지 않다.
다대다 관계인 경우 중간테이블을 놓고, Product 에서 Product_Category를 참조하기 위해서는 Category_Id의 List들을 관리하고 있으면 되는 것이다.
그래서 이도 역시 Dao로 구현하면 쉽게 구현할 수 있다. (member of 로 구현)
이 부분은 많은 영감을 주었다.
Store(가게)가 더 이상 상품을 등록하지 못한다고 가정했을 때, 서비스에 로직은 Store를 찾아온 뒤 isBlocked 를 호출하게 될 것이다.
그 다음에 Product를 서비스에 생성할 것인데, 이는 도메인 로직이 서비스에 전부 다 드러나있어, 중복코드가 많이 발생할수도 실수가 발생할 확률도 굉장히 크다.
그렇기 때문에, 유지보수성을 많이 떨어트릴 수 있는데, 이를 Store 애그리거트에서 Product 를 생성하는 방향으로 진행을 하면 조금 깔끔하게 해결이 가능하다. 하지만 이로써 애그리거트 간의 의존성이 생기게 되니, 양방향 의존이 생기지 않도록 유의하는 것이 중요할 것 같다.
아래는 예제이다.

출처 : 도메인 주도 개발 시작하기
기존의 코드


출처 : 도메인 주도 개발 시작하기
애그리거트를 팩토리로 사용

출처 : 도메인 주도 개발 시작하기
만일 더 많은 정보가 필요하더라도 이도 생성자에 주입
DDD professor, Kim. 잘 봤어요 🦔👍