时间: 2021-07-30 11:22:03 人气: 5 评论: 0
实例化需求不仅解决了需求分析和撰写的问题,也给出了需求沟通和澄清的方法。本文从实例化需求的定义出发,从使用实例化需求的原因、实例化需求的产生输出、自动化测试和操作流程这几个方面对实例化需求进行了说明介绍,与大家分享。
实例化需求的英文是 Specification by Example,简称 SBE,直译过来就是用实例说明需求。
实例化需求是一组方法,它以一种对开发开发团队有所帮助的方式(理想情况下表现为可执行的测试)描述计算机系统的功能和行为,让不懂技术的利益相关者也可以理解,即使客户的需求在不断变化,它也具有很好的可维护性,可以保持需求的相关性。从而帮助团队交付正确的软件产品。
为避免需求沟通过程中的「知识诅咒」,“实例化需求”方法从场景出发,以用户的操作实例来澄清需求。
相比一般的规格说明,实例更加场景化,能够激发参与和深度讨论;同时,实例是具体的,其典型形式是:「在什么情况下,做什么操作,**得到什么结果」。基于具体的实例,更加便于沟通中的双向确认,保证理解的一致和场景覆盖。
上图是对实例化需求的概念说明:
如此形成闭环,这个三角是实例化需求的核心概念。
在「实例化需求」中,开发、测试和业务人员一起沟通需求,避免信息传递的噪音和损耗。
实例化需求的核心是,让项目的所有干系方进行有效的协作和沟通,用实例的方式说明需求,用自动化测试的方式频繁地验证需求,从实例化的需求说明和自动化测试用例中演进出一套“活文档系统”。这套“活文档系统”既可以有效地对系统进行说明,又可以当做交付验收的标准。
实例化需求有9个过程模式:从目标获取范围、协作产生需求说明、举例说明、提炼需求说明、在不修改需求说明的情况下实现自动化验证、频繁验证、以及演化出一个活文档系统。这 9 个过程模式涉及了如下的输出(制品):目标和范围、需求说明、例子、自动化测试及活文档系统。
下面我们一个个来详细说明。
实例化需求的第一步“澄清价值”,它包含两个子步骤:
针对目标和问题的典型挑战性检验是:
认真回答上面两个问题,往往能挖掘出需求的本质,确保我们在解决的是真正的用户或业务问题。
在实践中,我们所产生的“需求说明”更具体的体现形式是:
工作流也称为业务流程或业务场景,是用户通过一系列步骤,达成系统业务目标的一种实现方式。在实例化需求工作坊中,参与人员在白板上使用顺序图、活动图、带有泳道的活动图等方式,共同绘制出工作流。当然,如果工作流足够明显,也可以直接采用业务用例的形式,列出标题,理清它们之间的先后关系即可。
简单来说,就是为了实现上面的目标,系统需要支持哪些用户操作?这些操作的流程是什么样的?具体分为两个子步骤:
1)列出用户的操作。产品的功能体现为它所支持的用户操作,列出用户操作,可以涵盖其功能性需求。如下图,我们通过用例图描述了用户的操作。用例图定义了为完成特定目标,操作者和系统之间的交互,它包含操作者和操作两个部分。
用例是需求工程中获取和列举功能需求最常用的手段之一,如果不习惯用例的表示法,更简单的方法是直接列出用户和用户的操作。
2)画出用户操作的流程步骤。这一步的目的是:定义操作的具体交互流程。下图使用了活动图和时序图两种形式,来表达操作步骤。其中,活动图形式上与流程图类似,只不过它表达的是用户操作流程,而不是技术实现流程;时序图则在表达系统间的交互方面更胜一筹,例如针对金融类系统的需求,可以用时序图表示系统间的资金往来和记录存取等。
活动图示例
带泳道的活动图示例:
时序图:
这两种表示法,都表示了操作的步骤,团队应该灵活选取适合的表达方式,当然也可以选取其它表示法如通信图、状态机等。
状态机:
用户注册通信图:
针对操作和步骤的典型挑战性检验是:
或者就是简单地采用列表的形式,列出几个相关的用户场景:
绘制工作流的目的不是为了描述,而是为了信息发现和挑战(challenge, 这里是褒义),即既有的工作流是否合理,是否存在遗漏,是否需要进一步讨论其中的业务数据和业务规则,等等。
在上面的工作流中,我们可以看到的挑战包括:
回答上述挑战的过程,事实上是一个需求澄清的过程,它也**对应的更新工作流、领域模型和业务规则。在进行挑战和回答挑战的过程中,也一般都**包含了对每个业务流程或规则背后的业务价值的讨论,以及紧急程度的讨论。例如:
在上述案例中,一个可能的讨论结果是:代理商的多管理员功能虽然是需要的,但是在当前阶段可以暂缓实现,等等。
大多数讨论都是很热闹的,但是效果却不尽相同。其实,热闹的背后是七嘴八舌还是井然有序,常常是因为概念引起的。大多数人都有过这样的经验:两个人争论的面红耳赤,但是最终发现我们说的其实根本不是一件事情!或者发现我们说的其实就是同一个观点!根本就无需争论!
在讨论中,我们常常看到有这么一种人能够打破僵局,推动讨论:“来,让我们看看每个人说的是什么”。
每个人在内心所建的概念的差异,往往是导致争论的根源。
领域模型有很多方面的价值,但是让我们首先聚焦于它所表达的概念,对业务实体和它们之间的关系进行建模。例如下面的这个领域模型:
有了上述的模型,当我们在讨论中说到代理商基本信息的时候,所有人就都知道哪些是基本信息。说到子代理商的时候,所有人都知道子代理商其实也是一个代理商。这其实就是领域驱动设计(Domain Driven Design, DDD)中所讲述的“统一语言”的应用。
同时,领域模型带来的统一语言,使得业务规则讨论变得更加精确,也更加高效。
例如:如果子代理商权限为”无“,则代理商不能创建子代理商。代理商可以查询子代理商的基本信息。
像上面的这种模型如何获得?尽管存在各种各样的方法,例如关注需求描述中的名词等等,但是可以肯定的一点是,模型是通过讨论获得的。它是持续演进的结果。这个过程常常是这样一个模式:
具体领域模型使用 UML(统一建模语言)表示法,并体现为不包含操作的类图,领域模型由三个要素构成:
实例化需求的最重要输出是需求验收标准,它们可以表达为一条条的业务规则。上一步,我们已经列出了操作和操作步骤,用它们来组织业务规则非常合适,对于操作中的主要步骤,团队可以列出它们的业务规则。
最常见的业务规则可以表达为三段式的结构,也就是「Given(当),When(如果),Then(那么)」。比如:
实例的形式表达场景和业务规则,这是”实例化需求“这个词的来源。之前对用户操作步骤的分析,正好可以用来组织这些实例。上图所示,正是按操作步骤分别列举对应的实例(业务规则)。
这些实例可以用条目化的方式表达。同时,当规则组合较多时,可以将他们抽取为数据表格。上图中关于”共同贷款人审查“这一步骤的规则,就被抽象成了表格。这一方面让规则更清晰和易于理解;另一方面,将来表格在映射为测试用例时,能自然的做到测试流程和测试数据分离,更易于阅读、维护和扩展。
以上列出的都是功能性的需求和规则。在实际过程中可能还**涉及非功能性需求,如可用性、可靠性、性能、安全性等。非功能性需求大部分体现在系统级别,而实例化需求针对的是单个需求。实例化需求过程中,一般只需要列出与特定功能相关的非功能性需求,如针对某一特定操作的特定安全性和性能要求。
针对业务规则的典型挑战性检验是:
先来一起看一下某测试:
这是一个反例。需求必须精确,不能在用户故事开始实现时仍处于模糊的状态。例如,付款支票应该包括哪些信息?这属于领域建模的范畴,应该通过领域模型予以回答。除此之外,我们仍然**提出下面的一些问题,例如:付款支票日期究竟应该使用发薪日期还是当前日期?工资发放的计算规则是否在本需求范围内?付款支票号码的编号策略有没有什么要求?等等。
即使一个看起来很清楚的需求,我们也建议举一两个实际的案例来说明。就像下面这种图**展示的那样:
举例说明是项目需求交流过程中不可或缺的,团队中的人领域背景不同,对同一个事物的理解也可能不尽相同,通过举例说明的方式可以让目标更一致。
功能模块的例子必须具有精确性(不是简单的是或否的答案,使用具体的例子)、真实性(使用真实数据,从客户那儿获取真实的例子)、完整性(使用不同的数据组合去试验,利用其他方式去检验和测试),并易于理解(不用试验所有组合,寻找隐含的概念)。
虽然协作过程中的需求讨论可以建立大家对相关领域的共识,但得到的实例往往包含很多不必要的细节。关键实例是从这些实例中提炼出来的,虽然精简但足以说明业务的实例。并且这些提炼好的实例本身就可以当作交付的验收条件。
一个好的需求说明的例子:
一个劣质的需求说明的例子:
根据原则改进的例子:
在传统的流程中,庞大的需求说明往往跟不上实际开发中的需求变更,导致需求文档在交付之时就已经过时。代码才是唯一能真正信任的。但是,如果通过持续集成对需求说明进行频繁验证,我们就能及时发现需求说明和系统代码之间的差异,及时解决它们,从而保证需求说明和代码是一直同步的。可以像信任代码一样信任需求说明。
频繁验证的依据就是提炼需求产生的实例化需求,它是所有过程实施中都必须要反复进行的工作。需求通过频繁验证与用户进行频繁确认;设计通过实例 化需求来频繁验证设计是否满足用户的需求;开发通过实例化需求频繁验证代码中业务逻辑;测试通过实例化需求来频繁验证交付的功能,并作为最后验收测试的依据。
提炼好功能的需求说明之后,我们就有了实现要达到的清晰目标,并且有了一个精确的方式来衡量何时已经实现了目标。每当系统有所变更,提炼过的需求说明就可以用来检查原有功能是否依然生效。自动化验证带实例的需求说明中,如果必须大量修改需求说明,那么就**失去提炼需求说明带来的价值。
主流自动化可执行需求说明工具中,自动化代码依赖于需求说明,而需求说明并不依赖于自动化代码。
手动测试中,准备上下文环境所花的时间往往是主要瓶颈所在。而在自动化测试中,时间主要花在了寻找测试失败的原因上。传统的自动化测试描述的是一系列相互依赖的步骤,所以出了问题很难定位究竟是什么导致了问题。因此如果我们不去使用一个较大的脚本,转而使用更多较小的、专注的且独立的测试,那么可以让测试更具弹性且可以降低维护成本,可以更快找出问题。
用户界面自动化的3个层次:
需求说明应该以业务规则层来描述。自动化层应该通过组合技术行为上编写的程序块来处理用户工作流层。这样的测试易于理解、编写高校,而且维护成本也相对较低。
维护需求文档,通常是件让人头疼的事情。过于繁琐的需求文档**让人丧失维护的动力。可是,系统的重构和更新又偏偏需要这样一份文档。怎么办呢?所幸的是,实例化需求为我们提供了这样一种省时省力的方式——从自动化测试用例中提取文档!
最成功的团队不**满足于一些频繁验证的可执行的需求说明,他们能确保很好的组织需求说明,让大家很容易找到和获取,并让他们保持一致。活文档是关于系统功能可靠的、权威的信息源。他和代码一样可靠,但是更容易阅读和理解。支持人员可以用它来查明系统在做什么以及这样做的原因。开发可以用它作为开发目标。测试用来测试。分析功能变更请求的影响时,业务分析师可以从他开始着手。还提供了回归测试。
提炼出来的需求实例是对系统做了什么事最有力、最准确、最新鲜的描述。而自动化测试用例又使用了可执行的方式实现了这些需求实例,我们再使用一些工具把自动化测试用例提炼为HTML或是PDF的文本,那么,砰!一份简单易懂的活文档就产生了!水到渠成,简单易懂,永不过时!
如果没有活文档,任何重大的重构都是自寻死路。
参加人
产品、开发、测试代表
目标
选择优先级高的需求进行需求澄清和实例撰写、精炼,获得相对成熟的需求规格说明书,并明确下一迭代的backlog。
内容
产品准备好需求说明和基础实例(描述预期功能的关键实例,作为测试的基础用例),产品、开发、测试代表一起对需求进行澄清。
随后开发和测试一起对实例进行扩展(如边界情况、需重点标识的有问题的地方),再精炼,得到相对成熟的需求规格说明书,并准备好cucumber的验收标准。
基本要求是将下一个迭代的全部需求的需求说明和基础实例准备好,其中优先级高的有若干个可以已准备好cucumber验收标准。
小技巧
反馈调查。是检验一组人员是否对需求说明达成共识的好方法。在讨论过一个故事之后,如果有人对故事提出了一个特殊用例,工作坊的主持人必须请参与者写下他们认为系统应该怎样工作,然后比较全组的回答。如果回答不一致,可以按回答结果分成多个小组,每个小组选出一个人来解释他们的回答。通过讨论可以揭示误解的根源。
“我们能出找出**让这个例子失效的数据?”
备注
参加人
团队全员
内容
产品对本次迭代需求进行讲解和澄清。
产品、开发、测试一起对backlog里故事的需求说明及实例进行审核。
随后开发进行规模评估和任务拆解。
需要指定故事负责人。故事**分配给某个特定的开发,他**坚持到该故事完成,他负责与其他团队进行沟通、有效传递信息而无需所有开发人员都参与审核来确保他们理解故事,在看板上跟踪进度、在每日例**上检查状态和清除障碍)开**并仔细检查所有测试。
待澄清
针对还未形成cucumber验收标准的需求,开发与测试结对,扩展和精炼实例,并编写cucumber验收标准。
在完成编写后,与产品再次进行确认,三方沟通无误后,该需求可进入待实现队列。
待实现
针对已经相对成熟的需求,开发编写BDD测试代码(TDD也进行),然后进行实现。过程中有发现新的用例,则对需求规格说明和cucumber进行更新。
在开发阶段结束前,所有可执行的需求说明都必须运行通过,且通过开发自测。
待验证
测试对已经通过自动化测试的故事进行手工测试和探索性测试。
待验收
全部测试通过后,团队给产品做一个快速的产品演示,让他验收。
待部署
全部集成后,重新运行整个系统的自动化测试,测试对核心功能做手工测试,无误后,代码可上线进入生产环境。
1.《实例化需求:不可或缺的精益、敏捷需求实践》
2.《实例化需求》
本文由 @扶木桑 原创发布于人人都是产品经理。未经许可,禁止转载
题图来自Unsplash,基于CC0协议