DDD (Domain Driven Design) 은 Domain 을 중심으로 System 을 Design 하는 것이다. 보통 Event storming 을 통해 Bounded Context 들을 구성한다. Boris Diagram, SnapE 의 과정을 거쳐 MSA (Micro Service Architecture) 를 디자인 한다.
도메인 주도 설계 (DDD, Domain-Driven Design)는 소프트웨어 개발 방법론으로, 핵심 비즈니스 도메인을 이해하고 모델링하는 것의 중요성을 강조한다. 여기서 비즈니스 도메인이란 소프트웨어가 다루고자 하는 주제 영역 또는 문제 범위를 말한다. DDD는 공통 언어, 모델, 패턴을 활용하여 실제 도메인의 필요 사항, 개념, 규칙을 정확하게 반영하는 소프트웨어를 만드는 데 초점을 맞춘다.
DDD는 도메인 전문가(비즈니스 이해 관계자와 같은)와 소프트웨어 개발자 간의 긴밀한 협력이 필요하며, 이를 통해 도메인 지식이 소프트웨어 설계에 효과적으로 반영되도록 한다. DDD의 주요 측면은 다음과 같다.
- 유비쿼터스 언어(Ubiquitous Language): 도메인 전문가와 개발자가 도메인 개념, 규칙, 프로세스를 설명하는 데 사용하는 공유되고 일관된 언어. 이 언어는 오해를 방지하고 팀원 간의 의사소통을 개선하는 데 도움이 된다.
- 유한한 경계(Bounded Context): 도메인의 특정한 부분을 캡슐화하는 논리적인 경계로, 다른 부분들로부터 분리하고 집중, 복잡성 저하 및 경계 범위 안의 일관성을 보장한다. 유한한 경계는 다른 팀이나 응용 프로그램의 부분이 독립적으로 발전할 수 있게 한다.
- 엔티티, 값 객체, 그리고 집합체: 도메인 모델을 만들기 위한 구성 요소들이다. 엔티티는 독특한 신원을 가진 객체들 (예: 고객, 제품)이며, 값 객체는 불변하고 속성들에 의해서만 정의된다 (예: 색, 가격). 집합체는 관련된 객체들의 묶음으로 하나의 루트 엔티티가 상호 작용의 진입점 역할을 한다.
- 리포지토리와 팩토리: 리포지토리는 엔티티와 집합체의 인스턴스를 저장, 검색, 관리하는 데 사용되며, 데이터 지속성 세부 정보를 추상화해준다. 팩토리는 복잡한 도메인 객체나 집합체를 생성하고 객체 인스턴스화 로직을 캡슐화한다.
- 도메인 이벤트: 도메인 상태의 변화 또는 비즈니스 프로세스의 중요한 발생을 나타내는 이벤트로, 시스템의 다른 부분에서 작업이나 부작용을 실행할 수 있다.
도메인 주도 설계는 도메인에 대한 명확한 이해와 정확한 표현이 매우 중요한 복잡하고 변화하는 소프트웨어 시스템에 특히 유용하다. 도메인에 대한 깊은 이해를 바탕으로 팀원 간의 효과적인 의사 소통을 촉진하고, 잘 정의된 모델과 패턴을 활용함으로써 유지 관리가 쉬운, 유연하고, 비즈니스 중심적인 소프트웨어 솔루션을 만들 수 있다.
- DDD START! 도메인 주도 설계 구현과 핵심 개념 익히기
- The Anatomy Of Domain-Driven Design
- DDD introduction by infographic
- Domain Driven Design 이란 무엇인가?
- 마이크로서비스 개발을 위한 Domain Driven Design @ youtube
- MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가? @ slideshare
- "마이크로 서비스 어디까지 해봤니?" 정리
- 진화하는 혹은 오래 사는 시스템 만들기
- Domain Storytelling 을 설명한다. DDD 의 실무방법중 하나로 이해하자.
- Domain Storytelling Tool
Term | Description |
---|---|
Domain | 해결하고자 하는 문제영역 |
Domain Model | Domain 을 개념적으로 표현한 것. 주로 UML (Class, Activity, Sequence Diagram) 로 표현한다. |
[Requirement]
요구사항을 파악한다. 파악한 것을 그림 및 글로 정리한다. 개념모델을 구현모델로 바꾸어 간다.- 도메인 규칙을 글로정리해본다. Access pattern 도 정리한다.
- 도메인 용어 사전을 작성하여 기획자와 sync-up 한다.
- Context Map 을 그려본다. 하나의 Bounded Context 는 여러 Aggregate 으로 구성된다.
- 하나의 Aggregate 는 여러 Domain Model 즉 Entity, Value 로 구성된다. Entity, Value 는 Class 로 구현한다. Aggregate 는 하나의 Aggregate Root 즉 Root Entity 를 갖는다.
[Design]
Layered Architecture 를 참고하여 설계한다.- Class Diagram 을 작성한다. Class 별로 Field, Method, Relation 을 정리한다.
- Activity Diagram, Sequence Diagram 을 작성한다.
[Development]
구현한다.- Entity, Value 를 Class 로 구현한다.
- JPA 를 사용한다면 Entity 는 Interface, Class 로 구현한다. Interface 는 Domain Layer 에
@Entity
Class 는 Infrastructure Layer 에 구현한다.
[Validation]
통합테스트 및 디버깅한다.
Layer | Description |
---|---|
Presentation | User 에 보여지는 화면 또는 데이터를 구현한다. |
Application | User 가 원하는 기능을 Domain layer 를 조합하여 구현한다. |
Domain | Domain model 을 구현한다. |
Infrastructure | RDBMS, MQ 와 같은 외부시스템 연동을 구현한다. |
Domain Layer 는 Entity, Value, Aggregate, Repository, Domain Service 로 구성된다. Aggregate 가 명사로 쓰일 때는 애그리거트라고 발음한다. 동사로 쓰일때는 애그리게이트이다.
Component | Description |
---|---|
Entity | 식별자를 갖는 Domain Model 이다. 자신의 라이프사이클을 갖는다. 예를 들어 Order, Member, Product 등이 해당된다. |
Value | 식별자를 갖지 않는 Domain Model 이다. 주로 Entity 의 속성이다. 예를 들어 Address, Money 가 해당된다. |
Aggregate | 관련된 Entity, Value 객체를 개념적으로 하나로 묶은 것이다. 예를 들어, 주문 Aggregate 은 Order Entity, OrderLine Value, Orderer Value 를 포함한다. |
Repository | Domain Model 의 영속성을 제공한다. 예를 들어 DBMS 테이블의 CRUD 를 제공한다. |
Domain Service | Domain Logic 을 제공한다. 예를 들어 "할인 금액 계산" Domain Service 는 상품, 쿠폰, 회원등급, 구매 금액등 다양한 조건을 이용해서 할인된 금액을 계산한다. |
Aggregate 는 복잡한 Domain Model 들을 하나로 묶은 것이다. Aggregate 는 여러 Entity, Value 들로 구성된다. 하나의 Aggregate 는 하나의 Repositoty 에 대응된다.
먼저 다음과 같이 대략의 Domain Model 들을 그려본다.
그리고 상위 Domain Model 들을 하위 Domain Model 들로 나누어 본다.
하위 Domain Model 들을 다시 Aggregate 로 묶어 본다. 복잡한 Domain Model 들을 수월하게 파악할 수 있다.
Aggregate Root 는 Aggregate 의 대표 Domain Model 즉 대표 Entity 를 말한다. Aggregate 의 모든 Domain Model 은 직접 혹은 간접적으로 Aggregate Root 와 연관되어 있다. Aggregate 의 상태를 변경하고 싶다면 Aggregate Root 를 통해서 한다. 예를 들어 다음의 그림과 같이 주문 Aggregate 에서 Aggregate Root 는 Order Entity 이다.
하나의 Aggregate 에서 다른 Aggregate 를 참조할 때는 Aggregate Root 를 참조한다. 예를 들어 Order Aggregate 의 Orderer Entity 는 Member Aggregate 의 Member Entity 를 참조한다.
Bounded Context 는 Domain Model 의 경계가 되는 문맥을 말한다. 예를 들어 Ctalogue Bounded Context 의 Product 와 Instock (재고) Bounded Context 의 Product 는 의미가 다르다.
하나의 Context 는 여러 Aggregate 로 구성된다. 하나의 Context 가 곧 하나의 micro service 가 될 수 있다. Bounded Context 들 끼리 ACL (Anti Coruption Layer), OHS (Open Host Service) 로 연결된다. 다음과 같이 Bounded Context 의 관계를 그림으로 표현한 것을 Context Map 이라고 한다. Bounded Context 는 대표 Aggregate 와 함께 표기한다.
ACL, OHS 는 Shared Kernel 로 연결된다. Shared Kernel 은 Google ProtoBuf, FlatBuffer, OpenAPI 등을 사용하여 구현한다.
하나의 Bounded Context 를 구현할 때 상태를 변경하는 것 (Command) 과 상태를 읽어오는 것 (Query) 을 나누어서 구현하는 방법이다.
Command 와 Query 는 다른 기술로 구현할 수도 있다. 예를 들어 다음의 그림과 같이 Command 는 DDD (Domain Driven Design) 의 Layered Architecture 로 구현하고 Query 는 Netty, MyBatis 를 포함한 DAO 로 단순하게 구현한다.
Asynchronous Event 를 사용하면 System 을 Decoupling 시킬 수 있다.
예를 들어 A 라는 microservice 에서 B 라는 microservice 에게 HTTP Request 를 보낼 때를 생각해 보자. B 가 HTTP Response 를 늦게 보내줄때 A micro service 는 Blocking 되어서는 안된다. A micro service 는 상태를 변경해 놓고 비동기로 처리한다.
여러 하위 트랜잭션 집합으로 구성된 LLT (Long Lived Transaction) 을 SAGAS 라고 한다. 다음과 같은 특징이 있다.
- 하위 트랜잭션들은 각각 단독 트랜잭션이다.
- 각 하위 트랜잭션들은 서로 연관되어 있다.
- 임의의 하위 트랜잭션이 실패하면 보상 트랜잭션을 실행한다.
- 일부만 성공한 것은 LLT 의 성공을 의미하지 않는다.
- 마이크로서비스 개발을 위한 Domain Driven Design @ youtube
- KCD 2020 [Track 2] 도메인 지식 탐구를 위한 이벤트 스토밍 Event Storming | youtube
-
Orange Sticker : Domain Event, something that happended.
Item Added to Cart
-
Blue Sticker : Command, Request to trigger, source of domain devent.
Item Add to Cart
-
Yellow Sticker : Aggregate, Object which has several attributes
@entity public class Item { private String sku; private String name; private Int quantity; private ProductId productId; }
-
Red sticker : External system
Aggreate 들 간에 synchronous, asynchronous event 들을 표기한다.
Aggregate 는 하나의 Micro Service 에 대응된다. API, Data, Stories, Risk, UI 를 기술한다.