1. DDD 核心概念回顾:领域、子域、限界上下文、实体、值对象、聚合根
在深入 API 契约治理之前,必须统一团队对领域驱动设计(DDD)核心战术与战略元素的认知。这些概念构成了聚合边界划分与 API 契约设计的理论基础。以下按战略层到战术层的顺序逐一回顾。
1.1 战略层:领域、子域、限界上下文
战略设计解决的是“大图景”问题——如何将一个复杂的业务系统拆解为可管理的模块,并明确每个模块的职责与通信边界。
| 概念 | 定义 | 类比(电商系统) |
|---|---|---|
| 领域 (Domain) | 组织所从事的业务范围与知识体系,是整个软件系统要解决的核心问题空间。 | 整个“电商”业务,包括商品、订单、支付、物流、用户等所有子域。 |
| 子域 (Subdomain) | 领域内部按业务能力或问题粒度划分的独立部分。分为核心、支撑、通用三类。 | 订单子域(核心)、库存子域(支撑)、支付子域(通用)。 |
| 限界上下文 (Bounded Context) | 模型的边界,包含明确的职责、术语和规则。每个上下文内部有统一的语言(Ubiquitous Language)。 | “订单上下文”与“物流上下文”对“订单”状态的定义可能不同。 |
关键区分:子域是问题空间的划分(业务视角),限界上下文是解决方案空间的划分(技术/模型视角)。一个子域可能对应一个或多个限界上下文,但实践中通常建议 1:1 映射以降低复杂度。
1.2 战术层:实体、值对象、聚合根
战术设计聚焦于限界上下文内部的模型构建,是定义聚合边界和 API 资源粒度的直接依据。
- 实体 (Entity):拥有唯一标识(ID),且在其生命周期中状态会发生变化的对象。例如:
Order(订单ID不变,但状态从“待支付”变为“已支付”)。 - 值对象 (Value Object):通过属性值定义自身,没有唯一标识,且不可变。例如:
Address({城市, 街道, 邮编} 完全相同时即为同一个地址)。 - 聚合根 (Aggregate Root):聚合的入口点,是唯一允许外部对象引用的实体。它负责维护聚合内部所有对象的不变规则(Invariants)。
聚合根设计铁律:外部对象只能通过聚合根的方法来修改聚合内部的状态。删除聚合根时,其内部的所有实体和值对象一并删除。这是保证数据一致性的核心机制。
1.3 核心关系图解
下图展示了从战略层到战术层的层级关系,以及聚合根在限界上下文中的核心位置。
1.4 概念对比速查表
以下表格从多个维度对比实体与值对象,这是设计聚合时最容易混淆的一对概念。
| 对比维度 | 实体 (Entity) | 值对象 (Value Object) |
|---|---|---|
| 标识 | 有唯一标识(ID) | 无标识,由属性值定义 |
| 可变性 | 可变(状态可更新) | 不可变(替换而非修改) |
| 相等性 | ID 相同即相等 | 所有属性相同即相等 |
| 生命周期 | 有独立生命周期 | 依附于实体,无独立生命周期 |
| 副作用 | 修改可能产生副作用 | 无副作用(纯数据) |
| 存储方式 | 通常独立表 | 通常序列化嵌入实体表 |
常见设计陷阱:将本该是值对象的概念设计为实体。例如,将“收货地址”赋予 ID 并允许独立修改,会导致聚合边界模糊和一致性问题。正确的做法是:
Order 聚合根内部包含一个不可变的 Address 值对象,修改地址时直接替换整个值对象实例。
1.5 聚合设计原则小结
- 一致性边界:聚合是事务一致性的边界。一个事务只应修改一个聚合实例。
- 小聚合原则:优先设计小聚合,只包含必须保持一致的属性。过大的聚合会降低并发性能。
- 通过 ID 引用:聚合之间通过全局唯一 ID 引用,而非直接持有对象引用。这是 API 契约中资源 ID 设计的理论来源。
- 最终一致性:跨聚合的状态更新应使用领域事件实现最终一致性,而非强事务。