- 一、先纠正一个常见误解
- 二、事件风暴中的“颜色语义”与对象抽象逻辑
- 三、从事件到对象的核心逆推公式
- 四、步骤一:只做一件事 —— 全量铺开业务事件
- 做法
- 关键约束
- 五、步骤二:对事件进行“归属聚类”(这是对象的第一个影子)
- 六、步骤三:找“状态变化轨迹”(对象是否成立的关键)
- 七、步骤四:回溯 Command —— 确认对象的“责任边界”
- 八、步骤五:逼出“不变量”——领域对象存在的终极理由
- 九、用事件风暴识别“边界”,而不是“流程”
- 十、事件风暴 vs 流程抽象的本质差异
- 十一、一句话总结(给架构师用的)
这是一个非常到位、也非常“架构级”的问题。
你提到的“两种思路”本质上对应两条完全不同的认知路径:
- 流程抽象:从 How 出发(事情是怎么做的)
- 事件风暴(Event Storming):从 What happened 出发(业务世界发生了什么)
在复杂业务系统中,事件风暴之所以更适合做领域建模,是因为它天然绕开流程幻觉,直达业务不变量。
下面我将系统性地回答:
基于事件风暴,如何一步一步抽象出“业务对象 / 领域对象”?
一、先纠正一个常见误解
❌ 事件风暴 = 贴事件便利贴
❌ 事件风暴 = 得到一堆事件就完了
事件风暴的真正目标不是事件,而是:
通过事件,逼出“谁在负责这件事的状态与规则”
也就是说:
事件只是探针,领域对象才是终点。
二、事件风暴中的“颜色语义”与对象抽象逻辑
标准事件风暴中,与你抽象领域对象直接相关的只有四类元素:
| 元素 | 本质问题 |
|---|---|
| Domain Event | 业务世界发生了什么 |
| Command | 谁决定让它发生 |
| Aggregate / Entity | 谁承载状态与不变量 |
| Policy | 事件发生后,业务如何反应 |
领域对象(Aggregate / Entity)一定是被“夹”在事件与命令之间的。
三、从事件到对象的核心逆推公式
如果一个东西:
- 在多个事件前后状态发生变化
- 并且这些变化必须遵守业务规则
👉 那它就是领域对象的候选
下面进入具体步骤。
四、步骤一:只做一件事 —— 全量铺开业务事件
做法
让业务专家用过去时描述事件:
- 报价已被锁定
- 客户信用额度已授予
- 订单已确认
- 支付已超时
- 销售机会已失效
关键约束
- 不允许出现技术词
- 不允许出现“如果 / 然后”
- 不允许出现流程顺序争论
📌 此阶段不要关心对象,不要关心流程
五、步骤二:对事件进行“归属聚类”(这是对象的第一个影子)
现在问一个非常关键的问题:
这些事件,究竟“发生在谁身上”?
例如:
| 事件 | 发生在谁身上 |
|---|---|
| 报价已被锁定 | 报价 |
| 报价已过期 | 报价 |
| 报价被接受 | 报价 |
| 订单已创建 | 订单 |
| 订单进入履约 | 订单 |
📌 当你发现一组事件总是围绕同一个“业务名词”展开
👉 这个名词就是候选领域对象
⚠️ 注意:
- 如果一个名词被多个完全不同的事件集使用
→ 很可能是假对象(跨上下文概念)
六、步骤三:找“状态变化轨迹”(对象是否成立的关键)
对每一组事件,问:
这些事件是否构成一个有意义的状态演进?
例如:
报价(Quotation)
Draft→ Locked→ Accepted→ Expired
订单(Order)
Created→ Confirmed→ InFulfillment→ Completed / Cancelled
📌 能形成稳定状态机的,才是领域对象
- 如果只是“发生了某件事”,但没有状态累积
- 那更可能是日志、记录、或值对象
七、步骤四:回溯 Command —— 确认对象的“责任边界”
现在从事件倒推命令:
| Command | 目标 |
|---|---|
| LockQuotation | 报价 |
| AcceptQuotation | 报价 |
| ConfirmOrder | 订单 |
然后问:
这个命令,是否只能由这个对象来决定是否成功?
如果答案是“是”:
- 说明规则在对象内部
- 说明它是聚合根(Aggregate Root)
如果命令可以绕开它执行:
- 说明对象边界不成立
- 或职责被拆错
八、步骤五:逼出“不变量”——领域对象存在的终极理由
【什么是不变量】不变量(Invariant)就是:在任何合法业务状态下,都必须成立的业务约束。
它不是“规则清单”,而是领域对象存在的根本理由。
对每个候选对象,强制回答:
- 哪些命令会被它拒绝?
- 在什么状态下必须拒绝?
- 拒绝的原因是否是业务语义?
例如:
- 报价一旦 Locked,不允许修改价格
- 已过期的报价不能被接受
- 已完成订单不能再履约
📌 如果没有“不变量”,这个对象不值得存在
九、用事件风暴识别“边界”,而不是“流程”
一个高阶技巧:
当事件时间线出现“语义跳变”时,通常是边界
例如:
- 订单已确认 → 发票已开具
(责任主体明显变化)
这往往意味着:
- 不同 Aggregate
- 不同 Bounded Context
- 通过 Domain Event 解耦
十、事件风暴 vs 流程抽象的本质差异
| 维度 | 流程抽象 | 事件风暴 |
|---|---|---|
| 出发点 | 如何做 | 发生了什么 |
| 结果 | 易得流程对象 | 易得领域对象 |
| 对变化适应 | 差 | 强 |
| 是否暴露不变量 | 容易隐藏 | 强制暴露 |
流程适合优化执行,事件风暴适合构建模型。
十一、一句话总结(给架构师用的)
事件风暴不是为了建事件模型,而是用事件把“承载业务不变量的对象”逼出来。
真正的领域对象,一定是那些对事件说“我能 / 我不能”的东西。
如果你愿意,下一步我可以:
- 用你熟悉的 销售系统 / 报价–订单–履约,完整演示一次事件风暴 → 聚合建模;
- 或直接对比:同一业务,用流程抽象 vs 事件风暴,领域对象会差在哪里。