도메인 주요 구성요소
요소 | 설명 |
---|---|
Entity | 고유의 식별자 를 갖는 객체로 라이프 사이클을 가짐.도메인의 고유한 개념을 표현하며, 도메인 모델의 데이터를 포함하고, 관련된 기능을 함께 제공 |
Value | 고유한 식별자를 갖지 않음 주로 개념적으로 하나인 값을 표현할 때 사용 Entity 의 속성으로 사용할 뿐만 아니라 다른 Value 타입의 속성으로도 사용 |
Aggregate | 연관된 Entity와 Value 객체를 하나로 묶은 것 |
Repository | 도메인 모델의 영속성 처리.(Entity 객체를 조회하거나 저장하는 기능) |
Domain Service | 특정 Entity에 속하지 않는 도메인 로직 제공. 도메인 로직이 여러 Entity와 Value가 필요한 경우 Domain Service에서 로직 구현 |
Aggregate
도메인 모델이 복잡해질수록 많은 Entity와 Value가 구현됩니다. 복잡해지게 되면 전체 구조보다 개별 Entity, Value에만 집중하게 되는 경우도 생기는데, 전체 구조를 이해할 수 있게 Aggregate가 도와줍니다.
Aggregate는 관련 객체를 하나로 묶은 것으로, Aggregate를 사용하면 개별 객체가 아닌 관련 객체를 묶어서 모델을 바라보고 Aggregate 간의 관계로 도메인 모델을 이해하고 큰 틀에서 관리할 수 있게 됩니다.
Aggregate 단위로 일관성을 관리하면, 복잡한 도메인을 단순한 구조로 만들어주며, 복잡도가 낮아지는 만큼 도메인 기능을 확장하고 변경하는데 필요한 노력도 줄어들게 됩니다.
Aggregate로 묶을 때 "A가 B를 갖는다"로 해석되더라도 반드시 A와 B가 한 개의 Aggregate에 속하지 않을 수 있다는 점에 유의해야 합니다.
Root Entity
Aggregate는 해당 묶음에 속하는 객체(Entity, Value)들이 일관된 상태를 유지할 수 있게 관리하는 Root Entity를 갖습니다. Root Entity는 Aggregate에 속한 Entity와 Value 객체를 이용해 구현해야 할 기능을 제공합니다. Aggregate는 Root Entity를 통해서 간접적으로 군집 내의 Entity, Value에 접근하게 되므로 Aggregate 단위로 구현을 캡슐화할 수 있게 돕습니다.
일관성
Root Entity의 핵심 역할은 Aggregate의 일관성이 깨지지 않도록 하는 것입니다. Aggregate 외부에서 Aggregate에 속한 객체를 직접 변경할 수 있게 되면 모델의 일관성을 깨는 원인이 되므로, 직접 변경하지 못하게 구현하는 것이 중요합니다.
- 단순히 필드를 변경하는 set method는 public 범위로 구현하지 않아야 한다.
- public set method는 도메인의 의미나 의도를 표현하지 못함
- 도메인 로직이 도메인 객체가 아닌 다른 응용/표현 영역으로 분산됨
- Value 타입은 불변으로 구현해야 한다.
- Aggregate 외부에서 Value 객체의 상태를 변경할 수 없음
- 내부 상태를 함부로 바꾸지 못하므로 일관성이 꺠질 가능성이 줄어듦
위 두 가지를 습관적으로 적용하면, 불필요한 중복은 피하고, Root를 통해서만 도메인 로직을 구현하게 만들 수 있습니다.
기능 구현
Root Entity는 기능 실행을 위임하기도 합니다.
이때, 팀 표준, 기술 제약에 맞춰 private나 protected 범위로 한정해서 외부에서 상태 변경을 실행 못하도록 방지해야 합니다.
Transaction
트랜잭션 범위는 작을수록 좋으며, 여러 개의 Aggregate를 수정하면, 충돌이 발생할 가능성이 높아지므로 한 트랜잭션에서는 한 개의 Aggregate만 수정할 수 있게 구현하는 것이 좋습니다.
만약, 부득이하게 한 트랜잭션으로 두 개 이상의 Aggregate를 수정해야 한다면, 응용 서비스에서 수정하도록 구현해야 합니다. 이 경우에는 도메인 이벤트를 사용해 한 트랜잭션에서는 하나의 Aggregate를 수정하면서 동기/비동기로 다른 Aggregate 상태를 변경하는 코드를 작성할 수 있습니다.
Aggregate 참조
Aggregate도 다른 Aggregate를 참조할 수 있으며, 다른 Aggregate를 참조한다는 것은 Root Aggregate를 참조한다는 것과 같습니다.
필드를 이용한 참조
Aggregate 간 참조는 필드를 통해 구현할 수 있지만 다음과 같은 문제점들이 존재합니다.
- 편한 탐색 오용
- 다른 Aggregate에 직접 접근할 수 있으면, 상태 또한 쉽게 변경할 수 있게 되므로, 관리 범위가 자기 자신을 벗어나게 될 수 있습니다.
- 성능
- lazy or eager 로딩 중 어떤 방식으로 조회할지에 따라 성능이 달라질 수 있으므로, 다양한 경우를 고려해서 전략을 세워야 합니다.
- 확장성
- 트래픽이 증가하면 부하를 분산하기 위해 하위 도메인별로 시스템을 분리하는데, 이 경우 다른 Aggregate Root를 참조하기 위해 단일 기술을 사용할 수 없게 되며, 제약이 생기게 됩니다.
ID를 위한 참조
위 필드를 이용한 직접 참조의 문제점은 ID를 이용해서 참조하여 문제점을 완화할 수 있으며, 다음 장점들이 있습니다.
- Aggregate의 경계를 명확히 할 수 있음
- 모델의 복잡도를 낮춤
- Aggregate 간 의존을 제거해 응집도를 높여줌
- 구현 복잡도가 낮아짐
Factory로 Aggregate 사용하기
Aggregate가 가진 데이터를 이용해 다른 Aggregate를 생성해야 한다면, Aggregate에 Factory method를 구현하는 것을 고려해 보는 것이 좋습니다.
Factory로 Aggregate를 생성하면, 필요한 데이터를 직접 제공하면서 동시에 중요한 도메인 로직을 함께 구현하여, 도메인의 응집도를 높일 수 있습니다. 이때 Aggregate를 생성할 때 많은 정보를 알아야 한다면, MembershipFactory
와 같이 직접 생성하지 않고 위임하는 방법도 있습니다.
'개발' 카테고리의 다른 글
MariaDB connector 2.x 분석 (2) | 2024.09.25 |
---|---|
Singleton Pattern (4) | 2024.09.23 |
DIP 의존 역전 원칙 (0) | 2024.09.21 |
DDD - 도메인 모델링 (0) | 2024.09.20 |
DDD - 도메인이란? (1) | 2024.09.19 |