用户故事从用户目标进入需求,让人先理解这个功能为什么存在,以及用户完成什么事情才算得到价值。它不是系统输入清单,也不需要穷举用户在界面上的每一次操作。
5.1 从用户目标组织需求
一份需求可以从两个方向展开。一个方向是列操作:上传图片、识别内容、生成文字、保存结果。另一个方向是从用户实际要完成的事情进入:把能够独立表达知识的图片转换成可以检索和引用的文字证据,同时避免普通照片或装饰图进入知识内容。
这是两个不同的方向。
用户故事采用的是第二个方向。它把一个角色、一个目标和这个目标带来的价值组织在一起:
作为某类用户,我希望完成某件事情,从而获得某种价值。
因此,用户故事确实是 SPEC 的一个切入点,但它不是系统的输入。用户上传图片、填写标题、点击保存,这些才是输入或操作。用户故事描述的是这些操作共同服务的目标,讨论的是系统解决了用户的什么问题。
以独立图片为例,可以写成:
作为个人知识库的使用者,我希望系统只把能够独立表达知识的图片转换成文字证据,避免装饰图和普通照片进入知识内容。
“上传图片”“识别内容”和“保存处理结果”不需要分别成为用户故事。它们共同完成“把有效图片转换成文字证据”这个目标,应该根据各自的作用写进验收场景或功能需求。
5.2 用户故事不负责穷举所有操作
用户故事应该覆盖主要角色和核心目标,但不追求穷举用户的每一次操作。如果把每个按钮、输入和格式都写成一条故事,SPEC 很快就会变成界面操作清单,读者反而看不出系统究竟为用户解决什么问题。
一条内容合适的用户故事,应该能够独立带来一段完整价值。判断某项内容是否值得单独成为用户故事,可以检查四件事:
- 它是否对应一个独立的用户目标?
- 单独实现以后,用户是否已经能够获得完整价值?
- 它是否可以独立测试和演示?
- 它是否需要单独确定优先级?
多数答案为“是”,就适合拆成独立用户故事。否则,它更可能是一条验收场景、功能需求或边界情况。
5.3 用户故事与功能需求互相补充
用户故事和功能需求不是两种互相排斥的写法。用户故事让读者从人的目标进入系统,功能需求则保证开发时没有漏掉必须遵守的行为。
| 内容 | 负责什么 | 是否追求完整覆盖 |
|---|---|---|
| 用户故事 | 按用户目标组织主要使用路径 | 覆盖主要角色和核心目标,不穷举操作 |
| 验收场景 | 把故事落到典型条件、动作和结果 | 覆盖故事成立所需的主要路径 |
| 功能需求 | 固定系统必须执行或禁止的行为 | 应尽可能完整、明确、可测试 |
| 边界情况 | 补充特殊、模糊和容易失败的输入 | 覆盖会改变结果的重要情况 |
所以,SPEC 不需要在“完全按用户经历写”和“完全按功能列表写”之间二选一。更合适的结构是:用用户故事建立阅读入口和优先级,用验收场景呈现典型使用路径,用边界情况补上特殊输入,再用功能需求完整规定系统行为。
用户故事
用户想完成什么,以及为什么有价值
↓
验收场景
典型条件、用户动作和预期结果
↓
边界情况
特殊、模糊和容易失败的输入
↓
功能需求
系统必须执行或禁止的完整规则
5.4 不同图片不必拆成多条用户故事
流程图、普通风景图和主体模糊的图表会得到不同处理结果,但它们不一定需要拆成三条用户故事。用户的目标仍然是让系统判断独立图片能否形成文字证据。三类图片的差异,可以通过验收场景、功能需求和边界情况分别规定。
只有当某类图片带来了独立的用户价值、明显不同的使用路径,或者需要单独确定实现优先级时,才值得拆成一条新的用户故事。
下一节继续使用独立图片这个例子。前面的讨论只解释各个栏目承担什么职责,接下来会把这些内容真正组织成一份完整的 spec.md。