김동형수 개발기

도메인 주도 개발 시작하기 - 3장 본문

책 스터디/[완료] DDD - 도메인 주도 개발 시작하기

도메인 주도 개발 시작하기 - 3장

김동형수 2023. 3. 9. 00:13

3장 애그리거트

 

애그리거트

 

상위 수준에서 모델을 정리하면 도메인 모델의 복잡한 관계를 이해하는 데 도움이 된다.

도메인 객체 모델이 복잡해지면 도메인 간의 관계를 파악하기 어려워진다.

주요 도메인 요소 간의 관계를 파악하기 어렵다는 것은 코드를 변경하고 확장하는 것이 어려워진다는 것을 의미한다.

꼼수를 부리면 장기적으로 코드를 더 수정하기 어렵게 만든다.

 

복잡한 도메인을 이해하고 관리하기 쉬운 단위로 만드는 방법이 애그리거트다.

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

애그리거트는 복잡한 도메인을 단순한 구조로 만들어준다.

애그리거트는 관련된 모델을 하나로 모았기 때문에 한 애그리거트에 속한 객체는 유사하거나 동일한 라이프 사이클을 갖는다.

한 애그리거트에 속한 객체는 다른 애그리거트에 속하지 않는다.

 

경계를 설정할 때 기본이 되는 것은 도메인 규칙과 요구사항이다.

 

처음 도메인 모델을 만들기 시작하면 큰 애그리거트로 보이는 것들이 많지만, 도메인에 대한 경험이 생기고 도메인 규칙을 제대로 이해할수록 애그리거트의 실제 크기는 줄어든다.

 

애그리거트 루트

애그리거트는 여러 객체로 구성되기 때문에 한 객체만 상태가 정상이면 안 된다. 애그리거트에 속한 모든 객체가 정상 상태를 가져야 한다.

애그리거트 전체를 관리할 주체가 필요한데, 이 책임을 지는 것이 바로 애그리거트의 루트 엔티티다.

 

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

애그리거트 외부에서 애그리거트에 속한 객체를 직접 변경하면 안 된다.

불필요한 중복을 피하고 애그리거트 루트를 통해서만 도메인 로직을 구현하게 만들려면 아래의 두가지를 습관적으로 적용해야한다.

  • 단순히 필드를 변경하는 set 메서드를 공개 범위로 만들지 않는다.
  • 밸류 타입은 불변으로 구현한다.

애그리거트 외부에서 내부 상탱를 함부로 바꾸지 못하므로 애그리거트의 일관성이 깨질 가능성이 줄어든다. 밸류 객체가 불변이면 밸류 객체의 값을 변경하는 방법은 새로운 밸류 객체를 할당하는 것이다.

 

애그리거트 루트는 애그리거트 내부의 다른 객체를 조합해서 기능을 완성한다.

애그리거트 루트가 구성요소의 상태만 참조하는 것은 아니다. 기능 실행을 위임하기도 한다.

불변으로 구현할 수 없다면 protected 범위로 외부에서 실행할 수 없도록 제한.

 

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

한 트랜잭션에서는 한 개의 애그리거트만 수정해야 한다.

한 트랜잭션에서 한 개의 애그리거트를 변경하는 것을 권장하지만, 다음 경우에는 한 트랜젝션에서 두 개 이상의 애그리거트를 변경하는 것을 고려할 수 있다.

 

리포지터리와 애그리거트

 

리포지터리는 보통 다음의 두 메서드를 기본으로 제공한다.

  • save
  • findById

애그리거트는 개념적으로 하나이므로 리포지터리는 애그리거트 전체를 저장소에 영속화해야한다.

리포지터리 메서드는 완전한 애그리거트를 제공해야 한다.

 

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

한 객체가 다른 객체를 참조하는 것처럼 애그리거트도 다른 애그리거트를 참조한다. 애그리거트 관리 주체는 애그리거트 루트이므로 애그리거트에서 다른 애거리거트를 참조한다는 것은 다른 애그리거트의 루트를 참조한다는 것과 같다.

 

JPA는 다른 애그리거트를 쉽게 참조할 수 있따.

애그리거트를 직접참조할때 가장 큰 문제는 편리함을 오용할 수 있다는 것이다.

구현의 편리함 때문에 유혹에 빠지기 쉽다.

 

애그리거트에서 다른 애그리거트의 상태를 변경하는 것은 결합도를 높여서 애그리거트의 변경을 어렵게 만든다.

애그리거트를 직접 참조하면 성능과 관련된 여러가지 고민을 해야한다.

확장의 문제. 애그리거트 루트를 참조하기 위해 JPA와 같은 단일 기술을 사용할 수 없음을 의미한다.

 

ID참조를 사용하면 모든 객체가 참조로 연결되지 않고 한 애그리거트에 속한 객체들만 촘조로 연결된다.

이는 모델의 복잡도를 낮춰준다.

 

애그리거트별로 다른 구현 기술을 사용하는 것도 가능해진다.

 

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

 

쿼리가 복잡하거나 SQL에 특화된 기능을 사용해야 한다면 조회를 위한 부부만 마이바티스와 같은 기술을 이용해서 구현할 수 있다.

 

애그리거트 간 집합 연결

애그리거트 간 1-N 관계는 Set과 같은 컬렉션을 이용해서 표현할 수 있다.

개념적으로 애그리거트간에 1-N 연관이 있더라도 성능 문제 때문에 애그리거트 간의 1-N연관을 실제 구현에 반영하지 않는다.

 

M-N 관계일 때 예시

상품상세 화면에서 카테고리를 조회하는 경우 관계상 M-N이지만 요구사항을 고려할 때 집합 연관은 필요하지 않다.

 

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

애그리거트를 팩토리로 사용할 때 도메인의 응집도가 높아진다.

애그리거트가 갖고 있는 데이터를 이용해서 다른 애그리거트를 생성해야 한다면 애그리거트에 팩토리 메서드를 구현하는 것을 고려해보자.

 

Comments