敏捷发展至今已经有无数分支,这些分支的发展有些是为了应对不同项目增删改了一些实践和规则,使得敏捷能够应用在一些特殊的项目上。而另一些则是一些人想接敏捷之手宣传自己的思想与实践,强行在敏捷中加入了自己的想法。这些原因使得如今的敏捷五花八门,甚至出现两人在谈论完全不一样的敏捷。
在接下来的文章中,所有敏捷实践将会使用极限编程来作为例子。这是因为在所有敏捷过程中,极限编程是定义最完整且最不混乱的。可以说其他的敏捷过程都是极限编程的子集或变体。极限编程是敏捷本质核心的原型,也是最好的代表。
生命之环
极限编程的生命之环由三个环构成。
最外层是极限编程的业务实践,同时也可以说是 Scrum 最初的构想,这些实践为软件开发团队和业务团队提供了一套管理和沟通的框架。
中间一层是团队实践,他们提供了开发团队内进行沟通和管理的框架。
最内层是技术实践,用来约束和指导程序员们,来确保得到最高的技术质量。
可以发现敏捷宣言中的每一句话都能在生命之环中找到体现的实践。这篇文章我们先从最外层的业务实践入手,看看敏捷在实践的时候是怎样一步步影响项目的走向的。
计划游戏(Planning Game)
计划游戏是极限编程生命之环外圈的一个业务实践,它主要指的是IPM以及为了支撑IPM的一系列实践,比如估点,故事优先级排列以及速率预估和检查等等。
为了能够大概知道项目会在什么时候完结,往往会在项目开始前或每个迭代(一般两周为一迭代,不同项目可以调整迭代时长)开始前对接下来的工作进行大概的估算。
这里的估算会将接下来的任务拆分成一个个独立的子任务(story),然后对这些独立的子任务的复杂度进行估算。需要明确的是,这里的复杂度并不直接代表该任务完成所需的时间,复杂度不代表一个任务完成需要多少人/天。
估算注定是不准确的,但是估算应该在精度适当的前提下尽量确切
故事
什么是故事
上面提到的子任务在敏捷实践中被叫做故事。故事通常会对该系统功能有一个简略的描述,这个描述在不同的团队中会有不同的规范。
- 有的团队可能喜欢
作为驾驶员,为了提高速度,我需要踩下油门
这样的given whtn then
模式 - 而有的团队可能直接写一个
加速
了事
一个个被拆分好的故事会在线上线下以故事卡的方式被管理,线上管理工具有很多比较成熟的如 jira/trello 等。可是为什么还需要线下卡片呢?线下卡片对于团队沟通,随手涂画,传递使用等方面有线上卡片无法比拟的优势。
刚建立好的故事卡不会有任何细节,只有零星简略的描述,稍后 BA 在迭代0才会增加一些细节,并在开发前的 kick off 中与 dev 和 QA 一起讨论更多的细节。
故事六原则
故事需要遵循一组简单的指导原则,这组原则的首字母缩写是 INVEST:
- I:独立(Independent) 用户故事彼此互相独立。这意味着在实现它们时不必遵循特定的顺序。当然这个要求并不是硬性要求,因为的确有一些故事要依赖于前置的故事。
- N:可协商(Negotiable) 开发人员和业务人员还有测试人员应该能够就故事的细节进行协商。例如可能业务部门需要一些精美的界面,但开发人员可以以成本低的理由协商该功能能否以另外的方式实现。
- V:(Valuable) 用户故事必须对业务具有明确且可量化的价值。这意味着重构、代码清理、架构设计等这类技术实践永远不可能是故事。同时这也意味着故事是一个垂直的切片,它不可能是一个单独的前端或后端的任务,需要是一个完整可被验证的端到端的功能。
- E:可估算(Estimable) 用户故事必须足够具体,以允许开发人员进行估算。
- S:小(Small) 用户故事应该不大于一到两个开发人员在一个迭代中实现的工作量。
- T:可测试(Testing) 业务部门应该能够提出用户故事的测试标准,通过这些测试意味着用户故事已完成。通常这些测试用例由 QA 编写,并被自动化,用于确定故事是否完成。
故事估算
每一张故事卡的复杂度通常都会以数字的形式用故事点来标记,前文提到过故事点代表了这张故事卡的复杂度,但是这个复杂度只是一个估计值。
故事点的规则有很多种,有简单粗暴的衬衫尺码法(Shirt Sizes)
直接将故事卡分为大中小三挡,也有直接12345网上走的数字法
,但其中用的最多的表示方法是计划扑克(Planning Poker)
。
计划扑克指的是一系列团队内自己定义的数字组合,犹如一张张扑克,这些扑克上的数字就代表了某个故事卡的复杂度,其中一种流行的牌组以斐波那契数列为基础,在里面加入一些特殊卡牌:?、0、1/2、1、2、3、5、8、13...、∞
其中 0 代表这个故事小到无法估计,相对地 ∞ 表示这个故事大到无法估计,? 表示你根本不知道如何估计这个故事卡。
如果某个故事用到了 0 那么意味着这个故事其实应该合并到另外的故事里去,∞ 则代表这个故事应该被继续拆分成更小的故事,通常我们的团队在一个故事超过 8 个故事点时就会将其拆分。如果某个故事你投了 ?,那么意味着你可能需要了解关于这个故事的更多具体细节,这个时候就需要引入穿刺(spike)
在估算故事卡时会将故事卡陈列在团队成员和利益相关者的面前,大家就某一个故事卡的复杂度投出自己认为应该有的复杂度,并在一系列讨论后达成一致。每当添加了新故事或了解到旧故事的新知识时,就会发生这样的估点会议。估算会议不必非常正式,但应该在每次迭代中定期发生。
分解、合并和穿刺
故事的分解就是将一个大的故事拆解成一个个小的故事,但是在拆分的过程中需要随时考虑拆分后的故事是否还能保持 INVEST 原则。
合并一个故事要比分解一个故事容易得多,因为大多数情况下两个独立的故事合并后依然是遵循 INVEST 原则的。
穿刺是一个元故事,即”用于估算故事的故事“。之所以成为穿刺,是因为我们经常需要开发一个长而很薄的切片,来打穿系统的所有层。只有在这样的端到端的情况下才能了解这个无法估算的故事的具体细节。这个故事的产出将作为被估算故事的估算和实现依据。
黄金故事
黄金故事是其他故事估算的一个基准故事。黄金故事不一定是故事点为 1 的故事,黄金故事只需要是一个就算没有其他参照大家也能大概估算的故事。
比如系统中的登录模块中的某个故事就是黄金故事比较好的选择,因为大家已经解除过许多个登录模块了,相比其他业务这个业务要更加熟悉。如果某个故事比登录模块简单,那么点数就会小一些,相反则会大一些。
迭代计划会议(Iteration Planning Meeting, IPM)
此时我们已经拥有了故事卡和每张卡的故事点,为了开启一个新的迭代,我们需要组织一次所有成员和利益相关者参与的计划会议。通常会议的时长与迭代的时长有一定关联,大概是迭代时间的二十分之一,例如一个持续两周的迭代,IPM 大概需要半天。
IPM 的目的是让利益相关者选择出本迭代需要完成的任务,然后由团队在接下来的这个迭代中完成它们。为了完成这个任务利益相关者需要知道团队一个迭代大概能完成多少故事点,也就是团队的速率。因为第一个迭代无法得到一个确切的速率,所以此时的速率是一个猜测值。
虽然此时我们已经有了一堆任务卡,但显然它们是有优先级的,利益相关者需要对它们做一个排序,让团队优先完成那些高价值低成本的故事,然后完成高价值高成本的故事,接下来再来考虑低价值低成本和低价值高成本的故事应该怎么处理。
管理迭代
现在迭代开始了,需要明确的是,迭代的目标是通过完成一个个故事来产生管理项目所需要的数据。
在 IPM 结束后程序员们就可以开始完成故事卡了,但是每一个故事卡应该是程序员自己去选择的,而不是由技术经理或是主管分发指定的。技术经理该做的更应该是引导有抱负的员工们,避免新员工承担超过他能力的工作。
理论上在故事开始前 QA 已经完成了故事卡的验收测试,我们不希望已经完成的故事在等待它自己的验收测试的编写。我们期望在迭代的中期检查(我们稍后会提到这一环节)之前完成该迭代全部故事卡的验收测试,如果没有,那么程序员们应该停止故事的编写,帮助 QA 编写验收测试。但是要避免程序员编写自己将要完成的故事的验收测试。
因为没有验收测试的话,一个故事是没办法完成的,只有通过了验收测试的故事才是完成状态的。我们完成的故事只能是整数,不能出现小数,带小数的故事就是没有完成的故事。
敏捷追求的不是快,而是要取得具体、可度量的进展,要取得可靠的数据。
中期检查
在迭代中,我们会将故事卡变成可工作的代码,于是故事卡在卡墙上从待办一步步移动到已完成。到一个迭代的一半时,我们应该已经有许多卡已经完成了,并且可以从这些已经完成的卡中计算出半个迭代的速率。
那么理论上接下来的半个迭代团队可能完成的故事点数应该与目前已经完成故事点数相等。比如已经完成了15个故事点,那么接下来推测团队可以完成15个故事点,但是剩下的故事卡还有25个故事点。那么就应该将剩下的故事挪出10个故事点。
但是在迭代末期其实只完成了25个故事点,并没有完成30个预期的故事点。那么问题来了,这次迭代失败了吗?
答案是没有,迭代不会失败。迭代的目的是为管理者生成数据,然后才是生成可工作的代码。也就是说生成代码的目的之一也是生成数据。而中期检查的目的也是为了根据上半个迭代及时修正下半个迭代的预期。为未来的规划做准备。
showcase
迭代以演示(showcase)结束。在演示中会展示所有故事的所有验收测试和单元测试,同时还应该由利益相关者来操作演示新添加的功能,这是为了避免开发人员试图隐藏某些信息。
速率
迭代的最后一步是更新速率图和燃尽图。经过几次迭代后,这两张图都将开始呈现出一条斜线。燃尽图可用于预测下一个主要里程碑(比如上线等)的日期,速率图则可以告诉我们项目管理的怎么样。
我们期望在最初的几次迭代之后,速率的斜率将变为零,也就是速率逐渐趋向水平。长期来看,我们不希望速率加速或放缓,如果出现了类似的加速或放缓,我们需要考虑是不是团队的管理出了问题。
加速
需要注意的是,如果速率图的斜率上升,未必表示团队正在加速,也可能是来自于管理者的压力迫使团队在加速前进。这会导致团队在估点时不自觉地增加故事点,使得项目从数据上来看前进得很快。
故事点犹如货币,这样的做法会造成通货膨胀,故事点将失去意义。所以速率是质量而不是目标,请不要给度量对象施加压力。
迭代中可以完成的故事点的估计值不是承诺,即使实际速率较低,并没有完成预期的故事点,团队也并非失败,只有无法产生数据的迭代或者是产生错误数据的迭代才是失败的迭代。
减速
最有可能导致速率图负斜率的原因是代码质量。团队放任代码腐烂,使得后期代码的修改和阅读越来越难,导致速率逐渐放缓,而放缓的速率会使故事点通货膨胀来掩盖速率放缓的事实。
黄金故事
这时候黄金故事的作用就体现出来了,由于黄金故事是在项目最初估计的,并且是大家最熟悉的故事,那么将其他故事的故事点与黄金故事作比较就可以发现到底有没有通货膨胀发生。
昨天的天气
在一个迭代结束后,我们将进行下一个迭代的故事排期。那么在第二个迭代中我们大约能完成多少故事点呢?显然,既然第一个迭代完成了25个故事点,那么第二个迭代应该跟第一个迭代差不多,所以利益相关者应该排入相同点数的故事卡。这个实践叫做昨天的天气。
然后新的迭代开始了,我们会再次经历中期检查的修正,并再次进入下一个迭代。再用“今天的天气”去预测“明天的天气”。
项目结束
每次迭代完成后的故事点都将作为燃尽图和速率图的数据。一个又一个迭代后,当利益相关者已经认为没有什么新功能需要添加或是认为已经有的故事卡已经不值得花时间再去完成了,这时项目便结束了,也就是说并不是做完所有故事项目才算结束。