[SDD 方法论]系统化实践指南
Version: v1.0 | Last Updated: 2026-06-27
本文档定义 SDD(规约驱动开发,Spec-Driven Development)的通用方法论。
目标读者:AI Agent(如 Claude Code)和人类开发者。
本文档可直接拷贝到任何采用 SDD 方法论的新工程中使用。
- [SDD 方法论]系统化实践指南
- [DataFlow-CV v1.5.0] SDD 实践与思考
- [DataFlow-CV v0.6.2] Vibe Coding 实践与思考
- [译] Specification-Driven Development (SDD)
- [译] Spec-driven development with AI: Get started with a new open source toolkit
一、核心理念
1 | Specs(什么是对的)→ 开发上下文(代码怎么写)→ 制定计划 → 代码实现 |
SDD 的三层体系:
| 层级 | 角色 | 修改频率 |
|---|---|---|
| Specs | 行为契约——定义”什么是对的” | 很少(需求变更时才改) |
| 开发上下文 | 架构知识——描述”代码怎么写的” | 随代码演进 |
| Code | 实现——实际运行的代码 | 日常 |
铁律:
- Specs 是最高权威。如果代码行为与 specs 冲突,以 specs 为准,改代码。
- Specs 是活文档。需求变更或 specs 不充分时,优先更新 specs,再动手。
二、开发工作流
2.1 接到新任务时
第一步:确定影响范围
问自己三个问题:
- 改动涉及哪个模块?
- 涉及哪个外部接口/格式?
- 是否跨模块?(跨模块改动风险最高,需特别小心)
第二步:读 spec,评估充分性
⚠️ Specs 是活文档。 读 spec 时带着批判眼光:
- Specs 是否覆盖了当前场景?定义是否清晰无歧义?
- Specs 的行为定义是否合理、内部是否一致?
- 如果不充分或不合理 → 优先更新 specs,再往下走。 不在不稳固的基础上盖楼。
Code ≠ Spec 处置流程: 当发现代码行为不在 spec 覆盖范围内:
- 判断当前行为是否合理
- 合理 → 补 spec 使之成为正式契约,代码不动
- 不合理 → 按 spec 精神修正代码(此时 spec 虽未明确但精神可循),同步补 spec
关键原则:永远不让”spec 没写”成为行为模糊的借口。没写就是缺失,缺失就要补。
第三步:对照开发上下文文档
读开发上下文文档(如 CLAUDE.md)的相关章节,重点关注:
- Known Gotchas(常见陷阱汇总)
- Critical Implementation Details(关键实现细节)
第四步:制定开发计划
读完 specs(知道”什么是对的”)和开发上下文文档(知道”代码怎么写的”)之后,显式制定开发计划再写代码:
- 列出涉及的所有文件:哪些需要创建、修改、删除
- 确定改动顺序:按依赖关系排定先后(先改基础接口,再改上层调用)
- 识别风险点:可能影响哪些现有功能?哪个环节最容易出错?
- 复杂任务先规划:跨模块改动或新增能力时,先出完整方案再动手
先计划,再实现——避免在实现中途发现架构冲突、推倒重来。
2.2 提交前
- 跑测试(必须通过)
- 格式检查(lint / format)
- 测试与 spec 的关系:测试是 spec 的可执行验证。每个 spec 定义的行为契约都应该有对应的测试用例覆盖。如果 spec 改了而测试没改,说明 spec 更新不完整——改 spec 的同时必须更新或新增测试。反之,如果一个行为已有测试但没有 spec 覆盖,应将行为补入 spec(或标记为实现细节,不需要契约化)。
- 文档同步检查(每次改动必做):
| 优先级 | 文档 | 检查条件 | 操作 |
|---|---|---|---|
| P0 | Specs | 行为发生变化(接口、契约、数据流) | 必须同步更新 |
| P1 | 开发上下文文档 | 新增架构细节、新陷阱、新硬约束、新关键实现 | 同步更新 |
| P1 | README | API 变化、新增功能入口、安装步骤变化 | 同步更新用户文档 |
| P2 | 示例代码 | 用户 API 变化、调用方式变化 | 更新示例 |
Git commit 格式(Conventional Commits):
1 | <type>(<scope>): <subject> |
类型:feat / fix / docs / refactor / test / style / chore / perf / build / ci
三、代码审查检查清单(通用)
每次改动后自查:
- 架构硬约束未被违反(模块间依赖规则、分层约束)
- 新增函数/类有对应的测试
- 测试全部通过
- 行为变化已同步更新 specs(P0)
- 新增架构细节/陷阱已同步更新开发上下文文档(P1)
- API / 功能入口变化已同步更新 README(P1)
- 用户接口变化已同步更新示例代码(P2)
四、Specs 目录结构
4.1 核心原则:WHAT 与 HOW 分离
Specs 目录按两层组织——WHAT(外部契约)和 HOW(内部架构)。这是 SDD 最重要的结构设计。
1 | specs/ |
WHAT 层的命名取决于项目领域:
| 项目类型 | 建议命名 | 示例内容 |
|---|---|---|
| 数据处理/格式转换 | formats/ |
数据格式定义、转换规则 |
| Web API | api/ |
REST/GraphQL 接口契约 |
| 库/SDK | interfaces/ |
公开 API 签名、类型定义 |
| 评估/评测 | evaluate/ |
指标定义、基准线 |
| 协议/通信 | protocols/ |
消息格式、状态机 |
WHAT 层可以有多个(如 formats/ + evaluate/),每个定义一类外部契约。HOW 层只有一个 modules/,与代码模块一一对应。
4.2 每层 index.md 模板
每个 spec 子目录都需要一个 index.md 作为入口。推荐结构:
1 | # <Layer Name> — Specification Index |
4.3 WHERE 原则
每个 spec 文件只回答一个问题:
| 文件类型 | 回答的问题 |
|---|---|
| 数据格式/协议 spec | 这个外部契约长什么样?定义了什么必填字段? |
| 转换/适配 spec | A 怎么变成 B?边界条件怎么处理? |
| 模块 spec | 这个模块的公开接口和行为契约是什么? |
如果一个 spec 文件同时回答了”数据长什么样”和”代码怎么实现”,就应该拆开。
4.4 Spec 版本管理
Specs 是活文档,需要版本追踪来回答”这份 spec 是什么时候改的、为什么改”。
最低要求:
- 每个 spec 文件开头标注版本号和最后更新日期
- 行为变化时同步更新版本号
- 版本号与 CHANGELOG 条目双向引用(commit 写 “docs(spec): …”,CHANGELOG 记 spec 变更)
推荐格式:
1 | # Spec: <Title> |
版本号策略:
| 场景 | 版本变化 |
|---|---|
| 新增定义/扩展现有契约 | 小版本递增(v1.0 → v1.1) |
| 行为变更(breaking change) | 主版本递增(v1.2 → v2.0) |
| 澄清/措辞修正(不改变行为) | 加日期、不改版本号 |
五、开发上下文文档模板
5.1 概述
开发上下文文档(如 CLAUDE.md)是 SDD 三层体系的中间层——连接 specs(什么是对的)和代码(具体实现)。它的读者是 AI Agent 和开发者,目的是降低上手成本、防止踩坑。
5.2 推荐结构
1 | # CLAUDE.md (或 CONTRIBUTING.md / DEVELOPER_GUIDE.md) |
5.3 编写原则
| 原则 | 说明 |
|---|---|
| 时效性 | 随代码演进同步更新,不是一次写完就不管 |
| 具体性 | 写”连接超时设为 30s”而非”合理设置超时”;写”密码必须 bcrypt 哈希后存储”而非”安全存储密码” |
| 可验证 | 每条 Critical Detail 应该能对应到一条测试或用例 |
| 分层清晰 | 本文档描述”怎么做”,不重复 specs 的”是什么” |
| 长度控制 | 目标 200-400 行。超过 400 行考虑是否有内容应该下沉到 spec 或上升为通用文档 |
六、Known Gotchas 编写规范
6.1 为什么需要
Known Gotchas 是开发上下文文档中投入产出比最高的部分——一行警告可以节省数小时的调试时间。它记录的是理论上不该出错、实际上反复有人踩的陷阱。
6.2 条目格式
1 | 序号. **问题关键词**:现象 + 正确做法。具体细节。 |
6.3 条目来源
| 来源 | 触发条件 |
|---|---|
| Bug 修复 | 每次修 bug 后检查:这条是否可预防?是 → 新增 Gotcha |
| 新人上手 | 新人遇到的每个阻碍都是潜在的 Gotcha |
| 代码审查 | 审查中反复指出的问题类型 |
| 架构决策 | 违反后果严重的架构约束 |
6.4 维护规范
- 按踩坑频率排序,最常见的排最前面
- 每条 Gotcha 与相关 spec / Critical Detail 保持双向引用
- 如果一条 Gotcha 对应的 bug 已被架构重构根除,删除它(避免腐化)
- Gotchas 数量没有硬性上限,但超过 20 条时考虑是否有一些应该升级为 Critical Detail
七、文档语言策略
7.1 核心原则
SDD 中的术语和解释需要不同的语言策略:术语必须和代码一致,解释可以用开发者的母语。 这条原则对所有非英语母语的开发者适用——中文、韩文、日文、法文……逻辑相同。
| 内容类型 | 语言 | 原因 |
|---|---|---|
| 术语、字段名、API 签名 | English | 必须和代码中的符号精确匹配,否则不可 grep |
| 公式、算法描述 | English | 数学/代码符号不可翻译 |
| 代码引用(类名、函数名、路径) | English | PaymentGateway 不是 支付网关,否则搜索不到 |
| 解释、背景、”为什么” | 随意 | 提升理解效率,用最熟悉的语言写最复杂的逻辑 |
| 注意事项、陷阱警告 | 随意 | 清晰度优先,出错的代价远高于语言的统一 |
| 纯工程架构描述 | 随意 | modules/ 可以全英文(结构清晰,不涉及复杂领域知识) |
7.2 分层推荐
对大多数非英语母语团队,推荐按 spec 层级选择语言密度:
1 | specs/ |
为什么 modules 可以全英文? 架构描述天然是术语密集型——类名、方法签名、依赖方向本身就是英文。母语翻译反而引入歧义(”用户服务” vs UserService——哪个更精确?)。
为什么 WHAT 层推荐混合? 领域知识(数据格式规范、评估指标定义、API 契约)涉及抽象概念,母语解释能显著降低学习曲线。但所有术语、字段名、公式保持英文。
7.3 反例与正例
1 | ❌ 全母语术语: |
八、适配新工程
将本方法论应用到新工程时,推荐按以下顺序完成初始化:
1 | 1. 创建 specs/ 目录结构(WHAT 层 + HOW 层) |
建议创建一份工程特有的开发指南文档(如 SDD_GUIDE.md),放在 specs/ 目录下,引用本方法论并补充工程特有内容:
1 | # SDD 开发指南 |