ARTICLE · 1132285
从沟通文档到工程契约:SDD 重塑 AI 辅助开发
从沟通文档到工程契约
SDD 重塑 AI 辅助开发
Spec-Driven Development · 四阶段流程 · 三文件体系
qztmy
📦 6 Parts + Conclusion
👉 滑动
PART 01
SDD 是什么
定义与反转
PART 02
为什么 SDD
问题与解法
PART 03
SDD 完整流程
四阶段+三文件
PART 04
Spec 怎么写
好坏对比+迭代
PART 05
SDD vs Vibe Coding
范式对比
PART 06
局限与陷阱
实战避坑
01
PART
SDD 是什么
WHAT IS SDD · 定义与反转
SDD(Spec-Driven Development)是一种以规格文档为核心的开发方法——先写 Spec,再让 AI 生成代码。
它和传统开发的根本区别在于:传统开发里代码是真值,Spec 只是给人看的沟通文档,写得糙点顶多影响沟通效率;SDD 里Spec 才是真值,代码是派生产物,Spec 写得好不好直接决定代码质量——因为现在写代码的是 AI,它只认 Spec。
02
PART
为什么 SDD
WHY SDD · 问题与解法
直接把需求丢给 AI 让它写代码,效果很不稳定——经常是代码写完后才发现,它一开始就没理解需求,整个推倒重来。
问题的根源在于:模糊的需求给了 AI 无限的解释空间,它按自己的理解填补了空白,而这些理解往往和你的真实意图不符。
在 AI 时代,人机分工的核心原则应该是:人定义 WHAT(做什么),AI 实现 HOW(怎么做)。SDD 的本质就是用结构化的 Spec 把 WHAT钉死,让 AI 在明确的边界内发挥。
03
PART
SDD 完整流程
FULL WORKFLOW · 四阶段+三文件
SDD 四阶段模型
Specify(规格定义)→ Plan(方案规划)→ Implement(代码实现)→ Validate(验证确认)
| 人 | ||
| AI | ||
spec.md / plan.md / tasks.md 每份需用户审批后进入下一阶段。验收报告不生成独立文件,直接基于 spec.md 的验收标准执行验证并报告结果。
三文件 + 项目宪法体系
GitHub 的 Spec Kit 简洁的三文件体系:
spec.md —— 需求规格
回答"背景"和"目标"、"功能需求"、"非功能需求"、"边界"、"验收标准",不涉及"怎么做"。
# CLI 工具添加 --version 参数 Spec
## 问题陈述
当前 mycli 命令没有 --version 参数,用户无法查看
当前安装的版本号,排查问题时不知道用的是哪个版本。
## 成功标准
- 执行 mycli --version 输出版本号并退出,退出码 0
- 版本号格式为 vMAJOR.MINOR.PATCH(如 v1.2.0)
- 版本号在构建时通过 ldflags 注入,源码中不硬编码
## 验收标准
- AC1:mycli --version 输出 vX.Y.Z 格式版本号并退出,退出码 0
- AC2:mycli -v 与 --version 行为一致
- AC3:版本号通过 go build -ldflags 注入,源码中无硬编码
- AC4:未注入版本号时输出 v0.0.0-dev
## 非目标
- 不做版本检查或自动更新
- 不输出构建时间、commit hash 等额外信息
## 约束
- 兼容现有 mycli 的参数解析方式(标准库 flag)
- 不引入新依赖
plan.md —— 架构方案
基于 spec.md 生成的技术方案,AI 起草、人审核。回答"怎么做"。
# CLI 工具添加 --version 参数 Plan
## 架构概览
在现有 mycli 主入口中注册 --version / -v flag,
解析后输出版本号并退出。版本号通过包级变量持有,
默认值 v0.0.0-dev,构建时由 ldflags 覆盖。
## 核心数据结构
### version 变量
- 类型:string
- 默认值:"v0.0.0-dev"
- 注入方式:go build -ldflags "-X main.version=v1.2.0"
## 技术决策
| 决策点 | 选择 | 理由 |
| 参数解析 | 标准库 flag | spec 约束"兼容现有方式" |
| 版本号注入 | ldflags -X main.version | spec 约束"源码不硬编码" |
| 短参数 -v | 复用 flag.Bool 注册同名 flag | spec 要求 -v 与 --version 一致 |
tasks.md —— 任务清单
将 plan 拆解为可执行的原子任务,每个任务可独立验证。
# CLI 工具添加 --version 参数 Tasks
## T1: 定义 version 变量并注册 flag
**文件:** main.go
**依赖:** 无
**步骤:**
1. 定义包级变量 var version = "v0.0.0-dev"
2. 在 main() 中注册 flag.Bool 处理 --version 和 -v
3. 解析后若为 true,输出 version 并 os.Exit(0)
**验证:** go build 编译通过;./mycli --version 输出 v0.0.0-dev
## T2: 验证 ldflags 注入
**依赖:** T1
**验证:** go build -ldflags "-X main.version=v1.2.0"
./mycli --version 输出 v1.2.0,./mycli -v 输出 v1.2.0
## 执行顺序
T1 → T2
constitution.md —— 不可变的项目原则
项目级别的「宪法」,定义所有 Spec 都必须遵守的不可违背约束,把团队技术决策固化为 AI 的「潜意识」。
# 项目宪法
## 技术栈
- 语言:Go 1.21+
- 模块管理:Go Modules
## 不可违背的约束
- 所有数据库查询必须使用参数化查询
- 敏感数据(密码、token、身份证号)禁止出现在日志中
- 所有公开 API 必须有单元测试
- 禁止引入新依赖,除非 constitution.md 中已登记
## 代码规范
- 遵循 Effective Go 和 Go Code Review Comments
- 错误处理必须显式判断,禁止忽略 error 返回值
- 包名使用小写单词,不使用下划线或驼峰
04
PART
Spec 怎么写
HOW TO WRITE · 好坏对比+迭代
好 Spec 的六要素
好 Spec vs 坏 Spec
坏 Spec:
mycli 需要支持 --version 参数,显示版本信息。
版本号要好看,用 cobra 库实现。
四个致命问题:
1. 模糊——"好看"是什么格式?
2. 遗漏边界——-v 短参数支持吗?
3. 缺乏理由——为什么要加?
4. 混入 HOW——"用 cobra"是实现方案
好 Spec:
## 问题陈述
当前 mycli 没有 --version 参数,用户无法
查看版本号,排查问题时不知道用的是哪个版本。
## 成功标准
- 执行 mycli --version 输出版本号并退出,退出码 0
- 版本号格式为 vMAJOR.MINOR.PATCH(如 v1.2.0)
- 版本号在构建时通过 ldflags 注入,源码中不硬编码
## 非目标
- 不做版本检查或自动更新
- 不输出构建时间、commit hash 等额外信息
差异的本质:好 Spec 是可测试的,坏 Spec 是可解释的。
粒度控制:一个实用的检验标准
Spec 的粒度很难拿捏。太粗,AI 会自作主张填补细节;太细,本质上就是在写伪代码。Spec Kit 提出了一个优雅的检验标准:
"用不同技术栈实现这个 Spec,Spec 是否仍然有效?"
❌ "使用 cobra 库注册 --version flag"
只对 cobra 方案有效,混入了 HOW
✓ "支持 --version 和 -v,输出版本号并退出,退出码 0"
无论用 cobra、标准库 flag 还是手写解析都成立
约束部分可以出现技术约束(如"兼容现有参数解析方式"),但那是"外部限制",不是"实现方案"。
实战经验:Spec 需要 3-5 轮迭代
第一版 Spec 通常问题百出。以 CLI --version 为例,第一版可能只写了:
## 成功标准
- 执行 mycli --version 输出版本号
让 AI 基于这版 Spec 起草 plan 时,问题立刻暴露:
• -v 短参数要不要支持?Spec 没说
• 版本号格式是什么?1.2.0 还是 v1.2.0?
• 未注入版本号时输出什么?
• 版本号从哪来?硬编码还是构建时注入?
修改 Spec 补全这些边界后,重新起草 plan,可能又发现新的盲点。这个「Spec → Plan → Review Spec → 修改 Spec → 重新 Plan」的循环通常要跑3-5 轮,直到 Spec 足够清晰。
这是把传统开发中"开发到一半发现需求有问题"的代价前移到了成本最低的阶段——改一行 Spec 的成本远低于改一百行代码。
附
APPENDIX
一个简单高效的 Spec Skill 完整版
SPEC-DRIVEN SKILL · 可直接复用
以下是自己使用的 spec-driven skill 完整版,可基于此生成自己的 spec skill。它定义了完整的四阶段流程、文件模板、自检清单和审批节点。
name: spec-driven
description: "SDD 规格驱动开发:将 Spec 作为唯一真实来源,人定义 WHAT,AI 实现 HOW。通过 constitution.md + spec.md → plan.md → tasks.md 文件体系,在 Specify → Plan → Implement → Validate 四阶段中驱动 AI 编程。在开始任何功能、模块开发前使用。"
---
# SDD 规格驱动开发
将 Spec 作为唯一真实来源,代码作为其派生产物。**先定义 WHAT,再让 AI 做 HOW。**
<HARD-GATE>
spec.md、plan.md、tasks.md 全部获得用户批准之前,禁止编写任何实现代码。无论项目看起来多简单,一律走完流程。
</HARD-GATE>
## 文件体系与流程
遵循三文件体系 + 项目宪法:
```
constitution.md(项目宪法,不可变约束)
+
spec.md(做什么)→ plan.md(怎么做)→ tasks.md(按什么顺序做)→ 代码 → 验收报告
```
| 阶段 | 主导者 | 产出 | 关键动作 |
|------|--------|------|---------|
| Specify | **人** | spec.md | 定义问题、边界、成功标准 |
| Plan | 人 + AI | plan.md | 架构选型、模块划分、接口定义 |
| Implement | **AI** | tasks.md + 代码 | 按 plan 逐任务实现 |
| Validate | 人 + AI | 验收报告 | 基于 spec.md 的 AC 验证 + 人工 Review |
spec.md / plan.md / tasks.md 每份需用户审批后进入下一阶段。验收报告不生成独立文件,直接基于 spec.md 的验收标准执行验证并报告结果。
---
## 阶段零:项目宪法 → constitution.md
在写 spec.md 前,先建立项目级「宪法」——所有 Spec 必须遵守的不可违背约束,把团队技术决策固化为 AI 的「潜意识」,避免每个 Spec
重复声明基本约束。
### constitution.md 模板
```markdown
# 项目宪法
## 技术栈
- 语言:Go 1.21+
- 模块管理:Go Modules
## 不可违背的约束
- 禁止引入新依赖,除非 constitution.md 中已登记
- 所有公开 API 必须有单元测试
- 错误处理必须显式判断,禁止忽略 error 返回值
## 代码规范
- ...
```
### 使用方式
- Specify 阶段开始前检查 constitution.md 是否存在,不存在则引导用户创建
- 生成 spec.md 时自动遵守其约束
- 自检阶段验证 spec.md 是否违反约束
---
## 阶段一:Specify → spec.md
**输入:** 用户的初步想法或粗略描述
**输出:** spec.md
**主导者:** 人
### 步骤
1. **了解上下文**:阅读现有代码、文档和提交记录,搞清楚当前状态和本次要做的新东西。
2. **澄清需求**:一次只问一个问题,能用选择题就不用开放题。关注问题陈述(为什么做)、成功标准(做到什么程度算完,必须可测试)、非目标(哪些不做)、约束(技术约束)。如果需求涉及多个独立子系统,先帮用户拆分。
3. **提出方案**:提出 2-3 种方案,说清优劣和推荐理由。推荐方案放第一个。
4. **分段呈现**:逐段呈现,每段确认后再展示下一段。
### spec.md 六要素
| 要素 | 作用 | 示例 |
|------|------|------|
| 问题陈述 | 定义「为什么做」 | "当前 mycli 没有 --version 参数,用户无法查看版本号" |
| 成功标准 | 定义「做到什么程度算完」 | "执行 mycli --version 输出版本号并退出,退出码 0" |
| 用户故事 | 定义「谁在什么场景下用」 | "作为用户,我可以执行 mycli --version 查看版本号" |
| 验收标准 | 定义「怎么验证」 | "mycli -v 与 --version 行为一致" |
| 非目标 | 定义「什么不做」 | "不做版本检查或自动更新" |
| 约束 | 定义「技术约束」 | "兼容现有参数解析方式(标准库 flag),不引入新依赖" |
### spec.md 模板
```markdown
# [标题] Spec
## 问题陈述
(要解决什么问题,当前已有什么)
## 成功标准
- ...(必须是可测试的,如 "P95 < 200ms" 而非 "系统应该很快")
## 用户故事
- 作为一个 [角色],我可以 [操作],以便 [目的]
## 验收标准
- AC1: ...
- AC2: ...
## 非目标
- ...
## 约束
- ...
```
### 好 Spec vs 坏 Spec
**坏 Spec:** `mycli 需要支持 --version 参数,显示版本信息。版本号要好看,用 cobra 库实现。`
——模糊(「好看」是什么格式?)、遗漏边界(`-v` 短参数支持吗?)、缺乏理由、混入 HOW。
**好 Spec:**
```
## 问题陈述
当前 mycli 没有 --version 参数,用户无法查看版本号,排查问题时不知道用的是哪个版本。
## 成功标准
- 执行 mycli --version 输出 vX.Y.Z 格式版本号并退出,退出码 0
## 非目标
- 不做版本检查或自动更新
## 约束
- 兼容现有参数解析方式(标准库 flag),不引入新依赖
```
**差异的本质:好 Spec 是可测试的,坏 Spec 是可解释的。**
### 粒度检验标准
> "用不同技术栈实现这个 Spec,Spec 是否仍然有效?"
- ❌「使用 cobra 库注册 --version flag」——只对 cobra 方案有效,混入了 HOW
- ✅「支持 --version 和 -v,输出版本号并退出,退出码 0」——无论底层用 cobra、标准库 flag 还是手写解析都成立
约束可出现技术约束(如「兼容现有参数解析方式(标准库 flag)」),但那是「外部限制」,不是「实现方案」。
### 写作规则
- **聚焦行为描述**——「支持 --version 参数,输出版本号并退出」——而非「注册 `flag.Bool("version", false, "show version")`」
- **保持语言无关**——同一份 spec 应该适用于 Go、Java 和 Python
- **方法名、类名、数据结构定义留给 plan.md**,具体文件路径留给 tasks.md
- **成功标准必须可测试**——「执行 mycli --version 退出码为 0」而非「mycli --version 应该正常工作」
- **每个小节写完整**,所有内容就绪后再提交审批
- **每条验收标准至少对应一条用户故事**
### 自检
1. **占位符扫描**——有没有 TBD、TODO、未完成的小节?有就补上。
2. **语言泄漏**——有没有方法名、类型定义或特定语言的术语?有就删掉。
3. **歧义检查**——有没有哪条需求可以被理解成两种意思?有就选一种,写明确。
4. **粒度检验**——换一个技术栈实现,这个 Spec 是否仍然有效?如果否,说明混入了 HOW。
5. **可测试性**——成功标准是否都是可测试的硬约束?
6. **验收覆盖**——每条用户故事是否都有对应的验收标准?
7. **宪法对齐**——spec.md 是否违反了 constitution.md 的约束?
### 用户审批
> spec.md 已生成。请 review:
> - 问题陈述是否清晰?成功标准是否可测试?
> - 非目标是否合理?验收标准是否可观测?
>
> 确认后进入方案规划阶段。
---
## 阶段二:Plan → plan.md
**输入:** 已批准的 spec.md
**输出:** plan.md
**主导者:** 人 + AI(AI 起草,人审核修改)
### 流程
1. 重新阅读已批准的 spec.md
2. 设计满足所有功能需求的架构
3. 定义核心数据结构和接口
4. 画出模块间的交互和数据流
5. 记录关键技术决策及其理由
6. **逐段呈现**,每段获得用户确认
### Spec-Plan 迭代
第一版 Spec 通常问题百出。让 AI 基于第一版 Spec 起草 plan 后回头审视 Spec,往往能暴露大量盲点。「Spec → Plan → Review Spec →
修改 Spec → 重新 Plan」的循环通常要跑 **3-5 轮**。改一行 Spec 的成本远低于改一百行代码。
### plan.md 模板
```markdown
# [标题] Plan
## 架构概览
(组件/模块划分,每个组件一段话)
## 核心数据结构
### [结构体名]
(字段定义及说明)
### [接口名]
(方法签名及用途)
## 模块设计
### [模块 A]
**职责:** ...
**对外接口:** ...
**依赖:** ...
## 模块交互
(调用链、数据流。哪个模块调哪个,什么顺序。)
## 文件组织
```
project/
├── internal/prompt/
│ ├── builder.go — Builder、Section 类型、BuildSystemPrompt
│ └── ...
└── ...
```
## 技术决策
| 决策点 | 选择 | 理由 |
|--------|------|------|
| ... | ... | ... |
```
### 写作规则
- **数据结构和方法签名在这一层定义**
- **说清架构如何满足 spec 的每条需求**
- **文件组织写到目录和文件级别**
- **技术决策同时写明选择和理由**
- **本文档与语言相关**——根据用户选择的语言来生成
### 自检
1. **spec 覆盖**——spec 的每条需求是否都在架构中有归属?列出缺口。
2. **接口完整性**——光看接口描述,能不能独立实现每个模块?
3. **依赖清晰度**——模块间的依赖是否明确且无环?
4. **矛盾检查**——有没有技术决策和 spec 需求冲突?
5. **宪法对齐**——架构是否遵守了 constitution.md 的约束?
### 用户审批
> plan.md 已生成。请 review:
> - 架构划分是否合理?核心接口定义是否完整?
> - 模块间交互是否清晰?技术决策是否认同?
>
> 确认后进入任务拆解阶段。
---
## 阶段三:Implement → tasks.md + 代码
**输入:** 已批准的 spec.md + plan.md
**输出:** tasks.md + 代码 + 测试
**主导者:** AI
### 流程
1. 重新阅读 spec.md 和 plan.md
2. 列出文件清单——要创建、修改、测试哪些文件
3. 把 plan.md 的组件拆成有序任务
4. 每个任务是**一个聚焦的工作单元**,2-5 分钟可完成
5. 每个任务带有明确的验证方式
6. 呈现 tasks.md 给用户审批后,按任务实现代码
### tasks.md 模板
````markdown
# [标题] Tasks
## 文件清单
| 操作 | 文件 | 职责 |
|------|------|------|
| 新建 | `internal/prompt/builder.go` | Builder、Section 类型、主入口 |
| 修改 | `internal/tui/tui.go` | 接入 BuildSystemPrompt |
## T1: [任务名]
**文件:** `path/to/file`
**依赖:** 无
**步骤:**
1. 定义 Section 结构体,包含 Name、Priority、Content 字段
2. 定义 Builder 结构体,实现 Add 和 Build 方法
**验证:** `go build ./internal/prompt/...` 编译通过
## 执行顺序
```
T1 → T2 → T3
↘
T4(可并行)→ T5 → T6
```
````
### 写作规则
- **文件路径可以写**——这是实现层,需要具体
- **每个任务必须有「验证」部分**——「运行 X,期望看到 Y」
- **每个任务自包含**,写清楚完整细节(执行者可能不按顺序读)
- **依赖关系必须明确**——如果 T3 依赖 T1,写出来
- **粒度 2-5 分钟**——超过就拆更小
### 自检
1. **plan 覆盖**——plan.md 的每个组件是否至少有一个任务?
2. **占位符扫描**——有没有模糊的步骤或「类似 TX」的引用?
3. **依赖链**——是否存在合法的执行顺序,没有循环依赖?
4. **验证完整性**——每个任务是否都有具体的验证步骤?
5. **类型一致性**——函数名/类型名和 plan.md 定义的是否一致?
### 用户审批
> tasks.md 已生成,共 N 个任务。请 review:
> - 任务粒度是否合适?依赖关系是否正确?
> - 有没有遗漏的实现步骤?
>
> 确认后开始实现。
### 实现
tasks.md 通过审批后,AI 按任务实现代码:
1. 读 tasks.md,为所有任务创建进度追踪
2. 按执行顺序逐个完成任务:按步骤执行 → 运行验证步骤 → **先有证据再下结论**(先跑命令、看输出,再报状态)→ 验证通过后才标记完成
3. 如果被阻塞:停下来问,不要猜
4. 所有任务完成后进入 Validate 阶段
**规则:**
- 按 tasks.md 的步骤执行,除非被阻塞否则不自由发挥
- 每个任务完成后必须跑验证,「应该没问题」不算证据
- 验证不通过就先修,修好再往下走
- 每个任务或每组逻辑相关的任务完成后提交代码
---
## 阶段四:Validate → 验收报告
**输入:** spec.md + plan.md + tasks.md + 实现代码
**输出:** 验收报告(不生成独立文件,直接基于 spec.md 的验收标准执行验证并报告结果)
**主导者:** 人 + AI
### 流程
1. 读 spec.md 的验收标准——每条对应一个验证项
2. 读 spec.md 的成功标准——每条对应一个性能/指标验证
3. 补充编译/测试/lint 检查
4. 至少一个端到端场景(覆盖完整用户流程)
5. 逐项执行验证,记录证据
### 验证项来源
| 来源 | 验证什么 | 怎么验证 |
|------|---------|---------|
| spec.md 的验收标准 | 功能是否实现 | 按 AC 描述运行/观察 |
| spec.md 的成功标准 | 指标是否达标 | 跑性能测试/统计 |
| plan.md 的模块交互 | 集成是否正确 | 集成测试 |
| tasks.md 的任务验证 | 任务级验证 | 跑各任务的验证命令 |
| constitution.md 的约束 | 约束是否遵守 | 静态检查/Review |
### 规则
- **先有证据再下结论。** 先跑命令,看输出,然后再报告。
- 报告**实际结果**,不是预期结果。
- **Spec 替代的是需求文档,不是 Code Review。** 即使有 Spec,AI 代码仍需要严格的 Review。
- 有不通过的条目不丢人——修好重跑即可。
### 验收报告
```
## 验收报告
### 通过(N/M)
- [x] AC1 — 证据:...
- [x] 成功标准 "P95 < 200ms" — 证据:压测结果 P95=150ms
### 未通过(如有)
- [ ] AC3 — 预期:X,实际:Y,修复方案:...
### 端到端
- [x] 场景 1 — 结果:...
```
---
## 危险信号
出现以下想法时,停下来——你在为跳过流程找理由:
| 想法 | 现实 |
|------|------|
| 「这个太简单了,不需要写 spec」 | 越简单的项目,未被审视的假设越多 |
| 「我直接写代码就行」 | HARD GATE:spec.md 通过了才能动代码 |
| 「spec 太明显了,直接跳到 plan」 | 「明显」意味着没被验证过,写出来让用户确认 |
| 「验证等做完了再补」 | spec.md 的验收标准就是验证依据,实现前就应明确 |
| 「测试过了就说明没问题」 | 测试验证代码,验收标准验证需求 |
| 「有了 Spec 就不用 Review 了」 | Spec 替代的是需求文档,不是 Code Review |
## 核心原则
- **Spec 是唯一真实来源**——代码是派生产物
- **人定义 WHAT,AI 实现 HOW**
- **一次一个问题**,优先用选择题
- **逐段审批**,每段确认后再继续
- **成功标准必须可测试**
- **YAGNI 铁律**——只设计和实现 spec 提到的内容
- **先有证据再下结论**——先跑验证,再报告结果
- **Spec 是活的**——随时可以增量更新,和代码变更同步
05
PART
SDD vs Vibe Coding
PARADIGM COMPARE · 范式对比
什么是 Vibe Coding
2025 年初,Andrej Karpathy 提出 Vibe Coding 概念,核心理念是:用自然语言描述需求,让 AI 全权负责编码,开发者不需要读代码、理解代码,报错了直接丢给 AI 修。
这种方式在原型验证、个人脚本、一次性数据处理等场景下确实快——几小时就能跑起一个应用。但快不等于可持续。
为什么 Vibe Coding 走不远
根本原因是上下文会丢失。LLM 在长对话中容易偏离最初意图,越往后越依赖"脑补"填补空白。项目简单时偏差可控,项目复杂后小偏差会滚成大问题。
几百行代码时 AI 还能看全貌,几万行时就只能基于局部做决策——而这些决策往往和其他模块冲突。
SDD 怎么补上这个缺口
Spec 是代码的压缩表示。10 万行代码的项目,Spec 可能只有几千行。AI 读完 Spec 就能掌握全局约束,不用靠脑补,改动前就知道边界在哪。
核心差异
个人最佳实践
Vibe Coding 和 SDD 不是对立的,而是适用于不同阶段。我的做法是分阶段切换:
1. 探索期用 Vibe Coding——快速试错,验证想法是否成立
2. 决定要做后立刻补 Spec——把探索中得到的认知固化成规格
3. 正式开发严格 SDD——所有变更先改 Spec,再改代码
探索和规格化是前后衔接的两步,不是非此即彼。
06
PART
局限与陷阱
PITFALLS · 实战避坑
SDD 不是银弹。下面这些局限和陷阱,都是实战中真实踩过的坑。
文档爆炸
情形:每个功能都走三件套,几十个功能文档堆了几百份。
结果:改一个接口要同步改三份文件,漏改就脱节。
缓解:按模块组织——一个模块一份 Spec,子功能用章节区分。做完的模块归档。
大项目的 Spec 膨胀
情形:Spec 膨胀到几千行,AI 读完上下文也快满了。
结果:Spec 本身成了上下文负担,这是 SDD 最难突破的天花板。
缓解:分层 Spec——项目级 constitution.md 定义全局约束,模块级 Spec 只描述本模块。
粒度过细
情形:Spec 写得比代码还长,连变量命名都要规定。
结果:退化成"用自然语言写伪代码",分工优势荡然无存。
缓解:拿粒度标准检查——"换一个技术栈,这个 Spec 还成立吗?"
规格落后
情形:代码迭代了十几个版本,Spec 还停在 V1。
结果:AI 拿过时 Spec 做增量开发,越改越乱。
缓解:Spec 不是一次性产物。需求变了、发现 BUG 了,同步更新 Spec。
规格形式主义化
情形:改个颜色也走全流程。
结果:开发人员嫌烦,绕过流程直接改代码,SDD 名存实亡。
缓解:判断标准:这个改动可能影响其他模块吗?会,走 Spec;不会,直接改。
虚假信心
情形:有了详细 Spec,放松对 AI 代码的审查。
结果:Spec 只定义"做什么",不保证实现是对的、安全的。
缓解:Spec 替代需求文档,Code Review 和 Validate 不能省。
工具复杂性
情形:引入 Spec Kit + Claude Code + CI/CD + 校验脚本 + Linter……
结果:配工具的时间比写 Spec 还长,本末倒置。
缓解:从最简方案开始:一个 spec.md + 一个 AI Agent。
Spec 是代码的压缩表示
人定义 WHAT,AI 实现 HOW
END · qztmy