2.8 软件需求
Overview and motivation
软件需求是对系统为了被其利益相关者接受,必须提供、满足或具备的某项能力或条件的陈述。需求工程()引出、分析、规格化、验证并管理这些陈述的这套有纪律的工作()恰好位于价值链的最前端。从架构到代码,再到验收测试,下游的一切都是在试图满足需求。因此,当需求本身是错误的、不完整的或含糊不清时,所有用来正确地构建错误事物的努力都是纯粹的浪费,而且是代价最高昂的浪费,因为你发现它的时间最晚。软件工程知识体系(SWEBOK)的软件需求知识领域,把这当作一门真正的工程学科来对待,而不是真正工作之前的文书前奏。
对大型团队而言,需求是让众多人建造出一个连贯系统的共同理解。一名开发者可以把意图放在脑子里;分布在众多团队中的数百人则做不到。需求成为需要某项能力的人与构建它的人之间的契约,成为在团队之间划分工作的依据,也成为判断某件事是否”完成”的标尺。它们直接对接探索环节(第 11.1 章,问题和机会在此浮现)、用户体验基础(第 5.1 章,你在此理解用户需求)、API 与接口设计(第 2.3 章,接口义务在此被固定下来)、架构与质量属性(第 3.1 章,非功能性需求在此驱动结构),以及项目管理(第 10.6 章,范围、成本和进度围绕需求来规划)。
在企业和政府场景中,需求承载着法律、合同和安全层面的分量。一个受监管的系统必须证明:每一项强制性义务(无障碍、隐私、安全、记录留存、财务控制)都被捕获为一条需求、被实现,并附有证据得到验证。政府采购往往围绕一份需求规格说明书来构建,而付款、审计和认证都依赖于把每条需求追溯到证明其已被满足的证据。在这里,需求不仅仅是良好实践,它们是问责制的支柱。
Key principles
- 需求表达的是需要或约束,而不是解决方案;它说明”是什么”和”为什么”,而不是”怎么做”。
- 每条需求都必须是必要的、明确的、可验证的、可行的和可追溯的。
- 需求是与利益相关者一起被发现和协商出来的,而不是被孤立地凭空发明出来的。
- 非功能性需求和约束条件对架构的塑造,不亚于功能性需求本身。
- 需求会演变;要有意识地管理变更,而不是冻结或忽视它。
- 从需要到需求,再到设计、测试和证据的可追溯性,是问责制的连接组织。
- 恰当的正式化程度取决于风险、规模和监管背景,而不是习惯。
Recommendations
清晰地定义需求并对其分类
有意识地为各类别命名。功能性需求陈述系统必须做什么:它提供的行为、转换和服务。非功能性需求(质量属性)陈述系统必须做得多好:性能、可用性、安全性、可用性(易用性)、无障碍性、可维护性等等;这些与架构(第 3.1 章)紧密绑定。约束条件是解决方案上不可协商的边界:强制指定的技术、标准、预算、法律规则,或与现有系统的接口。此外,还要把业务需求(组织为何想要这个系统)与用户需求(用户需要完成什么)以及系统需求(软件因此必须做什么)区分开。把这些层级混在一起,范围混乱很快就会随之而来。
从真实来源引出需求,而不是从假设出发
引出(elicitation)是一种主动的发现活动。通过访谈、研讨会、观察、原型,以及对现有系统和文档的分析,从利益相关者那里获取需求。追查每一位相关的利益相关者,包括那些容易被忽视的:运维人员、审计人员、支持人员,以及那些从不直接使用系统却受其影响的人。把引出工作与探索管线(第 11.1 章)和用户体验研究(第 5.1 章)绑定起来,使表述出来的诉求能够追溯回底层的真实需要。记录每条需求的来源和理由,因为知道一条需求为何存在,正是让你日后能够安全地修改它的关键。
分析、协商并排定优先级
被引出的原始需要之间存在冲突、重叠,加总起来往往超出可行范围。分析就是你用来调和这些矛盾的过程:对需求分类、发现冲突、权衡可行性和风险,并与利益相关者协商优先级。要公开地排定优先级,比如使用”必须/应该/可以”的区分,或价值与成本的排序,这样当时间紧迫时,你砍掉的才是正确的范围。并在模型能带来清晰度的地方为需求建模:流程图、状态图、数据模型和接口定义能暴露出散文描述所掩盖的缺口。
以恰当的正式化程度撰写需求
用适合风险和受众的形式把需求写下来。一个高保证等级的政府系统,可能需要按照 IEEE 29148 这样的标准来构建正式规格说明书;而一个快节奏的产品团队,可能会把需求捕获为待办事项列表中带有验收标准的用户故事。无论哪种方式,每条需求都应当是原子的、可验证的,不含”快""用户友好”或”等等”这类含糊其辞的用语。附上验收标准,使你在撰写需求的同一时刻,就定义了如何验证它。并保持唯一的权威来源,而不是让需求散落在邮件、工单和幻灯片之间。
在构建之前先验证
验证要确认你所规格化的需求是正确的,并且相互契合。与利益相关者一起评审它们,走查各种场景,并在可能的地方使用原型把抽象的陈述变得具体。验证的成本远低于任何后期的修正:在需求评审阶段发现的缺陷,其修复成本只是生产环境中发现同一缺陷所需成本的一小部分。
管理需求并维护可追溯性
需求会变化。你的工作是控制这种变化,而不是抗拒它。建立一套变更流程:在接受每一项提议的变更之前,先权衡其影响、成本和下游效应。在约定的节点为需求建立基线并进行版本管理。保持双向可追溯性,把每条需求向前链接到设计、代码和测试,向后链接到它所源自的需要。可追溯性回答了大型团队赖以生存的两个问题:如果这项需要发生变化,会影响到什么;对于这项已交付的功能,是哪项需要证明了它的合理性?在受监管的场景中,要把这条追溯链一直延伸到验收证据(测试结果、审计记录、签核),这样你就能证明合规性,而不仅仅是声称合规。
适应敏捷和计划驱动的场景
在计划驱动和受监管的项目中,你会相当早地规格化并为需求建立基线,并配以正式的变更控制。在敏捷场景中,需求以一份经过优先级排序、不断演进的待办事项列表的形式存在,在实现之前不久才被细化,并通过可运行的软件持续得到验证。两种场景中的底层活动是相同的;不同的只是时机、正式化程度和交付物。大型组织常常将两者结合:对稳定的、高保证等级的义务进行正式的规格化和追溯,同时对产品行为进行迭代式细化。应根据风险而非意识形态来选择平衡点。
Trade-offs: pros and cons
| 方案 | 最适用于 | 优点 | 缺点 |
|---|---|---|---|
| 正式的前期规格说明 | 高保证等级、受监管、范围固定的合同 | 可追溯性强;有清晰的验收依据;可审计 | 变更缓慢;有在尚未学到东西之前就过度规格化的风险 |
| 敏捷待办事项列表 | 利益相关者深度参与的持续演进型产品 | 反馈快;能适应新的认知;未构建范围上的浪费更少 | 长期可追溯性较弱;更难审计和签约 |
| 混合式(正式约束 + 敏捷行为) | 义务混杂的企业 | 在紧要处保持严谨,在其他地方保持灵活 | 需要判断哪些部分属于哪一类 |
核心张力在于稳定性与学习之间的权衡。早早固定需求能为你换来坚实的验收依据和可审计性,但代价是丧失了根据构建过程中所学到的东西进行调整的能力。推迟固定需求能换来适应性,但代价是长期可追溯性和合同层面的清晰度。在需求工程上投入更多,也是在用短期速度换取日后更少的返工:随着系统规模、生命周期和失败后果的上升,这种权衡就会变得划算。最大规模的项目和受监管程度最高的项目,都坚定地站在高投入的一侧。而一个低风险的内部工具则不然。
Questions to discuss with your team
对我们风险最高的系统而言,谁算作利益相关者?我们又总是把哪些人遗漏到验收阶段才想起? 在大型项目中,被遗漏的人很少是显而易见的用户:他们是凌晨三点运行系统的运维人员、必须为其做认证的审计人员、处理故障的支持人员,以及那些从未登录过、但你持有其数据的受影响的非用户。漏掉他们,你就会在最昂贵的时刻()验收阶段,或监管机构询问之后()才发现他们的需求。把一份具体的利益相关者图谱带到会议上并对其进行压力测试:对于每一项强制性义务(无障碍、隐私、记录留存、安全),说出负责它的人,以及捕获它的那条需求。如果你说不出负责人是谁,你就发现了一个缺口,正确的做法是现在就把这位利益相关者纳入引出工作,而不是日后把他们的需要硬塞进一个已经固定的架构中。
当一条需求发生变化时,我们能否在批准这项变更之前,先说清楚它会影响什么? 这是检验你们的双向可追溯性是真实存在还是徒有其表的实用测试。在一个大型或受监管的系统中,单条规则的变化可能波及设计、代码、测试和验收证据,盲目批准正是你交付出一个表面合规、实则悄悄违反了它曾经满足过的某条规则的系统的方式。把最近的一项变更请求带到会议上,尝试当场向前追溯:如果这需要花上一整个下午做考古式的调查,那你们的可追溯性就没有发挥应有的作用。答案应当促使你重塑变更流程,使影响评估变成对一条实时追溯链的一次快速查询,而不是一场人工搜寻,也让基线和版本管理为你提供一个稳定的变更起点。
我们需求的唯一权威来源存放在哪里?有多少真相散落在它之外? 需求扩散(真正的规格说明散落在邮件、工单、幻灯片和某个人的记忆里)是大型团队最常见的失败之一,在需要接受审计的系统中更是致命的。要明确地说出来:哪个系统记录才是权威的,在需求落地到该系统、并附上来源和理由之前,凡是在其他地方陈述的一切都只算草稿。带上证据:数一数最近有多少次范围争议,最终归结为两个人各自引用不同的”最终”版本。如果这个数字大于零,行动就是把需求归并到一个来源,并为每条需求写下理由,因为知道一条需求为何存在,正是让你日后能够安全地修改或删除它的关键。
我们的非功能性需求是否足够早地被捕获,从而能够驱动架构,还是我们总是在结构已经固定之后才发现它们? 性能、可用性、安全性和无障碍性方面的义务,对架构的塑造往往超过大多数功能,而在大型项目中,它们恰恰是最常被过晚发现的需求()往往等到本应满足它们的结构已经被浇筑成型之后。这里存在真实的相互竞争的拉力:功能性行为是利益相关者会大声提出、也容易演示的东西,而”峰值负载下亚秒级响应”或”符合 WCAG 无障碍标准”这样的需求,在被违反之前是不可见的。带上你们风险最高系统当前的非功能性需求清单、每一项被写下的时间点,以及架构(第 3.1 章)是把它们作为明确的驱动因素接收,还是靠推断得来。在企业和政府场景中,再加上强制性的质量义务(加密、记录留存、无障碍法规),检查每一项是否都是一条书面的、可衡量的、交给设计方的需求,而不是一种假设,因为在验收之后才补做质量属性,正是预算和进度悄悄死去的地方。
对我们拥有的每一个系统而言,什么样的正式化程度才是合适的?我们是依据风险来选择,还是依据习惯? 一个大型组织通常同时运行着一系列系统,从一个可随意丢弃的内部工具,到一个关乎生命安全的受监管平台,对所有系统套用同一种仪式,要么让低风险的工作被文书工作淹没,要么让高风险的工作规格不足。这里的张力在于正式前期规格说明的可审计性和坚实验收依据,与不断演进的待办事项列表所带来的快速反馈和更少浪费之间的权衡,而对大多数企业而言,诚实的答案是一种有意识的混合:对稳定的、高保证等级的义务进行正式化和追溯,同时对产品行为进行迭代式细化。带上一份简短的系统清单,按失败后果、监管暴露程度和变化速率排序,并为每一个系统说明你们实际采用的正式化程度,与风险所要求的正式化程度是否一致。对于锚定在招标书和 IEEE 29148 之类标准之上的政府项目,正式化程度部分是由合同规定的,因此讨论的重点应放在:可以在不破坏审计所依赖的可追溯性的前提下,在哪些地方叠加敏捷式细化。
我们风险最高系统中的每一条需求都能被验证吗?每一条是否都附有在需求撰写的那一刻就写下的验收标准? 一条你无法验证的需求不是需求,而是一个愿望,“快""安全”或”用户友好”这类含糊其辞的用语之所以能通过评审,恰恰是因为没有人能让它们不及格。对大型团队而言,这一点具有双重意义:不可验证的需求会在验收阶段引发范围争议,也使得你无法说清一项功能究竟何时算真正完成。相互竞争的考量是速度,因为为每条需求附上可衡量的标准和验证方法,比撰写一段散文要慢一些,但这是抵御日后最昂贵返工的最廉价防线。带上最近的一批需求样本,用一个简单的标准逐条检验:它是原子的吗?它是可衡量的吗?它是否说明了将如何被检查?在受监管和政府场景中,把这个检验延伸到证据层面:一条没有可追溯、通过的验收证据的需求,无论软件表面看起来如何,都不能算作已交付,因此验收标准正是你最终必须提交的合规记录的种子。
Sector lens
创业公司。 在团队小、跑道有限的情况下,把需求维持在你能承受的最轻量水平:在一个共享的待办事项列表里写带验收标准的用户故事,而不是一份规格说明文档。即便在这个规模上也值得坚持的纪律是:在构建之前先与真实用户交谈,并记录每个故事的来源和理由,这样你原本可能浪费在构建错误功能上的那一周,就变成了被节省下来的一周。可以跳过正式的可追溯性,但绝不要跳过那场告诉你真实需要是什么的对话。
小型企业。 你们很可能没有业务分析师或需求专家,因此这项工作落在离客户最近的人身上,而”买”还是”造”的问题会主导一切。把需求框定为一份简短的、按优先级排序的所需成果清单,然后用它来评估现成工具,而不是用来规格化一次定制开发。要严格区分底层需要和某个供应商的功能列表,因为一条写成”我们需要产品 X”的需求,会悄悄地排除掉本可以满足真实需要的更便宜的选项。
企业。 规模把需求变成了让众多团队建造出一个连贯系统的契约,因此优先事项是一套被一致应用的标准流程:明确的分类、从需要到测试的双向可追溯性、单一权威来源,以及带有基线的受控变更。明确区分业务、用户和系统这几个层级的需求,把非功能性需求作为驱动因素交给架构,这样范围和质量方面的义务就不会散落在各个团队之间。把针对稳定、高保证等级义务的正式规格说明,与产品行为的敏捷式细化结合起来,并依据风险而非某个团队的个人偏好来治理这种平衡。
政府。 采购规则往往把整份合同都建立在一份需求规格说明书之上,且常常按照 IEEE 29148 之类的标准来构建,因此精确性和完整性是合同要求,而非可选项。维护一份需求可追溯性矩阵,把每条需求链接到设计、测试用例和验收证据,因为供应商付款、审计和运营授权都依赖于被证明的覆盖率。透明度和公共问责制进一步抬高了门槛:无障碍、隐私和记录留存方面的强制性义务,都必须各自呈现为一条明确的、可验证的需求,而一条没有可追溯、通过的证据的需求,就根本算不上已交付。
Examples
创业公司。 一家四人的创业公司正在构建一款日程安排应用,他们把需求捕获为共享待办事项列表中带验收标准的用户故事,而不是一份正式规格说明。在撰写日历同步功能之前,创始人花了一个下午与五位潜在客户交谈,了解到真正的需要是避免在两个工具之间出现重复预订,而不是他们原本假设的同步本身。这一次对话就重新定义了这个故事,省下了一周构建错误功能的时间。即便在这样的规模上,他们也会写下每个故事的来源和理由,这样当优先级发生变化时,他们就能在不必重新论证其存在理由的情况下,砍掉或重做范围。
企业。 一家跨国银行正在替换其贷款发放平台。需求团队把业务需求(缩短审批时间、满足放贷法规)、用户需求(信贷员需要在一个视图中比较各种报价)与系统需求(该平台必须与三个核心系统集成)区分开来。非功能性需求(常见查询的亚秒级响应、99.95% 的可用性、个人数据加密)被明确捕获,并作为驱动因素交给架构(第 3.1 章)。每条需求都通过待办事项列表被追溯到自动化验收测试。因此当监管机构询问某条具体的放贷规则是如何被执行的时,团队只需沿着追溯链,从该规则一路查到验证它的测试即可。
政府。 某国家机构通过一次正式招标采购一套福利资格审核系统。合同锚定在一份按 IEEE 29148 构建的需求规格说明书上,涵盖功能性的资格规则、强制性的无障碍合规要求、隐私和记录留存方面的约束,以及安全控制措施。一份需求可追溯性矩阵把每条需求链接到设计要素、测试用例和验收证据。供应商付款和运营授权(在生产环境中运行该系统的正式批准)都依赖于被证明的覆盖率。一条没有可追溯、通过的验收证据的需求,无论软件表面看起来如何,都不被视为已交付。
Business case: motivations, ROI, and TCO
需求工程的经济学论证,建立在晚期修复缺陷的成本之上。行业研究一致发现,需求缺陷是项目失败最常见、也是代价最高的原因之一,而修复一个缺陷的成本,从需求阶段到生产环境会以数量级的方式攀升。因此,花在澄清和验证需求上的钱,其实是一种杠杆:早期的适度投入,能让你免于构建、测试和运维错误的东西。
需求的总拥有成本,包括在系统整个生命周期中持续投入的引出、规格化、工具和变更管理工作;这不是一次性成本。与之相对的,是糟糕需求所带来的成本:返工、范围争议、进度超支、验收失败、合同罚款,以及在受监管场景中的罚金或授权丧失。对领导层而言,应把需求成熟度定位为风险降低和可预测性。追踪需求波动率、缺陷来源,以及可追溯到经过验证的需要的已交付工作占比,并把这些与项目管理预测(第 10.6 章)联系起来。这份回报不会以一项功能的形式出现,它会以从未发生过的失败和返工的形式出现。
Anti-patterns and pitfalls
- 伪装成需求的解决方案: 规定某项特定技术或界面布局,而不是底层需要,从而排除了更好的选项。
- 含糊其辞的语言: “快""安全""直观”却没有任何可衡量的标准,使需求变得不可验证。
- 镀金: 捕获没有任何利益相关者真正需要的需求,抬高了范围和成本。
- 遗漏非功能性需求: 直到架构已经固定之后,才发现性能、安全或无障碍方面的义务。
- 需求扩散: 真相散落在邮件、工单和幻灯片之间,没有权威来源。
- 冻结或失控的变更: 要么拒绝一切变更,要么不经影响评估就接受每一项变更。
- 没有可追溯性: 无法说清一项变更会影响什么,或一项功能为何存在,这在需要审计的系统中是致命的。
- 分析瘫痪: 无休止的规格化,延误了从可运行软件中学习的机会。
- 被忽视的利益相关者: 运维人员、审计人员和受影响的非用户,直到验收阶段才被想起。
Maturity model
- 第 1 级,启动。 需求是隐含或口头的,捕获方式不一致且被动。范围争议和返工很常见;没有可追溯性、没有验收标准,也没有明确定义的流程。
- 第 2 级,发展。 一些团队会把需求写下来并按项目追踪,配有基本的优先级排序和临时的变更处理。实践确实存在,但因团队和个人而异,因此类别、正式化程度和质量在整个组织内并不一致。
- 第 3 级,标准化。 一套标准的需求流程被记录成文并在全组织范围内强制执行:明确的分类、引出与验证实践、在撰写时就附上的验收标准、单一权威来源,以及从需要到测试的双向可追溯性,并根据敏捷或计划驱动的场景做出一致的调整。
- 第 4 级,管理。 该流程被数据度量并加以控制。需求波动率、缺陷来源、可追溯性覆盖率,以及可追溯到经过验证的需要的已交付工作占比,都相对基线被追踪;可追溯性延伸到验收证据和合规性;需求相关指标反馈进项目预测(第 10.6 章),使变更和质量决策建立在证据而非意见之上。
- 第 5 级,编排。 需求实践在整个组织内被持续改进并深度集成。正式化程度依据风险和结果被自适应地调整,引出和可追溯性工具与探索、架构和交付相连接,组织利用自身的度量历史,在需求缺陷到达代码之前就阻止其反复出现。
Ideas for discussion
- 当一位资深利益相关者把某个方案当作需求来陈述时,你如何分辨出这是一项真正的需求,还是一个过早出现的解决方案?
- 对你们风险最高的系统和风险最低的系统而言,什么样的需求正式化程度才是合适的?由谁来决定?
- 在一个快速变化的敏捷待办事项列表中,你如何在不使其变成官僚式负担的前提下,保持双向可追溯性的实时性?
- 在你们组织中,哪些非功能性需求最常被过晚发现?为什么?
- 在一个受监管的项目中,什么样的验收证据才算充分证明一条需求已被满足?
- AI 辅助的引出与规格化工具,应当如何改变你们的需求实践?它们又带来了哪些新的风险?
Key takeaways
- 需求陈述的是需要和约束,而不是解决方案;它们必须是必要的、明确的、可验证的和可追溯的。
- 区分功能性、非功能性和约束条件这几类需求,以及业务、用户和系统这几个层级。
- 从真实的利益相关者那里引出需求,进行分析和排定优先级,以恰当的正式化程度规格化,在构建之前验证,并管理变更。
- 从需要到验收证据的双向可追溯性,是问责制的支柱,在受监管场景中尤其如此。
- 敏捷和计划驱动的场景共享同一套活动;区别只在于时机、正式化程度和交付物,因此应依据风险来选择。
- 糟糕需求的成本会在后期支付,并被放大;及早投入是对抗返工和验收失败的杠杆。
References and further reading
- IEEE and ISO/IEC, Guide to the Software Engineering Body of Knowledge (SWEBOK), Software Requirements knowledge area
- Karl Wiegers and Joy Beatty, Software Requirements
- ISO/IEC/IEEE 29148, Systems and software engineering: Life cycle processes: Requirements engineering
- Suzanne Robertson and James Robertson, Mastering the Requirements Process
- Dean Leffingwell, Agile Software Requirements
- Mike Cohn, User Stories Applied
- Ian Sommerville, Software Engineering(需求工程相关章节)