Skip to content

聚合识别设计原则 ​

本文回答「一份需求摆过来,怎么识别出应该有哪些聚合」。它是战略建模步骤,既用于全新需求从 0 识别,也用于迭代需求中「要不要新增一个聚合」的判断。识别结果直接喂给聚合设计(aggregate-design),并最终落为一份符合《聚合设计文档标准》的设计文档。

1. 定位与适用场景 ​

场景是否适用说明
全新需求是从需求文本 / 口述中识别一组聚合候选及其边界
迭代需求(加聚合)是判断「新能力应扩到既有聚合」还是「独立成新聚合」
迭代需求(改聚合)否聚合边界已定,走「聚合演进设计」;本文只负责识别,不负责改

识别阶段不写代码、不出设计文档正文,只产出「聚合候选清单 + 边界 + 不变量 + 粒度结论」,作为后续设计与文档的输入。

2. 识别四步(事件风暴) ​

2.1 列事件 ​

引导需求方列出业务已发生或会发生的事件(过去式、事实语义):「订单已支付」「库存已扣减」「物流已揽收」。

  • 每个事件归属一个潜在聚合;同一业务动作下事件密集、且需强一致的,归同一聚合候选。
  • 参考:事件建模指南 的事件命名与事实语义。

2.2 提炼不变性 ​

对每个候选聚合追问:「哪些业务规则必须在一次事务内保持一致?」

  • 强一致不变性(如「订单总额 = Σ 订单项金额」)→ 同一聚合内。
  • 最终一致(如「订单支付成功 → 扣库存」)→ 跨聚合,走领域事件。

2.3 定边界(强一致 vs 最终一致) ​

关系判定落点
A 的不变性依赖 B 的当前态、需同事务强一致A、B 同一聚合
A 只关心 B「发生了什么」,不关心其当前态最终一致A、B 跨聚合,B 发事件、A 订阅

2.4 定粒度(小聚合原则) ​

用「小聚合」原则校验候选是否过大:

  • 是否引入了不需要一起加锁的实体?(是 → 拆出)
  • 跨聚合是否只持 ID?
  • 子实体是否随父聚合存在、无独立访问?(是 → 同聚合子表;否 → 独立聚合)

3. 边界判据清单 ​

识别完成时,对每个候选应明确回答如下问题(缺一则回到 §2):

  1. 聚合根是谁?为什么是它?
  2. 包含哪些实体 / 值对象?
  3. 不归本聚合管什么(同样重要,防止边界蔓延)?
  4. 维护哪些核心不变量?
  5. 与其他聚合是强一致还是最终一致?

参考:聚合设计原则、聚合数据库设计原则、实体设计原则。

4. 迭代中的「加聚合」判定 ​

迭代需求常出现「这个新能力放哪」。判定顺序:

  1. 新能力的不变量是否与某既有聚合的不变性同事务强一致?是 → 扩到该聚合(走演进设计)。
  2. 否则,新能力是否有独立生命周期 / 独立访问?是 → 新增独立聚合。
  3. 仅是既有聚合的一个新只读视图 → 走投影读模型,不增聚合。

经验法则:当「加进既有聚合会让聚合膨胀、并发冲突上升」时,倾向独立成聚合,跨聚合以事件 / ID 协作。

5. 常见误判与反模式 ​

误判纠偏
一个聚合包下整个领域按不变性切分为小聚合
跨聚合持对象引用只持 ID(约束 13)
把最终一致当强一致(同聚合硬塞)跨聚合走领域事件
无身份值对象建独立子表并入父表 JSON
子实体被他聚合独立访问却塞同聚合提为独立聚合

6. 与其他最佳实践的关系 ​