开始

实例化需求说明的原则和实践主要影响软件交付团队中的人员沟通,以及他们如何同使用者和项目干系人进行协作。

通常遇到的主要是人的问题,而不是技术问题。

在企业中应用任何一项技术时,首要的法则是,在有效率的系统中导入自动化,将使效率倍增。第二条法则是,在缺乏效率的系统中导入自动化,会使效率更低下。

正确地构建产品和构建正确的产品是两码事。我们要二者兼顾才能取得成功。实例化需求说明可以帮助团队构建正确的软件产品,而技术实践可以确保正确地构建产品。

主要优点

从长远来看,实例化需求说明有助于团队创建一个活文档系统,它是一种具有相关性的、可靠的功能描述,会随着程序代码的变更自动更新。

实例化需求说明的实践配合短迭代(Scrum、极限编程)或基于流的开发方法(看板)一起使用,效果最好。有些思想也适用于结构化开发过程[统一软件过程(RUP)、瀑布过程]。

想要有效地构建正确的产品,软件开发实践必须满足以下几点:

  • 保证所有项目干系人和交付团队的成员都对需要交付哪些东西有一致的理解。
  • 有准确的需求说明,这样交付团队才能避免由模棱两可和功能缺失造成的无谓返工。
  • 有用来衡量某项工作是否已经完成的客观标准。
  • 具有引导软件功能或团队结构变更的文档。

需要能够做到:

  • 避免过度说明需求从而产生浪费,避免花时间在开发前会发生改变的细节上。
  • 有一种可靠的文档,可以解释系统的行为,据此我们能容易修改系统行为。
  • 可以有效地检查系统行为与需求说明的描述是否一致。
  • 以最少的维护成本维持文档的相关性与可靠性。
  • 适合短迭代和基于流的过程,这样能为即将开展的工作提供即时足够的信息。

对于敏捷项目,构建正确文档的关键因素:

png

实例化需求实践的收益:

  • 更有效地实施变更
    • 实例化需求说明能够在适当的时间提供恰好够用的文档,帮助使用短迭代或基于流的开发过程构建正确的产品。
  • 更高的产品质量
    • 他们清晰地定义了预期,使得验证过程很有效率。
    • 建立开发人员和测试人员之间的信任。
  • 更少的返工
    • 他们在需求说明上协作得更好,并确保所有团队成员对预期达成共识。
    • 使用实例化需求说明后,通常团队第一次实现的就是客户所要的,无需返工。
    • 节省大量的时间,并使得交付流程更具可预测性、更加可靠。
  • 同一项目不同角色的活动协调得更好
    • 改善协作形成定期的交付流程。

关键过程模式

  • 实例化需求说明是一组过程模式,它可以协助软件产品的变更,确保正确的产品能够有效地交付。
  • 实例化需求说明的主要过程模式是从目标中获取范围、协作制定需求说明、举例说明、提炼需求说明、自动化验证时不修改需求说明、频繁验证以及演进出活文档系统。
  • 对于实例化需求说明而言,功能需求、需求说明和验收测试都是一回事。其结果是一个活文档系统,它解释系统可以做什么,并且与编程语言代码一样确切和可靠,但更容易理解。
  • 不同背景的团队使用不同的实践来实施过程模式。

png

  • 从目标中获取范围
    • 不盲目接受需求,而要将其作为未知问题的解决方案。
    • 以客户的业务目标为起始,然后通过协作办公室可以实现目标的范围。
    • 团队与商业用户一起工作确定解决方案。商业用户专注于商业目的和价值,团队提议解决方案。
  • 协作制定需求说明
    • 成功的团队不会依赖于某个人独自去收集正确的需求,而是会与商业用户一起协作制定解决方案。
  • 举例说明
    • 成功的团队不会等待需求被精确表述,而会举例说明需求。
    • 团队与商业用户一起工作,确定出那些描述预期功能的关键实例。
    • 如果关键实例容易理解和沟通,就可以被有效用作清晰和详细的需求。
  • 提炼需求说明
    • 提炼需求说明,成功的团队能够移除多余的信息并为开发和测试创建一个具体的、精确的上下文。
    • 他们以适量的细节来定义目标,以便实现和验证。
    • 他们应明确软件该做什么,而不是软件该如何工作。
    • 提炼好的实例可以当作交付的验收条件。只有当所有实例在系统中都可以正常工作时,开发才算完成。
  • 自动化验证时不修改需求说明
    • 测试就是需求说明,需求说明就是测试。
    • 使用同一个文档获取商业用户的澄清。
    • 如果我们要变更需求说明,只要在一个地方变更即可。
  • 频繁验证
  • 演化出一个文档系统
    • 活文档是关于系统功能可靠的、权威的信息源,任何人都可以获得。
    • 它和代码一样可靠,但是更容易阅读和理解。

开始改变

如何开始改变过程:

  • 把实施实例化需求说明当作更广阔的过程变更的一部分。
  • 专注于提高质量。先找出提高软件质量的最大阻碍,然后解决这个问题。
  • 从功能测试自动化开始。
  • 引入一个可执行需求说明的工具。
  • 使用测试驱动开发作为踏脚石:可执行的需求说明就是针对业务功能的测试。

如何开始改变团队文化:

  • 避免使用“敏捷”术语。实施过程变更无需技术术语,只需使问题变得显而易见,同时逐渐把大家推向解决问题的正确方向上。
  • 确保你得到管理层的支持。
  • 把实例化需求说明当作是比执行验收测试更好的方式来推销。
  • 不要让测试自动化成为最终的目标。
  • 不要太关注工具。
  • 在迁移过程中,遗留脚本也要有人维护。
  • 跟踪哪些人在运行(以及没有运行)测试自动检查程序。

团队如何在流程和迭代中集成协作:

  • 通过快速周转来提供快速反馈和重点。高效地完成软件的一小块,而不是试图一次性处理一大块。
  • 强调有效、高效的沟通,而不是冗长、乏味的文档。
  • 建立共享所有权,这样在需求说明变成代码或测试的过程中,开发人员与测试人员不会互不通气。
  • 整合跨职能团队,为了制定正确的系统需求,测试人员、分析师和开发人员一起进行工作,而非各自为战。

处理签收和可追溯性:

  • 在版本控制系统中保存可执行需求说明。
  • 通过导出的活文档来签收。
  • 签收的是范围,而非需求说明:比方说,签收用户故事或用例。
  • 在“精简的用例”上签收。
  • 引入用例实现。

警告信号:

  • 注意频繁改动的测试
    • 如果后台的代码更改了,他们会认为那个测试是一个良好的测试。
    • 如果测试更新了而源代码没有更新,他们会认为那是一个不好的测试(需求有变等其他原因造成的)。
  • 当心回退
    • 回退是指一个故事或者产品功能清单中的项目,在发布后不到一个月的时间内又返回到项目过程中。
    • 团队认为已经完成了,但事实上仍需要返工。
    • 将来出于业务需要对产品进行创新、演进,而对现有的需求进行扩展,不属于回退。
  • 注意组织级的失调
    • 一旦熟悉了可执行需求说明,并且自动化代码变得稳定之后,应该可以在同一个迭代中完成一个故事,并彻底做好测试工作(包括人工的探索性测试)。
    • 如果测试人员滞后于开发,那就做错了。
  • 当心“以防万一”的代码
    • 通过交流沟通,以及持续不断地检查,从我们当前所做的当中是否可以看出清晰的商业模式。
    • 通过领域建模,你可以很容易地分解出任务。那些任务是你唯一需要做的。
  • 注意霰弹式修改
    • 尽量避免对一个类做很小的改动后,你又需要对几个相关的类作出一系列改动。

关键过程模式

从目标中获取范围

当需求作为任务分配给你时,先停一停.请获得必要的信息,以便理解真正的问题, 然后进行协作设计解决方案。

如果无法避免任务式需求,请先想办法获取到高层次的实例,解析需求如何起作用。如此将有助于理解谁以及为什么需要这些需求,这样你才能设计解决方案。

为了获取适当的范围,请考虑一下当前这个里程碑的商业目标,想一想哪些项目干系人可以出一份力,又有哪些项目干系人会受到这个里程碑影响。

以系统的输出为出发点,可以让商业用户更多地参与进来。

把组件团队改组为能够交付完整功能的团队。

调查新兴技术,包含特性注入、用户故事映射以及效应映射,以便有效地从目标中获取范围。

大多喜欢把需求描述成解决方案;他们很少会去讨论想要达到的目标,或者亟待解决的问题具有什么特殊性质。我见过太多的团队有一种危险的误解,他们认为客户总是正确的,客户要求的东西总是一成不变的。这导致很多团队盲目地接受客户建议的解决方案,然后竭尽全力去实现。成功的团队不会那么做。

成功的团队先推开那些需求,获取更多实际问题的信息,然后进行协作,设计出方案。他们对待范围也是如此,范围隐含着解决方案,成功的团队不会把定义范围的责任推到其他人身上,他们会积极协作,同商业用户一起,确定良好的范围,以期达到他们的目标。这就是从目标中获取范围的本质。

在构建正确软件产品的过程中,确定范围扮演着重要的角色。没有正确的范围,其余的工作只是在做无用功。确定范围很适合基于价值链的设计过程,价值链的概念由于精益软件开发的普及而越来越受到欢迎。

构建正确的范围

需要注意的是每个故事应该拥有一个明确关联的商业价值。商业用户常常随意地选择价值的表达方式(它通常是冰山一角)。但是当我们知道故事应当交付什么的时候,就可以更深入地调查研究并提出替代解决方案。

  • 理解“为什么”和“谁”
    • 理解为什么有人需要某个特定的应用程序以及他们将如何使用,往往能得到更好的解决方案。
  • 理解价值从何而来
    • 比起只在故事层次上进行讨论,在目标层次上进行讨论能使团队更加高效地处理范围和优先级。
  • 了解商业用户预期的输出是什么
    • 当很难确定目标的时候,预期系统的输出是比较有用的出发点:研究为什么需要这些输出以及软件如何提供这些结果。
    • 一旦你明确了期望的输出,就可以专注于实现这些输出背后的需求, 分析为什么需要这些输出结果可以帮助你构想出项目的目标。
    • 我们应该从输出结果的实例开始着手,而不要和商业用户一起讨论如何往系统里增加某些东西。这将帮助商业用户加入到讨论中来,并让他们对系统的输出有一个清晰的认识。
  • 让开发人员提供用户故事的“我想要”部分
    • 商业用户给出故事中的利益相关者和期望的价值,开发团队给出隐含解决方案的部分。
    • 在标准的用户故事格式中,这意味着商业用户提供“作为……”和“为了……”语句,开发人员提供“我想要……”语句。

在没有高层次控制权的情况下,协作确定范围

  • 询问“为什么这些东西有用?”
  • 询问替代方案
  • 不要只顾最低层次的需求
  • 确保团队交付完整的功能

通过协作制定需求说明

协作制定需求说明是一个非常好的方法,可以对我们需要完成的内容建立共识,并确保系统的各个方面都被包含在需求说明中。协作还有助于团队制定易于理解的需求说明和容易维护的测试。

实例化需求说明非常依赖于商业用户和交付团队成员之间的协作。

交付团队的所有人都要对需求说明的正确性负责。开发人员和测试人员必须提供关于技术实现和验证方面的建议。

大多数团队协作制定需求说明分为两个阶段:有人事先准备功能的初始实例;然后该功能的项目干系人进行讨论,并添加实例来澄清或完成需求说明。

事先准备工作与协同工作之间的平衡,要根据以下几个因素来定:产品的成熟度、交付团队的领域知识水平、典型更改需求的复杂度、过程瓶颈以及商业用户是否有空。

最热门的协作模型

  • 尝试大型的全体工作坊
    • 适用于:从一开始就使用实例化需求说明时.
    • 团队全体参加的大型需求说明工作坊是建立共识并获取实例最有效的途径之一,那些实例对功能进行了详细的描述。
    • 在工作坊中,程序员和测试人员可以了解业务领域。商业用户开始理解系统的技术约束。由于团队全体的参与,工作坊可以有效地利用商业利益相关者的时间,并且以后不再需要做知识传递。
  • 尝试小型工作坊
    • 适用于:需要频繁地澄清领域问题时.
    • 如果领域逻辑很复杂,程序员和测试人员需要频繁澄清,那么由一个人单独负责编写测试,甚至还包括审核,就不是一个好的方法。
    • 举办小型的工作坊,由一个开发人员,一个测试人员和一个业务分析师参与
  • 结对编写
    • 适用于:成熟的产品.
    • 分析师可以提供正确的行为,而开发人员知道编写测试的最佳方式,这样之后就可以很容易地进行自动化并融入到活文档系统的其余部分中。
  • 让开发人员在迭代开始前频繁地审查测试
    • 适用于:分析师编写测试时.
    • 让资深的开发人员审查需求说明。
  • 尝试非正式交谈
    • 适用于:商业项目干系人随时都在的时候.
    • 只要有任务相关的人员参加非正式的交谈就足够了,这样就可以对所需完成的內容建立起清晰的定义。

准备协作

png

1 举办介绍会

有众多项目干系人的团队(例如,当软件使用者涉及公司多个部门,或者软件需求是由多个外部的客户所驱动的),一般来说需要在迭代开始前几天举办介绍会。有些团队把这个会议叫做预先计划会议。

介绍会的目的是为即将要做的故事收集一些初始的反馈,并从计划中筛选掉一些需求模糊不清的故事。

介绍会的目的并不是为了得到精炼的需求说明,而是给团队提供足够的时间,对那些可以快速定位的关键问题来收集外部反馈。这不是迭代计划会议或Scrum计划会议。在sprint开始前几天举办介绍会,团队就有机会在真正提炼需求说明或计划会议之前和外部的项目干系人一起讨论一些开放性的问题。

2 邀请项目干系人

团队交付的产品都达到了业务分析师或产品负责人的期望,但是这些期望往往不是最终用户想要的。在我看来,业务分析师是交付团队的一部分,而非客户代表。要获得最佳效果,实际的项目干系人都要参与到协作需求说明中。他们是真正能做决定的那些人。

3 进行具体的准备工作并事先审查

项目干系人远离团队的时候,团队至少应该有一个人负责事先准备具体的实例。

4 让团队成员尽早审查故事

如果团队发现他们没有足够的信息来编写可执行的需求说明,就得有人能较早地提供分析。这个人不必是业务分析师或领域专家,他可以是测试人员或开发人员。

5 只准备初始的实例

项目干系人都有空回答问题时,团队不需要花太多的时间事先准备详细的实例。但他们发现,为了在讨论前获取到基本的结构,确定一些初始的实例仍然是非常有用的。

确定初始的实例能帮助我们获得需求说明的基本结构,并可以让讨论更加高效。

6 不要让过度的准备阻碍了讨论

准备阶段应该是为了让协作更加高效,而不是用来代替协作的。因为测试人员是从组合功能性回归检测的角度来看待可执行的需求说明,所以有些团队事先准备的信息太多了,他们找出了测试中输入参数所有可能的组合。

复杂的需求说明难以理解,所以大多数人在这些需求说明中发现不了功能分歧以及不一致的地方。

使用复杂的需求说明,事先分析的效果就如同传统需求从分析师传递到开发人员一样。开发人员只是拿到需求,而非协作构建共识,这将导致误解的产生,而且很有可能到过程晚期才发现功能分歧。

选择协作模型

决策因素:

  • 产品的成熟度如何?
  • 团队拥有多少领域知识?
  • 典型的更改需要多少分析?
  • 商业用户和开发团队有多近?他们是否有空讨论并验证实例?
  • 过程中的瓶颈在哪儿?

不成熟的产品需要大型的工作坊和大量的事先分析。对于不成熟的产品,让测试人员和开发人员更积极地帮助定义需求说明很重要,因为底层系统变化频繁,而这些人员拥有商业用户所没有的洞察力。

成熟产品可以有较少的事先分析,可以考虑其他的协作模型。成熟产品可能意味着较少的意外。业务分析师和产品负责人大多十分了解技术能给他们带来什么,而且他们可以事先很好地准备实例。

如果团队比较新或测试人员和开发人员对商业领域的知识了解得不够,那么做大型工作坊就比较值得。在把商业领域知识有效传授给整个团队方面,全体工作坊是一个非常好的方式。一旦团队更好地理解了商业领域,那么小型的、比较专注的讨论可能就足够了。

如果典型的更改需要大量的分析,那么应该有个担任分析师角色的人先于团队与项目干系人一起准备详细的实例。否则,工作坊中的讨论都会结束得很快,并留下大量未解决的问题。如果要开发的是相对较小且能够被充分理解的功能,那么事先准备一些基础实例来让讨论更加流畅,可能也就足够了。

举例说明

例子是避免沟通问题的好工具。如果我们自始至终都能够捕获所有的例子,并在分析、开发和测试中一致地使用它们,那么我们就可以避免进入传话游戏中(而导致信息失真)。

对需求进行举例说明的方法比抽象的陈述说明来得更有效。因为例子是具体的、明确的,所以它们是制定精确需求的理想工具,这就是为什么我们在日常交流中用其来澄清意思的原因。检验需求是否完整的最好方法是试着对其设计黑盒测试。如果我们没有足够多的信息去设计出好的测试用例,那么我们也绝对没有足够多的信息来构建系统。那些用来说明需求的例子就是很好的黑盒测试。

  • 始终使用同一组例子贯穿需求说明、开发以及测试阶段,以确保全体人员对需要交付的内容有同样的理解。
  • 用于说明功能的例子必须精确、完整、真实以及容易理解。
  • 比起在实施阶段才发现问题,真实的例子有助于更快地发现不一致的地方和功能分歧。
  • 有了一组初始的例子后,就可以立即使用数据进行试验,同时可以寻找替代方法来测试一个功能,以便完成需求说明。
  • 当例子很复杂并且例子太多或者出现太多因素时,你就要寻找缺失的概念并尝试使用更高层次的抽象来解释例子。使用一组集中的例子来单独说明新的概念。

例子必须精确到位

好的例子可以帮助我们避免模棱两可。要做到这一点,必须完全没有误解。每个例子都必须清晰地定义好上下文以及系统如何在一个给定的情况下工作,并且理想情况下这种描述必须很容易进行校验。

1 不要在例子中出现“是/否”的回答

提防例子中出现“是/否”的回答,试着将其重写得更加精确到位。

2 避免使用等价抽象类

不要使用等价类,要使用有代表性的具体的例子。具体的例子让我们可以无需修改就直接自动化需求说明的验证,并能确保所有团队成员达成共识。

例子必须完整

  • 用数据作试验
  • 使用替代方法来检验功能

例子必须要真实

  • 避免虚构自己的数据
  • 直接从客户那里获得基本的例子

例子应该易于理解

1 避免探讨所有可能的组合

当举例说明需求时,寻找那些可以推进讨论并增进理解的例子。

2 寻找隐含的概念

如果用来描述某个功能的例子太多了,或者所用的例子很复杂,往往意味着这些例子应该用更高层次的抽象来描述。

应该仔细查看这些例子,并且试着找出缺失和隐含的概念。将这些概念显式化,并单独对它们进行定义。重整这类例子会使需求说明更易理解,并带来更好的软件设计。

无论何时看到一个需求说明里有太多或太复杂的例子,你可以试着提高这些描述的抽象层次,然后另行说明基本概念。

描述非功能性需求

1 取得精确的性能需求

清晰地指定性能条件和举例说明可以帮助我们建立共识,并可以给开发团队提供清楚的目标实现。

2 为UI使用低保真度的原型

3 试用QUPER模型

QUPER使用成本、价值和质量的坐标轴来可视化按比例缩放的需求。该模型的思想是对可以按比例缩放的需求进行成本效益断点和障碍的评估,使大家可以去讨论这种需求。

为可以按比例缩放的需求定义障碍点和断点,可以让我们就产品适舍市场中的什么位置以及我们的市场定位是什么做出更有意义的讨论。

4 讨论时使用核查清单

在评审一个故事的时候,为讨论准备一份核查清单可以确保你将所有重要问题都纳入了考虑的范围。你可以用它来判定哪个交叉关注点适用于某个特定的故事,而后你就可以重点描述这些方面了。

5 建立一个参照的例子

举例说明不可量化的功能,行之有效的一种方式是建立一个参照的例子。

总而言之,不要使用“非功能性需求”的分类来避免艰难的对话,要确保团队对商业用户对系统的预期(包括交叉的关注点)达成一个共识。即使最终的例子以后不易进行自动化,我们还是有必要进行前期讨论,并使用例子来明确化和精确化用户的预期,这样可以确保交付团队专注于构建正确的产品。

提炼需求说明

理想情况下,带实例的需求说明应该从业务角度出发清晰地定义所需的功能,而不是去定义系统应该如何实现细节。这样,开发团队才可以自由地找出符合需求的最佳方案。要达到这样的目标,需求说明应该满足以下条件:

  • 精确、可测
  • 是真正的需求说明,而不是脚本
  • 是关于业务功能的,而不是关于软件设计的

一旦完成了某个功能,描述它的需求说明就会派上其他用场。它将成为系统功能的文档,并提醒我们功能退化的情况。为了发挥它作为长期功能文档的用处,我们所编写的需求说明必须能让其他人在创建数月甚至数年之后拿起依然能很容易地理解它在做什么、为什么需要它,以及它所描述的是什么。因此,需求说明应该是:不言而喻的、专注的、使用领域语言编写的。

  • 不要直接使用最初的实例,要对它们进行提炼,以得出需求说明。
  • 为了充分利用实例,最终的需求说明应该是精确的、可测的、不言自明的、专注的,并以领域语言编写,同业务功能相关。
  • 在需求说明中要避免使用脚本,避免谈及软件设计。
  • 不要试图覆盖所有用例。需求说明不是用来替代组合回归测试的。
  • 所有重要的用例集,都要先从一个例子开始着手,并增加值得程序员和测试人员特别关心的例子。
  • 在需求说明、软件设计以及测试中定义并使用统一语言。

提炼需求说明时要关心什么:

1 实例要精确可测:需求说明必须基于精确的、实际的例子

2 脚本不是需求说明

脚本解释如何测试某个东西。它通过与系统较低层次的交互描述业务功能。脚本要求读者从操作开始向上推导,理解什么是真正重要的,以及它到底在描述什么。脚本还会把测试与工作流及session约束混合在一起,即使背后的业务规则不变,将来它们仍有可能会改变。

需求说明解释系统在做什么。它以最直接的方式去关注业务功能。需求说明较短,因为它们直接描述业务概念。这让它们比脚本易于阅读和理解。同时需求说明比脚本稳定得多,因为工作流与session约束的改变不会影响到它们。

3 不要使用流程式的描述

要提防流程式的描述(先做这个,然后做那个……)。除非你是在制定一种真正的处理流程,否则这通常是使用脚本来描述业务规则的信号。这样的脚本会造成许多长期维护的问题。

要提防关于系统应该如何工作的描述。我们应当去考虑系统应该做什么。

4 需求说明应关注业务功能,而不是软件设计

5 避免编写与代码紧密耦合的需求说明

6 不要在需求说明中引入技术难点的临时解决方案

把技术难题放到自动化层去处理。不要试图在测试说明中解决。

7 不要陷入到用户界面的细节里

不要老想着用户界面的细节,考虑用户在站点上的操作过程会更加有用。协作制定需求说明时,应当按照各部分内容对业务的重要程度来投入与此相称的时间。重要的、高风险的东西应该仔细探索而不必对那些不重要的东西定义得那么精确。

8 需求说明应该是不言自明的

9 使用叙述性标题并使用短篇幅阐释目标

在需求说明开始的地方节省笔墨可以产生很大的改观,还可以为今后节约许多时间。

如果需求说明只包含输入与预期的输出,那么阅读这份文档的人就不得不从实例中重建出业务规则。

为需求说明选择一个具有叙述性的标题是至关重要的。标题应该要总结出需求说明的意图。

10 展示给别人看并保持沉默

检查需求说明是否是不言自明的

为了检查需求说明是否是不言自明的,可以让其他人来察看文档并试着理解它,而你什么都不要说。

为了确保需求说明真的能不言自明,可以请其他人来解释他们对需求的理解,看看是否符合你的意图。

当我向别人展示需求说明的时候,如果我发现自己必须给他们作解释,我会写下这些解释并将它们放到头部。解释这些实例通常会驱使我使用更有意义的名字,或者我会插入一些注解,以便让实例更易于理解。

11 不要过度定义实例

对于需求说明而言,定义3个良好的关键实例比定义100多个蹩脚的实例来得更加有用。

不要试图覆盖所有情况。

12 从简单的例子入手,然后逐步展开

13 需求说明要专注

一个需求说明应该单独描述一件事情:一条业务规则、一个功能,或者过程的一个步骤。专注的需求说明比那种定义多个相关规则的需求说明要容易理解。同时需求说明应该只专注于例子的关键属性,这些属性对其试图展示的内容来说必须是非常重要的。

专注对于需求说明有两个重要的好处。首先,专注的需求说明比较简短,因此相对于长的、不够专注的需求说明来说更容易理解。其次,它们还更易于维护。当系统有关的所有方面中某一方面有所变动时,一个覆盖多个规则的需求说明会受到影响,这会让基于此需求说明的自动化测试遭受更为频繁的破坏。更糟糕的是,当这样的测试失败时,很难找到问题的症结。

14 在需求说明中使用“Given-When-Then”语言

一般来说,一个需求说明应该要声明上下文环境,指定一个单一的动作,然后定义好预期的后置条件。

可以提醒我们这么做的一个好方法是使用Given-When-Then或者Arrange-Act-Assert。Given-When-Then是定义系统行为的一种常见格式,它由早期的关于行为驱动开发的文章推广开来。它要求我们以3个部分来编写系统行为的场景:

  • 假定(Given)一个前提
  • 当(When)某个行为发生时
  • 那么(Then)后置条件就会得到满足

15 不要在需求说明中明确建立所有依赖

把所有跟需求说明的目标不相干的依赖全部移入到自动化层中,并保持需求说明只专注于重要的属性和对象。

16 在自动化层中应用缺省值

创建有效的对象是自动化层的职责。

自动化层可以使用合理的缺省值预先填充对象,并建立起相关依赖,这样我们就不必显式地对它们进行说明。这使得我们在编写需求说明的时候只关注于重要的属性,以让需求说明更容易理解和维护。

17 不要总是依赖缺省值

如果一个实例的关键属性与自动化层提供的缺省值相匹配,尽管可以省略,但显式地对其进行说明仍然是明智的做法。

18 需求说明应使用领域语言

自动化验证而不修改需求说明

  • 自动化提炼好的需求说明时必须尽量减少改动。
  • 自动化层应该定义如何进行测试,而需求说明则应该定义要测试什么内容。
  • 使用自动化层执行业务语言与用户界面、API和数据库之间的转换。为需求说明创建更高级别的可重用组件。
  • 尽可能在用户界面之下进行自动化。
  • 除非万不得已,否则不要太依赖于现存数据。
  • 可执行需求说明的自动化验证完全不同于开发人员和测试人员常用的单元测试、录制与脚本化的功能自动化。自动化的同时保留可读性,需要团队学习如何使用新的工具并探索将自动化契合到系统中的最好方式。

从自动化开始

  • 为了学习工具,先尝试一个简单的项目
  • 事先计划自动化
  • 不要拖延自动化工作或将其委派他人
  • 避免根据原有的手动测试脚本进行自动化
  • 通过用户界面测试赢得信任

管理自动化层

  • 别把自动化代码当作二等公民
  • 在自动化层里描述验证过程
  • 不要在测试自动化层里复制业务逻辑
  • 沿着系统边界自动化
  • 不要通过用户界面检查业务逻辑
  • 在应用程序的表皮之下进行自动化

对用户界面进行自动化

  • 以更高层次的抽象来详细说明用户界面的功能
  • UI需求说明只检查UI功能
  • 避免录制的UI测试
  • 在数据库中建立环境

管理测试数据

  • 避免使用预填充数据
  • 尝试使用预填充的引用数据
  • 从数据库获取原型

频繁验证

专用的持续集成系统会频繁地构建产品并运行测试以确保系统不仅仅在开发人员的机器上运行正常。这一实践通过快速地找到潜在问题让我们保持在正确的道路上,并在必要时只要采取小而廉价的措施就可以纠正。持续集成可以确保产品在被正确地构建起来后,能始终保持正确。

同样的原则也可以应用到构建正确的产品上。一旦构建了正确的产品,我们就要确保它一直正确。当它偏离设计的方向时,只要我们能尽早地知道,就可以更容易更廉价地解决问题,不让问题累积起来。我们可以频繁地验证可执行的需求说明。持续构建的服务器可以频繁地检查所有的需求说明,并保证系统始终符合需求。

  • 要频繁地验证可执行需求说明,以确保它们的可靠性。
  • 相比用单元测试做持续集成,持续验证的两大难点是快速反馈和稳定性。
  • 请建立独立的持续验证环境,并使部署完全自动化,使其更为可靠。
  • 想办法获得更快的反馈。分开快速和缓慢的测试,为当前迭代的需求说明创建测试包,把运行时间较长的可执行需求说明集合拆分成更小的集合。
  • 不要只是禁用失败的测试。要么修复问题,要么把测试挪到低优先级的回归测试包并密切进行监控。

提高稳定性

1 找出最烦人的问题并将其解决掉,然后不停地重复

不要想一下子就解决问题,更有效的策略是一个迭代一个迭代地做些小的改变。

一个迭代一个迭代地提高稳定性是构建可靠验证过程的好方法,同时又不会过多地妨碍交付流程。这种方法还可以让我们在提高系统可测性的过程中不断学习并适应。

2 用CI测试历史找到不稳定的测试

只要可执行需求说明在持续构建(CI)系统中运行,我们就可以从测试的运行历史中看到哪些测试最不稳定。

3 搭建专用的持续验证环境

没有专用的环境,很难知道测试失败是由于存在缺陷、由于有人对测试环境做了改变,还是由于系统不稳定所导致的。专用的环境可以排除计划外的改变,并可以降低环境不稳定的风险。

4 使用全自动部署

全自动部署可以确保升级只有唯一的标准流程,同时可以确保所有的开发人员拥有和测试环境一样的系统部署。

5 为外部系统创建较简单的测试替代品

6 选择性地隔离外部系统

选择性地隔离一些外部服务可以让测试更快,故障排除更容易。

7 尝试多级验证

要使用多级验证。每个团队都应该有隔离的持续验证环境,任何变更都应该先在那里进行测试。

8 在事务中执行测试

数据库事务可以隔离外界的影响。

9 对引用数据做快速检查

专门设置一组完全独立的测试来验证引用数据是否与我们期望的一致。

10 等待事件,而非等待固定时长

要可靠地验证异步过程,需要在自动化层(通常是在生产系统中)进行一些计划和细心的设计。对异步系统的测试,我们经常会见到的错误是花一定时间等待某件事情发生。症状之一是存在“等待10秒”这样的测试步骤。

去等待一个事件的发生,而不要等待一段时间的流逝。这会使测试可靠得多,而且不会造成不必要的反馈延迟。

11 将异步处理变成可选

有个提高测试稳定性的好方法,就是将异步处理作为一个可选项。

12 不要用可执行需求说明做端到端的验证

不要在一个大的可执行需求说明中同时测试太多东西。

获得更快的反馈

  • 引入业务时间
  • 将较长的测试分割成较小的模块
  • 避免使用内存数据库做测试
  • 把快速的和缓慢的测试分开
  • 保持夜间测试的稳定
  • 为当前迭代创建一个测试包
  • 并行运行测试
  • 禁用风险较低的测试

管理失败的测试

  • 创建已知失败了的回归测试包
  • 自动检查那些被禁用的测试

演化出文档系统

  • 了尽可能发挥活文档系统的优势,请保持其一致性,并确保单个可执行需求说明易于理解,并且任何人都能方便地访问,包括商业用户在内。
  • 演化并使用统一语言,保持一致性。
  • 随着系统的演进,请注意冗长的需求说明,或者几个小的只有细微差别的需求说明。寻1找更高抽象级别的概念会让这些事情更容易阐释。
  • 将活文档系统组织成层次化结构,可以很容易地找出当前迭代的所有需求说明,以及之前实现的所有功能。

活文档必须易于理解

  • 不要创建冗长拖沓的需求说明
  • 不要使用许多小的需求说明来描述单个功能
  • 寻找更高层次的概念
  • 避免在测试中使用技术上的自动化概念

活文档必须前后一致

  • 演化出一种语言
  • 将需求说明语言拟人化
  • 协作定义语言
  • 将构建模块文档化

活文档必须组织得井井有条,便于访问

1 按用户故事组织当前的工作

如果你使用可执行需求说明的自动化工具,那么将目前正在进行的工作归类在一起通常是一种很好的做法。按层次结构归类需求说明,我们就可以将此类需求说明以测试包的形式快速执行。

通常一个用户故事需要我们更改多处功能区。例如,一个关于改进注册功能的用户故事,它可能影响后端的用户报表以及系统验证年龄的行为。也可能需要实现与PayPal和Gmail的新的集1成。所有这些功能都应该由独立的并且专门的需求说明来描述。同时对于每个用户故事的时间完成标准还要有清晰的定义。与一个用户故事相关的所有内容都应该归类在一起,以便容易地执行所有这些测试。

2 按功能区域组织用户故事

很多团队在完成可执行需求说明后,会按功能区域对其进行重新组织,使其具有层次结构。这样浏览基于业务功能的层次结构就可以很容易地找到一个功能的详细解释。

以功能区域(比如付款和用户管理)组织的活文档层次结构。当前迭代的需求说明是以用户故事和功能来组织的。一些还需等待更多信息的已知问题,也可以单独放在一个分支里:

png

3 按用户界面的导航路径组织

4 按业务流程来组织

5 引用可执行需求说明时请使用标签而不要使用URL

思想总结

  • 协作制定需求能在项目干系人与交付团队之间建立信任
  • 协作需要事先准备
  • 协作的方式多种多样
  • 将最终目的视为业务流程文档,不失为一种有用的模型
  • 活文档带来的长期价值数式编程简介

参考

版权声明:本文为博主原创文章,转载请注明出处。 旭日酒馆