跳到主要内容

写需求:和歧义的战争

这一章讲四件事: 需求错误随时间升值的汇率表;让每条需求「可以被点名」的编号法; 自然语言与形式化模型怎么配合着消灭歧义(本书最精彩的一段对照,走查给你看); 以及三类最容易漏写的「没说清」。读完你就明白:需求文档不是写给客户看的作文,是给下游的合同。

1. 先看现象:同一句中文,两个团队做出两个系统

「系统应及时响应用户请求」——写这句话的人觉得清楚极了。 设计团队读成「半秒内返回」,测试团队按「两秒内都算过」写用例,客户上线后发现「等三秒才出结果」,投诉。

没有一个人做错了。每个人都「忠实实现」了那句中文。 歧义(同一句话有多种读法)不产生争论——它产生两个各自都说得通、但不一样的系统, 等发现时,两个都已经造完了。

这就是本章的全部动机:需求一旦写下,就会被下游当真。写得含糊,等于授权下游替你做决定。

2. 顶层全景

需求找对了(第 03 章)
│ 写下来的那一刻,错误开始「升值」

汇率表:设计阶段 5× → 编码 10× → 单元测试 20× → 交付 200×
│ 所以每个字都要可追责

编号(P52)+ 记录动机(P43)+ 排优先级(P50)
│ 文字本身还有歧义,两头夹攻

自然语言(人人能读) + 形式化模型(无歧义探误器)
│ 三类「没说清」单独显式写

可靠性口径(P57) · 环境越界行为(P58) · 待定项死线(P59)

图说:左列是动作,右列是它防住的事故。
这条链走完,需求文档才从「作文」变成「合同」。

3. 核心原理

3.1 需求错误的汇率表:为什么这里最值得花时间

原则 41 给出的数字是全书被引用最多的一张表1——需求规格说明里的一个错误, 每往下游多活一个阶段,修复代价乘一次:

错误活到了修复代价
设计阶段5 倍
编码阶段10 倍
单元测试阶段20 倍
交付之后200 倍

这些倍数怎么来的?想想火星轨道器那个「磅当牛顿」的错误(第 01 章): 在纸上改一个单位是 1 分钟的事;错在真机上,连改的机会都没有。 错误越晚发现,它周围已经盖起来的东西越多——设计照着它做了,代码照着设计写了,测试照着代码过了。 200 倍不是精确汇率,它的量级来自「下游一切都要返工」这个结构。

作者称这是「要在需求阶段修错误」最令人信服的证据1

3.2 让每条需求可以被点名:编号

要修错误,先得能指认它。「第 38 页那个响应时间的问题」不算指认。原则 52 给的最低要求: 每条需求单独编号2。书里给了三种做法,由重到轻:

  1. 每条需求打唯一标识,如 [需求R27];
  2. 段落编号到句子:「段落 3.2 第 k 句的需求」编号为「需求 3.2-sk」;
  3. 规定每条需求必含「应该」二字,用文本搜索程序自动提取编号、汇总成附录。

编号不是文书洁癖——它承重两次:设计要能追到需求(第 05 章 5.2 的对照表),测试要能追到需求(第 08 章 8.2 的表格)。 两张追溯表都以「每条需求有唯一编号」为地基。

3.3 编号之外,还要记「它为什么在」

原则 43:每条需求旁边,记下它从哪来——哪次访谈、谁说的、什么时候3。 书里的例子:决策「响应时间应该是两秒」旁边要记访谈的日期、时间、参与者,最好附上原话或录音。

这条防的是两种事故:客户后来要求改这条需求时,你查得到当初为什么定两秒,才能判断改了会不会伤到别的; 系统做不出两秒时,你拿得出依据,去和客户谈「改成四秒行不行」,而不是空对空地吵。

3.4 排优先级:不是所有需求都一样重要

原则 50 的例子选得好:载人飞船的需求单里,既有「速溶橙汁」也有「全功能生命维持系统」。 缺橙汁不会中止发射,生命维持坏了会——它们显然不该在同一张「必须完成」的清单里4

给出的两个工具,任选:每条需求标上三档——必须(不做就不能发布)、期望(有它更好)、 可选(没有也行),英文行话 M/D/O(Mandatory/Desirable/Optional); 或者每条打 0~10 的分。第 03 章那个「客户可忍 10% 必需功能按时、90% 晚拿」的判断5, 就是靠这张优先级表才可能说出口的。

3.5 主走查:同一件事,两种写法——形式化模型当探误器

现在到本章核心:歧义战争。自然语言(人写的日常语言)天生一词多义; 彻底消灭歧义只有一条路——用形式化方法(用数学符号代替日常语言来写规则的做法)。 但纯形式化写法别人读不懂,怎么办?原则 53~55 给出的答案是「配合」,并且配了一组对照原文,值得整段走完6

第一步:先写自然语言(注意顺序,后面解释为什么):

用户为拨打长途电话,应该拿起电话。系统应该在 10 秒内返回一个拨号音。 用户应该拨「9」。系统应该在 10 秒内返回一个不同的拨号音。

第二步:再写形式化模型。 这里用有限状态机(把系统写成「若干状态 + 什么事件让它从哪个状态跳到哪个状态」的图)改写:

系统包含四种状态:空闲、拨号音、不同的拨号音和接通。要从「空闲」转换到「拨号音」,应拿起电话。 要从「拨号音」转换到「不同的拨号音」,应拨「9」。

第三步:用模型反咬自然语言。 把第二段摆到第一段旁边,自然语言立刻显出三个漏洞: 「拿起电话后 10 秒没拨呢」——模型里没有这个状态,回填;「拨了非 9 的键呢」——模型里也没写;「『接通』状态怎么进」——原文根本没说。 作者的原话:试写形式化版本,会帮你在自然语言里发现问题;修掉这些问题,你就得到了更好的文档7

为什么顺序必须是「先自然语言」? 作者用第三段对照展示:如果写状态机, 再回头写「自然语言版本」,写出来的会是——

系统包含四种状态:空闲、拨号音、不同的拨号音和接通。要从「空闲」状态转换到「拨号音」状态,应拿起电话……

这不是自然语言,这是把模型用日常词复述了一遍——它描述的是那个模型,而不是要解决的问题。 读者从这段里得不到任何模型之外的信息,所以「完全没给读者提供帮助」8

两步的分工由此清楚:自然语言负责让人读懂系统该干什么,形式模型负责把「干什么」逼到无歧义; 后者是探误器,不是替代品。 书里建议两者并排放在对开页上,人工核对一致9

作者还顺手给了一个务实的尺寸:不必整份需求形式化——先写自然语言全文,再挑最要命、最容易出事的几节试写形式模型, 写完把发现的问题修回自然语言,形式版可以删掉不留10。每项目配一个熟手即可10

3.6 三类「没说清」,必须显式写死

走查之外的三个机制,每个都是「不写就一定出事」的类型。

其一:可靠性到底是哪个口径。 原则 57 说,「这个系统有 99.999% 的可靠性」这句话没有任何意义11—— 它至少能读成三种不同的合同(年=525,600 分钟;525,600 × 0.001% ≈ 5.3 分钟,除法是我们做的):

口径问题例句
需求失效系统被要求动作时,做对的百分比「正确报告 99.999% 的病人生命体征异常」——每十万次漏报不超过 1 次
失败率单位时间内错的次数「错报病人生命体征每年不超过 1 次」
可用性时间上可用的百分比「一年 99.999% 时间可用」=全年宕机不超过约 5 分钟

病人监护设备和电话系统,该选的口径完全不同——不写死口径,等于让每个下游各选一个11

其二:环境越界时系统怎么办。 原则 58 的例子:空管系统的需求写着「一个区域最多同时处理 100 架飞机」, 系统照此建成并正确。三年后的某一天,第 101 架进来了。软件怎么办?书里列了四个选项: 打印错误信息、崩溃、忽略第 101 架、处理它但可能突破时间约束(如屏幕刷新变慢)。 前三个显然不可接受,但基于那份(没写的)需求,它们都算正确响应。 正解:凡是为环境定义的限制,都要在需求里写明「越界时预期的系统行为」12。 这和第 08 章「压力测试要测 x+1」是同一枚硬币的正反面。

其三:没想好的事,给它一个死线。 原则 59:需求文档里的待定项(TBD,To Be Determined,意思是「此处待定」) 本身可以接受,但每条必须带「自毁注释」——到何时、由谁解决。 书里的样例格式:「开发经理将在 1995 年 12 月之前解决这个待定项」13。 没有死线的 TBD 会在文档里住到退役。

3.7 配套的写作纪律(一张表说完)

围绕「让文字可检查」这个唯一主题,书里还散落了几条小纪律,合并在一张表里:

纪律一句话内容它防什么
书写简洁14「目标跟踪功能应提供显示所有活动目标的当前跟踪坐标的能力」改成「跟踪时,系统应显示所有活动目标的当前位置」读者在读套话时漏掉真正的承诺
不在需求里做设计15需求只写外部行为;实在要用图辅助,加注「此处包含设计,仅供理解,设计者可另选方案」把架构决定走私进需求,设计者失去选优空间
用对方法、多视角16数据密集用实体关系图,实时系统用状态机,部件之间配合的难题用 Petri 网,决策密集用决策表——并用组合一种符号盖不住系统的全部侧面
按读者习惯组织17电话交换系统按「单方通话/双方通话/多方通话→主叫/被叫视角」分层读者找不到自己关心的那片
需求进数据库18编号、文本、来源、优先级、预期变更率、适用版本都存库;文档=数据库的导出变更时查不到影响面
同一概念同一名字19「有三类特殊命令。常规命令有四种类型」改成「有三类特殊命令。有四类常规命令」读者疑心「重述里藏了新信息」
每份文档配术语表和索引(索引:全书词目与其出现位置的对照表)20术语表定义里避免再用需查表的词读者被生词卡住;维护者找不到东西

3.8 验收这一仗的地面部队:评审

写完不等于写对。原则 45:需求基线(定稿封版、改动要走流程的那个版本点)确立前, 必须让用户、客户、市场、开发、测试、质量保证全都正式过一遍21。 自然语言评审没有自动化办法,靠人多眼杂;凡 3.5 节写了形式模型的部分, 不但可以人工核对,有的还能直接「执行」给相关方看(书里举了可执行需求语言 PAISLey)21

4. 作者的判断与证据

说法谁的证据
错误汇率 5×/10×/20×/200×作者引 Boehm1行业经验数据;书里未给样本构成
先自然语言、后形式模型作者本人(原则 55)8对照例证(拨号音两段),论证清晰
99.999% 无意义,须拆三口径作者引 Sommerville11概念澄清,非实测
空管 101 架飞机作者自设案例12思想实验;结论由「需求没写=怎么都行」推得
2021:MVP 环境下自然语言+跟踪工具就够作者 2021 自述22他自己的实践;且声明这正是原则 60 的精神

判断(我们的,不是书里的): 「自然语言为主、形式模型为辅」的配比,前提是需求的主要读者是人。 如果某天下游的主要读者变成了机器(比如直接消费需求的代码生成系统),形式化的配比就该反过来涨—— 因为机器不会「感觉」出歧义,它只会随机锁死一种读法。作者 2021 年自己还在用自然语言加跟踪工具22, 但他的下游是人。这条边界,读的人要按自己的下游重算。 如果错,会错在: 如果机器消费需求前仍要经过人的评审与拍板(现实里几乎总是),那自然语言就仍是主干, 形式化加码就还是锦上添花——本判断只在「人退出评审环节」这个前提下才成立。

5. 边界与局限

  • 形式化方法的现实使用率极低——作者自己招的。 1995 年要求每项目配一名熟手10; 2021 年承认 26 年里没有一个共事工程师真用过,虽然他们都会「以形式化方式思考」23。 本章教的「探误器」用法(3.5)正是低成本的折中,但要不要用,团队得自己赌。
  • 汇率表的倍数依赖流程。 5×~200× 出自瀑布式分阶段的世界;今天小步快跑、错误几天内就被测试逮住的团队, 实际倍数会小得多。但「越晚越贵」的单调关系不依赖流程成立。
  • 评审参与方越多越慢。 原则 45 列了六类相关方全过一遍21;书里没有讲怎么对付「评审会变成人肉慢放」, 这笔账要和 3.1 的汇率表对冲着算。
  • 工具更替。 「存进数据库」在 2021 年已是问题跟踪工具(Jira 之类)的默认能力22; 书里的字段(表格里一格一格的属性)清单(编号/文本/来源/优先级/预期变更率/适用版本) 仍然就是今天需求条目的字段清单。

6. 可带走的

  1. 需求错误按阶段升值:5×、10×、20×、200×——需求评审多花的一天,是全项目最便宜的保险;
  2. 每条需求给唯一编号,记下来源(日期/人/场合)——后续设计追溯、测试覆盖、变更谈判全靠它;
  3. 优先级必须写:M/D/O 或 0~10 分;「橙汁和生命维持系统」不在同一张必须清单里;
  4. 歧义战的打法是配合不是替换:先写自然语言,再试写形式模型,用模型反咬文字,修回文字;
  5. 先写模型的陷阱:回头写的「自然语言」只是模型的复述,读者一无所获;
  6. 「99.999% 可靠」必须拆成三口径之一(做对百分比/每年错几次/可用时间占比),不拆=授权下游各选各的;
  7. 每个环境限制旁写一句「越界时系统该怎么办」——需求没写,崩溃也算「正确」;
  8. 每条 TBD 带死线和责任人:「到何时、由谁解决」;
  9. 同一概念永远同一个名字;文档配术语表——这两条不为优雅,为可检查。

7. 原文地图

主题原书章原文位置
错误汇率 5×~200×第3章 需求工程原则text/15-ch03.txt:67(搜「200倍」)
需求编号三法第3章 需求工程原则text/15-ch03.txt:219(搜「R27」)
记录需求动机(两秒例)第3章 需求工程原则text/15-ch03.txt:87(搜「两秒」)
优先级(橙汁/MDO)第3章 需求工程原则text/15-ch03.txt:195(搜「橙汁」)
歧义三招(范根检查/形式模型/对开页)第3章 需求工程原则text/15-ch03.txt:235(搜「范根」)
自然语言辅助增强而非替换第3章 需求工程原则text/15-ch03.txt:253(搜「对开的页面」)
拨号音对照、先自然语言第3章 需求工程原则text/15-ch03.txt:219(搜「拨号音」) · text/15-ch03.txt:267(搜「四种状态」)
形式化方法的务实用法第2章 一般原则text/14-ch02.txt:275(搜「离散数学」) · text/14-ch02.txt:277(搜「某些部分」)
可靠性三口径第3章 需求工程原则text/15-ch03.txt:285(搜「99.999%」)
101 架飞机、四个选项第3章 需求工程原则text/15-ch03.txt:303(搜「101架」)
待定项自毁第3章 需求工程原则text/15-ch03.txt:319(搜「自毁」)
简洁(跟踪坐标例)第3章 需求工程原则text/15-ch03.txt:207(搜「跟踪坐标」)
需求里别做设计(警告注记)第3章 需求工程原则text/15-ch03.txt:131(搜「辅助理解」)
多视角(实体关系图/状态机/决策表)第3章 需求工程原则text/15-ch03.txt:141(搜「决策表」) · text/15-ch03.txt:151(搜「决策树」)
按读者组织(电话交换)第3章 需求工程原则text/15-ch03.txt:161(搜「电话交换」)
需求进数据库第3章 需求工程原则text/15-ch03.txt:329(搜「数据库」)
同名同义(特殊命令例)第2章 一般原则text/14-ch02.txt:349(搜「三类特殊命令」)
术语表第2章 一般原则text/14-ch02.txt:327(搜「沮丧」)
评审需求(可执行需求)第3章 需求工程原则text/15-ch03.txt:117(搜「正式的评审」) · text/15-ch03.txt:119(搜「PAISLey」)
2021:自然语言+跟踪工具作者序text/08-fm.txt:37(搜「优先级」)
2021:形式化方法没人真用过作者序text/08-fm.txt:33(搜「形式化方法」)

Footnotes

  1. 出处:「第3章 需求工程原则」第 67 段(text/15-ch03.txt:67,搜「200倍」)。四级倍数与「这是要在需求分析阶段修复错误的最令人信服的证据」同段;出处标注为 Boehm 1976。 2 3

  2. 出处:「第3章 需求工程原则」第 219 段(text/15-ch03.txt:219,搜「R27」)。三种编号法与「对设计中追踪需求和测试中追踪需求是必要的」同段;中文版译者注补充说具体手法可能过时,但「编号以便追踪」的思路不变。

  3. 出处:「第3章 需求工程原则」第 87 段(text/15-ch03.txt:87,搜「两秒」)。记录日期、时间、参与者与「只有基于这样的档案记录,才能扩展需求或对未满足做出响应」同段。

  4. 出处:「第3章 需求工程原则」第 195 段(text/15-ch03.txt:195,搜「橙汁」)。M/D/O 后缀法与 0~10 打分法同段。

  5. 出处:「第7章 管理原则」第 41 段(text/19-ch07.txt:41,搜「10%」)。

  6. 出处:「第3章 需求工程原则」第 219 段(text/15-ch03.txt:219,搜「拨号音」)。两段对照文字均为原文内容;「有限状态机」这个名字见第 161 段前的原则 53(text/15-ch03.txt:129,搜「有限状态机」)。

  7. 出处:「第3章 需求工程原则」第 231 段(text/15-ch03.txt:231,搜「减少歧义」)与「第2章 一般原则」第 277 段(text/14-ch02.txt:277,搜「某些部分」)。「尝试用更形式化的方式书写,会帮助你发现在自然语言中存在的问题」出自后者。

  8. 出处:「第3章 需求工程原则」第 267 段(text/15-ch03.txt:267,搜「四种状态」)。原文评价复述版「完全没给读者提供帮助」。 2

  9. 出处:「第3章 需求工程原则」第 253 段(text/15-ch03.txt:253,搜「对开的页面」)。

  10. 出处:「第2章 一般原则」第 275 段(text/14-ch02.txt:275,搜「离散数学」)。先用自然语言、再试写某些部分、完成后可以去掉形式描述、每项目至少一人熟练,均在此段。 2 3

  11. 出处:「第3章 需求工程原则」第 285 段(text/15-ch03.txt:285,搜「99.999%」)。三个口径的原文例句:「系统应正确报告99.999%的病人生命体征异常」「无法正确报告……每年不超过1次」「(至少)在99.999%的时间可用」。 2 3

  12. 出处:「第3章 需求工程原则」第 303 段(text/15-ch03.txt:303,搜「101架」)。四个选项与「前3个选项都是不可接受的……它们都是正确的系统响应」同段。 2

  13. 出处:「第3章 需求工程原则」第 319 段(text/15-ch03.txt:319,搜「自毁」)。样例注释原文:「开发经理将在1995年12月之前解决这个待定项」。

  14. 出处:「第3章 需求工程原则」第 207 段(text/15-ch03.txt:207,搜「跟踪坐标」)。

  15. 出处:「第3章 需求工程原则」第 131 段(text/15-ch03.txt:131,搜「辅助理解」)。

  16. 出处:「第3章 需求工程原则」第 141 段(text/15-ch03.txt:141,搜「决策表」)与第 151 段(text/15-ch03.txt:151,搜「决策树」)。

  17. 出处:「第3章 需求工程原则」第 161 段(text/15-ch03.txt:161,搜「电话交换」)。

  18. 出处:「第3章 需求工程原则」第 329 段(text/15-ch03.txt:329,搜「数据库」)。字段清单同段;理想状态是「需求规格说明本身就是整个数据库有组织的导出」。

  19. 出处:「第2章 一般原则」第 349 段(text/14-ch02.txt:349,搜「三类特殊命令」)。

  20. 出处:「第2章 一般原则」第 331 段(text/14-ch02.txt:331,搜「数据流图」)、第 333 段(text/14-ch02.txt:333,搜「索引」)。

  21. 出处:「第3章 需求工程原则」第 117 段(text/15-ch03.txt:117,搜「正式的评审」)。相关方清单、Boehm 评审指引、可执行需求 PAISLey(搜「PAISLey」)同段。 2 3

  22. 出处:「作者序」第 37 段(text/08-fm.txt:37,搜「优先级」)。2021 年作者创业环境:问题跟踪工具中以自然语言维护需求,带优先级、目标版本、状态、注解。 2 3

  23. 出处:「作者序」第 33 段(text/08-fm.txt:33,搜「形式化方法」)。