Overview
DDD Skill provides comprehensive guidance on Domain-Driven Design, helping developers and architects perform domain modeling, bounded context decomposition, and tactical pattern implementation.
When to Use
When users need to:
- Analyze complex business domains and perform domain modeling
- Decompose bounded contexts and subdomains
- Design aggregate roots, entities, and value objects
- Implement domain services and domain events
- Perform microservice boundary decomposition
- Apply CQRS/event sourcing patterns
- Design hexagonal architecture/onion architecture
Quick Start
1. Strategic Design
Determine the boundaries of the business domain and the relationships between contexts:
核心域(Core Domain)→ 竞争优势所在
支撑域(Supporting Domain)→ 支持核心业务
通用域(Generic Domain)→ 可外购/复用
2. Tactical Design
Perform detailed modeling within bounded contexts:
聚合根(Aggregate Root)
├── 实体(Entity)- 有唯一标识
├── 值对象(Value Object)- 无标识,不可变
└── 领域事件(Domain Event)- 记录业务变化
Core Concepts
Bounded Context
A bounded context is a core concept of DDD that defines the boundaries of a domain model:
┌─────────────────────────────────────────────────────┐
│ 订单上下文 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 订单 │ │ 订单项 │ │ 支付 │ │
│ │ 聚合根 │ │ 实体 │ │ 值对象 │ │
│ └─────────┘ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────────────┘
│
│ 上下文映射
▼
┌─────────────────────────────────────────────────────┐
│ 库存上下文 │
│ ┌─────────┐ ┌─────────┐ │
│ │ 库存 │ │ 库存项 │ │
│ │ 聚合根 │ │ 实体 │ │
│ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────────────┘
Aggregate Design Rules
- Protect business invariants - Data consistency within the aggregate boundary is protected by the aggregate root
- Small aggregate principle - Aggregates should be as small as possible and contain only essential elements
- Reference by ID - Aggregates reference each other by ID, not by directly holding object references
- One aggregate per transaction - Modify only one aggregate per transaction
- Eventual consistency - Achieve eventual consistency between aggregates through domain events
Modeling Workflow
Step 1: Event Storming
Identify key events in the domain:
橙色便签:领域事件(发生了什么)
蓝色便签:命令(触发事件的动作)
黄色便签:聚合(处理命令、产生事件)
紫色便签:策略(响应事件的规则)
粉色便签:外部系统
Step 2: Identify Bounded Contexts
Divide context boundaries based on the results of event storming:
- Group related events and aggregates into the same context
- Use Ubiquitous Language
- Determine the relationships between contexts
Step 3: Context Mapping
Define the integration relationships between contexts:
| Pattern | Description | Applicable Scenarios |
|---|---|---|
| Shared Kernel | Share part of the model | Closely collaborating teams |
| Customer-Supplier | Upstream-downstream dependency | Clear service dependencies |
| Anticorruption Layer | Isolate external models | Integrate legacy systems |
| Open Host Service | Provide a standard API | Multi-consumer scenarios |
| Published Language | Shared data format | Event-driven integration |
Step 4: Tactical Modeling
Perform detailed design within each context:
# 聚合根示例
class Order(AggregateRoot):
def __init__(self, order_id: OrderId, customer_id: CustomerId):
self.id = order_id
self.customer_id = customer_id
self.items: List[OrderItem] = []
self.status = OrderStatus.DRAFT
def add_item(self, product_id: ProductId, quantity: int, price: Money):
"""添加订单项 - 业务逻辑封装在聚合内"""
if self.status != OrderStatus.DRAFT:
raise DomainException("只能向草稿订单添加商品")
item = OrderItem(product_id, quantity, price)
self.items.append(item)
self.add_event(OrderItemAdded(self.id, item))
def submit(self):
"""提交订单 - 触发领域事件"""
if not self.items:
raise DomainException("订单不能为空")
self.status = OrderStatus.SUBMITTED
self.add_event(OrderSubmitted(self.id, self.total_amount))
# 值对象示例 - 不可变,无标识
@dataclass(frozen=True)
class Money:
amount: Decimal
currency: str
def add(self, other: 'Money') -> 'Money':
if self.currency != other.currency:
raise ValueError("货币类型不匹配")
return Money(self.amount + other.amount, self.currency)
# 领域事件示例
@dataclass(frozen=True)
class OrderSubmitted(DomainEvent):
order_id: OrderId
total_amount: Money
occurred_at: datetime = field(default_factory=datetime.utcnow)
Architecture Patterns
Hexagonal Architecture (Ports and Adapters)
┌─────────────────────────────────┐
│ 应用层(Application) │
┌───────────┐ │ ┌─────────────────────────┐ │ ┌───────────┐
│ REST │◄──┼──│ 端口(Ports) │──┼──►│ 数据库 │
│ API │ │ └─────────────────────────┘ │ │ 适配器 │
└───────────┘ │ │ │ └───────────┘
│ ▼ │
┌───────────┐ │ ┌─────────────────────────┐ │ ┌───────────┐
│ 消息 │◄──┼──│ 领域层(Domain) │──┼──►│ 消息 │
│ 队列 │ │ │ 聚合、实体、值对象 │ │ │ 适配器 │
└───────────┘ │ └─────────────────────────┘ │ └───────────┘
└─────────────────────────────────┘
CQRS Pattern
命令端(Command Side) 查询端(Query Side)
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Command Bus │ │ Query Bus │
└──────────────┘ └──────────────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ 聚合根 │──事件──► │ 读模型 │
│(写模型) │ │(优化查询) │
└──────────────┘ └──────────────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ 事件存储 │ │ 查询数据库 │
└──────────────┘ └──────────────┘
Resource Files
Detailed Reference Documentation:
references/strategic-design.md- Strategic Design Explainedreferences/tactical-design.md- Tactical Design Patternsreferences/patterns.md- DDD Architecture Patternsassets/ddd-model-template.drawio- Domain Model Templates
Frequently Asked Questions
Q: How do you determine aggregate boundaries?
- Identify business invariants (rules that must always be true)
- Entities involved in an invariant should be within the same aggregate
- Prefer small aggregates, and achieve cross-aggregate consistency through domain events
Q: When should domain services be used?
- When business logic does not naturally belong to any entity or value object
- When operations need to coordinate multiple aggregates
- For example: a transfer service (coordinating two account aggregates)
Q: How do you handle cross-aggregate transactions?
- Use the Saga pattern to orchestrate long-running transactions
- Achieve eventual consistency through domain events
- Avoid distributed transactions and embrace compensation mechanisms