💡阅读指南

需求简报与 SPEC 最重要的区别,不是一个简略、一个详细,而是 SPEC 必须把产品判断写成可以验收的行为约定。这一节先看清一份 SPEC 由哪些部分组成,以及这些部分分别解决什么问题。

4.1 不是概要版与详细版的区别

在一般的软件工程语境里,SPEC 本身就是一种需求规格文档。因此,这里比较的并不是“需求文档”和“SPEC”,而是需求发现阶段形成的需求简报与 Spec Kit 生成的正式 spec.md

需求简报负责记录产品判断。我们要解决什么问题,为什么要做这个功能,第一版保留什么、放弃什么,都应该在需求简报中讨论清楚。SPEC 根据已经确认的需求继续展开,把其中含糊的地方变成可以测试和验收的系统行为。

所以,两者不能简单理解成“概要版”和“详细版”。需求简报也可以写得很长,SPEC 也可以很短。真正的分界线,在于这份文档能不能作为开发与验收之间的明确约定。

文档 核心职责 主要回答的问题
需求简报 完成产品判断 为什么做、服务谁、做什么、保留什么、放弃什么
SPEC 固定可验收的产品行为 在什么条件下,系统必须产生什么结果

它们与后续开发工作的关系可以写成:

Text
需求简报
完成产品决策
    ↓
SPEC
把产品决策转换成无歧义、可验收的行为约定
    ↓
Plan / Tasks
决定怎样实现,并拆成开发任务

如果一份需求简报已经写出了完整的验收场景、功能规则和边界处理,那么它实际上已经开始承担 SPEC 的职责。文档叫什么并不是关键,关键是它能不能让开发者和验收者对同一个结果达成一致。

4.2 一份 SPEC 通常包含哪些栏目

按照本项目使用的 Spec Kit 模板,一份 spec.md 通常包含下面这些栏目:

栏目 是否必需 需要写清的问题
基本信息 必需 功能名称、创建日期、当前状态、原始需求输入是什么
用户故事 必需 谁在什么场景下,希望完成什么事情,为什么值得优先实现
独立测试 每个用户故事必需 只实现这一条用户故事时,怎样单独验证它已经产生用户价值
验收场景 每个用户故事必需 在什么前提下发生什么动作,系统必须产生什么结果
边界情况 按需求填写 哪些异常、模糊或临界输入容易让系统产生不同解释
功能需求 必需 系统必须具备哪些行为,又明确禁止哪些行为
关键实体 涉及数据时填写 系统处理哪些核心对象,这些对象记录什么,并且有什么关系
成功标准 必需 达到什么可衡量结果,才能确认这个功能整体成功
假设与依赖 按需求填写 当前 SPEC 依赖哪些前提,哪些合理默认并未在需求简报中明确

文件开头还会记录功能分支、创建日期和草稿状态。这些属于文档管理信息,不直接参与功能验收。真正决定 SPEC 质量的,是用户故事、验收场景、功能需求和成功标准能否互相对应。

一个 SPEC 可以包含多个用户故事。每个用户故事都有自己的优先级、独立测试和验收场景;功能需求负责汇总整个功能必须遵守的规则,成功标准则从整体上判断这个功能是否达到了预期。不能给每一条小需求机械复制一整套栏目。

生成 SPEC 时还可能出现 [NEEDS CLARIFICATION]。这不是正式栏目,而是提醒我们某个重要选择尚未确定。产品负责人确认答案以后,应该把结果写回验收场景、功能需求或假设,正式 SPEC 中不能继续保留这类标记。

4.3 范围边界、边界情况与功能需求

这三个概念很容易混在一起,因为它们都可能出现“不处理”或者“不得处理”这样的表述。判断它们属于哪一类,不能只看句子里有没有“不”字,而要看它正在限制什么。

我以前也经常搞不清楚这三者的区别,所以写 SPEC 文档的时候很困惑。程序员都会有这样的问题,但这是必须要搞清楚的。

范围边界限制的是对象、场景和职责。它回答的是:这件事归不归当前功能负责?例如,独立图片处理功能只负责没有正文、图注或用户说明作为上下文的图片。用户同时提交了说明文字,这张图片仍然可以由系统处理,但不再归独立图片功能负责。

边界情况描述的是范围内那些容易产生歧义、失败或异常的输入。例如,一张图片有标题,主体却模糊不清。它仍然属于独立图片,只是系统很难判断它能否形成完整证据。

功能需求限制的是系统行为。它规定系统面对范围内的对象时必须做什么,以及明确禁止什么。例如,一张普通风景图仍然属于独立图片,系统也需要接收并判断它;判断完成后不得生成文字证据。这是一条负向功能需求,不是范围排除。

可以用一句话记住它们的区别:

范围边界排除的是对象和职责;边界情况描述的是特殊输入;功能需求规定的是系统行为。

同一问题可能同时出现在边界情况和功能需求中,但承担的职责不同。边界情况记录“图片主体模糊”这种特殊输入,功能需求则规定系统面对它时应该标记为待确认,并且不得编造文字证据。

Spec Kit 没有要求把范围边界单独设为固定标题。它可以写在用户故事、功能需求或假设中,也可以在范围复杂时增加一个独立栏目。无论放在哪里,都必须明确哪些对象属于当前功能,哪些对象不属于。

下一步需要继续理解用户故事。它是读者进入 SPEC 的主要入口,但并不负责穷举用户的每一次输入和操作。