法不净空,觉无性也。

第 11 章 需求分析:从模糊到精确

2026.08.29

11.1 为什么需求分析是第一步(编码阶段改需求成本远高于分析阶段)

你正在做一个设备借用管理系统。产品经理扔给你一句话:"做一个借用申请功能。"你打开 AI 工具,复述了这句话。AI 花了 30 秒,生成了一套包含 5 个数据表、12 个 API 接口的方案。你看着这份方案,觉得哪里不对劲——但说不上来。你让它继续编码。

两周后,功能开发完了。你拿给业务部门演示,对方看了一眼说:"不对,我们的流程不是这样。"

你才发现,AI 默认的流程是"申请 → 审批 → 出库 → 归还",但你们公司的实际流程是"申请 → 领用 → 使用 → 归还 → 检查"。而且"领用"和"出库"在业务上是两个完全不同的动作——领用是员工从仓库取走设备,出库是仓库管理员登记设备出库。AI 把它们当成一个东西做了。

问题出在第一步。你把一句模糊的需求直接扔给了 AI。AI 没有读心术,它只能从训练数据中"猜"一个最可能的实现。而猜,在工程中是最昂贵的。

大多数 AI 编码失败的根源,不是"AI 写不出代码",而是"AI 做错了功能"。你描述了一个需求,AI 理解了一个版本,你心里想的是另一个版本。等 AI 把代码写出来,你才发现这不是你要的。这时候返工的成本远高于做之前说清楚。

这个问题的根源在于:人脑中的需求是模糊的,但代码必须是精确的。当你说"做一个借用申请功能"时,你脑海中有一整套业务上下文——谁可以借用、借用什么、借用多久、什么情况下可以借用、什么情况下不可以。但这句话传给 AI 时,所有这些上下文都丢失了。训练数据中的"借用申请"可能是图书馆的图书借用、是工具房的设备借用、是企业的固定资产借用——这三个系统的差异巨大。

你可能会想:"没关系,等 AI 做出来我再改。"但这里有一个隐藏的成本问题:在编码阶段改一个需求,成本通常远高于需求分析阶段——经验上常被引用为十倍量级(即软件工程中"变更成本随阶段递增"的经典法则在 AI 编码下的延续)。因为编码阶段改需求意味着你要重写代码、重跑测试、重做验收,而需求分析阶段改需求只需要改一行文字。

需求分析(Requirements Analysis)就是解决这个问题——把脑子里模糊的想法,变成 AI 和人类都能准确理解的结构化文档。它的核心产出不是代码,而是一份"双方对齐后的精确描述"。

11.2 Event Storming:用"业务事件"对齐需求

传统的需求分析方法是"功能清单法"。分析师问业务人员:"你希望系统有什么功能?"业务人员回答:"借用管理、设备管理、人员管理。"分析师拿着这个清单去设计系统。

这个方法有一个根本问题:功能清单是技术视角的产物,不是业务视角的产物。业务人员真正关心的不是"借用管理"这个模块,而是"员工提交借用申请之后,我需要做什么"这个流程。当你把"借用管理"作为一个功能扔给 AI,它不知道你的业务流程是"先审批后出库"还是"先领用后登记",它只能猜一个默认的通用流程。

Event Storming 换了一个问法。它不问"系统需要什么功能",而是问"业务中发生了什么事件"。这个问法的转变,把对话的锚点从"技术方案"拉回到了"业务流程"。

让我们用一个完整的例子来展示 Event Storming 的全过程。

场景:你在做一个设备借用管理系统。你召集业务人员开一个需求讨论会。你不问"系统需要什么功能",而是问:"从员工借设备开始,到设备归还结束,中间发生了哪些事情?"

业务人员会说:

员工提交申请 → 主管审批通过 → 仓库出库设备 → 员工领用设备 → 员工使用中 → 员工归还设备 → 仓库检查设备状态 → 设备入库完成

这些就是"业务事件"。注意,事件都是用过去式描述的——"提交了申请""审批通过了""出库了"——因为事件是已经发生的事情,不是将要发生的事情。

从这些事件中,你可以推导出:

  • 命令(Commands)——谁触发了这个事件?"提交申请"由"员工"触发,命令就是"提交借用申请";"审批通过"由"主管"触发,命令就是"审批申请";
  • 聚合(Aggregates)——这些事件和命令操作的核心数据是什么?借用申请、设备、员工、仓库记录——这些都是聚合;
  • 有界上下文(Bounded Contexts)——哪些事件和聚合属于同一个业务领域?借用申请和审批属于"借用管理"上下文,设备出库和入库属于"库存管理"上下文,员工信息属于"人员管理"上下文。

来看一个具体的对比

❌ 功能清单法:
1. 借用管理:申请、审批、查询
2. 设备管理:添加、编辑、删除、查询
3. 人员管理:添加、编辑、删除

✅ Event Storming 方法:
业务事件流:员工提交申请 → 主管审批 → 设备出库 → 员工领用 → 使用中 → 归还 → 检查 → 入库
有界上下文:
1. 借用管理上下文:申请、审批
2. 库存管理上下文:出库、入库、检查
3. 人员管理上下文:员工信息维护

看出区别了吗?功能清单告诉你"系统有什么模块",事件流告诉你"系统怎么工作"。后者天然包含了业务流程的依赖关系——你不能先做出入库功能再做申请功能,因为入库是在申请之后发生的。这个依赖关系在事件流中是显式的,在功能清单中是隐形的。

Event Storming 还有一个隐藏的好处:它让业务人员在"事件"上对齐,而不是在"技术方案"上对齐。业务人员可能不懂"数据库""API""有界上下文",但他们一定知道"员工提交申请"和"仓库出库设备"的区别。当你说"我们先列一下业务事件",业务人员可以毫无障碍地参与讨论;当你说"我们先设计数据库表",业务人员就只能沉默了。

一句话总结:Event Storming 用业务的语言描述业务,而不是用技术的语言描述业务。

11.3 需求分析的两大产出:REQUIREMENTS.md 与分歧记录

需求分析完成后,应该产出两份文档。

产出一:REQUIREMENTS.md。

一份完整的 REQUIREMENTS.md 应包含:

  1. 项目概述——一句话说明项目做什么;
  2. 用户角色——谁用这个系统,每个角色能做什么;
  3. 功能列表——按优先级排列的功能清单;
  4. 业务事件——核心业务流程的事件流;
  5. 数据实体——核心数据模型(初步);
  6. 约束条件——技术约束、时间约束、合规要求。

产出二:分歧记录。

在需求分析过程中,有一个容易被忽视但极其重要的产出:分歧记录

需求分析的本质是"做决策"。但很多人只关注"最终决定了什么",忽略了"放弃了什么"。为什么记录"放弃了什么"很重要?因为每个被放弃的方案背后都有一个权衡——而未来某一天,项目环境变化时,这个权衡可能需要重新审视。

来看一个教学重组的例子(细节经过合并与脱敏)。某项目在 MVP 阶段,产品经理要求支持"部分退款"功能。经过讨论,团队决定第一版不做,但记录了分歧:

分歧1:是否支持部分退款?
决策:第一版不支持。
原因:MVP 阶段需要控制范围。部分退款涉及复杂的金额拆分逻辑,
     且与支付网关的对接需要额外开发工作。
影响范围:订单状态机、退款流程、财务报表。
记录日期:2025-03-15

半年后,业务增长迅速,用户开始频繁要求部分退款。团队打开分歧记录,立刻理解了当初为什么没做、影响范围是什么、需要做什么才能支持。他们直接从这个记录出发开始设计,避免了重复讨论和踩坑。

如果没有这个记录,会发生什么?新来的开发者看到"不支持部分退款"这个现状,会以为是"忘了做"而不是"有意放弃"。他们可能会花大把时间讨论"要不要做"——而半年前这个讨论已经进行过了。

分歧记录的核心价值是:让"过去的决策理由"穿越时间,为未来的决策提供上下文。记录格式不需要复杂,关键是三个信息:分歧是什么、决策是什么、为什么这样选。

分歧N:[问题描述]
决策:[最终选择]
原因:[选择的原因]
影响范围:[这个决策影响哪些模块]
记录日期:[YYYY-MM-DD]

11.4 常见需求分析错误:过度抽象、功能堆积、忽略非功能需求

错误一:过度抽象。

"做一个通用的工作流引擎,支持各种业务场景。"这是最常见的需求分析陷阱。通用 = 模糊。AI 无法为"通用"设计出你想要的方案。

正确做法:先做具体场景,再抽象通用方案。"先做一个请假审批流程,然后我们看看能不能抽象成通用引擎。"

错误二:功能堆积。

"这个系统需要:订单管理、用户管理、商品管理、库存管理、财务管理、报表分析、消息推送、权限管理……"当功能列表超过 10 项时,需求分析的重点应该从"加功能"转向"排优先级"。

正确做法:区分 MVP(最小可行产品)和后续版本。"第一版只做:订单管理 + 用户管理。其他功能在后面的版本中逐步添加。"

错误三:忽略非功能需求。

"系统能处理每天 1000 个订单"和"100 万个订单",技术方案完全不同。非功能需求(性能、安全、可用性、可扩展性)直接影响架构设计。如果不说清楚,AI 可能选了一个不适合你规模的方案。

正确做法:在需求分析阶段就明确非功能需求。"数据量:每天约 100 个订单,总数据量不超过 10 万条。不需要高并发。但数据安全性要求高,因为涉及财务信息。"

【实操】用 Event Storming 分析一个业务场景

题目:选一个你熟悉的业务场景(如:图书借阅、会议室预约、报销审批、点餐下单),用 Event Storming 方法完成一次需求分析。

步骤引导

  1. 列事件:从开始到结束,列出所有的业务事件(用过去式)。至少列出 8 个。
  2. 推导命令:对每个事件,标注"谁触发了它?"→ 得出命令清单。
  3. 识别聚合:这些命令和事件操作的核心数据是什么?→ 得出聚合清单。
  4. 划分上下文:哪些事件和聚合属于同一个业务领域?→ 得出有界上下文清单。
  5. 写分歧记录:如果在分析中有任何"要不要做"的争论,用分歧记录格式记下来。

参考答案示例(以图书借阅为例):

业务事件流:读者提交借阅申请 → 系统检查可借数量 → 馆员确认借出 → 
           读者收到借出通知 → 读者按期归还 → 馆员检查图书状态 → 系统登记归还

命令:提交借阅申请(读者)、确认借出(馆员)、登记归还(馆员)
聚合:借阅单、图书、读者、逾期记录
有界上下文:借阅管理(申请/确认/归还)、馆藏管理(图书状态/数量)、读者管理(读者档案)

分歧记录:
分歧1:逾期是否自动生成罚金?
决策:第一版手动登记,不自动计算。
原因:罚金规则涉及费率配置与支付对接,MVP 阶段控制范围。

验收要点

  • 学员是否用"过去式"描述事件(而不是"要发生")?
  • 学员是否区分了"事件"与"功能"?
  • 学员的分歧记录是否包含:分歧、决策、原因、影响范围、日期?