软件规格文档中的 10 个常见错误

10 Common Mistakes in Software Specifications
Daniel Marsh · Spec-First 工程笔记

我评审过的每一个失败项目都有 spec。问题是 spec 里没写真正重要的那些事。下面这十个错误在我评审过的 spec 里反复出现——我自己写的也不例外。它们都不难修,但在截止日期的压力下,每一个都容易被漏掉。

发布于 2026-02-25 · ✓ 已更新 2026-05-11 · 阅读约 7 分钟 · 作者:Spec Coding 编辑团队 · 审校政策:编辑政策

1. 只描述功能,不描述决策

功能描述告诉读者系统会做什么。而决策告诉读者的是:系统会做这个,而不是别的什么。"用户可以通过邮箱重置密码"描述的是功能。"用户通过邮箱重置密码——不用短信、不用安全问题、也不用 magic link——因为邮箱是我们对未认证用户唯一已验证的联系渠道"描述的是决策。

如果你的 spec 只是功能的一遍走马观花,没有任何"因为",那你写的就不是 spec,而是宣传册。决策是歧义真正藏身的地方,要把它们摆到台面上来。

2. 本该写数字的地方写了形容词

"快"、"可靠"、"合理"、"性能可接受"——这些词在不同读者眼里永远意味着不同的东西。只要 spec 里描述系统行为的形容词还没被换成一个带单位的数字,这份 spec 就不该发出去。

3. 缺失非目标

我见过的每一个延期交付的项目,要么根本没有非目标,要么只有几句不承诺任何东西的套话。非目标能在实现阶段挡住范围蔓延。如果 spec 里只有目标那一节,却没有非目标那一节,那就是最先该补的东西。

每个中等规模的功能,目标是明确列出 3–6 条非目标。每一条都附带一个理由——推迟、否决,或者不在范围内。

4. 不是标准的验收标准

"用户应该能够看到自己的订单历史"是一个功能诉求,不是 AC。QA 没法测"应该能够"。他们需要的是:输入、触发条件、以及具体可观测的输出。

给自己做个测试:把"应该"这个词去掉,这句话还通顺吗?如果通顺,那它多半是一条可测试的主张。如果不通顺,说明你还有活要干。

5. 跳过了失败路径

每一条走得通的 happy path AC,都至少对应三条需要写下来的失败路径:校验失败、授权失败、下游依赖失败。只覆盖 happy path 的 spec,就是你错误处理最后沦为一串生产环境才发现的 500 的根本原因。

对每一条 AC,问一问:这一步失败时用户会看到什么?如果答案是"我不知道",那这份 spec 就还没写完。

6. 范围归属含糊

"团队会决定"不是归属——那是一个被推迟的争论。每一个范围问题都需要一个具名的人,这个人能说 yes 或 no,而不是一个"大家讨论一下"的小组。当功能在实现中途膨胀时(它一定会),你需要知道谁有权力说"不,这个里程碑不做"。

一个人。写在 spec 里。哪怕这个人就是你自己。

7. 把实现细节伪装成需求

"系统使用 Redis 存储会话"是实现细节。除非 Redis 本身是用户可观测的行为(并不是),否则它不该出现在 spec 里。spec 应该描述可观测的行为:会话在刷新后仍然保持、会话在 30 分钟不活动后过期、会话在服务器重启后仍然存在。

至于底层是 Redis、Postgres 还是内存缓存,那是工程团队的判断。把它写进 spec 只会约束团队,却没有给评审者增加任何清晰度。

8. 把发布计划当作事后补充

这种情况我几乎每周都能见到。一份五页的 spec,AC 写得很详尽,然后底下就一行字:"Rollout:feature flag"。凌晨两点出事的时候,这一行字对任何人都没什么用。

一个发布章节至少要有:具名阶段和明确的门禁、数值化的止损阈值、以及按类型描述的回滚机制(flag 翻转 vs. 代码回退 vs. 迁移回滚)。每一项都只要几分钟就能写完,却能在事故时替你省下几小时。

9. 没有并发方案

如果两个用户可能同时操作同一条记录,那无论 spec 承不承认,你都已经有了并发问题。我评审过的大部分 spec 完全跳过了并发。结果就是实现阶段悄悄地挑了一种策略——通常是 last-write-wins 而且不给用户任何提示——然后第一个真正的竞态条件以客户投诉的形式浮出水面。

把并发规则明确写出来。"Last-write-wins,不显示冲突提示"是一个合法的选择。"乐观并发,冲突时返回 409"也是。唯一不合法的,是把这件事留给实现去凭空发明。

10. 当过去不存在的 spec

新功能的 spec 常常把功能描述得好像是在真空里上线。实际上,大多数功能都要和已有流程、已有数据、已有的用户预期打交道。spec 需要一个章节——哪怕只是一段——说清楚这次变更相对于现状改了什么。

那些"只是加一点东西"的功能,仍然要回答这些问题。"只是"两个字,往往就是生产环境意外最爱藏身的地方。

这些错误的共同点

注意这个规律:每一个错误都是 spec 把某个决策留给了以后。不是"决策做错了"——而是"决策没做"。spec-first 这套纪律不是要你一次就把事情想对,而是不要把决策推给实现阶段,那里改起来代价最贵。

我评审自己的 spec 时,就是扫这十件事。不是因为别的错误不会犯,而是因为这十个是我自己反复在犯的。你自己的那一份清单可能不一样。找到属于你自己的那十个,才是真正的功夫。

评审时看什么

这篇文章适合用在清理一份看似完整但藏着缺口的规格时。别从“原则”聊起,直接拿一条真实改动来对照,看看规格里还缺什么。

这篇文章适合直接当审稿清单用。扫完后应该得到几处具体修改,而不是一句“文档还需要更清楚”。

例子:“管理员可以管理用户”至少藏着四个决策:哪些角色算管理员、哪些用户状态允许编辑、审计日志写什么、目标用户被锁定时怎么处理。评审时先拆这些词。

落地例子

“用户可以邀请队友”这句话要拆开看:谁有邀请权限,访客算不算队友,重复邀请如何处理,链接多久过期,被禁用域名是否拦截,审计日志写什么。它们听起来像细枝末节,但上线后安全例外、客服工单和权限争议大多就出在这里。

所以评审规格时,不要满足于句子顺畅。看到“管理”“支持”“处理”这类词,先问它具体落到哪个状态、哪条记录、哪种错误路径。

一个简单的自查口径

如果一份 spec 读完后,开发、QA 和产品各自能讲出三个不同版本,那它还没写完。我会用下面这张小表做最后检查,特别适合抓住看起来完整但其实很空的文档。

Spec self-check:
- Goal: can be explained in one sentence
- Non-goals: name specific excluded work
- Acceptance criteria: each maps to a test
- Failure paths: include timeout, permission, validation, duplicate request
- Data contract: fields, states, and events are named
- Rollback: owner and trigger are explicit

边界:不要为了通过清单而把 spec 写成长文。清单是找洞的,不是逼你堆段落。

把常见错误变成 review 评论

发现“目标含糊”时,不要只说“写清楚”。直接要求作者补用户、行为、输出和证据。发现“没有失败路径”时,让他补 timeout、权限、重复请求和回滚。评论越具体,spec 修改越快。

如果团队已经有模板,可以把这张自查表变成 PR bot 评论:缺非目标、缺回滚、缺 API 字段、缺测试证据时自动提醒。自动提醒不替代 review,但能减少最无聊的一轮来回。

可复制产物:规格写作片段

当工单看似清楚但还缺验收语言时使用。它要求作者写出角色、触发、结果和证据。

规格写作评审片段:软件规格文档中的 10 个常见错误

本次要做的决策:
- 把模糊需求改写成可以由工程和 QA 共同判断的验收条款。

责任人检查:
- 产品责任人:
- 工程责任人:
- QA 或运维评审:

范围边界:
- 本次包含:
- 本次不包含:
- 仍需确认的假设:

验收证据:
- 测试或 fixture:
- 日志、指标或截图:
- 人工复核步骤:

写作边界:避免模糊动词,每条验收标准都要有可见的通过或失败信号。

评审追问:
- 没参加需求会的人还会误解哪里?
- 哪个证据能证明这次改动足够安全,可以发布?

编辑复核记录

复核日期:2026-04-28。本次补充了可复用产物,按相关主题 Hub 检查了文章定位,并收紧下一步链接,让页面更像可操作参考,而不是孤立长文。

评审改写示例:把一段空话改成工程产物

下面这种改写,能让规格从“会议纪要”变成真正可以评审、联调和验收的工程文档。

修改前:
新的导出流程应该快速、稳定、易用。出问题时要通知用户。

修改后:
50k 行以内的 CSV 导出必须在 2 秒内开始。
超过 50k 行进入异步任务,并展示 job_id。
任务失败时,用户看到 failed 状态、retry 操作和 last_error_code。
QA 未验证 timeout、retry、重复请求、permission denied 前,不允许发布。

第二版写清了数字、状态、错误和发布证据。它仍然容易读,但不再把决策藏进形容词里。

关键词:spec 错误 · 常见错误 · 规格撰写 · 技术规格 · 软件需求

专题阅读路径

这篇文章归入 Spec-First 开发 主题。先读 Hub,再结合下面的清单、模板或工具落到具体项目里。

交互式生成规格
填写表单,生成完整的功能规格 Markdown——免费使用,无需注册。
试用规格生成器

编辑说明

最近复核:2026-04-28。编辑部检查了示例、内链和可复制评审片段,确保内容更适合真实项目使用。

本文面向软件交付团队,介绍软件规格文档中的 10 个常见错误。示例均为工程场景说明,不构成法律、税务或投资建议。