原文链接:https://dannorth.net/whats-in-a-story/
行为驱动开发是一种由外到内的开发方式。它首先从外部定义业务成果,再深入到能实现这些成果的特性集合中去。每个特征都会转化成相应的包含了验收准则和范围的“故事”。这篇文章介绍行为驱动开发的实现方式,定义和标识故事及其验收标准。
介绍
软件交付是关于编写软件来实现业务功能的。听起来容易,但总是有政治或者环境因素使我们忘记初衷。有时候软件交付就表现得像递交报告来迎合高层管理人员,或者仅是创建“忙碌的工作”来保持人们持续支付费用。额。。。我们还是另开题目改天再讨论软件交付吧。
业务功能开发通常是很粗糙的,其表现为直接编写程序(你是怎么开始编写“节省5%的运营成本”功能的?)。所以我们需要用某些中介形式定义需求来让工作美满完成。
行为驱动开发就是瞄准你能将需求转化成实现,编写可测试的,生产环境可运行的,简单,高效的代码的这个环节,当然前提是需求是清晰明确,每个人都能理解的。为了做这项工作,我们需要一种让业务人员,分析师,开发者和测试者都明白需求是怎么实现满足的方法来描述需求。由此大家都能同意这项工作“完成”。借此我们能避开“这不是我想要的”和“我忘记告诉你还有其他情况”。
接下来我们讲解“故事”的规则。它必须用于描叙需求和它的业务效益,其包含一组所有人都同意“完成”的标准。这是一个比其他敏捷方法更为严谨的定义。这个描述等同于“一个场景下的承诺”和“一个特征的描述”。一个“故事”可以描述非功能性需求,只要它的工作可以度量,评估和同意。
“故事”的结构
行为驱动开发提供一个结构给一个“故事”,这不是强制要求的,你可以用不同的故事形式来做行为驱动开发。但我在这里仍然要展示例子给你,因为这已经在不同形态大小的项目中证明能够工作。最起码的要求,你的“故事”必须在模板中包含所有描述元素。“故事”模板大概是这样的:
标题(用一行来描述故事)
叙事:
作为(一个角色)
我想要(某些特征)
因此我可以得到(收益,效益)
验收标准:(场景描述)
场景1:标题xx
给定 (语境)
和(更多语境)
当(某个事件发生)
就会有(某个结果)
和(某个结果)
场景2:...
Title (one line describing the story)
Narrative:
As a [role]
I want [feature]
So that [benefit]
Acceptance Criteria: (presented as Scenarios)
Scenario 1: Title
Given [context]
And [some more context]...
When [event]
Then [outcome]
And [another outcome]...
Scenario 2: ...
"讲故事"
一个故事应该能够转化成有几个人参与的对话。业务分析师跟业务相关的人员讨论特性或者需求,然后帮助他们构建“故事”的描述。测试人员帮助定义“故事”的描述范围--写在表格的验收标准,也帮助决定哪些场景重要,哪些是无用的。技术代表会提供一个大概的关于“故事”包含了哪些工作的评估,提供可选择的实现方式。好多关于系统的好主意都是来自开发和第一个要求这个事情的人。
这做起来像一个迭代过程。相关人员会产生关于想要什么的想法。但他们通常不知道有多少工作要被包含进来,或者工作是怎么分配的。通过技术专家和测试专家的帮助,他们会明白每个场景的花费和收益,并决定他们是否需要。当然,这是与另外一个需求相关的,我们要决定先覆盖更多这个“故事”的场景还是先覆盖另外一个“故事”的场景。
有时候开发团队做的工作评估可能不是很好。这种情况下,为了更加清晰理解需求,他们可以选择进行一些调查工作(类似极限编程里面的spike
概念)。(我将在往后的文章中讨论更多细节。)
一个好“故事”的特征
使用《介绍行为驱动开发》里面的例子,让我们来一起观察关于ATM提款这个需求需求。
故事:账户持有人提取现金
作为一个账户持有人。
我想从ATM中提取现金。
这样就算银行营业厅关门,我都能够取到钱。
场景1:账户里面有足够的资金
假设 账户里面有300元
而且 银行卡是合法的
而且 ATM里面存放了足够的钱
当 账户持有人请求提取200元
因此 ATM机器应该吐出200元
而且 账户里面的余额该为100元
而且 银行卡应该会被退返
场景2:账户里面没有足够的资金
假设 账户里面有100元
而且 银行卡是合法的
而且 ATM里面存放了足够的钱
当 账户持有人请求提取200元
因此 ATM机器不应该吐出任何钱
而且 ATM机器会说账户余额不足
而且 账户里面的余额该为100元
而且 银行卡应该会被退返
场景3:银行卡已经被取消
假设 银行卡已经被取消
当 账户持有人请求提取200元
因此 ATM机器收回这张银行卡
而且 ATM机器会说银行卡已经被收回
场景4:银行卡已经被取消
code here...
你能看到,这里有很多场景需要考虑,有些是关于账户余额的,有些是银行卡的,有些是关于ATM机器自身的。让我们一起来分析故事是否足够优秀。
标题应该描述一项活动
“故事”的标题,“账户持有人提取现金”,描述了一个关于账户持有人提款的活动。账户持有人没办法从ATM提取现金直到我们完成这个特征。一旦我们交付,我们会得到一个很明确的“完成”标识来表示是否完成。
如果我们的标题是“帐户管理”或者“ATM工作方式”,我们必须话费时间去看内容才能明白怎么算完成,而且界定范围可能更加模糊。举个例子,“帐户管理”可能不合适做申请贷款,而且“ATM工作方式”可能包括改变我银行卡的PIN码。“故事”标题应该总是描述一个系统用户的实际行为。
描述应该包含角色,特征,收益
模板做为一个“X角色”,我想要“Y特征”,由此得到“Z收益”
有很多好处。在叙述中明确角色,你会明白谁在讨论“特征”。在叙述中明确收益,你会明白“故事”的作者为什么他们会想要这个“特征”。
有意思的是如果你发现你写的特征不能实际地表达收益。这通常意味着你有一个失踪的故事。一个故事是描述当前特征,表达的收益却不相同,意味着这是一个隐藏故事,你需要编写不同的特征来表达收益。
故事例子告诉我们有一个账户持有人关心所交付的功能,因此我们知道怎么去探索这个功能需要做的事情。
情景的标题应该说明有什么不同
你应该有能力将场景排列出来,同时仅仅是使用题目来描述他们的不同。在我们的例子当中,我们可以看到情景描述仅仅说明每个场景之间的差异。你不用在标题中写“一个账户持有人从一个资金不足的账户中提取金钱,他不能够完成交易”。同时,这个场景对比其他场景你是否关心是很明显的。
场景应该是基于给定的描述,事件和结果
应用行为驱动开发方法,这在团队中是简单强大的行为转移。用“假定/当/然后”词汇就可以使业务人员,分析师,测试人员,开发者共同发现一个模糊的世界消失了。
不是所有场景都这么简单。事件序列是最好的表现。描述为“假设(某些内容),当(我做某事),就会(产生某个结果),当(我做另外的事情),就会(发生另外的事情),如此继续。一个例子就是向导式网站(你会一步一步进入场景,来构建你的数据模型)。这完美地将事件结果序列混合在一起,只要你有这方面思考的习惯。
一个有趣且紧急的行为是对话质量改变。你会很快发现你有错误的假设,或者忘记验证结果。这是我在一个特别的项目中观察到的,他们的技术负责人告诉我,有些时候,分析师和工程师讨论问题,但他们都没有办法来展示他们的意图。介绍了几日“假定/当/就”词汇之后,他就能看到他们的交流有非常优秀的提升。
在不超过所需的背景的前提下,“假设”应确定所有条件。
不论是从技术上还是业务上,任何附加的条件都会令第一次阅读“故事”的人感觉理解困难。缺少假定的情况同理。如果你从相同的假定条件中能够得到不同的结果,这肯定少了某些假设情况。
在例子中,第一个场景说了某些关于账户余额的情况,银行,ATM机器。所有这些都要求完整地定义场景。在第三个场景中,我们不说任何有关账户余额的事情,或者ATM是否有足够的资金。这表明机器会收回银行卡无论账户余额剩余多少,或者ATM的机器状态是怎么样。
事件应该描述特征
事件本身很简单,通常是一个简单的调用生产代码。当我们讨论这个的时候,某些场景是比这个复杂得多的,但大部分“故事”场景会转化为一个单一事件。他们的差别仅仅在于给定的假设内容和得到的结果不一样。
故事应该足够小来适应迭代。
这里没有关于怎么做迭代的硬道理或者第一定理,只要你能够明显地分切块。通常来说,如果这里有超过5个或者6个场景,一个“故事”可能可以拆分成更小的分组。
我们不能够说清楚ATM例子的“故事”的场景到底需要多少个,但我怀疑这里需要几个甚至更多。本质上来说,我们在这个故事里面有三个moving part
,分别命名为账户余额,银行卡状态,和ATM状态。我们可以讨论一下关于银行卡的细节:如果它过期了会怎么样?我不能够用它提款,但ATM仍然会返回给我吗?如果ATM在交易过程中发生故障会怎样?如果我的账户有透支的情况呢?
这可能将一个“故事”分拆成三个“故事”更好。
- 账户持有人提取现金(假设ATM工作良好且银行卡合法)
- 账户持有人用非法卡提取现金(假设ATM工作良好)
- 账户持有人在坏的ATM上提取现金(假设银行卡合法)
这虽然像是故意而为之的,这让你可以展示过程给业务团队,而且给你更多的数据点去追踪。重要的事情是根据业务线来决定是否要打破这个“故事”。(同时假设明确),而不是根据技术线来做(一次是数据库工作,一次是图形界面工作)。这样大家能够展示过程,而不仅仅取决于你说的话。
跟用例之间有什么区别呢?
这是用例,这就是用例。对于Alistair Cockburn 描述用例的方法(),我是他的大粉丝。假设我在用例驱动项目中没有什么经验,我会让其他人来做这个比较。
其次,我同意他从低精度(成果,目标)到高精度的方法,因为当你行动的时候,你会发现更多意外场景。这意味从业务结果开始,一直贯穿到高层次的功能领域,这是为了深入到包含验收标准的特定故事。
在现实世界中,你的过程是否标识明确或者需求描述详细并不重要。如果能够帮助你组织你的想法,你想写需求文档也是好的。但,如果是为了一直通过这些文档,好像它们实际上封装了你的想法,这就有问题了,因为它们没有!你应该将需求文档或者用例堆放到一边并重新开始从业务成果中定义故事。这样在知识方面是安全的,因为你的勤奋工作已经表明了所有在你脑中的答案--至少,有足够好的理解来描述你现在能在看到的工作。
总结
行为驱动开发用故事来作为基本的工作单元,并以此来做交付。故事里面已经包含了验收标准,从效果上看,它们定义了行为的范围,同时生成了一个大家都能理解的“完成”。它也可以用来基本评估我们要做的工作计划。
最重要的是,故事是项目负责人,业务分析师,测试人员,开发者沟通交流的结果。行为驱动开发更关注的方面是不同人在项目中的相互作用,同时亦关注开发过程的输出结果。