事件风暴:领域建模实战工作坊
1. 事件风暴概述
1.1 什么是事件风暴
事件风暴(Event Storming)是一种快速探索复杂业务领域的协作式建模方法,由Alberto Brandolini在2013年提出。
传统需求分析 vs 事件风暴:
传统方法:
需求文档 → 评审 → 开发 → 测试
↓
问题:理解偏差大、反馈慢
事件风暴:
业务专家 + 开发团队 → 共同建模 → 快速验证
↓
优势:快速对齐认知、发现问题1.2 事件风暴的价值
核心价值:
- 快速 - 几小时内探索整个业务流程
- 协作 - 业务和技术共同参与
- 可视化 - 贴满便利贴的时间线
- 发现问题 - 暴露业务规则的模糊点
2. 事件风暴准备
2.1 参与角色
必需角色:
┌─────────────────────────────────────┐
│ 领域专家 (Domain Expert) │
│ - 深入理解业务 │
│ - 决策业务规则 │
│ - 2-3人 │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ 开发团队 │
│ - 架构师、后端、前端 │
│ - 提出技术问题 │
│ - 5-8人 │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ 引导师 (Facilitator) │
│ - 控制节奏 │
│ - 引导讨论 │
│ - 解决冲突 │
│ - 1人 │
└─────────────────────────────────────┘
可选角色:
- UX设计师
- 产品经理
- QA测试2.2 物料准备
必备物料清单:
┌────────────────────────────────┐
│ 便利贴(不同颜色) │
│ ┌──────┐ 橙色 - 领域事件 │
│ │事件 │ 蓝色 - 命令 │
│ └──────┘ 黄色 - 聚合 │
│ 淡紫色 - 策略 │
│ 粉色 - 外部系统 │
│ 红色 - 问题/风险 │
└────────────────────────────────┘
┌────────────────────────────────┐
│ 白板/长墙 │
│ - 至少5米长 │
│ - 或多张白板拼接 │
└────────────────────────────────┘
┌────────────────────────────────┐
│ 马克笔 │
│ - 黑色粗笔 │
│ - 多支备用 │
└────────────────────────────────┘2.3 场地布置
理想场地布置:
投影仪
↓
┌─────────────────────────────────────────┐
│ 超长白板/墙面 │
│ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │
│ │事件│ │命令│ │聚合│ │事件│ │命令│ │
│ └───┘ └───┘ └───┘ └───┘ └───┘ │
│ │
│ 时间线 ──────────────────────────────► │
└─────────────────────────────────────────┘
参与者围站(不坐着)
👤 👤 👤 👤 👤 👤 👤 👤
便利贴堆 白板笔桶
📝 🖊3. 事件风暴流程
3.1 Big Picture Event Storming(全局视图)
阶段1:领域事件风暴
目标: 识别系统中发生的所有重要事件
步骤1: 无序发散
┌────────────────────────────────────────┐
│ 所有人同时贴便利贴 │
│ - 不讨论 │
│ - 不排序 │
│ - 尽可能多 │
│ - 15-20分钟 │
└────────────────────────────────────────┘
示例:电商系统的领域事件
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│用户已注册 │ │商品已上架 │ │订单已创建 │
└──────────────┘ └──────────────┘ └──────────────┘
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│订单已支付 │ │库存已扣减 │ │订单已发货 │
└──────────────┘ └──────────────┘ └──────────────┘
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│订单已签收 │ │评价已提交 │ │退款已完成 │
└──────────────┘ └──────────────┘ └──────────────┘命名规范:
- 过去式
- 业务语言
- 具体明确
✓ 好的命名:
- 订单已支付
- 库存已扣减
- 用户已注册
✗ 不好的命名:
- 保存订单(太技术化)
- 更新数据(太抽象)
- 处理完成(不明确)阶段2:时间线排序
步骤2: 按时间顺序排列事件
┌───────────────────────────────────────────────────────┐
│ 时间线(从左到右) │
│ │
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │用户已 │─►│商品已 │─►│订单已 │─►│订单已 │ │
│ │注册 │ │上架 │ │创建 │ │支付 │ │
│ └────────┘ └────────┘ └────────┘ └────────┘ │
│ │ │
│ ↓ │
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │订单已 │◄─│订单已 │◄─│库存已 │◄─│支付已 │ │
│ │完成 │ │签收 │ │扣减 │ │确认 │ │
│ └────────┘ └────────┘ └────────┘ └────────┘ │
└───────────────────────────────────────────────────────┘发现并行流程:
主流程:
订单已创建 → 订单已支付 → 订单已发货
并行流程:
┌──────────────┐
│积分已增加 │ ← 订单支付后触发
└──────────────┘
┌──────────────┐
│优惠券已使用 │ ← 订单支付后触发
└──────────────┘
┌──────────────┐
│库存已预占 │ ← 订单创建时触发
└──────────────┘阶段3:识别关键点
添加热点(问题/疑问):
使用红色便利贴标记:
┌────────────────────────────────────┐
│ 问题/疑问 │
│ 🔴 支付失败后库存如何处理? │
│ 🔴 订单超时未支付怎么办? │
│ 🔴 并发下单库存扣减冲突? │
└────────────────────────────────────┘
↓ 贴在相关事件附近
┌──────────────┐ 🔴 支付失败后
│订单已支付 │ 库存如何处理?
└──────────────┘3.2 Process Level Event Storming(流程级别)
深入到具体业务流程,添加更多细节。
阶段4:添加命令
命令: 触发事件的用户操作或系统行为
命令 + 事件关系:
蓝色便利贴(命令) → 橙色便利贴(事件)
┌──────────────┐ ┌──────────────┐
│ 创建订单 │──────►│订单已创建 │
│ (命令) │ │ (事件) │
└──────────────┘ └──────────────┘
↑
│
谁发起?
┌──────────────┐
│ 👤 用户 │
└──────────────┘完整流程示例:
用户下单流程:
👤 用户
│
↓
┌──────────────┐ ┌──────────────┐
│ 添加购物车 │──────►│商品已添加 │
└──────────────┘ └──────────────┘
│
↓
┌──────────────┐ ┌──────────────┐
│ 创建订单 │──────►│订单已创建 │
└──────────────┘ └──────────────┘
│
检查库存(策略)
│
↓
库存充足?
┌──────┴──────┐
Yes│ No│
↓ ↓
┌──────────────┐ ┌──────────────┐
│库存已预占 │ │订单已取消 │
└──────────────┘ └──────────────┘阶段5:添加聚合
聚合: 处理命令并产生事件的业务对象
黄色便利贴(聚合)
┌──────────────┐
│ 创建订单 │
│ (命令) │
└──────────────┘
↓
┌──────────────┐ ┌──────────────┐
│ 📦 订单 │──────►│订单已创建 │
│ (聚合) │ │ (事件) │
└──────────────┘ └──────────────┘
聚合负责:
- 验证业务规则
- 保持一致性
- 产生事件完整建模:
┌─────────────────────────────────────────────────────┐
│ 下单流程 │
│ │
│ 👤 用户 │
│ │ │
│ ↓ │
│ ┌────────┐ ┌────────┐ ┌──────────┐ │
│ │创建订单│──────►│📦订单 │─────►│订单已创建│ │
│ │(命令) │ │(聚合) │ │(事件) │ │
│ └────────┘ └────────┘ └──────────┘ │
│ │ │
│ │ 规则:检查库存 │
│ │ │
│ ┌────────┐ ┌────────┐ ┌──────────┐ │
│ │支付订单│──────►│📦订单 │─────►│订单已支付│ │
│ │(命令) │ │(聚合) │ │(事件) │ │
│ └────────┘ └────────┘ └──────────┘ │
│ │ │
│ ↓ │
│ ┌────────────────────────────┐ │
│ │ 触发其他服务 │ │
│ │ - 扣减库存 │ │
│ │ - 发送通知 │ │
│ │ - 增加积分 │ │
│ └────────────────────────────┘ │
└─────────────────────────────────────────────────────┘阶段6:添加策略/规则
淡紫色便利贴(策略/业务规则)
┌──────────────┐
│ 支付订单 │
└──────────────┘
↓
┌──────────────────────┐
│ 💡 业务规则 │
│ - 订单状态必须是 │
│ "待支付" │
│ - 金额必须大于0 │
│ - 支付方式有效 │
└──────────────────────┘
↓
┌──────────────┐ ┌──────────────┐
│ 📦 订单 │──────►│订单已支付 │
└──────────────┘ └──────────────┘阶段7:识别外部系统
粉色便利贴(外部系统/第三方服务)
┌──────────────┐
│ 支付订单 │
└──────────────┘
↓
┌──────────────┐ ┌──────────────┐
│ 📦 订单 │──────►│支付请求已发送│
└──────────────┘ └──────────────┘
│ ↓
│ ┌──────────────┐
│ │🔌微信支付API │
│ │(外部系统) │
│ └──────────────┘
│ ↓
↓ ┌──────────────┐
┌──────────────┐ │支付回调已收到│
│订单已支付 │◄──────└──────────────┘
└──────────────┘4. 实战案例:电商订单系统
4.1 完整事件风暴板
电商订单系统事件风暴(简化版):
用户注册流程:
───────────────────────────────────────────────────
👤 用户
│
↓
┌──────┐ ┌──────┐ ┌──────────┐
│注册 │───►│📦用户│───►│用户已注册│
└──────┘ └──────┘ └──────────┘
│
↓
┌──────────┐
│欢迎邮件 │
│已发送 │
└──────────┘
商品浏览流程:
───────────────────────────────────────────────────
👤 用户
│
↓
┌──────┐ ┌──────┐ ┌──────────┐
│搜索 │───►│📦商品│───►│搜索结果 │
│商品 │ │目录 │ │已返回 │
└──────┘ └──────┘ └──────────┘
下单流程:
───────────────────────────────────────────────────
👤 用户
│
↓
┌──────┐ ┌──────┐ ┌──────────┐
│添加 │───►│📦购物│───►│商品已添加│
│购物车│ │车 │ │至购物车 │
└──────┘ └──────┘ └──────────┘
│
↓
┌──────┐ ┌──────┐ ┌──────────┐
│创建 │───►│📦订单│───►│订单已创建│
│订单 │ │ │ │ │
└──────┘ └──────┘ └──────────┘
│ │
💡 检查库存 ↓
│ ┌──────────┐
└──────►│库存已预占│
└──────────┘
支付流程:
───────────────────────────────────────────────────
┌──────┐ ┌──────┐ ┌──────────┐
│支付 │───►│📦订单│───►│支付请求 │
│订单 │ │ │ │已发送 │
└──────┘ └──────┘ └──────────┘
│
↓
┌──────────┐
│🔌支付网关│
└──────────┘
│
↓
┌──────────┐
│支付已确认│
└──────────┘
│
┌─────────────┼─────────────┐
↓ ↓ ↓
┌──────────┐ ┌──────────┐ ┌──────────┐
│订单已支付│ │库存已扣减│ │积分已增加│
└──────────┘ └──────────┘ └──────────┘
物流流程:
───────────────────────────────────────────────────
🤖 系统调度
│
↓
┌──────┐ ┌──────┐ ┌──────────┐
│分配 │───►│📦物流│───►│订单已分配│
│物流 │ │单 │ │给快递员 │
└──────┘ └──────┘ └──────────┘
│
↓
┌──────┐ ┌──────┐ ┌──────────┐
│发货 │───►│📦订单│───►│订单已发货│
└──────┘ └──────┘ └──────────┘
│
↓
┌──────────┐
│物流信息 │
│已更新 │
└──────────┘
│
↓
┌──────┐ ┌──────┐ ┌──────────┐
│确认 │───►│📦订单│───►│订单已签收│
│签收 │ │ │ │ │
└──────┘ └──────┘ └──────────┘
│
↓
┌──────────┐
│订单已完成│
└──────────┘4.2 识别的问题和决策
热点问题记录:
┌─────────────────────────────────────────────┐
│ 🔴 问题1: 库存并发扣减 │
│ 决策: 使用乐观锁 + 库存预占机制 │
│ │
│ 🔴 问题2: 支付超时处理 │
│ 决策: 订单30分钟未支付自动取消 │
│ 释放预占库存 │
│ │
│ 🔴 问题3: 支付成功但回调失败 │
│ 决策: 定时任务轮询支付状态 │
│ + 手动对账机制 │
│ │
│ 🔴 问题4: 库存扣减失败但订单已支付 │
│ 决策: 补偿机制(自动退款) │
│ + 运营工单 │
└─────────────────────────────────────────────┘4.3 从事件风暴到限界上下文
事件聚类识别上下文边界:
用户相关事件 → 用户上下文
┌──────────────────────┐
│ - 用户已注册 │
│ - 用户已登录 │
│ - 用户信息已更新 │
└──────────────────────┘
订单相关事件 → 订单上下文
┌──────────────────────┐
│ - 订单已创建 │
│ - 订单已支付 │
│ - 订单已发货 │
│ - 订单已完成 │
└──────────────────────┘
库存相关事件 → 库存上下文
┌──────────────────────┐
│ - 库存已预占 │
│ - 库存已扣减 │
│ - 库存已释放 │
└──────────────────────┘
支付相关事件 → 支付上下文
┌──────────────────────┐
│ - 支付请求已发送 │
│ - 支付已确认 │
│ - 退款已完成 │
└──────────────────────┘5. 引导技巧
5.1 常见挑战和应对
挑战1: 讨论跑题
解决方案:
- 引导师及时打断
- "这个问题很重要,我们记下来,稍后讨论"
- 使用Parking Lot(停车场)记录延后问题
挑战2: 沉默寡言
解决方案:
- 直接提问:"张三,你怎么看?"
- 小组讨论后汇报
- 匿名投票决策
挑战3: 过于技术化
解决方案:
- 提醒使用业务语言
- 禁止讨论技术实现
- "我们关注What,不是How"
挑战4: 意见分歧
解决方案:
- 两种观点都贴出来
- 用红色便利贴标记为待决策
- 领域专家最终拍板5.2 时间管理
半天工作坊时间分配(4小时):
09:00-09:15 开场&破冰 15分钟
09:15-09:45 事件风暴 30分钟
09:45-10:30 时间线排序 45分钟
10:30-10:45 休息 15分钟
10:45-11:30 添加命令&聚合 45分钟
11:30-12:15 讨论热点问题 45分钟
12:15-12:30 总结&下一步 15分钟5.3 远程事件风暴
使用在线协作工具:
推荐工具:
- Miro
- Mural
- FigJam
- Lucidspark
在线版事件风暴模板:
┌───────────────────────────────────────────┐
│ Miro Board Layout │
│ │
│ Frame 1: 事件收集区 │
│ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │事件1│ │事件2│ │事件3│ │
│ └─────┘ └─────┘ └─────┘ │
│ │
│ Frame 2: 时间线区 │
│ ───────────────────────────────────────► │
│ ┌─────┐→┌─────┐→┌─────┐→┌─────┐ │
│ │事件A│ │事件B│ │事件C│ │事件D│ │
│ └─────┘ └─────┘ └─────┘ └─────┘ │
│ │
│ Frame 3: 问题停车场 │
│ 🔴 待解决问题列表 │
│ │
└───────────────────────────────────────────┘6. 输出物
6.1 事件风暴照片/截图
拍照检查清单:
✓ 全景照片(整个时间线)
✓ 关键流程特写
✓ 热点问题区域
✓ 决策记录6.2 整理成文档
事件目录:
markdown
# 订单系统事件目录
## 订单相关事件
- OrderCreated (订单已创建)
- OrderPaid (订单已支付)
- OrderShipped (订单已发货)
- OrderCompleted (订单已完成)
- OrderCancelled (订单已取消)
## 支付相关事件
- PaymentRequested (支付请求已发送)
- PaymentConfirmed (支付已确认)
- PaymentFailed (支付已失败)
- RefundCompleted (退款已完成)
## 库存相关事件
- InventoryReserved (库存已预占)
- InventoryDeducted (库存已扣减)
- InventoryReleased (库存已释放)6.3 转换为代码
事件定义:
java
// 从事件风暴到代码
// 事件风暴中的便利贴:
// ┌──────────────┐
// │订单已创建 │
// └──────────────┘
// 转换为代码:
public class OrderCreatedEvent implements DomainEvent {
private final OrderId orderId;
private final CustomerId customerId;
private final Money totalAmount;
private final LocalDateTime occurredAt;
public OrderCreatedEvent(
OrderId orderId,
CustomerId customerId,
Money totalAmount,
LocalDateTime occurredAt) {
this.orderId = orderId;
this.customerId = customerId;
this.totalAmount = totalAmount;
this.occurredAt = occurredAt;
}
// getters...
@Override
public LocalDateTime occurredAt() {
return occurredAt;
}
}7. 最佳实践
7.1 Do's and Don'ts
✓ Do:
- 使用业务语言,不用技术术语
- 鼓励所有人参与
- 快速迭代,不追求完美
- 及时记录问题
- 保持能量(站立、走动)
- 时间盒限制(番茄工作法)
✗ Don't:
- 不要过早讨论技术实现
- 不要让某个人主导
- 不要陷入细节争论
- 不要坐着开会
- 不要超时(疲劳导致效率低)7.2 成功指标
事件风暴成功的标志:
✓ 业务专家和技术团队达成共识
✓ 识别出关键业务流程
✓ 发现并解决了模糊点
✓ 明确了系统边界
✓ 团队对领域理解更深入8. 进阶话题
8.1 设计级事件风暴
在流程级基础上,进一步细化到可实现的程度。
添加更多细节:
┌────────────────────────────────────────┐
│ Read Model (读模型) │
│ - 用于展示数据 │
│ - CQRS中的查询端 │
└────────────────────────────────────────┘
┌────────────────────────────────────────┐
│ UI/UX Mock (界面原型) │
│ - 用户看到什么 │
│ - 用户可以做什么 │
└────────────────────────────────────────┘8.2 与Event Sourcing结合
事件溯源视角:
传统存储:
┌──────────────┐
│ Order表 │
├──────────────┤
│ id: 1001 │
│ status: PAID │
│ amount: 100 │
└──────────────┘
事件溯源:
┌────────────────────────┐
│ Event Store │
├────────────────────────┤
│ 1. OrderCreated │
│ 2. OrderPaid │
└────────────────────────┘
↓ 重放
┌──────────────┐
│ Current State│
│ status: PAID │
└──────────────┘9. 总结
事件风暴的核心价值:
- 快速对齐 - 几小时内建立共同理解
- 发现问题 - 暴露业务逻辑的模糊地带
- 可视化 - 整个业务流程一目了然
- 协作 - 打破技术和业务的隔阂
事件风暴不是银弹,但是DDD实践中最有效的工具之一。定期举行事件风暴工作坊,可以持续保持团队对业务的深入理解。
💬 讨论
使用 GitHub 账号登录后即可参与讨论