safety-eval-service/docs/spec指导手册.md

374 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 高质量 Spec 编写指南
**核心原则**:人定义 WHATAI 实现 HOWSpec 是唯一的真实来源。
---
## 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 返回 200And 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 认证)。
### 步骤四迭代打磨35 轮)
基于第一版 AC,生成简要实现计划或测试大纲,检查模糊、遗漏、矛盾之处,反复修订直至六要素与 AC 自洽。一般需 35 轮迭代。
### 步骤五:分配测试锚点(可选)
为每条 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/rolesbody { "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 MetricsConstraints 之间是否可追溯?
---
## 7. 常见陷阱与应对
| 陷阱 | 表现 | 应对 |
|------|------|------|
| 过度规格化 | AC 变成分步操作手册,描述实现细节 | 用「换技术栈检验法」:若 Spec 绑定特定框架或算法,删去实现细节 |
| AC 非原子化 | 一条 AC 包含多个动作,或 Given 依赖其他 AC | 坚持「一个动作,一个结果」,用数据夹具直接创建初始状态 |
| 遗漏边界条件 | 只写 Happy Path,没有异常场景 | 每个 Story 至少包含:1 条正常、1 条权限/认证异常、1 条数据边界 |
| 指标不可测 | 「系统应该快速响应」 | 改为「P95 < 200ms」或「3 秒内返回结果」 |
| Spec 腐烂 | 代码迭代了,Spec 未更新 | Spec 纳入版本控制,与代码同步提交;采用增量 Spec |
| 约束与方案混淆 | 把「使用 Redis 缓存」当成约束 | 若是强制要求(如公司中间件标准)则为约束;否则归入实现计划决策 |