🛠️ 第11章 场景三:跨前后端功能开发
📄 一句话概括

一句话需求里有五个空洞:谁用、什么数据、边界、失败怎么办、怎么算完成。 可验证的唯一判据:能不能写成一个输入加一个期望输出。 带「健壮」「好」「顺畅」的小项都不算小项——形容词不能被判定。

📝 本章和前面几章的关系

上一章修 bug,这一章做功能。修 bug 的输入是错误,做功能的输入是一句话。 前者至少有现场,后者什么都没有。 为什么「拆解」这一步放在跨前后端这一章的最前面? 因为跨端的活一旦拆错,返工的不是一段代码,是一条链路——接口定义错了,前端后端都要重做。 Demo 拿一句十四个字的需求,先标出五个空洞,再拆成六条能验证的小项, 最后用三句「看起来像小项」的话说明判据。

一、一句话需求里的五个空洞

「给商品加个标签功能,能筛选。」 这句话不难懂,但它有五个关键决定是空着的。

空洞 具体在问什么 不定会怎样
谁用 运营打标签,还是用户自己打 权限和数据归属不清楚
什么数据 自由文本,还是固定词表 决定要不要建表
边界 一个商品最多几个标签 决定校验和索引
失败怎么办 重复、超长、空 决定错误码
怎么算完成 什么现象出现算做完 决定验收

五个空洞里,前四个是技术决定,第五个是验收决定。 技术决定错了可以改,验收决定空着,你连「做完了」都说不出口。 最常见的结局是「先这样吧」。 「先这样」听起来是妥协,其实是一个未定义的状态—— 它会在两个月后变成另一张需求单,而那张单子上的第一条正是当初跳过的空洞。

二、拆成可验证的小项

拆的目标不是「拆得细」,是「每条都能被判对错」。 判据只有一条:能不能写成一个输入加一个期望输出。 Demo 里六条小项,每条都带两列:「怎么验」和「该看到什么」。 比如「单个商品最多挂五个」——验法是挂第六个,该看到的是返回 400。 这两句话写出来,这条小项就没有解释空间了。

写着像小项的 为什么不算
标签功能要健壮 「健壮」不是一个能判定的状态
性能要好 没给数字,快慢都算好
体验要顺畅 没有可观察的现象

三句话里各有一个形容词:健壮、好、顺畅。 形容词不能被判定,这是它们唯一的问题。 把它们换成数,「性能要好」就变成「筛一千个商品两百毫秒内返回」,这时候它才能被验。 换的时候要小心一个坑:数不一定是时间。 「两百毫秒内返回」是数,「不超过五条错误日志」也是数,「重复提交两次结果一样」还是数。 可判定的形式有很多种,别只想到性能。

三、先写验收再写实现

顺序反了会怎样? 先写完实现,再去想「怎么验」,你会不自觉地按已经写出来的东西定标准——那不叫验收,叫追认。 先写验收的好处有两个,第二个更重要。 第一个:写验收的时候会发现需求里的空洞—— 你想写「挂第六个返回 400」,才发现没人说过上限是五。 第二个:验收标准可以直接变成测试。 Demo 里那六条「怎么验」,每一条都是一条测试的雏形——输入、期望输出、判定方式,三样齐了。 这意味着拆解和写测试是同一件事的两个说法,不是两件事。 所以跨端功能的正确顺序是: 先把验收写成六条,再定接口,再写前后端。 接口定义在验收之后,因为接口要能满足验收,而不是反过来。

四、动手 Demo:从一句话需求到六条可验证的小项

一句十四个字的需求,先标出五个空洞,再拆成六条带验证方式的小项。 最后用三句「看起来像小项」的话,说明可验证的判据。 这一篇没有代码跑——拆解是判断,不是计算。 但每条小项的「怎么验」都能直接变成一条测试,这一点在下一章会真跑起来。

ITEMS = [
    ("建 tags 表(id、name、唯一索引)", "插入同名两条", "第二条被拒"),
    ("商品与标签多对多关联表", "给商品挂两个标签", "查出来是两个"),
    ("单个商品最多挂 5 个", "挂第 6 个", "返回 400"),
    ("标签名 1~12 字,去首尾空格", "提交「  abc  」", "存成 abc"),
    ("按标签筛选商品", "筛「新品」", "只返回挂了这个标签的"),
    ("标签为空时不报错", "筛一个不存在的标签", "返回空列表,200"),
]

for i, (what, how, want) in enumerate(ITEMS, 1):
    print(i, what, "|", how, "|", want)

实跑输出:

--------------------------------------------------------------------
从一句话需求到六条可验证的小项
--------------------------------------------------------------------

  一句话需求里有五个空洞。不补,Agent 会替你补——而它补的往往不是你想要的。

  ① 原始需求,和它的五个空洞
  --------------------------------------------------------------------

  [需求原话]
  | 给商品加个标签功能,能筛选。
  十四个字,看着清楚,其实五个关键决定都空着。

| 空洞 | 具体在问什么 | 不定会怎样 |
|---|---|---|
| 谁用 | 运营打标签,还是用户自己打? | 权限和数据归属 |
| 什么数据 | 标签是自由文本,还是固定词表? | 决定了要不要建表 |
| 边界 | 一个商品最多几个标签? | 决定了校验和索引 |
| 失败怎么办 | 标签重复、超长、空,分别怎么处理? | 决定了错误码 |
| 怎么算完成 | 什么现象出现算这个需求做完了? | 决定了验收 |

  五个空洞里最容易被跳过的是第五个:怎么算完成。
  ! 没有验收标准的需求,做完了也说不清做没做对——最后变成「先这样吧」,
  而「先这样」会在两个月后再改一次。

  ② 补完之后,拆成六条可验证的小项
  --------------------------------------------------------------------
| # | 小项 | 怎么验 | 该看到什么 |
|---|---|---|---|
| 1 | 建 tags 表(id、name、唯一索引) | 插入同名两条 | 第二条被拒 |
| 2 | 商品与标签多对多关联表 | 给商品挂两个标签 | 查出来是两个 |
| 3 | 单个商品最多挂 5 个 | 挂第 6 个 | 返回 400 |
| 4 | 标签名 1~12 字,去首尾空格 | 提交「  abc  」 | 存成 abc |
| 5 | 按标签筛选商品 | 筛「新品」 | 只返回挂了这个标签的 |
| 6 | 标签为空时不报错 | 筛一个不存在的标签 | 返回空列表,200 |

  六条,每条都有「怎么验」和「该看到什么」。
  这是「可验证」的唯一判据:能不能写成一个输入加一个期望输出。

  ③ 可验证性的尺子
  --------------------------------------------------------------------
| 写着像小项的 | 为什么不算 |
|---|---|
| 标签功能要健壮 | 「健壮」不是一个能判定的状态 |
| 性能要好 | 没给数字,快慢都算好 |
| 体验要顺畅 | 没有可观察的现象 |

  三条的共同点:里面都有一个不能判定的形容词——健壮、好、顺畅。
  ! 把形容词换成一个数,「性能要好」就变成「筛一千个商品两百毫秒内返回」,这时候它才能被验。

  ④ 六条小项的真实成本
  --------------------------------------------------------------------
| 类型 | 条数 | 主要成本在哪 |
|---|---|---|
| 建表与索引 | 2 | 迁移脚本要能回滚 |
| 校验规则 | 2 | 边界值要逐个写测试 |
| 查询与筛选 | 2 | 索引和分页 |

  六条里两条是「改结构」,两条是「加约束」,两条是「加查询」。
  三类的工作方式完全不同,混在一起估工期一定估错。

六条小项里,第三、四、六条最值得看。 它们全是「边界」和「异常」——而这恰好是需求原话里完全没提的部分。 拆解的价值就在这里:它把「没提的部分」逼出来了。 你没拆之前不知道有这些,拆的时候每写一条「怎么验」,就暴露一个原本空着的地方。 第四行那条「提交『 abc 』存成 abc」,是最典型的例子。 不写这一条,前后端会各按各的理解处理空格—— 前端 trim 了,后端没 trim,然后查重的时候两条记录算两条。 这种 bug 不会报错,只会让数据慢慢脏掉。 最后一段那三句「要健壮」「要好」「要顺畅」是全篇的反面例子。 它们的共同点不是「写得不够细」,是「不能被判定」——你没法写出一条会失败的测试来验它。

30 秒实验

  1. 找一句你最近接到的需求原话,标出那五个空洞。 标不出来的那一个,就是你后来返工的原因。
  2. 把「性能要好」改成带数字的版本,看能不能写出来。 写不出来,说明你还不知道这个功能给谁用、用在什么场景。
  3. 给你的需求写六条验收,每条都要有「怎么验」和「该看到什么」。 写不满六条,说明这个需求还不够大,或者还没想清。

常见误区

  1. 「需求越模糊,实现越自由。」 自由的是你,遭殃的是联调。 跨端功能里,模糊的部分一定会变成两边理解不一致的地方。
  2. 「拆得越细越好。」 细不是目标,可判定才是。 拆到「改个变量名」这种粒度,除了增加清单长度没有别的用。
  3. 「先写完再想怎么验。」 那叫追认,不叫验收。 写验收的时候才会发现需求里的空洞——这一步不能倒过来。
自测三问(点开对答案) 1. 五个空洞里哪个最容易被跳过? —— **第五个:怎么算完成。** **前四个是技术决定,错了能改;这个空着,你连「做完了」都说不出口。** 2. 可验证的判据是什么? —— **能不能写成一个输入加一个期望输出。** **带形容词的都过不了这一关。** 3. 为什么验收要写在实现之前? —— **因为写完实现再定标准,你会按已经写出来的东西定,那是追认。** **而且写验收的过程会逼出需求里的空洞。**

下一篇把验收翻译成接口:契约先行,以及怎么判断一次变更是破坏性的。

相关笔记