Skip to content

事件风暴:领域建模实战工作坊

1. 事件风暴概述

1.1 什么是事件风暴

事件风暴(Event Storming)是一种快速探索复杂业务领域的协作式建模方法,由Alberto Brandolini在2013年提出。

传统需求分析 vs 事件风暴:

传统方法:
需求文档 → 评审 → 开发 → 测试

问题:理解偏差大、反馈慢

事件风暴:
业务专家 + 开发团队 → 共同建模 → 快速验证

优势:快速对齐认知、发现问题

1.2 事件风暴的价值

核心价值:

  1. 快速 - 几小时内探索整个业务流程
  2. 协作 - 业务和技术共同参与
  3. 可视化 - 贴满便利贴的时间线
  4. 发现问题 - 暴露业务规则的模糊点

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. 总结

事件风暴的核心价值:

  1. 快速对齐 - 几小时内建立共同理解
  2. 发现问题 - 暴露业务逻辑的模糊地带
  3. 可视化 - 整个业务流程一目了然
  4. 协作 - 打破技术和业务的隔阂

事件风暴不是银弹,但是DDD实践中最有效的工具之一。定期举行事件风暴工作坊,可以持续保持团队对业务的深入理解。

💬 讨论

使用 GitHub 账号登录后即可参与讨论

基于 MIT 许可发布