전술적 설계 - AGGREGATE 와 REPOSITORY
Last updated
Last updated
DDD 를 하게 되면 무수한!! VALUE OBJECT, ENTITY 가 등장하게 되고, 이는 분할의 결과물이다.
관련 객체를 하나로 묶은 군집을 AGGREGATE 라고 부른다. (논리적 구조)
애그리거트로 묶어서 바라보면 좀 더 상위 수준에서 도메인 모델 간의 관계를 파악할 수 있다.
애그리거트에 속한 객체는 유사하거나 동일한 라이프사이클을 갖는다. (동일한 라이프사이클을 갖는 케이스는 많지 않다.. 그래서 헷갈린다)
같은 애그리거트 내에서 소멸시점은 동일하나, 생성시점은 다른 케이스들이 많다.
때문에, 비지니스 로직을 수행해야 할 단위라는 표현이 직관적으로 이해하기가 좋다.
비지니스 로직 = 불변식 (불변식을 지켜야한다)
ex, 강의의 정원 25명, 수강생은 25명을 넘을 수 없다. (때문에, 수강생이 25명이 넘을 수 없도록 강의와 수강생은 같은 애그리거트로 묶어야 한다, 라이프 사이클은 다르다!)
한 애그리거트에 속한 객체는 다른 애그리거트에 속하지 않는다.
두 개 이상의 엔티티로 구성되는 애그리거트는 드물게 존재한다.
애그리거트 루트의 핵심 역할은 애그리거트의 일관성이 깨지지 않도록 하는 것이다.
애그리거트 루트는 애그리거트가 제공해야 할 도메인 기능을 구현한다.
애그리거트 루트는 애그리커트 묶음에서 유일하게 외부에 노출된다.
ex, 학급에서 가정통신문을 분배할 때, 반장이 가정통신문을 나누어준다.
이는 애그리거트의 내부 구현을 숨겨서 애그리거트 단위로 구현을 캡슐화할 수 있도록 돕는다.
루트 엔티티는 애그리거트에 속해 있는 엔티티와 밸류 객체를 이용해서 애그리거트가 구현해야 할 기능을 제공한다.
위와 같은 특징 때문에, 애그리거트 내부에 있는 엔티티나 밸류 오브젝트간에 협력은 이루어져서는 안된다.
만약 애그리거트 내부에 있는 엔티티나 밸류 오브젝트간에 협력이 이루어진다면 캡슐화 위반!!
애그리거트는 애플리케이션 레벨에서 ACID 를 지키는 방법이다!
애그리거트에서 다른 애그리거트와 직접 참조하게 되면 ACID 를 지키지 못하게 된다.
애그리거트를 직접 참조할 때 발생할 수 있는 가장 큰 문제는 편리함을 오용한다는 것이다.
애그리거트의 ACID 지키기 위해서는 간접 참조를 사용해야 한다.
간접(ID) 참조를 사용하면 모든 객체가 참조로 연결되지 않고 한 애그리거트에 속한 객체들만 참조로 연결된다.
간접 참조 방식을 사용하면 복잡도를 낮추는 것과 함께 한 애그리거트에서 다른 애그리거트를 수정하는 문제를 원칙적으로 방지할 수 있다.
DDD 에서는 애그리거트 간의 참조를 ID 로 간접참조 할 뿐이지, 애그리거트 내부에서는 엔티티와 밸류 오브젝트간 직접 참조가 이루어진다!
JPA 레포지토리, DDD 레포지토리는 다르다. (여기서는 DDD 레포지토리를 설명)
레포지터리는 애그리거트 단위로 도메인 객체를 저장하고 조회하는 기능을 정의하는 클래스!
때문에, 애그리거트를 구하는 레포지터리 메서드는 완전한 애그리거트를 제공해야 한다.
애그리거트의 일부 필드가 빠지면, ACID 를 위반하게 된다!
애그리거트의 일부 필드가 빠지면, 애그리거트 기능을 실행하는 도중에 NullPointerException
이 발생한다.
레포지토리는 애그리거트(루트) 단위로 존재하며 테이블 단위로 존재하는 것이 아니다.
만약 테이블 단위로 레포지토리가 존재한다면 DDD 레포지토리가 아닌 JPA 레포지토리이다.