3.1 从问题陈述到可验证需求
需求工作要让团队对问题、边界、优先级和验收方式形成可验证的共同理解。文档的长度并不能替它完成这件事。一个需求如果不能说明谁需要它、为什么需要、怎样判断完成,就还不足以指导实现。
先区分问题、需求与方案
三句话看起来相近,所处层次却不同:
问题:报名高峰时,管理员要手工合并多个表格,容易重复录入。
需求:管理员能在报名截止后得到一份去重且可追溯的参赛名单。
方案:使用 Redis Set 保存报名者 ID。前两句描述业务处境与期望能力,第三句已经选择技术。过早把方案写成需求,会让团队跳过替代方案,也很难判断方案是否真的解决了问题。
一页问题陈述
在拆用户故事前,先写一页短说明:
| 项目 | 要回答的问题 |
|---|---|
| 目标 | 哪个结果需要改变? |
| 利益相关者 | 谁使用、运营、购买、审计或承受风险? |
| 当前流程 | 现在怎样完成,痛点在哪里? |
| 系统边界 | 本系统负责什么,不负责什么? |
| 约束 | 法规、期限、预算、既有系统和技术边界是什么? |
| 成功信号 | 上线后怎样知道问题得到改善? |
| 未知项 | 哪些假设仍需访谈、原型或实验验证? |
“用户”只是利益相关者的一类。运维人员关心恢复和诊断,安全人员关心权限边界,财务人员关心结算可核对性;这些关注点都会形成需求。
用户故事是讨论入口,不是完整规格
常见格式是:
作为 <角色>,我想要 <能力>,以便 <价值>。例如:
作为参赛者,我想取消尚未截止的报名,以便在无法参赛时释放名额。这张卡片只提供讨论索引。真正需要确认的内容包括:截止时间按哪个时区计算、取消后是否允许重新报名、费用怎样退回、管理员代取消是否留下审计记录。
技术工作也有价值,但不要勉强伪装成“作为系统,我想要……”。可以把数据库迁移、可观测性改造等作为工程任务,并链接到它支持的风险、质量属性或用户故事。
用示例消除歧义
下面是可保存为 cancellation.feature 的 Gherkin 规格,使用英文关键字和中文步骤。它还需要 step definitions 与被测实现才能执行;单有场景文本不代表验收通过。Given–When–Then 用来描述可观察行为:
Feature: 报名取消
Scenario: 截止前取消已确认的报名
Given 参赛者 A 有一条状态为 CONFIRMED 的报名
And 赛事报名截止时间为 2026-08-10T18:00:00+08:00
And 当前时间为 2026-08-10T17:59:00+08:00
When 参赛者 A 取消报名
Then 报名状态变为 CANCELLED
And 赛事可用名额增加 1
And 系统记录操作者、操作时间与原报名编号还需要反例和边界:
- 截止时刻本身是否允许取消;
- 已取消的请求重试时返回成功还是冲突;
- 退款失败时,报名状态与退款状态怎样组合;
- 两个取消请求并发到达时,名额只能释放一次。
这些问题可以先形成一组待确认的选择,再补成场景:
| 条件 | 示例约定 |
|---|---|
| 首次取消恰好发生在截止时刻 | 拒绝;不释放名额 |
| 已成功取消后以同一幂等键重试 | 返回原结果;名额总共只增加 1 |
| 两次取消并发 | 至多一次完成状态转换和名额释放 |
| 取消成功但退款暂时失败 | 报名保持 CANCELLED;退款进入可重试状态 |
首次操作的时间以服务端作出业务判定的时钟为准;测试注入固定时钟,不依赖墙上时间刚好走到某一秒。是否允许退款失败后保留取消结果,仍需业务方确认,不能由测试作者默默决定。
验收示例应描述外部可观察结果。若它断言某个私有方法调用了三次,测试已经越过需求边界进入实现细节。
功能需求之外:质量属性
“系统要快、稳定、安全”无法验收。质量属性需要放进具体场景。SEI 常用六个要素描述质量属性场景:刺激源、刺激、环境、受影响对象、响应和响应度量。
下面是一个待利益相关者确认的示例,数字不是通用标准:
| 要素 | 示例 |
|---|---|
| 刺激源 | 已登录观众 |
| 刺激 | 请求当前积分榜 |
| 环境 | 决赛直播期间,3,000 个并发会话 |
| 对象 | 排名查询接口及其依赖 |
| 响应 | 返回不超过 5 秒前的排名快照 |
| 度量 | 5 分钟窗口内 p95 延迟低于 300 ms,成功率不低于 99.9% |
3000 个会话没有说明每秒请求数。还可约定持续 5 分钟、每秒发起 1500 次查询,并固定数据规模、请求分布和超时;这组假设共发起 450000 次请求。延迟从客户端发起到接收完整响应计时,超时和拒绝也计入请求总体及失败数;新鲜度超过 5 秒的响应不能只因 HTTP 成功就算合格。不要只拿缓存命中的成功样本作图。
度量必须说明统计窗口和负载条件。只有“平均延迟 100 ms”会掩盖尾延迟,也没有说明在什么流量下成立。
常见质量属性还包括可用性、可修改性、安全性、可测试性、可观测性和成本。它们经常互相牵制:更强一致性可能增加延迟,更细审计会增加存储与隐私治理成本。需求阶段要暴露权衡,不是许诺所有指标同时最大化。
约束、偏好与假设不要混写
约束:支付数据必须留在指定区域。
偏好:团队熟悉 PostgreSQL,希望优先复用。
假设:首年峰值写入不超过每秒 200 次。约束通常不能绕开;偏好可以在收益足够时改变;假设需要验证并设置复审触发条件。把三者都写成“必须”,会制造没有依据的架构限制。
建立领域词汇表
如果“比赛”“场次”“报名”“参赛资格”在产品、代码和数据库中各有不同含义,图画得再精美也无法消除误解。词汇表至少记录:
Tournament(赛事):一次有报名窗口和赛程的竞赛活动。
Match(对局):赛事内两名参赛者的一次对战。
Registration(报名):参赛者申请参加某赛事的记录。
Eligibility(参赛资格):允许报名必须满足的规则集合。词汇不是一次性文档。需求、API、事件和监控指标应尽量使用同一语言;含义变化时记录变更影响。
从需求到可追踪交付
一个轻量追踪链可以是:
业务目标
-> 用户故事 / 质量属性场景
-> 验收示例
-> 架构决策与接口契约
-> 实现、测试和运行指标追踪的目的不是给每一行代码编号,而是在需求变化或生产指标失守时,能找到受影响的决策与验证手段。
进入架构设计前的最小产物
- 一页问题陈述与明确的系统边界;
- 利益相关者及其关键关注点;
- 排过优先级的用户故事和验收示例;
- 可度量的关键质量属性场景;
- 约束、偏好、假设及验证计划;
- 领域词汇表和仍未解决的问题。
这些内容不会消除变化,但会让变化可见。下一节据此选择架构视图,并记录真正影响系统结构的决策。