实例化需求:用户故事拆分的更好线索

GitChat 作者:吴穹、雷晓宝、张刚
原文:实例化需求:用户故事拆分的更好线索
关注微信公众号:「GitChat 技术杂谈」 一本正经的讲技术

【不要错过文末彩蛋】

用户故事拆分是敏捷实施的入门实践——没有用户故事拆分,就没有真正意义上的迭代,也就没法做到敏捷所倡导的快速反馈、快速学习和快速价值交付。

INVEST 原则常常被看做是用户故事拆分的基本要求[1]。但是,不少敏捷团队在如何获得 INVEST 原则所要求的用户故事方面仍然感到困惑。一些常见的情况是:用户故事拆不开,没法在一个迭代内完成;拆开了的用户故事,支离破碎,很难被管理;用户故事变成了内部的技术需求,不能做到端到端,成了只有研发团队关心的“故事”。等等。

存在一些比较流行的用户故事拆分原则。但是,在过去几年中,我们似乎已忘记了用户故事拆分这个实践。当我们进行需求澄清的时候,通常是一个实例化需求工作坊结束,完全符合 INVEST 原则的用户故事就已经在那儿了。

我们将通过这篇文章来分享我们的一些经验,也希望帮助仍然纠结于怎么写出小的用户故事的敏捷团队,能通过更小的代价和更有序的方法来获得高质量的用户故事。

用户故事和反模式

用户故事是一个来自于极限编程(XP, Extreme Programming)的实践。今天,用户故事的应用范围早已超越了 XP——无论是 Scrum,还是看板,用户故事都作为需求的基本形态被广泛运用。在 Scrum 中,用户故事扮演了 Product Backlog Item (PBI) 的角色,而看板中的流动的价值单元(Value Unit),也往往是由用户故事来扮演。

说到用户故事,浮现到脑海里的第一个印象是什么呢?一张像这样的索引卡片?

实例化需求:用户故事拆分的更好线索_第1张图片

很多人(包括我们自己),第一下在脑海里浮现出来的,其实就是这么一张卡片。形式上的东西总是特别容易传播,比如著名的 Scrum 每日站会。用户故事卡片也是如此。

但是,一旦开始实践,就会冒出一些通过形式复制解决不了的问题,甚至出现一些反模式,比如下面这些:

庞大而模糊的用户故事:

作为一个企业软件销售商,

我需要开发一个代理商管理系统,

从而可以实现对代理商的管理。

这是一个有效的史诗级(Epic)故事,但是,它没法有效地支撑开发活动。

用户故事降格为团队开发任务:

使用 redis 缓存用户的访问计数。

这确实是开发团队需要完成的任务,但需求人员和测试人员都无法理解这样的任务,它不是“用户”故事。

以用户故事之名,行需求文档之实。

比如:需求人员不再撰写需求规格说明,而改为撰写用户故事,然后开发人员基于用户故事进行开发。不但没享受到多少敏捷方法带来的好处,反而还不如原来的需求规格说明清晰。

INVEST 和 3C:好的用户故事标准

因为上述问题出现得如此频繁,敏捷社区流行一个广为人知的原则:INVEST。INVEST 是六个单词的缩写,简言之:

  • Independent:独立性。最好用户故事不要彼此依赖。

  • Negotiable:可协商。故事卡片是一种提醒,团队成员应该基于此对话,而不是把故事卡片看做确定性的需求。

  • Valuable:具有外部价值。避免仅仅对开发人员有价值的故事。

  • Estimatable:可估计。用户故事规模适中,对应的业务知识和技术知识得到澄清,从而可以估计用户故事的规模。

  • Small:小。即将开发的用户故事应该足够小,从而能便于迭代、便于调整优先级,便于需求澄清,等等。

  • Testable:可测试。可测试的故事意味着需求是清晰、可验证的。

Ron Jeffries给出了关于用户故事的另外一组特性2,这就是著名的 3C:Card(卡片), Conversation(对话)Confirmation(确认)

为了更快进入正题,本文不深入展开上述原则,但我们希望提及,基于我们的实践经验,在上述原则中,最容易被忘记的往往是 Conversation 和 Confirmation 。而最不容易实现的,是 Small。而这些,恰恰是敏捷方法的精髓,也是用户故事区别于传统的需求管理方法的关键所在。

用户故事必须小

虽然大的用户故事可以作为Epic存在,但是进入开发阶段的用户故事必须要小。这是因为:

大的用户故事隐藏细节。细节是魔鬼。软件开发中隐藏的细节,足够摧毁一切看似有序的计划。当用户故事仅仅在Epic层面讨论时,需求往往看起来是清楚的,或者虽然觉得不那么清楚,但是也说不出所以然。比如,在前述的代理商管理的例子中,“一个代理商可以管理子代理商”看起来是一个功能。但是,这个描述没能说清下面的这些细节:

  • 所有的代理商都可以创建子代理商吗?

  • 子代理商是否需要资质审核?

  • 代理商和子代理商在创建时需要有哪些必须的属性?

  • 上级代理商能查看子代理商的哪些信息?哪些信息不能查看?

而任何一个细节的变化,都足够开发团队忙上一段时间的。如果不能识别这些细节,那么白板上的这个用户故事,就会导致大量的后期讨论(这往往是高成本的)和返工。

大的用户故事降低灵活性。有没有经历过这种对话?——“这个迭代功能太多了,让我们推迟实现一些功能吧。” ——“这些功能都很重要,这个迭代都要支持。” 如果我们把用户故事拆分的小一些,也许你就会发现,去协商暂不实现“代理商可以按关键字检索子代理商的信息”要比暂不实现“代理商管理系统”要容易多了。这是因为,当没有进行用户故事拆分时,大的用户故事的优先级是必须按照其中最高的价值来计算的,哪些不那么重要的功能也被捆绑在其中。而一旦进行拆分,则就可以在一个迭代中只关注那些高优先级的部分,自然就提高了灵活性。

实例化需求:用户故事拆分的更好线索_第2张图片

事实上,协商的困难,大多数时候真的不是市场方不通情理,而实在是交付团队所能提供的交付灵活性太少了。

在上面的图中,如果把实线框中包括的总面积看作是迭代所交付的价值的话,那么未拆分的需求显然降低了价值交付能力。延迟了价值交付,同时也降低了端到端的反馈和学习能力。这是我们不想看到的。

“拆分”的困难

存在一些比较流行的用户故事拆分模式。例如[3]:

  • 业务规则:首先实现业务规则的一个子集。

  • 数据:首先完成和一部分数据的相关的功能。

  • 界面接口:首先完成一部分界面或接口,然后支持其他类型的界面或接口。

  • 简单/复杂:首先完成核心、基本的业务价值,然后完成其它的。

  • 操作:区分配置和查询等等。

  • 工作流的步骤:首先完成工作流步骤中的一部分,然后完成其他部分。

  • 非功能需求:区隔非功能需求的实现。

没错,这些规则都对,都是我们可以考虑的维度。但是,在实际中执行的又是如何呢?——实际情况是:只要看一下这些模式中提及的术语,就能体会到其中的困难。“业务规则”、“数据”、“界面和接口”、“简单和复杂”、“操作”,等等。

本质上说,人类的大脑并不那么善于掌控复杂性,而这些堆积起来的术语,往往只有经验非常丰富的团队才能理解的很透彻。但是还不仅如此,真正困难的还不是掌握这些拆分规则。概念是有些复杂,但是熟能生巧,勤学苦练,总归能学会了吧。应用这些模式的最重要的困难是:你怎么才能发现存在哪些“业务规则”、“数据”、“界面和接口”等等,然后把它们用于拆分?

大多数失败的拆分,不是由于拆分故事的技巧不足造成的,而是对信息量不足,也就是对需求本身的探索不够所导致的。没有清晰定义的业务规则,没有清楚的数据描述,…

沟通和探索才是本质

现在让我们回到 Ron Jeffries 的 3C 原则。对于用户故事来说,除了 Card, 还有更重要的 Conversation 和 Confirmation 。如果用户故事的“撰写”、“拆分”都是由团队中的个人完成的,那么无论是不是采取了故事卡片的形式,无论是否进行了拆分,它其实和传统的需求分析方法没有什么区别。真正有别于传统需求方法的,是我们可以通过一组有序的工作步骤、通过协作,从看似模糊、混乱的业务需求中梳理出清晰的脉络,并以此指导后续的开发活动,当然也包括了用户故事的拆分。

这里我们援引 Mike Cohn 在《用户故事和敏捷方法》[4]中对 3C 的概括:

  • 一份书面描述,用于做计划和提示。

  • 关于故事的对话,具体化故事细节。

  • 测试,用于表达和编档故事细节,并且用于确定故事何时完成。

Ron Jeffries 说到了用户故事应该 Conversation,应该 Confirmation,但是并没有就 conversation 和 confirmation 的具体方法给出建议。当然 Ron Jeffries 关于 3C 的文章发表于 2001 年,那时也还没有太多成熟的实践来支撑 3C 的目标。

实例化需求给出了一个需求澄清活动的更好方式。在过去的很多项目中,我们通过实例化需求来实现Conversation 和 Confirmation,达到了很好的效果。

实例化需求的核心是需求

“实例化需求”?那不是接收测试驱动开发(ATDD),用 Cucumber 或 RobotFramework 写测试吗?可能有同学会产生这样的疑问。

确实,有不少公司和团队都声称他们在采用“实例化需求”的实践,但是具体的做法却可能大相径庭。单单“实例化需求”这个术语,也存在3个不同的近似词语:“实例化需求(Specification By Example, SBE)”、“接收测试驱动开发(Acceptance Test Driven Development, ATDD)”、“行为驱动开发(Behavior Driven Development)”。Gojko Adzic在他的书籍《实例化需求:团队如何交付正确的软件》中给出了关于这3个概念的辨析,在此不在赘述。但毫无疑问的是:

在我们的实践中,实例化需求的核心关注是”需求“,而不是“测试”或者“开发”。只是说,如果没有开发和测试的参与,需求没法达到所需的质量。通过需求、测试、开发的对话,通过使用实例进行澄清,才能获得高质量的需求。这恰恰是和用户故事的3C匹配的。

产生哪些输出?

Gojko Adzic 给出了关于实例化需求的9个过程模式:从目标获取范围、协作产生需求说明、举例说明、提炼需求说明、在不修改需求说明的情况下实现自动化验证、频繁验证、以及演化出一个活文档系统。这 9 个过程模式涉及了如下的输出(制品):目标和范围、需求说明、例子、自动化测试及活文档系统。

只是泛泛的提及上面的制品,仍然不足以看出为什么实例化需求能有效支持用户故事的澄清和分解。在实践中,我们所产生的“需求说明”的更具体体现形式是:

  • 工作流

  • 领域模型

  • 业务规则

后面让我们通过举例来对三者进行详细阐述。

1. 工作流

工作流也称为业务流程或业务场景,是用户通过一系列步骤,达成系统业务目标的一种实现方式。在实例化需求工作坊中,参与人员在白板上使用顺序图、活动图、带有泳道的活动图等方式,共同绘制出工作流。当然,如果工作流足够明显,也可以直接采用业务用例的形式,列出标题,理清它们之间的先后关系即可。

整个过程中,尽量使用白板而不要使用计算机。这其实是一个技巧。当把工作流在白板上建模出来时,可以把参与讨论的人的关注点收敛到一起,从而共同进行讨论和发现问题。也正是如此,我们强烈建议“不使用软件工具进行建模”。它不容易创造沟通的焦点,或者说,使用计算机建模会创造出一个不正确的焦点——正在操作计算机的同事。 在整个过程中,描述是次要的,核心是对话和验证。一个讨论的场景如下图:

实例化需求:用户故事拆分的更好线索_第3张图片

下面是一个工作流描述的例子:

实例化需求:用户故事拆分的更好线索_第4张图片

或者就是简单地采用列表的形式,列出几个相关的用户场景:

  • 新开通一个子代理商。

  • 为子代理商充值。

  • 为子代理商修改密码。

  • 修改子代理商的基本信息。

  • 查询子代理商列表。

绘制工作流的目的不是为了描述,而是为了信息发现和挑战(challenge, 这里是褒义),即既有的工作流是否合理,是否存在遗漏,是否需要进一步讨论其中的业务数据和业务规则,等等。

在上面的工作流中,我们可以看到的挑战包括:

  • 子代理商的初始化密码怎么设定?

  • 子代理商首次登录时是否要被提示修改密码?

  • 子代理商可以自己添加用户吗?

  • 子代理商的基本信息包括哪些?哪些信息需要校验?

  • 是否需要在创建时就为子代理商进行充值?

  • 创建的子代理商可以进一步创建子代理商吗?

回答上述挑战的过程,事实上是一个需求澄清的过程,它也会对应的更新工作流、领域模型和业务规则。在进行挑战和回答挑战的过程中,也一般都会包含了对每个业务流程或规则背后的业务价值的讨论,以及紧急程度的讨论。例如:

  • 密码的一般性规则(例如必须包含特殊字符)是否要适用于初始密码?这会不会对线下过程带来困扰?

  • 我们为什么要把联系人和管理员区分开?

  • 在我们的当前阶段,能否延迟支持代理商的多管理员功能?

在上述案例中,一个可能的讨论结果是:代理商的多管理员功能虽然是需要的,但是在当前阶段可以暂缓实现,等等。

下面是一个带有稍微有些复杂的使用带有泳道的活动图描述工作流的例子:

实例化需求:用户故事拆分的更好线索_第5张图片

2. 领域模型(统一术语)

大多数讨论都是很热闹的,但是效果却不尽相同。其实,热闹的背后是七嘴八舌还是井然有序,常常是因为概念引起的。大多数人都有过这样的经验:两个人争论的面红耳赤,但是最终发现我们说的其实根本不是一件事情!或者发现我们说的其实就是同一个观点!根本就无需争论!

在讨论中,我们常常看到有这么一种人能够打破僵局,推动讨论:

“来,让我们看看每个人说的是什么”。

每个人在内心所建的概念的差异,往往是导致争论的根源。

领域模型有很多方面的价值,但是让我们首先聚焦于它所表达的概念,对业务实体和它们之间的关系进行建模。例如下面的这个领域模型:

实例化需求:用户故事拆分的更好线索_第6张图片

有了上述的模型,当我们在讨论中说到代理商基本信息的时候,所有人就都知道哪些是基本信息。说到子代理商的时候,所有人都知道子代理商其实也是一个代理商。这其实就是领域驱动设计(Domain Driven Design, DDD)中所讲述的“统一语言”的应用。

同时,领域模型带来的统一语言,使得业务规则讨论变得更加精确,也更加高效。

例如:

如果子代理商权限为”无“,则代理商不能创建子代理商。

代理商可以查询子代理商的基本信息。

像上面的这种模型如何获得?尽管存在各种各样的方法,例如关注需求描述中的名词等等,但是可以肯定的一点是,模型是通过讨论获得的。它是持续演进的结果。这个过程常常是这样一个模式:1)发现既有词汇不足以表述需求,或者发现参与人员在过程中产生了困惑; 2) 试图提出一些关于新的词汇的假设,对既有模型进行修正和补充 3)辩驳这些假设;4)修正,推翻,达成一致。 词汇存在歧义是一个常见的问题,这类问题如果不通过讨论,很难快速取得一致。上述模型的达成过程事实上首先是在白板上完成的:

实例化需求:用户故事拆分的更好线索_第7张图片

3. 业务规则

先来一起看一下某测试:

  1. 首先添加员工信息。

  2. 执行发放工资的动作。

  3. 检查工资数值是否正确。

  4. 检查付款支票号码正确。

这是《实例化需求》[5] 一书中的一个反例。需求必须精确,不能在用户故事开始实现时仍处于模糊的状态。例如,付款支票应该包括哪些信息?这属于领域建模的范畴,应该通过领域模型予以回答。除此之外,我们仍然会提出下面的一些问题,例如:付款支票日期究竟应该使用发薪日期还是当前日期?工资发放的计算规则是否在本需求范围内?付款支票号码的编号策略有没有什么要求?等等。

下面是一种可能的业务规则描述:

每位员工 1 张支票,支票上有员工姓名、地址以及薪资数据

支票日期使用发薪日期

支票号码唯一

下一个可用的支票号码按升序排序

按照员工姓名顺序进行打印

尽管只有业务人员这些规则也能被描述,但显然测试人员在其中能扮演更重要的角色。Confirmation是Conversation的自然结果。

上面的需求够清楚了对吗?其实不一定。即使一个看起来很清楚的需求,我们也建议举一两个实际的案例来说明。就像下面这种图片展示的那样:

实例化需求:用户故事拆分的更好线索_第8张图片

关于举例,我们不准备过多赘述。只提及一点:具体的东西永远比抽象的东西更容易激起讨论,更容易发现原本未注意到的重要因素。

回到“用户故事”

在上述的实例化需求工作坊中,用户故事扮演了什么角色?我们并没有去“拆分”用户故事。我们在“讨论”用户故事。讨论使得用户故事的工作流、业务规则都已经足够详尽。事实上,现在不是用户故事拆不开的问题,而是要多细节,就有多细节,也许我们发现,为了方便管理,有些场景下还可能需要做一些小的归并。无论如何,迭代项怎么划分的自主权已经完全把握在工程人员手中。

例如,我们可以选择首先实现一个工作流的主干部分,可以选择首先实现工作流的一个业务步骤,可以选择首先实现几条业务规则,推迟后续几条业务规则,等等。

值得说明,并不是需求的所有情况都讨论完毕,才能开始迭代,需求只要有了一个完整的例子就能开始迭代。尚未讨论完全的情况可以视作模糊的东西在迭代中做探索。即便是简单的例子,在程序开始开发后也能发现问题。通过完成一些例子反而能够更好辅助后面未讨论完全的场景明晰起来。在项目开始阶段实例化需求工作坊会比较密集,但是这样的讨论每个迭代都应该持续发生,用户故事卡片,是一种占位符(Card),能够持续推动活动进行。

结论和建议

我们建议放弃“用户故事拆分”这个术语。“拆分”这个词语带来了一种暗示,似乎需求本来是一大块完整的东西,只是为了适应基于迭代的敏捷开发,才需要人为的把它切开。不是的。这不是事实。

真实的情况是:需求原本就是由一大堆彼此缠绕的细节构成,它们需要被辨识,而不是需要被拆分。无论它们是否已经被辨识到,这些细节都隐藏在哪里,甚至比你原本想象的要更细微,更复杂。我们需要一种有效的认知手段,把它们从需求的重重迷雾中发掘出来,识别、澄清、归类这些细节,然后按照价值大小、成本高低、依赖关系等因素为它们分配优先级,成为可以在开发迭代中持续流动的价值单元。

  • [1] Bill Wake. INVEST in Good Stories, and SMART Tasks. http://xp123.com/articles/invest-in-good-stories-and-smart-tasks/

  • 2 Ron Jeffries. http://ronjeffries.com/xprog/articles/expcardconversationconfirmation/

  • [3] http://agileforall.com/wp-content/uploads/2012/01/Story-Splitting-Flowchart.pdf

  • [4] Mike Cohn. 用户故事和敏捷方法

  • [5] Gojko Adzio. 实例化需求: 团队如何交付正确的软件


作者介绍:

  • 吴穹, 资深创新管理顾问,精益看板专家。

  • 张刚, 资深架构师、敏捷顾问,专注于领域驱动设计、微服务、实例化需求等在企业的落地实施。

  • 雷晓宝,工程实践顾问,专注企业软件设计、测试自动化,开发生产力等领域。


彩蛋

重磅 Chat 分享:

《高效学习,快速变现:不走弯路的五大学习策略》

分享人:
一名会在 B 站直播写代码,会玩杂耍球、弹 Ukulele、极限健身、跑步、写段子、画画、翻译、写作、演讲、培训的程序员。喜欢用编程实现自己的想法,在 Android 市场上赚过钱,有多次创业经历。擅长学习,习惯养成,时间管理。身体力行地影响他人做出积极的改变!目前就职于 ThoughtWorks,致力于传播快乐高效的编程理念。业余创立软件匠艺社区 CodingStyle.cn,组织超过30场技术活动。

Chat简介:
说到学习呀,真是头大哟:碎片化,没有较长的连续时间来学习难专注,捧起书,手机却在召唤:来呀,快活呀~ 反正有,大把时光~做不到,看了很多书,生活中却做不到然并卵,学了方法和工具,找不到使用场景效率低,学习速度跟不上知识产生的速度记不牢,学习速度赶不上遗忘速度在这个知识泛滥、跨界竞争的年代,学习能力才是核心竞争力。你想想,过去一周,有没有哪一件工作是不需要学习就能完成的?尽管如此重要,大部分人却没研究过学习这件事,以为上下班路上打开「得到」听本书,就是碎片时间终身学习者了。

我是程序员,咨询师,培训师,这几个角色都要求我必须学得又快又好。本场 Chat 将分析学习的「趋势,原则,策略」,帮你站在更高的视角看待学习,从「内容,动机,交互,收益,资源」五方面制定策略,解决学习痛点,助你成为高效学习者!

想要免费参与本场 Chat ?很简单,「GitChat技术杂谈」公众号后台回复「高效学习」

实例化需求:用户故事拆分的更好线索_第9张图片

你可能感兴趣的:(运维开发)