2.2 SDD:先写规格的契约思维
小李的团队上周花了一整个下午吵架——前端说接口返回 userName,后端说规格里写的是 username。联调时才发现分页参数也不一致,一个用 page,一个用 offset。
"如果一开始就写好 OpenAPI 规格,根本不会有这个问题。"——这就是小李坚持 SDD 的原因。
❌ 没有 SDD vs ✅ 有 SDD
❌ 没有 SDD 的协作方式
前端:"用户接口返回什么格式?"
后端:"你等等,我还没写完。"
……三天后联调……
前端:"你返回的是 userName,我用的是 username!"
后端:"你分页传的是 page,我期望的是 offset!"
结果:联调三天,全在修字段名不一致的问题✅ 有 SDD 的协作方式
先写 OpenAPI 规格 → 前端基于 Mock 开发,后端按规格实现 → 契约测试验证
结果:零联调扯皮,文档永远最新,前后端并行开发SDD 的核心:规格即真理
SDD 的核心理念可以用一句话概括:
规格是唯一真实来源,所有代码、测试、文档都从规格生成。
小李的实际操作
让我们看小李设计"博客文章管理 API"的 SDD 过程:
第一步:写规格(最重要的产出物)
# blog-api-spec.yaml —— 小李花半天写的规格
openapi: 3.0.3
info:
title: 博客文章管理 API
version: 1.0.0
paths:
/articles:
get:
summary: 获取文章列表
parameters:
- name: page
in: query
schema:
type: integer
default: 1
- name: limit
in: query
schema:
type: integer
default: 10
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/ArticleList'
post:
summary: 创建新文章
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CreateArticleRequest'
responses:
'201':
description: 文章创建成功第二步:从规格自动生成一切
规格文档 (OpenAPI)
├── 自动生成 → Swagger UI(交互式文档)
├── 自动生成 → Prism Mock 服务器(前端不用等后端)
├── 自动生成 → TypeScript 类型定义
├── 自动生成 → 代码骨架(Controller、Service)
└── 自动生成 → Dredd 契约测试第三步:前后端并行开发
- 前端:基于 Mock 服务器开始开发,API 响应格式已经确定
- 后端:按照规格实现逻辑,契约测试确保不跑偏
第四步:验证
后端开发完成后,运行契约测试验证"实现是否符合规格"。
为什么 SDD 在 AI 时代特别重要?
这里有一个关键洞察:
在 AI 生成的代码库中,歧义的成本是数千行听起来合理但微妙错误的代码。
LLM 需要精确的输入才能产生精确的输出。而规格文档,正是人类能给 AI 的最精确的指令。
对比一下:
模糊指令 → LLM → 大量可能错误的代码
"做一个用户管理 API"
精确规格 → LLM → 精确符合要求的代码
openapi: 3.0.3
paths:
/users:
get:
responses:
'200':
schema:
type: array
items:
$ref: '#/components/schemas/User'SDD 的工具生态
SDD 不是只有一个工具,而是一整个工具链:
传统 SDD 工具:
| 类别 | 工具 | 用途 |
|---|---|---|
| API 规格 | OpenAPI / Swagger | REST API 规范定义 |
| Mock 服务 | Prism / WireMock | 基于 API 规格的 Mock |
| 测试验证 | Dredd / Schemathesis | 自动契约测试 |
| 代码生成 | OpenAPI Generator | 从规格生成代码 |
| 行为规格 | Cucumber / Gherkin | BDD 风格的行为定义 |
2025-2026 AI 原生 SDD 工具:
| 工具 | 提供方 | 核心特点 |
|---|---|---|
| Kiro | Amazon (AWS) | 双模式 IDE:Vibe Mode 和 Spec Mode |
| Spec Kit | GitHub | 结构化 Spec、Plan、Task 工作流 |
| Tessl | Tessl 团队 | 从规格直接生成代码 |
| ZeeSpec | 开源 | 60 个结构化问题引导规格编写 |
SDD 的局限
SDD 很强大,但也有明显的代价:
| 局限 | 具体表现 |
|---|---|
| 前期投入大 | 写规格本身就需要时间,小型项目可能不值得 |
| 学习曲线陡 | OpenAPI、TLA+ 这些规范语言需要学习 |
| 灵活性降低 | 需求变更时,规格和代码都要改 |
| 不适合探索 | 你还不确定要做什么的时候,没法写规格 |
SDD vs BDD vs TDD
这三个缩写经常被混淆,但其实很清楚:
关注:代码是否正确
粒度:函数/方法级别
关注:行为是否符合预期
粒度:功能/场景级别
关注:系统契约是否正确
粒度:系统/API 级别
可以理解为:TDD 是微观的验证,BDD 是中观的行为描述,SDD 是宏观的系统契约。
📌 本节核心要点
| 概念 | 要点 |
|---|---|
| SDD 核心 | "规格先行"——规格是唯一真实来源,一切从规格生成 |
| AI 时代的关键 | LLM 需要精确输入才能产生精确输出,规格是给 AI 最好的指令 |
| 核心流程 | Specify(定义)→ Plan(规划)→ Implement(实现)→ Verify(验证) |
| 代表工具 | 传统:OpenAPI、Prism、Dredd;AI 时代:Kiro、Spec Kit、Tessl |
| 不适合 | 快速探索、小团队内部工具、需求不明确的项目 |
| SDD vs TDD vs BDD | TDD 验证代码,BDD 描述行为,SDD 定义系统契约 |
知识检查
问题 1:为什么说 SDD 在 AI 时代特别重要?用"歧义成本"来解释。
查看答案
在人类写的代码中,歧义的成本是几小时的调试。但在 AI 生成的代码中,歧义的成本是数千行听起来合理但微妙错误的代码。LLM 需要精确的输入才能产生精确的输出,而 SDD 的规格文档正是人类能给 AI 的最精确的指令。
对比:
- 模糊指令 "做一个用户管理 API" → AI 可能猜错细节
- 精确规格(OpenAPI 定义了每个字段类型和约束)→ AI 按规格生成精确代码
问题 2:SDD 的一个完整工作流程是怎样的?从规格文档可以自动生成哪些东西?
查看答案
工作流:写规格 → 自动生成 → 前后端并行开发 → 契约测试验证
从规格可自动生成:
- 交互式文档(Swagger UI)
- Mock 服务器(前端不用等后端)
- TypeScript 类型定义
- 代码骨架(Controller、Service)
- 契约测试(Dredd)
问题 3:TDD、BDD、SDD 三者的关注点和粒度有什么区别?
查看答案
- TDD:起点是单元测试,关注"代码是否正确",粒度为函数/方法级别(微观验证)
- BDD:起点是用户场景,关注"行为是否符合预期",粒度为功能/场景级别(中观描述)
- SDD:起点是形式化规格,关注"系统契约是否正确",粒度为系统/API 级别(宏观契约)
问题 4:列出 2 个 SDD 不适合的场景,并说明原因。
查看答案
- 快速探索/原型阶段——需求还不清楚,写规格本身就很难
- 小团队内部工具——投入产出比低,写规格的时间可能比写代码还长
下一节预告
TDD 和 SDD 都很"严谨",但有一种方法论恰恰相反——它鼓励你"不看代码"。下一节我们看 Vibe Coding。