故事(Stories)作为一种“皮钦语”(译者注:pidgin language,又称混杂语言,一种简化版本的自然语言,这种语言来自于两个或两个以上的群体,他们之间没有共同语言,为了彼此沟通而发展出的语言。不同族群之间为了贸易,常会发展出这种语言,或是这个族群居住的国家,使用的语言与这个族群不同时,也会发展出皮钦语。皮钦语不是其中任一个族群的母语,但常被当成第二语言),双方(用户和开发者)可以达成足够的共识,从而有效地合作。
-比尔·威克(Bill Wake),极限编程的共同发明者
故事
故事是用用户语言编写的一小块所需功能的简短描述。敏捷团队实现的是系统功能的小的、垂直的切片,其大小可以在单个迭代中完成。
故事是敏捷中用来定义系统行为的主要工件。它们是对功能的简短描述,通常从用户的角度出发,用用户的语言写成。每一个故事的目的都是为了实现系统行为的一个小的、垂直的片断,以支持增量开发。
故事提供了足够的信息,让业务人员和技术人员都能理解其意图。故事的细节将被推迟到故事准备实施之前才讨论。通过验收标准和验收测试,故事变得更加具体,有助于确保系统质量。
用户故事(User stories)将功能直接交付给最终用户。使能故事(Enabler stories)为支持探索、架构、基础设施和合规性所需的工作项带来了可见性。
详细介绍
SAFe的需求模型描述了工件的四层结构,这些工件概述了功能系统的行为:史诗(Epic),能力(Capability),特性(Feature)和故事(Story)。他们共同描述了创建解决方案预期行为的所有工作。但详细的实施工作是通过故事来描述的,这些故事构成了团队Backlog。大多数故事来自于“Program Backlog”中的业务和使能特性(Feature),部分故事来自于团队识别的工作。
每个故事都是一个小的、独立的行为,可以逐步实现,并为用户或解决方案(Solution)提供一些价值。它是功能的垂直切片,以确保每次迭代都能带来新的价值。故事要拆分得相对较小,必须能在一次迭代中完成(参见拆分故事部分)。
通常情况下,故事会先写在索引卡或便签上。索引卡的物理性质在团队、故事和用户之间建立了一种有形的关系:它有助于让整个团队参与到故事编写中来。便签纸还提供了其他的好处:它们有助于将工作可视化,并且可以很容易地放在墙上或桌子上,按顺序重新排列,甚至在必要时传递。故事可以让人们更好地了解工作的范围和进度:
- “哇,看看我们将要完成的所有这些故事”(范围)
- “看看我们在这次迭代中完成的所有故事”(进展)
虽然任何人都可以写故事,但批准它们进入团队待办列表并接受到系统基线中是产品负责人的责任。当然,便利贴并不能很好地在整个企业中扩展,所以故事通常会迅速转移到敏捷生命周期管理(ALM,Agile lifecycle management)工具中。
在SAFe中,有两种类型的故事,即用户故事和使能故事,如下所述。
故事的来源
如图1所示,故事通常是由业务和使能特性的拆分来驱动的。
图1. 将业务特性拆分成故事的示例用户故事
用户故事是表达所需功能的主要方法。它们在很大程度上取代了传统的需求说明书。(然而,在某些情况下,它们可以用来解释和开发系统行为,这些行为随后被记录下来,以支持合规性、可追溯性或其他需求。)
因为它们关注的是用户感兴趣的主题,而不是系统,所以用户故事是以价值为中心的。为了支持这一点,推荐的表达形式是“用户声音”的形式,如下所示:
作为一个(用户角色),我想(活动),以便(业务价值)。
As a (user role), I want to (activity), so that (business value).
通过使用这种形式,引导团队了解谁在使用系统,他们在用系统做什么,以及他们为什么这样做。经常使用“用户声音”的形式往往会提高团队的领域能力(domain competence);他们会更好地理解用户的真实业务需求。图2提供了一个示例。
图2.“用户语音”形式的用户故事示例“用户画像(Personas)”描述了具有代表性的用户的具体特征,可以帮助团队更好地理解他们的终端用户。 图2中骑手角色的示例可以是一个追求刺激的“Jane”和一个胆小的骑手“Bob”。然后,故事说明将引用这些角色(作为Jane,我希望…)。
虽然用户故事语音很常见,但并不是每个系统都会与终端用户进行交互。有时“用户(user)”是一个设备(如打印机)或一个系统(如交易服务器)。在这些情况下,故事可以采用图3所示的形式。
图3. 以“系统”作为用户的用户故事示例使能故事
团队可能需要开发系统结构或基础设施,以实现一些用户故事或系统的支持组件。在这种情况下,故事可能不会直接接触任何终端用户。这些是使能故事,它们支持探索、架构或基础设施。使能故事可以用技术而不是以用户为中心的语言来表达,如图4所示。
图4.使能故事示例还有许多其他类型的使能故事,包括:
- 重构(Refactoring) 和探针(Spikes)(传统的XP定义)
- 建设或改善开发/部署基础设施
- 运行人工交互的工作(如为100万个网页编制索引)
- 为不同目的创建所需的产品或组件配置
- 验证系统质量(如性能和脆弱性测试)
使能故事和用户故事一样,通常是通过展示所获得的知识、制作的工件、或用户界面、打桩或模拟来展示。
编写好的故事
好的故事需要多个视角的观点。在敏捷中,整个团队(产品负责人、开发人员和测试人员)对要构建的内容有一个共同的理解,以减少返工并提高吞吐量。团队使用行为驱动开发(BDD)进行协作,定义详细的验收测试,明确描述每个故事。好的故事需要多角度的思考:
- 产品负责人为客户提供可行性和可取性的思考
- 开发人员提供技术可行性
- 测试人员针对异常情况、边界情况以及其他用户可能与系统交互的意外方式提供了广泛的思路
协同编写故事可以确保所有的观点都得到考虑,并且每个人都对故事的行为达成共识,其结果体现在故事的描述、验收标准和验收测试中。验收测试使用系统的领域语言(system’s domain language)与行为驱动开发(BDD)来编写。然后,BDD测试将自动执行并持续运行,以保持内建质量。BDD测试是根据系统需求(故事)编写的,因此可以作为系统行为的权威性声明(definitive statement),取代基于文档的功能详细说明(document-based specifications)。
3C:卡片,对话,确认
Ron Jeffries,XP的发明者之一,被认为是首先提出了描述故事的3C方法:
- 卡片 – 使用索引卡、便签或工具来捕捉用户故事的意图陈述。索引卡提供了团队和故事之间的物理关系。索引卡的大小从物理上限制了故事的长度和对系统行为具体性的过早建议。卡片还能帮助团队“感知”即将到来的范围,因为手里拿着十张卡片和看电子表格上的十行字有一些本质的不同。
-
对话 – 代表团队、客户(或客户的代理)、PO(可能代表客户)和其他利益相关者之间关于故事的“对话承诺”。为了确定实现此意图所需的更详细的行为,必须进行讨论。对话可能会以验收标准(下面的“确认”)或用户故事的附件的形式产生额外的具体内容。对话涵盖了故事生命周期中的所有步骤:
- 待办列表梳理(Backlog refinement)
- 计划(Planning)
- 实施(Implementation)
- 演示(Demo)
这些即时讨论创造了正式文档无法提供的对范围的共同理解。通过实例化需求(Specification by example)取代了详细的文档。对话还有助于发现用户场景和NFR的差距。
- 确认 – 验收标准提供了确保故事得到正确实施所需的信息,并且涵盖了相关的功能和NFR。图5提供了一个示例。有些团队经常使用故事卡的确认部分来写下要演示的内容。
敏捷团队通常以业务可读的特定领域语言(domain-specific language)自动执行验收测试。自动化创建了一个可执行的规范来验证和核实解决方案。自动化还提供了对系统进行快速回归测试的能力,从而增强了持续集成,重构和维护的能力。
投资于好故事
由Bill Wake [1]开发的INVEST模型描述了良好用户故事的特征:
- I – Independent,独立的(在其他故事中间)
- N – Negotiable,可协商的(灵活的意向成熟,而非合同)
- V – Valuable,有价值的(为客户提供有价值的垂直切片)
- E – Estimable,可估算的(小且可协商)
- S – Small,小的(适合在一个迭代内完成)
- T – Testable,可测试的(足以理解如何测试)
估算故事
敏捷团队使用故事点和“估算扑克”来估算他们的工作[1,2]。故事点是一个单独的数字,它代表了一组特性的组合:
- 数量(Volume) – 有多少?
- 复杂度(Complexity) – 有多难?
- 知识(Knowledge) – 什么是已知的?
- 不确定性(Uncertainty) – 什么是未知的?
故事点是相对的,它与任何具体的衡量单位无关。每个故事的大小(工作量)都是相对于最小的故事来估算的,最小的故事被赋予“1”的大小。 应用一个修正后的斐波那契序列(1,2,3,5,8,13,20,40,100),以反映估算中固有的不确定性,特别是大数(如20,40,100)[2]。
估算扑克
敏捷团队经常使用“估算扑克”,它结合了专家意见(expert opinion),类比(analogy)和分解(disaggregation)来创建快速但可靠的估算。分解是指将故事或特性分割成更小的,更容易估算的部分。
(请注意,还有一些其他的方法也在使用。)估算扑克的规则是:
- 参加者包括所有团队成员。
- 每个估算者都会得到一副牌,牌上有1、2、3、5、8、13、20、40、100、∞和?。
- PO参与但不估算。
- Scrum Master参与但不估算,除非他在做实际的开发工作。
- 对于要估算的每个待办事项,PO宣读故事的描述。
- 提问并回答。
- 每个估算者私下选择一张估算卡,代表他/她的估算。
- 所有卡片同时翻转,以避免偏差,并使所有的估算都能被看到。
- 估算最高和最低的估算者解释他们的估算。
- 经过讨论后,每个估算者选择一张卡片重新估算。
- 估算值很可能会趋于一致。如果没有,则重复这个过程。
进行一些初步设计讨论是合适的。然而,在设计讨论上花费太多时间往往是浪费精力。估算扑克的真正价值在于就一个故事的范围达成一致。这也是一种乐趣!
速率(Velocity)
团队在一次迭代中的速率等于满足完成定义(DoD)的所有已完成故事的故事点数之和。随着团队的不断合作,他们的平均速率(每次迭代完成的故事点)会变得可靠和可预测。可预测的速率有助于制定计划,并有助于限制在制品(WIP),因为团队承担的故事数量不会超过其历史速度所允许的范围。这个衡量标准也被用来估算交付史诗(epics)、特性(features)、能力(capabilities)和使能故事(enablers)所需的时间,这些时间也可以使用故事点进行预测。
容量(Capacity)
容量是指团队速率中实际可用于任何特定迭代的部分。假期、培训和其他事件会使团队成员在迭代的某些部分无法为迭代的目标做出贡献。这就降低了该团队在该迭代中的最大潜在速率。例如,一个平均每迭代交付40点的团队,如果一个团队成员休假一周,他们的最大速率就会调整到36点。提前知道这一点,团队在迭代计划时就只承诺最大36个故事点。这也有助于在PI计划期间预测PI中每个迭代的实际可用容量,从而使团队在构建PI目标时不会过度承诺。
估算的起始基准(Starting Baseline for Estimation)
在标准的Scrum中,每个团队的故事点估算以及由此产生的速率是一个团队内部的、独立的事务。从规模化敏捷的角度来看,当各个团队之间的速率的基准分歧很大时,将很难预测更大的史诗(Epic)和特性(Feature)的故事点大小。 为了克服这个问题,SAFe团队最初会校准一个起始故事点基准,在这个基准上,所有团队的故事点定义大致相同。不需要重新校准团队估算或者速率。在启动新的敏捷发布列车时,会进行一次校准。
标准化的故事点提供了一种方法,可以让故事和速率达到一个约定的起始基准,如下所示:
- 在双周的迭代中给团队中的每个开发和测试人员8个点(每个理想的工作日为1个点,减去2天的一般开销)。
- 为每个团队成员的休假日和节假日减去1个点。
- 找一个小故事,大约需要半天时间来编码,半天时间来测试和验证,将其定义为“1”个点。
- 其他故事相对于这个“1”的故事进行相对估算。
示例:假设一个6人团队,由3个开发人员,2个测试人员和1个PO组成,没有请假或节假日,那么估算的初始速率=5×8点=40点/迭代。(注:如果其中一个开发人员和测试人员兼职Scrum Master,可能需要将其调低一些)。
这样一来,各团队的故事点就有了一定的可比性。管理层可以更好地理解一个故事点的成本,并能更准确地确定一个即将到来的特性(Feature)或史诗(Epic)的成本。
虽然随着时间的推移,团队会倾向于提高他们的速率,这是件好事,但实际上,这个数字往往保持稳定。一个团队的速率受团队规模和技术环境变化的影响远远大于受生产力变化的影响。
拆分故事
较小的故事会带来更快、更可靠的实施,因为小的条目在任何系统中流转的速度更快、可变性更小、风险更低。因此,把较大的故事拆分成较小的故事是每个敏捷团队的必备技能。这既是增量发展的艺术,也是科学。Leffingwell的《Agile Software Requirements》[1]中介绍了十种拆分故事的方法。以下是对这些技术的总结:
- 工作流步骤
- 业务规则变化
- 主要工作量
- 简单/复杂
- 数据的变化
- 数据输入方式
- 递延的系统质量
- 操作(如:创建,读取,更新,删除[CRUD])
- 用例场景
- 突破性的探针
图6展示了一个按用例场景拆分的示例:
图6.将一个大故事拆分为多个小故事的示例SAFe需求模型中的故事
正如SAFe需求模型一文中所描述的,该框架应用了一系列的工件和联系,以精益和敏捷的方式管理复杂系统的定义和测试。图7说明了故事在SAFe全局中的作用。
图7.SAFe需求模型中的故事在规模化敏捷中,故事(Story)通常(但并不总是)由新特性(Feature)创建。而每个故事都有验收测试,也可能有单元测试。单元测试主要是为了确保故事的技术实现是正确的。同时,这也是测试自动化的一个关键起点,因为单元测试很容易实现自动化,这在测试驱动开发(TDD)一文中有所描述。
注:图7使用统一建模语言(UML)符号来表示对象之间的关系:零对多(0...*),一对多(1...*),一对一(1),以此类推。
了解更多
- Leffingwell, Dean. Agile Software Requirements。Agile Software Requirements: Lean Requirements Practices for Teams, Programs, and the Enterprise. Addison-Wesley, 2011. Addison-Wesley,2011.
- Cohn, Mike. User Stories Applied: For Agile Software Development. Addison-Wesley,2004.
Last update: 17 December 2019
网友评论