도메인 영역의 주요 구성요소는 아래 다섯가지가 있다.
요소 | 설명 |
---|---|
엔티티(Entity) | 고유의 식별자를 갖는 객체이다. 도메인 모델의 데이터를 포함하며, 해당 데이터와 관련된 기능을 함께 제공한다. |
밸류(Value) | 고유의 식별자를 갖지 않는 객체로, 주로 개념적으로 하나인 도메인 객체의 속성을 표현할 때 사용된다. (ex. 주소, 배송상태) 엔티티의 속성뿐만 아니라 다른 밸류 타입의 속성으로도 사용될 수 있다. |
애그리거트(Aggregate) | 애그리거트는 관련된 엔티티와 밸류 객체를 개념적으로 하나로 묶은 것이다. 도메인 관계 복잡도를 낮추기 위해 여러 하위 도메인을 독립된 객체군으로 나눈다. |
리포지터리(Repository) | 도메인 모델의 영속성을 처리한다. 애그리거트 단위로 도메인 객체를 저장하고 조회하는 기능을 정의한다. |
도메인 서비스(Domain Service) | 특정 엔티티에 속하지 않은 도메인 로직을 제공한다. 도메인 로직이 여러 엔티티와 벨류를 사용하는 경우에 이용한다. |
Entity
- domain model의 엔티티에서는 데이터와 도메인 기능을 함께 제공한다.
- 두 개 이상의 데이터가 개념적으로 하나인 경우 Value ****type을 이용해서 표현할 수 있다.
Value
- 밸류 타입은 개념적으로 완전한 하나를 표현할 때 사용한다.
- 값만으로 식별되는 비즈니스 도메인의 개념으로, 명시적인 ID 필드가 필요없다.
- 무결성과 참조 투명성을 지키기 위해 밸류 타입은 무조건 불변으로 만들어야 한다.
- 데이터뿐만 아니라 행동도 모델링 할 수 있다.
엔티티 식별자와 Value 타입
- 식별자는 도메인에서 특별한 의미를 지니는 경우가 많기 때문에 밸류 타입을 사용해 의미를 잘 드러낼 수 있다.
- 필드의 이름만으로 해당 필드를 알고 싶다면 식별자를 위한 밸류 타입을 만들어 사용할 수 있다.
도메인 객체 모델이 복잡해지면 개별 구성요소 위주로 모델을 이해하게 되어 전반적인 구조나 큰 수준에서 도메인 간의 관계를 파악하기 어려워지고, 코드 변경 및 확장이 힘들어진다.
그러한 문제를 해결하기 위해 애그리거트로 복잡한 도메인을 이해, 관리하기 쉽게 묶어 관리한다.
애그리거트는 모델을 이해하는 데 도움을 주고, 일관성을 관리하는 기준이 될 수 있다. 관련된 모델을 하나로 모았기 때문에 한 애그리거트에 속한 객체는 유사하거나 동일한 라이프 사이클을 갖는다.
애그리거트는 독립된 객체군이며 각 애그리거트는 자신 외에 다른 애그리거트를 관리하지 않는다.
애그리거트의 경계는 도메인 규칙과 요구사항에 따라 결정된다.
애그리거트 루트
-
도메인 규칙을 지키려면 애그리거트에 속한 모든 객체의 상태가 정상적이어야 한다. 애그리거트에 속한 모든 객체가 일관된 상태를 유지하려면, 전체를 관리할 주체가 필요한데 이 책임을 지는 것이 바로 애그리거트의 루트 엔티티이다.
-
애그리거트 루트는 애그리거트가 제공하는 도메인 기능을 구현한다. 해당 애그리거트에 속하는 객체는 애그리거트 루트만이 변경할 수 있다. (무분별한 setter X)
-
애그리거트는 트랜잭션의 경계 역할을 하므로 모든 데이터는 원자적인 단일 트랜잭션으로 커밋되어야 한다. 그리고 애그리거트는 도메인 이벤트를 통해 외부 엔티티와 상호작용할 수 있다.
Repository 인터페이스는 애그리거트 루트를 기준으로 작성한다. 객체의 영속성을 처리하는 리포지터리는 애그리거트 단위로 존재하며, 완전한 애그리거트를 제공해야 한다.
DB나 자료구조와 같은 인프라스트럭쳐 계층에 질의를 던지고 객체를 가져오는 책임은 Repository가 모두 가지고 있기 때문에, 보다 도메인에 중점적인 개발이 가능하다.
도메인 서비스는 특정 엔티티에 속하지 않은 도메인 로직을 제공한다. 즉, 도메인 로직이 여러 엔티티와 벨류를 사용하는 경우에 이용된다.
애그리거트나 밸류와 다르게, 도메인 서비스는 상태값 없이 로직만 구현한다.
도메인 서비스는 도메인 로직을 실행하므로 도메인 서비스의 위치는 다른 도메인 구성 요소와 동일한 패키지에 위치한다.