← 返回列表

AI系列面试16:一个好的spec coding应该是怎么样的?

一个好的 Spec Coding(规格驱动编程) ,核心是把“模糊想法”变成“精确、可验证、可执行的契约”。它不只是写一份文档,而是建立一套人与 AI(或人与人)之间无歧义的沟通语言。下面我会从规格的内容结构、编写原则、与 AI 的协作流程、质量验证四个维度,给出一个好 spec 的样子。


一、规格文档的标准结构(以功能模块为例)

章节 必填内容 示例
1. 目标与范围 一句话说明做什么,明确不做什么 “实现用户注册 API,不包含邮箱验证”
2. 输入/输出契约 数据结构、类型、必填/可选字段、示例值 POST /register 请求体 {email: string, password: string},响应 201400 含错误码
3. 行为与逻辑 业务规则、边界条件、状态转换 “密码长度 8-20 位,至少包含一个数字;邮箱已存在时返回 409
4. 错误处理 所有可能的异常场景及对应的错误码/消息 “数据库连接失败 → 返回 503,不暴露堆栈”
5. 非功能性要求 性能(响应时间 < 200ms)、安全(参数化查询)、日志、可观测性 “所有 SQL 必须使用预编译;记录 email 但不记录 password
6. 测试用例(关键) 至少 3 个典型输入 + 2 个边界/异常输入,给出期望输出 见下表
7. 依赖与约束 使用什么库、版本、环境变量 “Python 3.10+,FastAPI,环境变量 DB_URL

测试用例示例(内嵌在 spec 中)

场景 输入 期望输出
正常注册 email: a@b.com, pwd: Pass1234 201,返回 user_id
密码过短 pwd: Ab1 400,错误码 WEAK_PASSWORD
邮箱已存在 同上 email 409,错误码 EMAIL_EXISTS

好的 Spec 必须先写测试用例,因为 AI 可以根据它们直接生成单元测试,完成后自动验证。


二、编写 Spec 的核心原则(SMART 变体)

原则 解释 反例
精确(Precise) 使用具体数字、类型、布尔条件,避免“尽可能”、“通常” ❌ “密码要足够安全” → ✅ “密码至少 8 位,含大写、小写、数字”
可验证(Verifiable) 每个要求都能通过自动测试或人工检查判定通过/失败 ❌ “代码要优雅” → ✅ “函数圈复杂度 ≤ 10,无重复代码块”
无歧义(Unambiguous) 同一术语在全文中含义一致,必要时给出 glossary ❌ “如果用户不存在,返回错误” → ✅ “用户不存在 → 返回 404{code: 'USER_NOT_FOUND'}
完整(Complete) 覆盖快乐路径、所有异常路径、非功能性需求 ❌ 只写了成功场景 → ✅ 包含数据库超时、权限不足等
原子化(Atomic) 一个 spec 只描述一个可独立交付的功能点(便于 AI 一次完成) ❌ 用一个 spec 写“整个支付系统” → ✅ 拆成“生成支付单”、“回调验签”、“退款”

三、与 AI 协作时的 Spec Coding 流程

  1. 人写 spec(上述结构,尤其写好测试用例和函数签名)。
  2. 把 spec 一次性喂给 AI(不要对话式追加需求,避免 vibe 污染)。
  3. AI 输出代码 + 单元测试(AI 必须按照 spec 中的测试用例生成可执行的测试)。
  4. 运行测试:如果全部通过,进入下一步;如果不通过,修改 spec 或直接修正代码(此时可以进入小循环,但需记录变更)。
  5. 人工审查:检查是否引入 spec 之外的功能(scope creep),检查安全/性能。
  6. 固化:将 spec 文档和最终代码一起提交到仓库,作为永久文档。

关键实践:Spec 代码化 —— 使用 spec.md + test_spec.py,其中测试文件直接来自 spec 中的示例,这样后续修改代码时只需运行测试即可验证 spec 是否被破坏。


四、好的 Spec 带来的效果(可作为验收标准)

  • 确定性:相同 spec 给不同 AI(或不同人)产出相近的实现。
  • 可测试性:写完代码就立刻能自动验证 90% 的正确性。
  • 可维护性:半年后任何人看 spec,都能理解当初的设计意图。
  • 低沟通成本:团队讨论时只讨论 spec,不讨论具体代码行。
  • 安全/质量内置:安全要求(如参数化查询)和边界条件在 spec 中写明,AI 必须遵守。

五、一个好 Spec 的实例(极简版)

# Spec: 用户注册 API

## 范围
- 接收 email, password
- 不发送验证邮件,不检查邮箱真实性

## 契约
POST /register
Content-Type: application/json
Request: { "email": string, "password": string }
Response 201: { "user_id": string }
Response 400: { "code": "INVALID_PASSWORD" | "INVALID_EMAIL" }
Response 409: { "code": "EMAIL_ALREADY_EXISTS" }

## 行为
- email 必须符合 RFC 5322 基本格式(a@b.c)
- password: 长度 8-20,至少包含一个数字和一个大写字母
- 使用 bcrypt 加密存储,盐成本 10
- 如果在存入数据库前发现 email 已存在 → 409

## 测试用例(输入 -> 期望状态码+响应字段)
| 输入 email | password | 期望 |
|------------|----------|------|
| test@x.com | Pass1234  | 201, user_id 存在 |
| test@x.com | pass      | 400, INVALID_PASSWORD |
| bad        | Pass1234  | 400, INVALID_EMAIL |
| (已存在的邮箱) | Pass1234 | 409, EMAIL_ALREADY_EXISTS |

## 非功能
- SQL 必须使用参数化查询(防注入)
- 日志记录注册来源 IP,不记录密码
- 响应时间 95% 请求 < 100ms (不含 bcrypt)

## 依赖
- Python 3.10+, FastAPI, bcrypt, asyncpg

好的 Spec Coding = 把人的“设计决策”写成机器的“测试用例 + 类型签名 + 行为约束”,让 AI 只负责填充实现,而人始终掌控质量与方向。

评论

暂无已展示的评论。

发表评论(匿名)