| name | spec-driven-development |
| description | 在编码之前生成结构化的规格文档。当用户要求写 spec、设计功能、规划新项目,或需求模糊时使用(如"我想做一个X"、"帮我设计Y")。触发词:写spec、写规格、需求不清晰、新功能设计、帮我设计、技术方案、spec。 |
Spec-Driven Development
概述
生成结构化规格文档(spec)——定义构建什么、为什么、怎样算完成。不负责规划任务或写代码。spec 确认后交给 planning-and-task-breakdown。
核心原则
spec 结束时不应留下未决问题。 每一个模糊点要么从代码库找到答案,要么逐个向用户推荐默认方案并当场决策。
适用场景
- 启动新项目或新功能,尚未有书面 spec
- 需求模糊、不完整,或只是大概想法
- 即将做出重要的架构决策
- 多个协作者需要对齐"完成"的定义
不适用: 单行修复、需求已明确的改动。已有 spec 只需拆解任务——直接用 planning-and-task-breakdown。
Spec 生成流程
探索代码库 ──→ 逐个澄清 ──→ 撰写 ──→ 确认 & 保存
│ │ │ │
▼ ▼ ▼ ▼
能自己找到 每次只问 填充模板 人类审阅通过
的答案不问 一个问题 后保存到仓库
步骤 0:探索代码库(先于任何问题)
能从代码库推断的答案,绝不要问用户。 只在以下情况才提问:代码库没有答案、存在多种合理选择、或者选择不可逆且后果重大。
步骤 1:逐个澄清(一次只一个)
列出你认为确定的事实(从代码库推断出的结论),然后一次只问一个问题。
使用 ‘AskQuestion’ 工具进行提问
每个问题必须附带一个推荐方案——告诉用户你建议怎么做、为什么,让用户只需说是或否。
从代码库确认的事实:
- 技术栈:Spring Boot 2.x + MyBatis-Plus + MySQL(来自 pom.xml)
- 认证方案:Spring Security + JWT,session 无状态(来自 SecurityConfig.java)
- 前端:Vue 3 + Element Plus + TypeScript(来自 package.json)
需要确认的第 1 个问题:
推荐方案——数据模型用两张表:dict_type(类型)和 dict_item(字典项),
类型含 name/code/sort,项含 label/value/type_id/sort。
理由:与项目现有 Complaint 模块的两级结构一致,且支持按编码获取字典的公开 API。
→ 这样可以吗?
逐个推进。 等用户回答前一个问题,再问下一个。不要批量抛出。
当用户给出了你的推荐方案之外的回答,接受它——用户是领域专家。但当用户的回答与你从代码库观察到的事实矛盾时,指出来:"但代码中 User 表已有 phone 字段,不需要新增——用现有字段就行,对吗?"
步骤 2:撰写
每解决一个问题,就立即填入 spec 对应位置。不要等所有问题问完才动笔——边问边写。
Spec 覆盖六个核心领域:
- 目标 —— 构建什么、为什么、用户是谁、成功标准
- 命令 —— 完整可执行命令(
npm run build、npm test -- --coverage)
- 项目结构 —— 源码、测试、文档的目录布局
- 代码风格 —— 一个真实代码片段胜过三段文字。含命名规范和格式化规则,但要尽量简洁
- 测试策略 —— 框架、测试位置、覆盖率要求、各测试级别职责
- 边界 —— 三级约束:必须做 / 先问再做 / 绝不
Spec 模板:
# Spec: [项目/功能名称]
## 目标
[构建什么、为什么。用户故事或验收标准。]
## 技术栈
[框架、语言、关键依赖及版本]
## 命令
[构建、测试、lint、开发——完整命令]
## 项目结构
[目录布局及说明]
## 代码风格
[示例代码 + 关键约定]
## 测试策略
[框架、测试位置、覆盖率要求、测试级别]
## 边界
- 必须做: [...]
- 先问再做: [...]
- 绝不: [...]
## 成功标准
[如何判断完成——具体的、可测试的条件]
## 决策记录
[在澄清过程中做出的关键决策及理由。每条一句话。]
- 决策: 用两张表(dict_type + dict_item)而非单表——理由:支持按编码获取、避免 category 字段冗余
- 决策: 删除类型级联软删除其下字典项——理由:与项目 Complaint 模块的 complaint→complaint_reply 处理一致
注意:模板中没有"待澄清问题"章节。所有问题应在步骤 1 中逐个解决并记录到决策记录中。
将模糊描述转化为可测试的标准:
需求:"让仪表盘更快"
转化:
- 仪表盘 LCP < 2.5s(4G 网络)
- 初始数据加载 < 500ms
- 加载中无布局偏移(CLS < 0.1)
→ 这些目标是否正确?
步骤 3:确认 & 保存
将 spec 提交给人类审阅。确认:
保存到 docs/features/[功能名称]/spec.md。根据目标推导功能名称(如 "用户认证"、"支付集成")。保存前与用户确认路径。
保存后,明确告知用户: spec 已完成,下一步用 planning-and-task-breakdown 将 spec 拆解为可执行任务。
轻量级 Spec
对于小改动,写最小 spec:
# Spec: [功能名称]
## 目标
[一行——做什么、为什么]
## 成功标准
- [2-3 条可测试的条件]
## 边界
- [实施的约束条件]
6 行 spec 远胜于没有 spec。
后续步骤
| 技能 | 做什么 |
|---|
planning-and-task-breakdown | 将 spec 拆解为有依赖关系的可执行任务 |
incremental-implementation | 逐任务实现 |
test-driven-development | 用红-绿-重构验证每个任务 |
保持 Spec 存活
- 决策变更时更新 —— 数据模型要改?先更新 spec,再实施
- 范围变更时更新 —— 新增或砍掉的功能应反映在 spec 中
- 将 spec 纳入版本控制 —— spec 和代码一样属于仓库
- 在 PR 中引用 spec —— 关联每次 PR 对应的 spec 章节
常见借口
| 借口 | 真相 |
|---|
| "这个很简单,不需要 spec" | 简单任务仍需验收标准。两行 spec 就可以。 |
| "我先写代码,写完再补 spec" | 那是文档不是规格。spec 的价值在编码之前迫使你想清楚。 |
| "写 spec 太慢了" | 15 分钟写 spec 避免 15 小时返工。 |
| "需求反正会变" | 过时的 spec 仍比没有 spec 强。需求变了就更新它。 |
| "用户很清楚自己要什么" | 再清晰的需求也有隐含假设。spec 暴露这些假设。 |
红旗信号
| 症状 | 应对 |
|---|
| 没有书面需求就开始写代码 | 停。问:"什么叫'做完'?怎么验证?" |
| "直接开始做吧"而不先澄清 | 引导:"先花 5 分钟定一下成功标准。" |
| 做出架构决策却不记录 | 暂停,两句话写下决策和理由。 |
| 因为"很明显"而跳过 spec | 每个"明显"的任务至少藏着一个未说出口的假设。 |
| spec 结尾出现了"待澄清问题"列表 | 违反了核心原则——回到步骤 1,逐个解决。 |
应对抗拒
"这点改动写 spec 太麻烦了。"
→ 用轻量级 spec:目标(1 行)+ 成功标准(2-3 条)+ 边界。
"我知道要什么,直接做就行。"
→ "好的,我复述一下理解——30 秒。"写出 2-3 条成功标准。有不对的恰好证明 spec 的价值。
"我们边走边看吧。"
→ 只为第一个切片写 spec,做完再为下一个切片写。保持节奏,避免跑偏。