374 lines
15 KiB
Markdown
374 lines
15 KiB
Markdown
# 高质量 Spec 编写指南
|
||
|
||
**核心原则**:人定义 WHAT,AI 实现 HOW;Spec 是唯一的真实来源。
|
||
|
||
---
|
||
|
||
## 1. 核心概念
|
||
|
||
### 1.1 高质量 Spec 的标准
|
||
|
||
- **可测试**:每个需求都有明确验收标准,可被自动化测试验证。
|
||
- **有边界**:明确做什么、不做什么、在什么约束下做。
|
||
- **独立于实现**:描述 WHAT,不限制 HOW(外部约束除外)。
|
||
|
||
### 1.2 六要素模型
|
||
|
||
完整 Spec 须包含以下六个要素:
|
||
|
||
| 要素 | 回答的问题 |
|
||
|------|------------|
|
||
| **Problem Statement** | 为什么要做?背景和痛点是什么? |
|
||
| **Success Metrics** | 做到什么程度算成功?可量化的指标。 |
|
||
| **User Stories** | 谁、在什么场景下、获得什么价值? |
|
||
| **Acceptance Criteria** | 具体怎么验证?什么行为算通过? |
|
||
| **Non-Goals** | 明确本期不做什么。 |
|
||
| **Constraints** | 必须遵守的技术、法律、业务约束。 |
|
||
|
||
### 1.3 验收标准与原子性原则
|
||
|
||
**验收标准(AC)** 定义「怎么做才算对」。模糊 AC(如「用户可以登录系统」)会导致实现不一致。
|
||
|
||
**原子性 AC** 要求每条 AC 只验证一个独立业务行为:
|
||
|
||
- **单一职责**:一个场景只测试一个动作的结果。
|
||
- **无依赖**:可单独执行,不依赖其他 AC 的执行顺序。
|
||
- **可独立验证**:一条失败时能立刻定位到具体问题。
|
||
|
||
六要素提供全景结构,原子性 AC 提供可执行粒度,二者融合形成可被 AI 直接消费的精确指令。
|
||
|
||
---
|
||
|
||
## 2. 六要素编写规范
|
||
|
||
### 2.1 Problem Statement(问题陈述)
|
||
|
||
用简洁语言描述当前系统或业务存在的痛点、机会或待解决问题。
|
||
|
||
**对比**:
|
||
- ❌ 「用户需要搜索功能。」
|
||
- ✅ 「用户在 10,000+ 文档的知识库中查找目标文档平均需 3 分钟,效率低下;需提供搜索功能,将查找时间缩短至 10 秒以内。」
|
||
|
||
**要点**:
|
||
- 用数据或事实描述现状。
|
||
- 说明不解决的后果。
|
||
- 不在问题陈述中直接给出解决方案。
|
||
|
||
---
|
||
|
||
### 2.2 Success Metrics(成功指标)
|
||
|
||
可量化、可测量的成功标准,用于判断功能是否真正解决问题。
|
||
|
||
**对比**:
|
||
- ❌ 「搜索应该很快。」
|
||
- ✅ 「搜索 API 响应时间 P95 < 200ms;搜索结果 Top-5 相关性准确率 > 85%(基于人工标注测试集)。」
|
||
|
||
**要点**:
|
||
- 必须包含数字(时间、百分比、数量等)。
|
||
- 避免主观词汇(「好用」「快速」「美观」)。
|
||
- 每个指标须能在 AC 或后续测试中直接验证。
|
||
|
||
---
|
||
|
||
### 2.3 User Stories(用户故事)
|
||
|
||
从用户视角描述谁想做什么、为了什么价值。格式:「作为…,我希望…,以便…」
|
||
|
||
**示例**:
|
||
- 作为系统管理员,我可以创建自定义角色并分配权限组合,以便为不同部门提供差异化的系统访问能力。
|
||
- 作为普通用户,我的权限变更后无需重新登录即可生效,以便工作时不被中断。
|
||
|
||
**要点**:
|
||
- 每条故事体现独立的用户价值。
|
||
- 用户角色要具体,避免笼统使用「用户」。
|
||
- 故事不包含实现细节或技术术语。
|
||
|
||
---
|
||
|
||
### 2.4 Acceptance Criteria(验收标准)
|
||
|
||
对每条用户故事的具体验收规则,定义什么行为算完成。须采用 Given/When/Then 格式(或等效结构化场景),覆盖正常路径、异常路径和关键边界,且全部可自动化测试。
|
||
|
||
**示例结构**:
|
||
```gherkin
|
||
Scenario: 用正确密码登录
|
||
Given 用户 alice@example.com 已注册且密码为 "P@ssw0rd1"
|
||
When 她用该邮箱和正确密码登录
|
||
Then 返回 200,包含有效 JWT
|
||
```
|
||
|
||
---
|
||
|
||
### 2.5 Non-Goals(非目标)
|
||
|
||
明确本期**不**实现的范围,防止范围蔓延和过度设计。
|
||
|
||
**示例**:
|
||
- 本期不实现跨组织的权限委托。
|
||
- 不实现基于时间段的临时权限。
|
||
- 不涉及 UI 层的权限管理界面(由前端团队单独出 Spec)。
|
||
|
||
**要点**:
|
||
- 与成功指标互补:成功指标说「要什么」,非目标说「不要什么」。
|
||
- 将容易产生歧义或易被「顺手」加上的功能提前排除。
|
||
- 阻止 AI 自动添加不必要的复杂功能。
|
||
|
||
---
|
||
|
||
### 2.6 Constraints(约束条件)
|
||
|
||
技术、法规、业务等方面必须遵守的外部限制,是不可违反的边界。
|
||
|
||
**示例**:
|
||
- 必须兼容现有 OAuth2.0 认证流程。
|
||
- 权限数据存储使用现有 PostgreSQL 实例,不引入新的存储组件。
|
||
- 权限模型设计需参考 AWS IAM Policy 语法规范。
|
||
- 所有数据库查询必须使用参数化查询,禁止字符串拼接。
|
||
|
||
**要点**:
|
||
- 约束不是实现方案,而是「必须在这个框里做事」。
|
||
- 若某约束严重影响目标,须先修正约束(升级 Spec),而非绕过。
|
||
- 项目级约束放在项目级规范文档中,模块级约束放在当前 Spec 中。
|
||
|
||
---
|
||
|
||
## 3. 原子性验收标准(Atomic AC)设计
|
||
|
||
### 3.1 定义
|
||
|
||
一条原子性 AC 只描述**一个独立、完整、可单独验证的业务行为**:
|
||
|
||
- 不依赖其他 AC 的执行顺序。
|
||
- 一条失败时原因清晰,不会「一条挂、多条误伤」。
|
||
- 能一对一转化为一个自动化测试用例。
|
||
|
||
### 3.2 标准格式
|
||
|
||
推荐使用 **Gherkin** Scenario 格式:
|
||
|
||
- **Given**:前置条件,系统当前状态。
|
||
- **When**:触发动作,用户或系统操作。
|
||
- **Then**:预期结果,可观察的输出或状态变化。
|
||
|
||
### 3.3 编写原则
|
||
|
||
**① 单一职责**
|
||
|
||
一个 Scenario 只测试一个业务动作的结果。
|
||
|
||
❌ 「Given 未登录用户,When 他登录,Then 跳转首页,And 显示待办数量」
|
||
✅ 拆成两条:一条测登录成功,一条测首页数据展示。
|
||
|
||
**② 前置状态自给自足**
|
||
|
||
Given 通过数据夹具直接设定所需状态,不依赖「先执行 AC-1 再执行 AC-2」。
|
||
|
||
❌ 「Given 已通过上一个测试创建了用户」
|
||
✅ 「Given 数据库中已存在用户 alice@example.com,密码为…,登录失败次数为 3」
|
||
|
||
**③ Then 允许多个相关断言,但须属于同一结果**
|
||
|
||
✅ 「Then 返回 200,And body 中包含 access_token 字段,And token 有效期 3600 秒」
|
||
❌ 「Then 跳转首页,And 弹出欢迎提示,And 导航栏显示头像」(可能来自不同接口)
|
||
|
||
**④ 环境可恢复、隔离**
|
||
|
||
每条 AC 执行后不留影响其他 AC 的副作用;转化为测试时通过 `beforeEach/afterEach` 保证数据隔离。
|
||
|
||
### 3.4 常见反模式与修正
|
||
|
||
| 反模式 | 问题 | 修正方法 |
|
||
|--------|------|----------|
|
||
| 「用户完成整个订单流程」 | 包含浏览、加购、下单、支付多个动作 | 拆为浏览商品、加入购物车、提交订单、支付成功等多个独立 AC |
|
||
| Given 描述模糊:「系统正常运行」 | 无具体状态 | 明确系统状态,如「数据库已清空」「缓存已预热」 |
|
||
| Then 使用主观词:「页面美观」 | 不可测试 | 改为可观察行为,如「页面包含 CSS 类 primary-button」或视觉回归对比 |
|
||
| 异常场景与正常场景混在一起 | 定位困难 | 异常须单独成 AC,如「密码错误」「账户锁定」「参数缺失」 |
|
||
|
||
---
|
||
|
||
## 4. 编写流程:从六要素到可执行 Spec
|
||
|
||
### 步骤一:起草五要素
|
||
|
||
先完成除 Acceptance Criteria 外的五个要素,不急于写 AC,确保方向正确。
|
||
|
||
**输出示例(权限管理模块)**:
|
||
- Problem Statement:当前系统缺乏细粒度权限控制,无法满足不同部门差异化需求。
|
||
- Success Metrics:支持 5 种以上自定义角色;权限校验 P95 < 50ms;变更后 5 秒内生效。
|
||
- User Stories:
|
||
1. 管理员创建角色并分配权限
|
||
2. 用户权限变更后无需重新登录
|
||
- Non-Goals:不做跨组织委托;不实现临时权限。
|
||
- Constraints:必须兼容现有 OAuth2.0;使用现有 PostgreSQL。
|
||
|
||
Acceptance Criteria 暂时留空。
|
||
|
||
### 步骤二:为每条 User Story 生成原子性 AC
|
||
|
||
逐个故事展开,写出覆盖正常、异常、边界的原子性 AC。可用 AI 辅助生成草稿,但须逐条审查和修正。
|
||
|
||
以「管理员创建角色并分配权限」为例:
|
||
|
||
```gherkin
|
||
### Acceptance Criteria for User Story 1: 管理员创建角色
|
||
|
||
Scenario: 成功创建角色并分配指定权限
|
||
Given 管理员已通过 OAuth2.0 认证,且拥有「角色管理」权限
|
||
When 调用 POST /api/v1/roles,传入角色名「财务审核员」和权限列表 ["read:order", "write:order"]
|
||
Then 返回 201,角色创建成功
|
||
And 查询该角色权限,包含 "read:order" 和 "write:order"
|
||
|
||
Scenario: 创建已存在的角色名应被拒绝
|
||
Given 数据库中已存在角色「财务审核员」
|
||
When 管理员尝试创建同名角色
|
||
Then 返回 409,错误消息「角色名已存在」
|
||
|
||
Scenario: 无权限管理员无法创建角色
|
||
Given 管理员没有「角色管理」权限
|
||
When 调用创建角色接口
|
||
Then 返回 403,不产生任何数据
|
||
|
||
Scenario: 权限列表包含不存在的权限码应被拒绝
|
||
Given 系统合法权限码集合中不包含 "delete:everything"
|
||
When 创建角色时传入权限列表 ["read:order", "delete:everything"]
|
||
Then 返回 400,错误消息指明非法权限码
|
||
|
||
Scenario: 角色名为空应被拒绝
|
||
Given 管理员拥有创建权限
|
||
When 请求的角色名为空字符串
|
||
Then 返回 400,错误消息「角色名不能为空」
|
||
```
|
||
|
||
### 步骤三:反向验证覆盖度
|
||
|
||
检查所有 AC 是否覆盖 Success Metrics 和 Constraints。例如 Success Metrics 要求「权限变更后 5 秒内生效」,须有一条 AC 直接验证:
|
||
|
||
```gherkin
|
||
Scenario: 新增权限在5秒内生效
|
||
Given 用户 Alice 当前权限为 ["read:order"]
|
||
When 管理员为 Alice 新增 "write:order" 权限
|
||
And 等待不超过 5 秒
|
||
Then Alice 调用权限校验接口,返回的权限包含 "write:order"
|
||
|
||
Scenario: 移除权限在5秒内不再可用
|
||
Given Alice 拥有 "write:order"
|
||
When 管理员移除该权限,等待不超过 5 秒
|
||
Then Alice 调用权限校验,不包含 "write:order"
|
||
```
|
||
|
||
同时检查 Constraints:所有 AC 是否满足硬性约束(如上例中 OAuth2.0 认证)。
|
||
|
||
### 步骤四:迭代打磨(3–5 轮)
|
||
|
||
基于第一版 AC,生成简要实现计划或测试大纲,检查模糊、遗漏、矛盾之处,反复修订直至六要素与 AC 自洽。一般需 3–5 轮迭代。
|
||
|
||
### 步骤五:分配测试锚点(可选)
|
||
|
||
为每条 AC 分配唯一锚点(如 `[AUTH-ROLE-AC-01]`),便于在开发任务和测试代码中追溯。AC 可进一步拆解为实现任务,但与 Spec 本身解耦,属于实现计划范畴。
|
||
|
||
---
|
||
|
||
## 5. 完整示例:用户权限管理模块 Spec
|
||
|
||
```markdown
|
||
# Feature Spec: 用户权限管理模块
|
||
|
||
## Problem Statement
|
||
当前系统仅区分管理员(全部权限)和普通用户(只读),无法满足业务部门对细粒度权限的需求。需要支持至少 5 种自定义角色,每个角色可配置 20 种以上独立权限。
|
||
|
||
## Success Metrics
|
||
- 支持创建、编辑、删除自定义角色,每个角色可配置 ≥ 20 种独立权限。
|
||
- 权限校验 API 响应 P95 < 50ms。
|
||
- 权限变更后,无需用户重新登录,5 秒内生效。
|
||
- 向后兼容:现有管理员/普通用户的行为不变。
|
||
|
||
## User Stories
|
||
1. 作为系统管理员,我可以创建自定义角色并分配权限组合,以便为不同部门提供差异化访问能力。
|
||
2. 作为普通用户,我的权限变更后无需重新登录即可生效,以便工作不被中断。
|
||
|
||
## Non-Goals
|
||
- 本期不实现跨组织的权限委托。
|
||
- 不支持基于时间段的临时权限。
|
||
- 不涉及 UI 层的权限管理界面(前端团队单独出 Spec)。
|
||
|
||
## Constraints
|
||
- 必须兼容现有 OAuth2.0 认证流程。
|
||
- 权限数据使用现有 PostgreSQL 存储,不引入新组件。
|
||
- 权限模型设计参考 AWS IAM Policy 语法风格。
|
||
- 所有查询必须参数化,敏感数据不出现在日志中。
|
||
|
||
## Acceptance Criteria
|
||
|
||
### Story 1: 管理员创建角色并分配权限
|
||
|
||
Scenario: 成功创建角色并分配权限
|
||
Given 管理员已通过 OAuth2.0 认证,拥有 "role:manage" 权限
|
||
When 调用 POST /api/v1/roles,body 为 { "name": "财务审核员", "permissions": ["order:read", "order:write"] }
|
||
Then HTTP 201,响应体包含角色 ID
|
||
And 查询该角色权限列表,包含 "order:read" 和 "order:write"
|
||
|
||
Scenario: 角色名重复时创建失败
|
||
Given 数据库中已存在角色名 "财务审核员"
|
||
When 管理员尝试创建同名角色
|
||
Then HTTP 409,错误消息 "ROLE_ALREADY_EXISTS"
|
||
|
||
Scenario: 缺少必填字段
|
||
Given 管理员拥有创建权限
|
||
When 请求 body 中 name 为空
|
||
Then HTTP 400,错误消息 "NAME_REQUIRED"
|
||
|
||
Scenario: 包含非法权限码
|
||
Given 系统合法权限集合中无 "super:destroy"
|
||
When 创建角色时 permissions 包含 "super:destroy"
|
||
Then HTTP 400,错误消息 "INVALID_PERMISSION_CODE"
|
||
|
||
Scenario: 无权限管理员无法创建
|
||
Given 管理员不具备 "role:manage" 权限
|
||
When 调用创建角色接口
|
||
Then HTTP 403,无数据变更
|
||
|
||
### Story 2: 权限变更实时生效
|
||
|
||
Scenario: 新增权限在5秒内生效
|
||
Given 用户 Alice 当前权限为 ["order:read"]
|
||
When 管理员为 Alice 添加 "order:write" 权限
|
||
And 等待 ≤ 5 秒
|
||
Then Alice 调用 GET /api/v1/users/{userId}/permissions,结果包含 "order:write"
|
||
|
||
Scenario: 移除权限在5秒内生效
|
||
Given Alice 权限为 ["order:read", "order:write"]
|
||
When 管理员移除 "order:write"
|
||
And 等待 ≤ 5 秒
|
||
Then Alice 查询权限,结果不包含 "order:write"
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 质量自检清单
|
||
|
||
交付前逐项确认:
|
||
|
||
- [ ] **Problem Statement** 是否量化了痛点或机会?
|
||
- [ ] **Success Metrics** 是否包含具体数字,且每个指标可测试?
|
||
- [ ] **User Stories** 是否覆盖了所有核心用户角色和场景?
|
||
- [ ] **每条 AC 是否原子化**?能否单独运行?
|
||
- [ ] **AC 是否覆盖正常、异常、边界**?(空值、重复、权限不足、超时等)
|
||
- [ ] **Non-Goals** 是否明确了本期不做的范围?
|
||
- [ ] **Constraints** 是否列出了所有硬性技术/业务约束?
|
||
- [ ] 能否用另一种技术栈实现,而 Spec 依然有效?(说明没有泄露 HOW)
|
||
- [ ] 所有 AC 与 Success Metrics、Constraints 之间是否可追溯?
|
||
|
||
---
|
||
|
||
## 7. 常见陷阱与应对
|
||
|
||
| 陷阱 | 表现 | 应对 |
|
||
|------|------|------|
|
||
| 过度规格化 | AC 变成分步操作手册,描述实现细节 | 用「换技术栈检验法」:若 Spec 绑定特定框架或算法,删去实现细节 |
|
||
| AC 非原子化 | 一条 AC 包含多个动作,或 Given 依赖其他 AC | 坚持「一个动作,一个结果」,用数据夹具直接创建初始状态 |
|
||
| 遗漏边界条件 | 只写 Happy Path,没有异常场景 | 每个 Story 至少包含:1 条正常、1 条权限/认证异常、1 条数据边界 |
|
||
| 指标不可测 | 「系统应该快速响应」 | 改为「P95 < 200ms」或「3 秒内返回结果」 |
|
||
| Spec 腐烂 | 代码迭代了,Spec 未更新 | 将 Spec 纳入版本控制,与代码同步提交;采用增量 Spec |
|
||
| 约束与方案混淆 | 把「使用 Redis 缓存」当成约束 | 若是强制要求(如公司中间件标准)则为约束;否则归入实现计划决策 |
|