Spec Driven Development
Posted on Sun 09 November 2025 in Journal
| Abstract | Journal on 2025-11-09 |
|---|---|
| Authors | Walter Fan |
| Category | learning note |
| Status | v1.0 |
| Updated | 2025-11-09 |
| License | CC-BY-NC-ND 4.0 |
规范驱动开发(Spec Driven Development):代码与文档的协同之道
"代码会撒谎,但规范不会。" —— 某个被 Bug 折磨到凌晨三点的程序员
你是否经历过这些场景:代码写完了,文档还没写;文档写完了,代码已经改了好几版;好不容易同步了,结果发现前后端理解还是不一致;联调时发现接口对不上;维护文档比写代码还累。
这就是典型的"代码和文档分离"带来的痛苦。根据实践经验,开发者平均需要花费 30% 左右的时间来处理文档和接口不一致的问题。
本文将深入探讨规范驱动开发(Spec Driven Development,简称 SDD),一种让规范和代码保持同步的开发方法。通过实践案例和工具介绍,帮助你建立起更高效的开发流程。
什么是规范驱动开发
规范驱动开发的核心思想很简单:先写规范,再写代码,规范即文档,文档即代码。
这听起来有点像"先有鸡还是先有蛋"的哲学问题,但 SDD 的答案是:先有规范这个"蛋",然后孵化出代码这只"鸡"。
SDD 的基本流程
- 编写规范(Spec) - 用结构化的方式描述功能需求
- 生成代码框架 - 根据规范自动生成代码骨架
- 实现业务逻辑 - 在框架基础上填充具体实现
- 验证一致性 - 确保代码和规范始终保持同步
这个过程可以类比建房子:先画图纸(规范),再打地基(代码框架),最后装修(业务逻辑)。如果中途修改图纸,地基也需要相应调整,从而避免"图纸说东,房子朝西"的情况。
graph LR
A[编写规范<br/>Spec Definition] --> B[生成代码框架<br/>Code Generation]
B --> C[实现业务逻辑<br/>Implementation]
C --> D[验证一致性<br/>Validation]
D --> E{规范变更?}
E -->|是| A
E -->|否| F[部署上线<br/>Deployment]
style A fill:#e1f5ff
style B fill:#fff4e1
style C fill:#ffe1f5
style D fill:#e1ffe1
style F fill:#d4edda
规范驱动开发与其他方法论的对比
在软件开发中,存在多种"驱动开发"的方法论,各有侧重。理解 SDD 与其他方法的异同,有助于在实际项目中选择合适的开发策略。
mindmap
root((驱动开发<br/>方法论))
DDD
领域模型
业务理解
战略设计
战术设计
FDD
功能列表
快速迭代
特性交付
项目管理
SDD
接口规范
代码生成
文档同步
契约验证
BDD
行为场景
自然语言
协作沟通
验收测试
TDD
测试先行
重构
红绿循环
FDD:功能驱动开发
FDD 的核心特点: - 以功能(Feature)为核心组织开发 - 每个功能都是独立的、可交付的单元 - 强调快速迭代和频繁交付
FDD 的典型流程是:需求分析 → 功能列表 → 功能设计 → 功能实现 → 功能测试。
与 SDD 的对比: - 相似点:都强调结构化和可交付性 - 主要差异:FDD 关注"做什么"(功能清单),SDD 关注"怎么做"(接口规范);FDD 更偏向项目管理层面,SDD 更偏向技术实现层面
举例说明:
FDD 视角:
- Feature: 用户登录
- 子功能:邮箱登录、手机号登录、第三方登录
SDD 视角:
- Spec: 登录接口规范
- 输入:邮箱/手机号 + 密码
- 输出:token + 用户信息
- 错误处理:密码错误、账户锁定等
DDD:领域驱动设计
DDD 的核心特点: - 以领域模型为核心 - 强调业务专家和开发者的协作 - 通过"通用语言"(Ubiquitous Language)统一理解
DDD 的核心概念: - 实体(Entity)、值对象(Value Object) - 聚合(Aggregate)、领域服务(Domain Service) - 仓储(Repository)、工厂(Factory)
SDD vs DDD: - 相似点:都强调用结构化的方式表达业务 - 不同点: - DDD 关注"业务是什么"(领域模型),SDD 关注"系统怎么做"(接口规范) - DDD 更抽象,SDD 更具体 - DDD 说"用户是一个实体,有身份标识",SDD 说"用户接口的请求格式是..."
举个例子:
DDD 视角:
- 领域:电商系统
- 实体:订单(Order)、商品(Product)
- 值对象:金额(Money)、地址(Address)
- 领域服务:订单服务(OrderService)
SDD 视角:
- API 规范:创建订单接口
- POST /api/orders
- Request Body: { productId, quantity, address }
- Response: { orderId, totalAmount, status }
三者的关系:互补而非竞争
其实这三种方法并不冲突,它们可以很好地配合使用:
DDD(业务理解) → FDD(功能规划) → SDD(技术实现)
↓ ↓ ↓
领域模型 功能列表 接口规范
三者的关系可以这样理解:DDD 定义业务领域和模型,FDD 规划具体功能清单,SDD 制定技术实现规范。它们各有侧重,可以配合使用。
graph TD
subgraph DDD[领域驱动设计 DDD]
D1[业务理解<br/>Business Understanding]
D2[领域模型<br/>Domain Model]
D3[实体与值对象<br/>Entities & Value Objects]
end
subgraph FDD[功能驱动开发 FDD]
F1[功能列表<br/>Feature List]
F2[功能设计<br/>Feature Design]
F3[功能实现<br/>Feature Build]
end
subgraph SDD[规范驱动开发 SDD]
S1[接口规范<br/>API Specification]
S2[代码生成<br/>Code Generation]
S3[实现验证<br/>Implementation & Validation]
end
D1 --> D2 --> D3
D3 --> F1
F1 --> F2 --> F3
F3 --> S1
S1 --> S2 --> S3
style DDD fill:#e8f4f8
style FDD fill:#fff4e6
style SDD fill:#f0e6ff
BDD(Behavior Driven Development):行为驱动的"沟通大师"
在介绍完 FDD 和 DDD 之后,我们不能忘记另一个重要的"D家族成员":行为驱动开发(BDD)。如果说 DDD 是"哲学家",FDD 是"实干派",那么 BDD 就是"沟通大师"——它擅长用大家都能听懂的语言描述系统行为。
BDD 的特点: - 以用户行为和业务价值为中心 - 使用自然语言(Given-When-Then)描述场景 - 强调协作:业务人员、测试人员、开发人员共同定义行为 - 测试用例即需求文档
BDD 的核心模式:Given-When-Then
Feature: 用户登录
Scenario: 用户使用正确的凭证登录
Given 用户已经注册了账号 "user@example.com"
When 用户输入正确的邮箱和密码
Then 用户应该成功登录
And 系统应该返回用户信息和访问令牌
Scenario: 用户使用错误的密码登录
Given 用户已经注册了账号 "user@example.com"
When 用户输入错误的密码
Then 登录应该失败
And 系统应该返回 "密码错误" 的提示
SDD vs BDD:契约 vs 行为
| 维度 | SDD | BDD |
|---|---|---|
| 关注点 | 接口契约和数据结构 | 用户行为和业务场景 |
| 描述方式 | 技术规范(OpenAPI、JSON Schema) | 自然语言(Gherkin、Given-When-Then) |
| 主要用户 | 开发人员、架构师 | 业务分析师、测试人员、开发人员 |
| 输出物 | API 文档、代码框架 | 可执行的测试用例 |
| 验证方式 | 接口测试、类型检查 | 端到端测试、集成测试 |
相似点: - 都强调"规范先行"的理念 - 都试图弥合需求和实现之间的鸿沟 - 都可以自动生成测试或代码
不同点: - SDD 说:"这个 API 接受 JSON 格式,字段包括 email、password..." - BDD 说:"当用户输入正确的邮箱和密码时,系统应该返回成功..."
举个例子:同一个功能的不同视角
SDD 视角(技术规范):
paths:
/api/v1/users/login:
post:
requestBody:
schema:
type: object
properties:
email: {type: string, format: email}
password: {type: string, minLength: 8}
responses:
'200':
schema:
properties:
token: {type: string}
userId: {type: string}
BDD 视角(行为场景):
Scenario: 成功登录
Given 存在用户 "alice@example.com" 密码为 "SecurePass123"
When POST /api/v1/users/login
"""
{"email": "alice@example.com", "password": "SecurePass123"}
"""
Then 响应状态码应该是 200
And 响应包含 "token" 和 "userId" 字段
它们如何配合使用?
graph LR
A[业务需求<br/>Business Requirement] --> B[BDD 场景<br/>Behavior Scenarios]
B --> C[SDD 规范<br/>API Specification]
C --> D[代码实现<br/>Implementation]
D --> E[BDD 测试<br/>Acceptance Tests]
E --> F{测试通过?}
F -->|否| D
F -->|是| G[交付<br/>Delivery]
style B fill:#e8f4f8
style C fill:#f0e6ff
style E fill:#e1ffe1
实践中,BDD 和 SDD 可以完美配合: 1. BDD 定义"做什么":用 Given-When-Then 描述用户期望的行为 2. SDD 定义"怎么做":用技术规范描述 API 的细节 3. BDD 验证"做对了吗":用自动化测试验证行为是否符合预期
驱动开发方法全面对比
为了让大家更清晰地理解各种方法,这里提供一个全面的对比表:
| 特性 | SDD | BDD | TDD | DDD | FDD |
|---|---|---|---|---|---|
| 核心理念 | 规范即文档 | 行为即需求 | 测试先行 | 领域建模 | 功能交付 |
| 主要用户 | 全栈开发者 | 全团队 | 开发者 | 架构师 | 项目经理 |
| 起始点 | 接口规范 | 用户故事 | 测试用例 | 领域模型 | 功能列表 |
| 输出物 | API文档+代码 | 可执行测试 | 测试+代码 | 领域模型 | 功能模块 |
| 验证方式 | 规范一致性 | 行为验证 | 单元测试 | 模型验证 | 功能验收 |
| 学习曲线 | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐ |
| 工具依赖 | 中等 | 高 | 低 | 低 | 中等 |
| 适用规模 | 中大型 | 任意 | 任意 | 大型 | 中大型 |
| 团队协作 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
如何选择? - 🎯 API 开发 → SDD 首选 - 🎯 需求不明确 → BDD 首选 - 🎯 代码质量 → TDD 首选 - 🎯 复杂业务 → DDD 首选 - 🎯 快速交付 → FDD 首选
推荐组合: - 小型项目:TDD + SDD(轻量级) - 中型项目:BDD + SDD + TDD - 大型项目:DDD + FDD + SDD + BDD + TDD
规范驱动开发与文学编程的对比
文学编程(Literate Programming)是 Donald Knuth 在 1984 年提出的概念,它的核心理念是:程序应该像文学作品一样可读。
文学编程的特点
- 代码和文档交织在一起
- 按照人类的思维逻辑组织代码,而非编译器的要求
- 使用工具(如
noweb、CWEB)将文档和代码分离
文学编程的例子:
<<用户认证函数>>=
/**
* 用户登录验证
*
* 这个函数负责验证用户的登录凭证。
* 如果验证成功,返回用户信息;否则返回错误。
*/
int authenticate_user(const char* username, const char* password) {
<<验证用户名和密码>>
<<查询数据库>>
<<生成 token>>
return result;
}
SDD vs 文学编程
| 维度 | 文学编程 | SDD |
|---|---|---|
| 关注点 | 代码的可读性 | 规范的完整性 |
| 组织方式 | 按逻辑顺序 | 按接口结构 |
| 工具支持 | noweb, CWEB | spec-kit, OpenAPI |
| 适用场景 | 复杂算法、系统程序 | API 开发、微服务 |
| 文档位置 | 代码内部 | 独立规范文件 |
相同点: - 都强调文档的重要性 - 都试图让代码更易理解 - 都需要工具支持
不同点: - 文学编程是"代码即文档"(代码里写文档) - SDD 是"规范即文档"(规范文件就是文档)
举个例子:
文学编程风格(伪代码):
<<计算订单总价>>=
def calculate_total(order):
"""
计算订单的总价
这个函数会遍历订单中的所有商品,
累加每个商品的价格乘以数量。
"""
total = 0
for item in order.items:
total += item.price * item.quantity
return total
SDD 风格(规范文件):
# order-service.spec.yaml
endpoints:
- name: calculateTotal
method: POST
path: /api/orders/calculate
request:
schema:
type: object
properties:
items:
type: array
items:
price: number
quantity: number
response:
schema:
total: number
description: |
计算订单的总价。
遍历订单中的所有商品,累加每个商品的价格乘以数量。
实践案例:使用 SDD 开发用户服务
通过一个实际的用户注册功能来演示 SDD 的完整流程。
系统架构概览
在开始之前,让我们先看看整个系统的架构:
graph TB
subgraph Client[客户端层]
Web[Web 应用]
Mobile[移动应用]
end
subgraph Spec[规范层]
OpenAPI[OpenAPI Spec<br/>user-service.yaml]
end
subgraph Generated[生成层]
Models[数据模型<br/>Models]
Handlers[处理器<br/>Handlers]
Validators[验证器<br/>Validators]
Tests[测试用例<br/>Tests]
end
subgraph Implementation[实现层]
Business[业务逻辑<br/>Business Logic]
DB[(数据库<br/>Database)]
end
Web --> OpenAPI
Mobile --> OpenAPI
OpenAPI -.生成.-> Models
OpenAPI -.生成.-> Handlers
OpenAPI -.生成.-> Validators
OpenAPI -.生成.-> Tests
Handlers --> Business
Business --> DB
style OpenAPI fill:#f9d5e5
style Generated fill:#eeeeee
style Implementation fill:#d5f4e6
案例:用户注册功能
第一步:编写接口规范
使用 OpenAPI 格式定义接口(也可以使用 JSON Schema、Protocol Buffers 等其他格式):
# user-service.spec.yaml
openapi: 3.0.0
info:
title: 用户服务 API
version: 1.0.0
description: 提供用户注册、登录、信息查询等功能
paths:
/api/v1/users/register:
post:
summary: 用户注册
description: |
新用户注册接口。
需要提供邮箱、密码、昵称等信息。
系统会验证邮箱格式和密码强度。
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- email
- password
- nickname
properties:
email:
type: string
format: email
description: 用户邮箱
example: "user@example.com"
password:
type: string
format: password
minLength: 8
description: 密码,至少8位
example: "SecurePass123!"
nickname:
type: string
minLength: 2
maxLength: 20
description: 用户昵称
example: "张三"
responses:
'201':
description: 注册成功
content:
application/json:
schema:
type: object
properties:
userId:
type: string
description: 用户ID
email:
type: string
nickname:
type: string
createdAt:
type: string
format: date-time
'400':
description: 请求参数错误
content:
application/json:
schema:
type: object
properties:
error:
type: string
example: "邮箱格式不正确"
'409':
description: 邮箱已存在
第二步:使用代码生成工具
根据 OpenAPI 规范可以生成代码框架,常用工具包括:
- OpenAPI Generator(推荐)
# 安装
npm install @openapitools/openapi-generator-cli -g
# 生成 Go 代码
openapi-generator-cli generate -i user-service.spec.yaml -g go -o ./generated
# 生成 TypeScript 代码
openapi-generator-cli generate -i user-service.spec.yaml -g typescript-axios -o ./generated
# 生成 Python 代码
openapi-generator-cli generate -i user-service.spec.yaml -g python -o ./generated
- Swagger Codegen
# 使用 Docker
docker run --rm -v ${PWD}:/local swaggerapi/swagger-codegen-cli generate \
-i /local/user-service.spec.yaml \
-l go \
-o /local/generated
- oapi-codegen(Go 专用,轻量级)
# 安装
go install github.com/deepmap/oapi-codegen/cmd/oapi-codegen@latest
# 生成 Go 代码
oapi-codegen -package models user-service.spec.yaml > models/user.go
生成的 Go 代码框架示例:
// generated/models/user.go
package models
type RegisterRequest struct {
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"required,min=8"`
Nickname string `json:"nickname" validate:"required,min=2,max=20"`
}
type RegisterResponse struct {
UserID string `json:"userId"`
Email string `json:"email"`
Nickname string `json:"nickname"`
CreatedAt string `json:"createdAt"`
}
// generated/handlers/user_handler.go
package handlers
func RegisterUser(w http.ResponseWriter, r *http.Request) {
// TODO: 实现注册逻辑
// 1. 解析请求体
// 2. 验证邮箱格式和密码强度
// 3. 检查邮箱是否已存在
// 4. 创建用户
// 5. 返回响应
}
第三步:实现业务逻辑
在生成的框架基础上实现具体逻辑:
func RegisterUser(w http.ResponseWriter, r *http.Request) {
// 1. 解析请求体
var req models.RegisterRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
respondError(w, http.StatusBadRequest, "请求参数错误")
return
}
// 2. 验证邮箱格式和密码强度
if !isValidEmail(req.Email) {
respondError(w, http.StatusBadRequest, "邮箱格式不正确")
return
}
// 3. 检查邮箱是否已存在
if userRepo.Exists(req.Email) {
respondError(w, http.StatusConflict, "邮箱已存在")
return
}
// 4. 创建用户
user := &models.User{
Email: req.Email,
Password: hashPassword(req.Password),
Nickname: req.Nickname,
}
if err := userRepo.Create(user); err != nil {
respondError(w, http.StatusInternalServerError, "创建用户失败")
return
}
// 5. 返回响应
respondJSON(w, http.StatusCreated, models.RegisterResponse{
UserID: user.ID,
Email: user.Email,
Nickname: user.Nickname,
CreatedAt: user.CreatedAt.Format(time.RFC3339),
})
}
第四步:验证规范一致性
修改代码后,通过验证工具确保实现与规范保持一致:
# 验证 OpenAPI 规范文件格式
swagger-cli validate user-service.spec.yaml
# 使用 Spectral 进行更严格的校验
spectral lint user-service.spec.yaml
# 生成文档(验证规范可用性)
redoc-cli bundle user-service.spec.yaml -o docs/api.html
规范驱动开发的工具生态
在 SDD 的实践中,有两类主要的工具:API 规范工具和项目规范工具。它们各有侧重点,可以互补使用。
GitHub Spec-Kit:AI 驱动的规范工具
GitHub Spec-Kit 是 GitHub 官方开源的规范驱动开发工具包(46.5k+ stars),专门用于与 AI 编程助手(如 Claude Code)协同工作,将需求规范转化为可执行代码。
Spec-Kit 的核心理念
Spec-Kit 采用了一种人类定义规范、AI 执行实现的工作模式:
graph LR
A[0. 初始化项目<br/>specify init] --> B[1. 建立宪章<br/>/speckit.constitution]
B --> C[2. 定义规范<br/>/speckit.specify]
C --> D[AI:生成规范文档<br/>spec.md]
D --> E[3. 技术方案<br/>/speckit.plan]
E --> F[AI:创建方案<br/>plan.md]
F --> G[4. 任务列表<br/>/speckit.tasks]
G --> H[AI:生成任务<br/>tasks.md]
H --> I[5. 执行实现<br/>/speckit.implement]
I --> J[AI:实现代码]
style A fill:#e1f5ff
style B fill:#ffe1e1
style C fill:#fff4e6
style E fill:#f0e6ff
style G fill:#e6ffe6
style I fill:#ffe6e6
Spec-Kit 的工作流程
初始化项目
在项目目录中初始化 Spec-Kit:
# 在当前目录初始化项目
specify init --here --force --ai cursor-agent
# 或者创建新项目目录
specify init my-project --ai cursor-agent
这个命令会创建:
- 项目模板和目录结构
- CLAUDE.md 文件(AI 助手配置)
- memory/ 目录(存储项目记忆)
- specs/ 目录(存储功能规范)
- templates/ 目录(规范模板)
- scripts/ 目录(辅助脚本)
建立项目宪章
在编写功能规范之前,先定义项目的基本原则和约束,作为后续实现的指导方针:
/speckit.constitution Create principles focused on code quality, testing standards,
user experience consistency, and performance requirements
AI 会在 memory/constitution.md 中生成项目宪章,典型内容包括:
# 项目宪章 (Project Constitution)
## 代码质量原则
- 所有代码必须遵循 SOLID 原则
- 函数单一职责,最大长度不超过 50 行
- 必须有清晰的命名和注释
- 代码覆盖率不低于 80%
## 测试标准
- 所有公共 API 必须有单元测试
- 关键业务逻辑必须有集成测试
- 遵循 TDD 开发模式:先写测试,再写实现
- 测试命名格式:Should_ExpectedBehavior_When_Condition
## 用户体验一致性
- 所有界面必须支持响应式设计
- 加载时间不超过 3 秒
- 错误信息必须清晰且可操作
- 支持键盘快捷键操作
## 性能要求
- API 响应时间 < 200ms (P95)
- 数据库查询必须有索引优化
- 静态资源必须启用缓存
- 支持水平扩展
## 安全要求
- 所有输入必须验证和消毒
- 敏感数据必须加密存储
- 使用 HTTPS 传输
- 定期进行安全审计
这个宪章文件贯穿整个开发过程,AI 生成代码时会参考这些原则。
定义功能规范
描述需要构建的功能,专注于业务需求而非技术细节:
我想创建一个任务管理应用 Taskify,具有以下功能:
- 用户可以创建、编辑、删除任务
- 任务可以分配给团队成员
- 支持任务的优先级和截止日期
- 实时通知和更新
AI 会生成规范文档(spec.md),包含用户故事、验收标准等,并参考项目宪章中定义的原则。
创建技术方案
在规范基础上,指定技术栈和架构:
我们将使用 .NET Aspire 和 Postgres 数据库。
前端使用 Blazor Server,支持拖拽式任务面板和实时更新。
创建 REST API,包括项目 API、任务 API 和通知 API。
AI 会生成:
- 实现计划(plan.md)
- 数据模型(data-model.md)
- API 规范(api-spec.json)
- 技术研究(research.md)
AI 确保方案符合项目宪章中的质量标准和性能要求。
生成任务列表
自动将技术方案分解为可执行的任务:
/speckit.tasks
生成的 tasks.md 包含:
- 按用户故事组织的任务
- 任务之间的依赖关系
- 可并行执行的任务标记 [P]
- 具体的文件路径
- TDD 测试任务(如果宪章中要求 TDD)
执行代码实现
AI 按照任务列表自动实现代码:
/speckit.implement
AI 会: - 验证所有前置条件(constitution、spec、plan、tasks) - 按正确顺序执行任务 - 遵循项目宪章中定义的开发方法(如 TDD) - 自动检查代码是否符合质量标准 - 执行必要的 CLI 命令(测试、构建等) - 提供进度更新和错误处理
Spec-Kit 的项目结构
.
├── CLAUDE.md # AI 助手配置(由 specify init 创建)
├── memory/
│ └── constitution.md # 项目宪章(原则和约束)⭐️
├── specs/
│ └── 001-create-taskify/
│ ├── spec.md # 功能规范
│ ├── plan.md # 实现计划
│ ├── tasks.md # 任务列表
│ ├── data-model.md # 数据模型
│ ├── research.md # 技术研究
│ ├── quickstart.md # 快速开始指南
│ └── contracts/
│ ├── api-spec.json # API 规范(可转为 OpenAPI)
│ └── signalr-spec.md # SignalR 规范
├── scripts/
│ ├── check-prerequisites.sh # 检查前置条件
│ ├── setup-plan.sh # 规划脚本
│ ├── create-new-feature.sh # 功能创建脚本
│ ├── update-claude-md.sh # 更新 AI 配置
│ └── common.sh # 通用工具函数
└── templates/
├── CLAUDE-template.md # AI 配置模板
├── spec-template.md # 规范模板
├── plan-template.md # 计划模板
└── tasks-template.md # 任务模板
关键文件说明:
- constitution.md - 定义项目的开发原则和约束
- CLAUDE.md - AI 助手的配置文件
- spec.md - 功能规范文档
- plan.md - 技术实现方案
- tasks.md - 任务列表
Spec-Kit vs 传统 SDD 工具
| 维度 | Spec-Kit | OpenAPI 工具 |
|---|---|---|
| 定位 | 项目级规范 | API 级规范 |
| 使用场景 | 完整应用开发 | API 接口设计 |
| 工作方式 | AI 协同开发 | 代码生成 |
| 规范格式 | Markdown 文档 | YAML/JSON |
| 生成内容 | 完整代码实现 | 接口骨架 |
| 适合对象 | 新项目开发 | API 开发和文档 |
工具选择建议
Spec-Kit 适用场景: - 从零开始的新项目 - 需要 AI 助手协同开发 - 强调用户故事和需求验收 - 快速原型和 MVP 开发
OpenAPI 工具适用场景: - 专注于 API 设计和文档 - 需要跨语言客户端 SDK - 需要 Mock 服务和测试 - API 优先的开发模式
两者结合使用:
你可以在同一个项目中同时使用两种方法:
# 0. 初始化 Spec-Kit 项目
specify init --here --force --ai cursor-agent
# 1. 建立项目原则(定义代码质量、测试、性能等标准)
/speckit.constitution Create principles focused on code quality, testing standards,
user experience consistency, and performance requirements
# 2. 使用 Spec-Kit 定义项目规范
/speckit.specify
# 3. 使用 Spec-Kit 创建技术方案(包括 API 规范)
/speckit.plan
# 4. 从 Spec-Kit 生成的 API 规范创建 OpenAPI 文档
cp specs/001-feature/contracts/api-spec.json openapi.yaml
# 5. 用 OpenAPI 工具生成客户端 SDK
openapi-generator-cli generate -i openapi.yaml -g typescript-axios -o ./client
# 6. 生成任务列表
/speckit.tasks
# 7. 用 Spec-Kit 实现服务端代码(AI 会遵循 constitution 中的原则)
/speckit.implement
# 8. 用 OpenAPI 工具生成 API 文档
redoc-cli bundle openapi.yaml -o docs/api.html
# 9. 启动 Mock 服务(前端开发可以并行进行)
prism mock openapi.yaml
这种组合的优势: - Spec-Kit 负责整体项目管理和服务端实现 - OpenAPI 提供标准化的 API 文档和客户端 SDK - Constitution 确保代码质量和一致性 - 前后端可以并行开发(通过 Mock 服务)
OpenAPI 工具生态:API 规范的标准方案
对于 API 开发,OpenAPI 提供了成熟的工具生态。
核心工具分类
OpenAPI 工具生态可以分为以下几类:
1. 代码生成工具
生成客户端 SDK、服务端框架代码:
# OpenAPI Generator(支持 50+ 语言)
openapi-generator-cli generate -i api.yaml -g go -o ./client
# Swagger Codegen(老牌工具)
swagger-codegen generate -i api.yaml -l java -o ./client
# oapi-codegen(Go 专用,轻量高效)
oapi-codegen -package api api.yaml > api/generated.go
2. 文档生成工具
生成漂亮的 API 文档:
# Swagger UI(最流行)
docker run -p 8080:8080 -e SWAGGER_JSON=/api.yaml -v ${PWD}:/api swaggerapi/swagger-ui
# Redoc(更现代的风格)
redoc-cli bundle api.yaml -o docs/index.html
# Stoplight Elements(交互式文档)
npx @stoplight/elements-dev-portal api.yaml
3. Mock 服务器
根据规范生成模拟 API:
# Prism(推荐,功能强大)
prism mock api.yaml
# Mockoon(GUI 工具)
mockoon-cli start --data api.yaml
# json-server + OpenAPI
openapi-backend mock api.yaml --port 3000
4. 验证和校验工具
检查规范文件的正确性:
# Swagger CLI(基础验证)
swagger-cli validate api.yaml
# Spectral(规则引擎,可自定义校验规则)
spectral lint api.yaml
# OpenAPI Enforcer(严格校验)
openapi-enforcer validate api.yaml
常用工作流
方案一:完全自动化(推荐用于团队协作)
# 1. 编写/更新规范
vim api.spec.yaml
# 2. 验证规范
spectral lint api.spec.yaml
# 3. 生成代码框架
openapi-generator-cli generate -i api.spec.yaml -g go -o ./generated
# 4. 生成文档
redoc-cli bundle api.spec.yaml -o docs/api.html
# 5. 启动 Mock 服务(供前端开发)
prism mock api.spec.yaml &
# 6. 实现业务逻辑
vim src/handlers/user.go
# 7. 运行测试
go test ./...
方案二:半自动化(适合小团队)
# 使用 Makefile 简化流程
cat > Makefile << 'EOF'
.PHONY: validate generate docs mock
validate:
spectral lint api.yaml
generate:
openapi-generator-cli generate -i api.yaml -g go -o ./generated
docs:
redoc-cli bundle api.yaml -o docs/api.html
mock:
prism mock api.yaml
all: validate generate docs
EOF
# 然后只需要
make all
方案三:CI/CD 集成
# .github/workflows/openapi.yml
name: OpenAPI Workflow
on: [push, pull_request]
jobs:
validate-and-generate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Validate OpenAPI Spec
run: |
npm install -g @stoplight/spectral-cli
spectral lint api.yaml
- name: Generate Code
run: |
docker run --rm -v ${PWD}:/local openapitools/openapi-generator-cli generate \
-i /local/api.yaml \
-g go \
-o /local/generated
- name: Generate Docs
run: |
npm install -g redoc-cli
redoc-cli bundle api.yaml -o docs/api.html
- name: Commit Generated Files
run: |
git add generated/ docs/
git commit -m "Auto-generated from OpenAPI spec" || true
完整开发流程时序图
sequenceDiagram
participant PM as 产品经理
participant BE as 后端开发
participant FE as 前端开发
participant Spec as 规范文件
participant Tool as spec-kit
participant CI as CI/CD
PM->>BE: 提出需求
BE->>Spec: 编写 API 规范
BE->>Tool: 生成代码框架
Tool-->>BE: 返回代码骨架
par 并行开发
BE->>BE: 实现业务逻辑
and
Tool->>FE: 生成 Mock 服务
FE->>FE: 前端开发与联调
end
BE->>Tool: 生成 API 文档
Tool-->>FE: 提供最新文档
BE->>BE: 完成实现
BE->>Tool: 验证规范一致性
Tool-->>BE: 验证通过
BE->>CI: 提交代码
CI->>Tool: 自动验证规范
Tool-->>CI: 验证通过
CI->>CI: 部署到测试环境
FE->>BE: 联调真实 API
FE-->>BE: 反馈问题
BE->>Spec: 更新规范
Note over BE,Spec: 规范变更,<br/>重新生成代码
style Spec fill:#f9d5e5
style Tool fill:#d5f4e6
style CI fill:#eeeeee
SDD 的简化实践方案
对于不需要复杂工具的场景,可以采用更轻量级的方式:
graph TB
Start{项目规模?}
Start -->|大型/企业级| A[完整 SDD 工具链<br/>spec-kit + OpenAPI]
Start -->|中型/团队项目| B[轻量级方案<br/>Markdown + 结构化注释]
Start -->|小型/个人项目| C[极简方案<br/>测试即规范]
A --> A1[自动代码生成<br/>多语言支持<br/>Mock 服务器<br/>完整文档]
B --> B1[手动代码框架<br/>文档模板<br/>脚本辅助]
C --> C1[测试驱动<br/>代码注释<br/>最小化文档]
style A fill:#ff6b6b
style B fill:#ffd93d
style C fill:#6bcf7f
style A1 fill:#ffe5e5
style B1 fill:#fff8e1
style C1 fill:#e8f5e9
方法一:Markdown + 代码注释
使用 Markdown 文档配合代码注释:
# user-service-api.md
## 用户注册接口
**路径:** POST /api/v1/users/register
**请求:**
```json
{
"email": "user@example.com",
"password": "SecurePass123!",
"nickname": "张三"
}
响应:
{
"userId": "123",
"email": "user@example.com",
"nickname": "张三",
"createdAt": "2025-11-09T20:20:00Z"
}
错误码: - 400: 请求参数错误 - 409: 邮箱已存在
然后在代码中引用:
```go
// 实现规范:user-service-api.md#用户注册接口
func RegisterUser(w http.ResponseWriter, r *http.Request) {
// 按照规范实现...
}
方法二:结构化注释
在代码中使用结构化注释定义规范:
// @spec: User Registration API
// @method: POST
// @path: /api/v1/users/register
// @request:
// email: string (required, email format)
// password: string (required, min 8 chars)
// nickname: string (required, 2-20 chars)
// @response:
// 201: { userId, email, nickname, createdAt }
// 400: { error: "请求参数错误" }
// 409: { error: "邮箱已存在" }
func RegisterUser(w http.ResponseWriter, r *http.Request) {
// 实现...
}
然后用简单的脚本提取这些注释生成文档。
方法三:测试即规范
使用测试用例来定义规范:
func TestUserRegistration(t *testing.T) {
// 规范:用户注册成功
t.Run("注册成功", func(t *testing.T) {
req := RegisterRequest{
Email: "user@example.com",
Password: "SecurePass123!",
Nickname: "张三",
}
resp := RegisterUser(req)
assert.Equal(t, 201, resp.StatusCode)
assert.NotEmpty(t, resp.UserID)
})
// 规范:邮箱格式错误
t.Run("邮箱格式错误", func(t *testing.T) {
req := RegisterRequest{
Email: "invalid-email",
Password: "SecurePass123!",
Nickname: "张三",
}
resp := RegisterUser(req)
assert.Equal(t, 400, resp.StatusCode)
assert.Contains(t, resp.Error, "邮箱格式")
})
// 规范:邮箱已存在
t.Run("邮箱已存在", func(t *testing.T) {
// 先创建一个用户
RegisterUser(RegisterRequest{Email: "existing@example.com", ...})
// 再次注册相同邮箱
req := RegisterRequest{
Email: "existing@example.com",
Password: "SecurePass123!",
Nickname: "李四",
}
resp := RegisterUser(req)
assert.Equal(t, 409, resp.StatusCode)
})
}
这种方法的优势在于测试即规范,规范即测试。代码和规范的一致性由测试来保证,不一致时测试会失败。
方法四:GitHub Issues + 代码
使用 GitHub Issues 管理规范:
- 创建一个 Issue 模板:
## API 规范
### 接口名称
[描述]
### 请求格式
[格式]
### 响应格式
[格式]
### 实现
- [ ] 代码实现
- [ ] 测试用例
- [ ] 文档更新
- 每个功能创建一个 Issue
- 实现时引用 Issue:
Closes #123 - Issue 关闭时,规范就完成了
实用技巧
1. 从现有代码生成规范
如果你已经有代码了,可以反向生成规范:
# 使用工具从代码提取 API 信息
swagger-codegen generate -i existing-code -o spec.yaml
# 或手动整理
# 1. 列出所有接口
# 2. 提取请求/响应结构
# 3. 整理成规范格式
2. 规范版本管理
规范文件也要版本控制:
# api.v1.spec.yaml
openapi: 3.0.0
info:
version: 1.0.0
# api.v2.spec.yaml
openapi: 3.0.0
info:
version: 2.0.0
3. 规范审查
像代码审查一样审查规范:
## 规范审查清单
- [ ] 接口命名是否清晰?
- [ ] 请求/响应格式是否完整?
- [ ] 错误处理是否全面?
- [ ] 是否有安全考虑?
- [ ] 是否有性能要求?
4. 渐进式采用
不需要一次性重构所有代码,可以渐进式采用:
- 新功能用 SDD:所有新功能都先写规范
- 重构时补规范:重构旧代码时补充规范
- 重要接口优先:核心接口先规范化
总结与建议
规范驱动开发不是万能解决方案,但在合适的场景下能够有效提升开发效率。
SDD 的主要优势: - 保持代码和文档同步 - 规范作为前后端协作的契约 - 自动生成代码框架,减少重复劳动 - 规范本身就是文档,降低维护成本 - 可提供 Mock 服务,支持并行开发
适用场景: - API 开发(RESTful、GraphQL、gRPC) - 微服务架构 - 前后端分离项目 - 需要严格接口约定的项目 - 多团队协作的大型项目
实施建议: - 可以从轻量级方案开始(Markdown + 注释) - 使用测试来保证规范一致性 - 渐进式采用,新功能优先使用 SDD - 根据项目规模选择合适的工具
各种方法的协同关系
实用工具推荐
根据不同需求,这里是我的工具推荐:
| 需求 | 推荐工具 | 原因 |
|---|---|---|
| 代码生成 | OpenAPI Generator | 支持语言最多,社区活跃 |
| Go 代码生成 | oapi-codegen | 轻量、快速、符合 Go 惯例 |
| 文档生成 | Redoc | 美观现代,单文件输出 |
| Mock 服务 | Prism | 功能强大,支持各种场景 |
| 规范验证 | Spectral | 可自定义规则,IDE 集成好 |
| 在线编辑 | Swagger Editor | 实时预览,错误提示 |
各种方法的协同关系
graph LR
subgraph 需求阶段
BDD[BDD<br/>定义行为]
end
subgraph 设计阶段
DDD[DDD<br/>领域建模]
FDD[FDD<br/>功能拆分]
end
subgraph 实现阶段
SDD[SDD<br/>接口规范]
TDD[TDD<br/>测试驱动]
end
subgraph 交付阶段
CI[持续集成<br/>CI/CD]
end
BDD --> DDD
DDD --> FDD
FDD --> SDD
SDD --> TDD
TDD --> CI
style BDD fill:#e8f4f8
style DDD fill:#e8f4f8
style FDD fill:#fff4e6
style SDD fill:#f0e6ff
style TDD fill:#e1ffe1
style CI fill:#d4edda
选择工具的原则是实用性优先。复杂工具不适合就用简单方案,关键是让规范和代码保持同步。方法论是手段,解决实际问题才是目的。
延伸阅读
规范和标准
- OpenAPI Specification - RESTful API 规范标准
- JSON Schema - JSON 数据结构定义
- Protocol Buffers - Google 的数据交换格式
- GraphQL Schema - GraphQL 类型系统
工具和框架
- GitHub Spec-Kit - GitHub 官方的规范驱动开发工具包(AI 协同)
- OpenAPI Generator - 多语言代码生成工具
- Swagger Tools - Swagger 官方工具集
- Prism - Mock 服务器和验证工具
- Spectral - OpenAPI 规范校验工具
- Redoc - 美观的 API 文档生成器
- oapi-codegen - Go 语言专用代码生成器
设计方法论
- Literate Programming - Donald Knuth - 文学编程
- Domain-Driven Design - Martin Fowler - 领域驱动设计
- Feature Driven Development - 功能驱动开发
- API Design Best Practices - API 设计最佳实践
开发方法论
- Domain-Driven Design - Martin Fowler - 领域驱动设计
- Feature Driven Development - 功能驱动开发
- Behavior Driven Development - 行为驱动开发
- Test Driven Development - 测试驱动开发
文学编程
- Literate Programming - Donald Knuth - 文学编程原始论文
- Literate Programming - Wikipedia - 维基百科条目
工具和实践
- Swagger/OpenAPI Tools - OpenAPI 工具生态
- Postman - API 开发和测试平台
- Stoplight - API 设计和文档工具
- API Blueprint - API 设计语言
💬 最后的思考
软件开发从来没有银弹,但好的方法论可以让我们少走弯路。SDD 的核心价值不在于工具有多酷炫,而在于它倡导的理念:
让规范成为开发的起点,而不是终点的补充。
无论你选择使用完整的工具链,还是简单的 Markdown 文档,关键是找到适合你团队的方式,并坚持下去。
记住这三个原则: 1. 规范先行 - 在写代码之前先思考接口设计 2. 保持同步 - 让规范和代码始终一致 3. 持续改进 - 随着项目演进,不断优化规范
最后,如果你觉得这篇文章对你有帮助,不妨在下一个项目中尝试一下 SDD,哪怕只是从一个简单的 API 文档开始。
Happy Coding! 🚀
🔖 快速参考卡片
# SDD 快速参考
## 基本流程
1. 编写规范 → 2. 生成代码 → 3. 实现逻辑 → 4. 验证一致性
## 工具选择
- 大型项目:OpenAPI + spec-kit
- 中型项目:Markdown + 脚本
- 小型项目:测试 + 注释
## 最佳实践
✅ 规范先于代码
✅ 规范即文档
✅ 自动化验证
✅ 版本控制
✅ 团队协作
## 常见陷阱
❌ 先写代码后补规范
❌ 规范和代码不同步
❌ 过度设计
❌ 忽视工具学习成本
本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。