返回架构笔记
Arch Day 12

Arch Day 12: Event Storming高级

Event Storming是一种通过在墙上贴便签来发现领域知识、识别业务流程和设计系统架构的协作式工作坊方法。它的核心价值不是产出文档,而是让业务专家和技术团队在同一面墙前建立共同理解——这是DDD中Ubiquitous Language落地的最有效手段。

2026-04-11
第一阶段 - 架构基础
Event-Storming领域发现BigPictureProcessLevelDesignLevel引导技巧

日期: 2026-04-11 (Day 12) 阶段: 第一阶段 - 架构基础 标签: #Event-Storming #领域发现 #BigPicture #ProcessLevel #DesignLevel #引导技巧


核心概念

一句话定义

Event Storming是一种通过在墙上贴便签来发现领域知识、识别业务流程和设计系统架构的协作式工作坊方法。它的核心价值不是产出文档,而是让业务专家和技术团队在同一面墙前建立共同理解——这是DDD中Ubiquitous Language落地的最有效手段。

为什么资深架构师仍需关注

做了10年软件的人,参加过无数需求评审会。Event Storming之所以不同,是因为它解决了传统需求分析的三个致命问题:

  1. 业务专家被边缘化:传统方式是BA写文档→开发看文档。Event Storming让业务专家直接参与建模,不需要理解技术术语
  2. 知识的隐性传递:很多关键业务规则存在于业务专家的脑子里,不会写在文档中。Event Storming通过互动式讨论"逼"出这些隐性知识
  3. 全局视图缺失:传统需求文档是按功能/模块切割的,很难看到全局的业务流程。Event Storming把整个流程铺在一面墙上,所有人都能看到全貌

常见误区与反模式

误区真相后果
"Event Storming = 画流程图"ES是发现过程,不是记录过程;重要的是讨论变成了一个人在白板上画图,其他人旁观
"只需要技术人员参与"没有业务专家参与的ES毫无价值技术人员自己想象的领域模型
"一次做完整个系统"应该分多次workshop,每次2-3小时参与者疲劳,后半段质量骤降
"产出必须是完美的"ES的产出是"足够好"的,用来指导后续讨论追求完美导致进度停滞
"便签颜色不重要"颜色是约定,必须全员理解一致混乱,无法解读
"ES之后直接开始编码"ES到代码之间还需要Design Level细化代码和ES脱节

知识点详解

知识点1: Event Storming三层方法论

Alberto Brandolini设计了三个层级的Event Storming,从宏观到微观递进:

Layer 1: Big Picture Event Storming
├── 目的: 理解整个业务域的全貌
├── 参与者: 所有利益相关者(业务+技术+管理+运营)
├── 时间: 2-4小时
├── 产出: 业务全景图 + 关键热点 + Bounded Context候选
└── 粒度: 粗(一个事件可能代表一整个子流程)

Layer 2: Process Level Event Storming
├── 目的: 深入理解一个具体的业务流程
├── 参与者: 该流程的业务专家 + 技术团队
├── 时间: 2-3小时
├── 产出: 详细流程(命令→事件→策略) + 角色识别 + 集成点
└── 粒度: 中(每个步骤一个事件)

Layer 3: Design Level Event Storming
├── 目的: 将流程映射为具体的代码结构
├── 参与者: 技术团队(可选业务专家)
├── 时间: 1-2小时
├── 产出: 聚合根 + 命令 + 事件 + 读模型的直接映射
└── 粒度: 细(每个状态变化一个事件)

知识点2: Big Picture Event Storming

步骤详解:

Phase 1: 混沌阶段 (30min)
├── 每人拿一叠橙色便签
├── 规则: "写下你知道的、在这个业务中发生的事件"
├── 事件格式: 过去式动词 ("订单已创建"、"支付已完成"、"库存已扣减")
├── 不需要顺序,贴在墙上任意位置
└── 引导者不干预,让所有人自由表达

Phase 2: 时间线排序 (30min)
├── 一起把事件按时间线排列(从左到右)
├── 讨论: "这个事件是在那个事件之前还是之后?"
├── 发现冲突: 不同人对同一流程的理解不同
├── 合并重复的事件,澄清歧义
└── 这是最有价值的阶段——分歧暴露隐性知识

Phase 3: 标记热点 (15min)
├── 用粉色/红色便签标记"热点"(Hot Spot)
├── 热点 = 不确定的地方 / 争议 / 复杂度高 / 痛点
├── 不需要立刻解决,只需要标记出来
└── 热点是后续深入讨论的候选

Phase 4: 识别外部系统和用户 (15min)
├── 用黄色便签标记"外部系统"
├── 用小人图标标记"角色/用户"
├── 问: "这个事件是谁触发的?需要哪些外部系统参与?"
└── 这帮助识别系统边界和集成点

Phase 5: 识别Bounded Context (30min)
├── 在时间线上画竖线,分割不同的"语境"
├── 同一个词在竖线两侧含义不同 → 不同的BC
├── 讨论: "这些事件是由同一个团队负责的吗?"
└── 产出: 初步的Bounded Context划分

便签颜色约定(Brandolini标准):

颜色含义格式示例
橙色领域事件(Domain Event)过去式"订单已提交"
蓝色命令(Command)祈使句"提交订单"
黄色角色/外部系统(Actor)名词"客户"、"银行API"
粉色/红色热点(Hot Spot)问题/风险"审批超时怎么办?"
紫色策略/规则(Policy)条件"金额>10万需要二级审批"
绿色读模型(Read Model)名词"账户余额视图"
淡黄色聚合根(Aggregate)名词"订单"

知识点3: Process Level Event Storming

在Big Picture之后,选取一个关键流程深入:

Process Level的核心范式:

[角色] → 看[读模型] → 发出[命令] → [聚合根]处理 → 产生[事件] → 触发[策略] → ...

示例: 贷款审批流程

[客户经理] → 看[客户资质视图] → 发出[提交贷款申请]
  → [贷款申请]处理 → 产生[贷款申请已提交]
  → 触发[自动风控评估策略]
  → [风控引擎]处理 → 产生[风控评估已完成]
  → 触发[审批路由策略: 金额>100万走二级审批]

[审批经理] → 看[贷款申请详情+风控报告] → 发出[审批通过/拒绝]
  → [贷款申请]处理 → 产生[贷款申请已审批]
  → 触发[放款准备策略]

Process Level的关键产出:

  1. 完整的命令-事件链:每个步骤的输入和输出
  2. 策略(Policy)的识别:哪些步骤是自动触发的、哪些需要人工
  3. 读模型需求:每个角色在每个步骤需要看到什么信息
  4. 异常路径:超时、拒绝、取消、回退等异常场景

知识点4: Design Level Event Storming——从便签到代码

这是最关键的一步:如何把墙上的便签直接映射为代码结构

便签 → 代码的映射:

橙色(事件)    → 领域事件类
蓝色(命令)    → 命令类 + 命令处理器
黄色(角色)    → API端点的认证/授权
紫色(策略)    → 领域服务 / 事件处理器
绿色(读模型)  → 查询服务 / DTO
淡黄色(聚合根) → 聚合根类

直接映射示例:

便签:
[客户经理] → [提交贷款申请] → [贷款申请] → [贷款申请已提交] → [风控评估策略]

代码:
// 命令(蓝色便签)
class SubmitLoanApplicationCommand {
  constructor(
    readonly applicantId: string,
    readonly amount: Money,
    readonly term: number,        // 贷款期限(月)
    readonly purpose: string,
    readonly submittedBy: string   // 客户经理ID
  ) {}
}

// 聚合根(淡黄色便签)
class LoanApplication {
  private _id: string;
  private _status: LoanApplicationStatus;
  private _applicantId: string;
  private _amount: Money;
  private _term: number;
  private _riskScore: number | null;
  private _events: DomainEvent[] = [];

  static submit(command: SubmitLoanApplicationCommand): LoanApplication {
    const app = new LoanApplication();
    app._id = generateId();
    app._status = LoanApplicationStatus.SUBMITTED;
    app._applicantId = command.applicantId;
    app._amount = command.amount;
    app._term = command.term;
    app._riskScore = null;

    // 领域事件(橙色便签)
    app._events.push(new LoanApplicationSubmitted({
      applicationId: app._id,
      applicantId: command.applicantId,
      amount: command.amount,
      submittedBy: command.submittedBy,
      submittedAt: new Date()
    }));

    return app;
  }

  recordRiskAssessment(score: number, result: RiskResult): void {
    if (this._status !== LoanApplicationStatus.SUBMITTED) {
      throw new Error("Can only assess submitted applications");
    }
    this._riskScore = score;
    this._status = LoanApplicationStatus.RISK_ASSESSED;

    this._events.push(new RiskAssessmentCompleted({
      applicationId: this._id,
      score: score,
      result: result
    }));
  }

  approve(approvedBy: string, conditions: string[]): void {
    if (this._status !== LoanApplicationStatus.RISK_ASSESSED) {
      throw new Error("Can only approve risk-assessed applications");
    }
    this._status = LoanApplicationStatus.APPROVED;

    this._events.push(new LoanApplicationApproved({
      applicationId: this._id,
      approvedBy: approvedBy,
      conditions: conditions,
      approvedAt: new Date()
    }));
  }

  reject(rejectedBy: string, reason: string): void {
    if (this._status !== LoanApplicationStatus.RISK_ASSESSED) {
      throw new Error("Can only reject risk-assessed applications");
    }
    this._status = LoanApplicationStatus.REJECTED;

    this._events.push(new LoanApplicationRejected({
      applicationId: this._id,
      rejectedBy: rejectedBy,
      reason: reason
    }));
  }
}

// 策略(紫色便签) → 事件处理器
class AutoRiskAssessmentPolicy {
  constructor(private riskEngine: RiskEngine) {}

  // 当贷款申请提交后,自动触发风控评估
  async handle(event: LoanApplicationSubmitted): Promise<void> {
    const score = await this.riskEngine.assess({
      applicantId: event.applicantId,
      amount: event.amount
    });

    // 发出命令给LoanApplication聚合根
    await this.commandBus.send(new RecordRiskAssessmentCommand({
      applicationId: event.applicationId,
      score: score.value,
      result: score.result
    }));
  }
}

// 策略(紫色便签): 审批路由
class ApprovalRoutingPolicy {
  async handle(event: RiskAssessmentCompleted): Promise<void> {
    if (event.score >= 80) {
      // 高评分 → 自动审批
      await this.commandBus.send(new AutoApproveCommand(event.applicationId));
    } else if (event.score >= 60) {
      // 中等评分 → 一级审批
      await this.notificationService.notifyApprover(
        ApprovalLevel.LEVEL_1, event.applicationId
      );
    } else {
      // 低评分 → 二级审批
      await this.notificationService.notifyApprover(
        ApprovalLevel.LEVEL_2, event.applicationId
      );
    }
  }
}

// 读模型(绿色便签)
class LoanApplicationView {
  applicationId: string;
  applicantName: string;
  amount: string;
  term: number;
  status: string;
  riskScore: number | null;
  submittedAt: Date;
  approverName: string | null;
}

知识点5: 引导(Facilitation)技巧

这是Event Storming成败的关键——如何引导一屋子人有效地协作。

引导者的角色:

引导者 ≠ 主讲人
引导者 ≠ 决策者
引导者 = 过程的管理者

职责:
├── 设置规则和节奏
├── 鼓励沉默的参与者发言
├── 打断跑题的讨论("这是个好问题,我们先贴个热点便签")
├── 识别关键争议并引导讨论
├── 控制时间
└── 确保所有声音都被听到

常见场景及应对:

场景应对策略
业务专家沉默不语直接提问: "在你的工作中,XX之后通常会发生什么?"
技术人员过早讨论实现"这个实现细节我们后面再讨论,先关注业务流程"
两人争论不休"你们说的可能都对,我们贴两个不同颜色的便签表示两种观点"
某人主导发言"谢谢XX的观点,其他人怎么看?"
讨论跑题"很好的观点,但它属于另一个流程,我们先贴个热点"
参与者疲劳休息10分钟,回来后从热点开始讨论(热点通常更有趣)

房间和物资准备:

必须:
├── 大面白墙(或白板墙/大卷纸) - 至少5米宽
├── 多色便签(至少橙/蓝/黄/粉/紫/绿)
├── 粗马克笔(细笔写的字远处看不清)
├── 站立工作(不要坐着 - 坐着的人会变成旁观者)
└── 2-4小时的连续时间块

禁止:
├── 笔记本电脑(除非用于查资料)
├── 投影仪(PPT会让人变成被动听众)
└── 超过15人(超过则分组并行)

知识点6: 热点(Hot Spot)和策略(Policy)的识别

热点是Event Storming最独特的产出之一:

热点的类型:
├── 不确定性: "这个流程到底是先审批还是先风控?"
├── 争议: "业务说A,运营说B,谁是对的?"
├── 复杂性: "这里有10种异常情况需要处理"
├── 痛点: "这个步骤经常出错/很慢/被用户投诉"
├── 知识缺口: "没人知道这个流程的细节"
└── 技术债: "这里是遗留系统的接口,很脆弱"

热点的价值:
├── 是后续深入讨论的优先级列表
├── 是产品backlog的输入
├── 是架构风险的早期信号
└── 比任何需求文档都更真实地反映了系统的痛点

策略(Policy)是连接事件和后续行为的规则:

策略的识别方法:
在每个事件后面问: "这个事件发生后,会自动触发什么?"

如果答案是"有人需要手动操作" → 不是策略,是人工步骤
如果答案是"系统自动做XX" → 这是策略(自动化规则)
如果答案是"当XX条件满足时才做" → 这是条件策略

示例:
[支付已完成] → 策略: "自动发送收据邮件"
[订单已逾期] → 策略: "超过30天自动取消"
[风控评分<60] → 策略: "自动路由到人工审核"

对比分析

Event Storming vs 传统需求分析方法

维度Event Storming用户故事地图传统需求文档UML用例图
参与者所有角色PM+设计+开发BA单独编写架构师
时间投入2-4小时/次半天-1天数周数天
知识传递实时面对面半实时文档异步文档异步
全局视图强(整面墙)中(有层级)弱(按模块割裂)弱(按用例割裂)
发现隐性知识强(讨论驱动)
到代码的距离近(Design Level直接映射)
学习曲线低(贴便签)低(写文档)高(UML语法)
适合阶段项目初期/重构前产品规划需求确认系统设计

三层Event Storming对比

维度Big PictureProcess LevelDesign Level
目标全貌理解流程细化代码映射
粒度
参与者10-15人(全角色)5-8人(领域+技术)3-5人(技术为主)
时间2-4小时2-3小时1-2小时
产出BC划分+热点命令-事件链+策略聚合根+读模型
频率项目初期1-2次每个核心流程1次每个BC内多次

架构设计实操

实操: "贷款申请→审批→放款→还款→逾期" 完整三层Event Storming

Layer 1: Big Picture

事件时间线(从左到右):

┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐
│  申请阶段        │  │  审批阶段        │  │  放款阶段        │
│                 │  │                 │  │                 │
│ 客户已注册       │  │ 风控评估已完成    │  │ 放款已执行       │
│ 实名认证已通过    │  │ 审批已通过/拒绝   │  │ 合同已签署       │
│ 贷款申请已提交    │  │ 条件已补充       │  │ 资金已到账       │
│                 │  │ 复审已完成       │  │                 │
└─────────────────┘  └─────────────────┘  └─────────────────┘

┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐
│  还款阶段        │  │  逾期阶段        │  │  结清阶段        │
│                 │  │                 │  │                 │
│ 还款计划已生成    │  │ 还款已逾期       │  │ 贷款已结清       │
│ 还款已执行       │  │ 催收通知已发送    │  │ 征信报告已更新    │
│ 提前还款已申请    │  │ 催收任务已分配    │  │                 │
│ 部分还款已确认    │  │ 诉讼已发起       │  │                 │
└─────────────────┘  └─────────────────┘  └─────────────────┘

热点标记:

🔴 热点1: "风控评估需要多长时间?实时还是异步?" (性能关注)
🔴 热点2: "审批通过后客户不签合同怎么办?有效期多长?" (业务规则不明)
🔴 热点3: "提前还款的违约金计算规则是什么?" (业务复杂度)
🔴 热点4: "逾期催收的升级规则是什么?" (策略复杂度)
🔴 热点5: "多个贷款同时还款时的优先级" (并发复杂度)

初步BC划分:

BC1: 客户管理 (注册/认证)
BC2: 贷款申请 (申请/审批)
BC3: 风控评估 (独立的风控引擎)
BC4: 合同管理 (签约/合同条款)
BC5: 放款执行 (资金划转)
BC6: 还款管理 (还款计划/执行/提前还款)
BC7: 催收管理 (逾期/催收/诉讼)
BC8: 征信报告 (外部系统集成)

Layer 2: Process Level (聚焦"贷款申请→审批"流程)

[客户经理] → 看[客户资质概览] → [提交贷款申请]
                                      │
                                      ▼
                              [贷款申请] 聚合根
                                      │
                                      ▼
                           [贷款申请已提交] 事件
                                      │
                           ┌──────────┤
                           │          │
                    [自动风控策略]   [补充材料策略]
                           │          │
                           ▼          ▼
                    [风控引擎评估]   [通知客户补充]
                           │
                           ▼
                    [风控评估已完成] 事件
                           │
                    [审批路由策略]
                    ├── 评分≥80: 自动审批
                    ├── 评分60-79: 一级审批
                    └── 评分<60: 二级审批
                           │
                           ▼
[审批经理] → 看[申请详情+风控报告+历史贷款] → [审批通过/拒绝/要求补充]
                                                    │
                                                    ▼
                                          [贷款申请已审批/已拒绝] 事件
                                                    │
                                   ┌────────────────┤
                                   │                │
                           [审批通过策略]       [拒绝通知策略]
                           │                        │
                           ▼                        ▼
                    [生成合同草案]            [发送拒绝通知]
                    [通知客户签约]            [记录征信]

Layer 3: Design Level (聚焦"贷款申请"聚合根)

// 直接从便签映射的代码结构

// ===== 命令 (蓝色便签) =====
interface SubmitLoanApplication {
  applicantId: string;
  amount: Money;
  termMonths: number;
  purpose: LoanPurpose;
  collateral?: CollateralInfo;
}

interface RecordRiskAssessment {
  applicationId: string;
  riskScore: number;
  riskLevel: RiskLevel;
  factors: RiskFactor[];
}

interface ApproveLoanApplication {
  applicationId: string;
  approvedBy: string;
  approvedAmount: Money;  // 可能不是申请全额
  conditions: string[];
  interestRate: number;
}

interface RejectLoanApplication {
  applicationId: string;
  rejectedBy: string;
  reason: string;
}

// ===== 事件 (橙色便签) =====
interface LoanApplicationSubmitted {
  applicationId: string;
  applicantId: string;
  amount: Money;
  termMonths: number;
  submittedAt: Date;
}

interface RiskAssessmentCompleted {
  applicationId: string;
  riskScore: number;
  riskLevel: RiskLevel;
  assessedAt: Date;
}

interface LoanApplicationApproved {
  applicationId: string;
  approvedAmount: Money;
  interestRate: number;
  conditions: string[];
  approvedAt: Date;
}

interface LoanApplicationRejected {
  applicationId: string;
  reason: string;
  rejectedAt: Date;
}

// ===== 聚合根 (淡黄色便签) =====
class LoanApplication {
  // 状态机(从ES中识别):
  // DRAFT → SUBMITTED → RISK_ASSESSED → APPROVED/REJECTED
  //                                   → PENDING_SUPPLEMENTARY

  // 每个命令对应一个方法
  // 每个方法产生一个事件
  // 每个方法检查状态前置条件
}

// ===== 策略 (紫色便签) =====
// AutoRiskAssessmentPolicy: 申请提交后自动评估
// ApprovalRoutingPolicy: 风控完成后路由到合适的审批人
// ContractGenerationPolicy: 审批通过后自动生成合同

// ===== 读模型 (绿色便签) =====
// LoanApplicationListView: 审批人看的待审批列表
// LoanApplicationDetailView: 审批人看的详情(含风控报告)
// ApplicantHistoryView: 客户的历史贷款记录

AI增强实践

AI在Event Storming中的应用

1. 事前准备——领域知识预研

Prompt: "我们要对 [业务领域] 做Event Storming。请帮我:
1. 列出这个领域中最常见的30个领域事件
2. 识别关键角色(Actor)
3. 列出可能的外部系统集成点
4. 预测可能的热点(复杂/争议/不确定的地方)
这些不是最终答案,只是帮我准备引导问题的参考。"

2. 事后整理——便签到文档

Prompt: "以下是我们Event Storming的照片/记录:
[描述或列出便签内容]
请帮我:
1. 整理为结构化的事件时间线
2. 标注命令-事件-策略的关系
3. 识别潜在的Bounded Context边界
4. 生成Design Level的代码框架"

3. 代码生成——Design Level到代码

Design Level的产出可以直接让AI生成代码框架:

  • 聚合根的状态机
  • 命令和事件的类型定义
  • 策略的事件处理器骨架
  • 读模型的DTO定义

AI vs 人工边界:

任务AI能力人工不可替代
预研领域事件列表优秀(泛化知识)特定业务的独特规则
整理ES产出优秀-
生成代码框架优秀-
引导ES工作坊不适用现场氛围和人际互动
识别热点有限需要业务上下文和直觉
解决争议不适用需要组织政治判断

与Web3/DeFi的关联

传统ES概念Web3对应关键差异
领域事件链上Event Log链上事件不可篡改,天然的事件存储
命令交易(Transaction)链上命令需要Gas费和签名
策略(Policy)智能合约逻辑/链下Bot链上策略=合约代码,链下策略=Keeper/Bot
聚合根智能合约合约=状态+行为,类似充血聚合根
读模型Subgraph/IndexerThe Graph等索引器构建读模型
热点Gas优化热点链上的"热点"往往与Gas成本相关

用Event Storming分析DeFi协议:

以Aave借贷协议为例:

事件时间线:
[用户已存款] → [利息已累计] → [借款已发起] → [健康因子已更新]
→ [健康因子低于阈值] → [清算已触发] → [清算已执行]

策略:
- 利率计算策略: 根据利用率自动调整利率
- 清算触发策略: 健康因子<1时自动触发
- 预言机更新策略: Chainlink价格更新时重新计算健康因子

热点:
🔴 价格闪崩时的级联清算风险
🔴 预言机延迟导致的错误清算
🔴 Gas价格飙升时清算bot是否能及时执行

今日思考

  1. 回想你参加过的最好的和最差的需求讨论会。 最好的那次,是什么让它有效?最差的那次,问题出在哪里?Event Storming的哪些元素能解决你经历过的问题?

  2. 在远程工作时代,如何做Event Storming? 用Miro/FigJam等工具能替代物理便签吗?远程ES损失了什么(物理走动、面对面互动)?如何弥补?

  3. DeFi协议的Event Storming有什么不同? 传统系统的事件是"可能发生也可能不发生的",但链上事件是"一旦发生就不可逆的"。这种不可逆性如何影响ES中"异常路径"的设计?


面试题准备

Q1: Event Storming和传统需求分析有什么区别?

30秒版本: 三个核心区别:第一,参与者不同——ES让所有角色(业务+技术+运营)同时参与,而不是BA独自写文档;第二,知识传递方式不同——ES是实时面对面讨论,能暴露隐性知识;第三,产出形式不同——ES的产出可以直接映射为代码结构(事件→命令→聚合根),比需求文档到代码的距离更短。

2分钟版本:

Event Storming的核心价值在于三个方面。

第一,打破信息孤岛。传统需求分析中,业务专家告诉BA,BA写文档,开发读文档。信息在每次传递中都会丢失和扭曲。ES让所有人在同一面墙前讨论,分歧当场暴露和解决。

第二,发现隐性知识。业务专家脑中有大量"理所当然"的规则,不会主动告诉你。ES通过事件时间线的排序过程,强迫所有人检查"这个事件之后会发生什么",从而"逼"出这些隐性规则。

第三,到代码的距离短。ES的Design Level直接产出命令、事件、聚合根、策略——这就是代码的骨架。传统需求文档到代码之间还需要大量的翻译工作。

在我的实践中,一次2-3小时的ES工作坊产出的领域知识,相当于2-3周的传统需求调研。关键成功因素是引导者的水平——好的引导者能让沉默的业务专家开口,能在争论中识别真正的问题。

追问准备:

追问: "如何处理业务专家不配合的情况?" 回答: 三种策略。第一,不要叫它"Event Storming"或任何技术名词,就说"我想请你帮忙梳理一下XX流程"。第二,从具体场景开始,"上周那个XX客户的案例,流程是怎样的?"比抽象讨论有效得多。第三,如果业务专家实在没时间全程参与,至少请他们参加30分钟的"验证环节"——看看我们理解的对不对。

Q2: 从Event Storming到代码,中间还需要什么?

30秒版本: 需要三步:第一,细化Design Level——将Process Level的事件进一步细化为聚合根的状态转换;第二,确定持久化策略——事件要存在哪里、读模型怎么构建;第三,定义API契约——外部如何触发命令、如何查询读模型。ES到代码不是一步到位的,但ES大幅缩短了这个距离。

2分钟版本:

ES的Design Level已经非常接近代码了,但还需要补充三个方面。

第一,聚合根的不变量细化。ES告诉你有哪些命令和事件,但具体的业务规则(如"贷款金额不能超过年收入的30倍")需要在Design Level之后进一步明确。

第二,技术决策。ES不涉及技术选型——数据库、消息队列、缓存策略等。这些需要在ES之后,结合架构特征需求单独决策。

第三,非功能需求。ES关注的是业务流程,但性能SLA("风控评估必须在3秒内完成")、安全要求("敏感数据必须加密")等需要额外补充。

我的做法是在ES之后立即产出三个文档:一是事件目录(所有事件的schema定义),二是聚合根设计(状态机+不变量),三是ADR(关键技术决策)。这三个文档加上ES的墙面照片,就足以开始编码了。


学习资源

  1. Alberto Brandolini - "Introducing Event Storming" - 官方书(在线连载): https://www.eventstorming.com/
  2. Alberto Brandolini - EventStorming Workshop视频 - YouTube上有多个演讲
  3. Nick Tune - "Domain-Driven Design Starter Modelling Process" - 将ES融入完整的建模流程
  4. Miro Event Storming模板 - 远程协作工具
  5. EventStorming Glossary Cheat Sheet - DDD Crew: https://github.com/ddd-crew/eventstorming-glossary-cheat-sheet
  6. 《Domain-Driven Design Distilled》 - Vaughn Vernon - Chapter 7: Event Storming

明日预告

Day 13: 微服务治理(高级) —— 从"拆出微服务"到"管好微服务"。我们将深入服务网格(Istio/Linkerd)、分布式追踪(OpenTelemetry)、熔断限流降级(Resilience4j)、Saga模式(编排vs协调)、API版本演进策略。实操:设计一个完整的"支付平台"微服务方案,包含服务通信矩阵、Saga设计和API演进计划。