模板
spec 模板
以 intent 开头的需求与设计规格,含验收标准
亲历产品组织阶段 · 通用更新于 2026-10-16
spec 回答“做成什么样才算对”:以 intent 开头,接着是用户故事、可以直接写成测试的验收标准、设计决定、测试决定和不在范围内的事。放在 docs/specs/YYYY-MM-DD_<slug>.md,以仓库里的这份为准,Issue 里只贴链接。产品负责人确认之后才进入开发;一人公司里,确认人就是你自己。
模板
# <功能名>
- 状态:草稿 / 已确认(确认人,日期)
- Issue:#<编号>
- 计划:docs/plans/YYYY-MM-DD_<slug>-plan.md(确认后再写)
## 1. Intent
- 要做什么:
- 为什么:
- 约束:
- 不做什么:
- 成功指标:
## 2. 用户故事
1. 作为<角色>,我想<做什么>,以便<得到什么>
## 3. 验收标准
(每条都能直接写成一个测试;正常路径和异常路径都要有)
- 当<触发条件>时,系统应<响应>
- 如果<异常情况>,系统应<响应>
- 在<某个状态>期间,系统应<响应>
## 4. 设计决定
- 涉及的模块和接口:
- 数据结构变更:
- 关键决定:(难以逆转的,另写 ADR 并在这里链接)
## 5. 测试决定
- 在哪些接口边界上测:
- 参照仓库里已有的哪类测试:
## 6. 不在范围内
## 7. 开放问题示例:验收标准
接着 intent 模板里“给待办加标签”的例子:
## 3. 验收标准
- 当用户在待办详情里输入一个新标签并按回车时,系统应把标签加到这条待办上,并在 1 秒内显示在列表里
- 当用户点击列表里的某个标签时,系统应只显示带有这个标签的待办
- 如果一条待办已经有 10 个标签,系统应拒绝新增,并提示"每条待办最多 10 个标签"
- 如果标签名为空或只有空格,系统应拒绝保存
- 系统应把只有大小写不同的标签名视为同一个标签
- 在离线状态下,系统应禁用添加标签的输入框,并提示"联网后可添加"验收标准用 EARS 句式
业界做法 EARS(Easy Approach to Requirements Syntax)是 Alistair Mavin 等人在 Rolls-Royce 提出的需求写法(出处),用几种固定句式约束需求,让每一条都只有一种读法:
| 句式 | 写法 | 什么时候用 |
|---|---|---|
| 普遍 | 系统应…… | 任何时候都成立的要求 |
| 事件 | 当……时,系统应…… | 某个动作或事件触发 |
| 状态 | 在……期间,系统应…… | 只在某个状态下成立 |
| 异常 | 如果……,系统应…… | 错误输入、超限、失败 |
| 可选功能 | 在启用……的情况下,系统应…… | 只对部分配置成立 |
这种写法对 agent 特别友好:每一条都能一对一地变成一个测试,tdd 按条实现,审查时也能逐条对照。
每一节怎么填
| 节 | 怎么填 | 最容易犯的错 |
|---|---|---|
| Intent | 从 intent 原样搬过来,不要改写 | 进入设计后悄悄改了范围,却没回头改 intent |
| 用户故事 | 从用户视角写,一条一个能力 | 写成技术任务,比如“作为开发者,我想要一张表” |
| 验收标准 | 用 EARS 句式,每条都能写成测试 | 写“体验流畅”这种没法测的话;只写正常路径,漏掉“如果……”那几条。agent 实现时最常漏的就是 spec 隐含、却没写出来的异常输入 |
| 设计决定 | 写模块、接口、数据结构这些决定 | 写具体文件路径和代码片段,它们很快会过时,那是 plan 的事 |
| 测试决定 | 写在哪些接口边界上测,只测外部行为 | 不先约定测试边界,结果测了一堆实现细节,一重构就全红 |
| 不在范围内 | 明确列出这次不做的 | 省略,然后在审查时为“要不要顺手做”来回扯皮 |
| 开放问题 | 还没定的事,以及谁来定 | 带着开放问题就进入开发 |
怎么写出来
- 用
/mattpocock-skills:grill-with-docs把需求问清楚,它会顺手更新术语表和 ADR - 用
/mattpocock-skills:to-spec把对话整理成 spec。它默认发到 Issue,按迁移页的说明改成先写进docs/specs/ - 补上验收标准一节,逐条检查能不能写成测试
- 确认后把状态改成“已确认”,再进入 plan
to-spec 自带的结构是问题、方案、用户故事、实现决定、测试决定、不在范围内、补充说明。上面的模板在它的基础上多了 Intent 和验收标准两节,两者可以直接对应。