Scrum and XP
前言
这部分内容是个人在阅读《硝烟中的Scrum和XP》时的理解和记录,用于帮助个人更好地在学习团队中应用Scrum和XP。
什么是Scrum?
Scrum是敏捷开发模式的一种方法论,是一种框架,用于指导帮助需要的团队进行敏捷开发实践。Scrum的实施过程符合敏捷开发的原则和标准,同时还结合了UP(Unified Process,统一开发)过程的特点。因此,良好的Scrum有以下基本要求:
- 每个迭代要有固定时长(也就是“时间盒”或“timebox”),迭代时长在2~6个星期,不能超过六个星期,也不要少于两个星期。
- 在每一次迭代的结尾,代码都必须经过QA的测试,能够正常工作。
- Scrum团队必须要有产品负责人,而且团队都清楚这个人是谁。
- 产品负责人必须要有产品Backlog,其中包括团队对它进行的估算。
- 团队必须要有燃尽图,而且要了解他们自己的生产率。
- 在一个Sprint中,外人不能干涉团队的工作。
根据上述基本要求,在Scrum实践过程应该会有如下产物:产品Backlog、Sprint Backlog、对于两个Backlog分别的估算和燃尽图。而这些关于Scrum的术语是本文将主要介绍的内容。
什么是XP?
XP(Extreme Programming,缩写为XP)是极限编程的英文简称,也是属于敏捷开发的一种方法论。XP和Scrum均关注“尽可能早地、持续地对有价值软件的交付”,具体来讲,即是在每次迭代结束均有一个可发布的软件版本,每个版本不一定是最完善的,但它是有改进的(系统改进或功能增加),对于客户来说均是有使用价值的。
同时,二者也有不同的关注点,XP关注的是实际的编程实践,而Scrum注重的是管理和组织实践。但是,这并不影响两者的组合使用,组合使用Scrum和XP能够为敏捷团队带来累累硕果。而两者的组合会使用到以下方法:结对编程、测试驱动开发(TDD)、增量设计和持续集成等等。这些内容将会在后续再次提到。
Scrum术语
什么是Backlog?
用例、故事
在开始具体介绍Backlog的含义之前,必须先要了解下UP过程中的两个关键术语——用例和故事。如果读者已经熟悉这部分的内容,可以直接跳过,也可以选择阅读回顾。
用例,即Use case的定义如下:
“Use case is a collection of related success and failure scenarios that describe an actor using a system to support a goal.”
翻译过来,即用例是参与者使用系统达成目标的一系列成功和失败场景的集合。理解这个概念,需要关注到以下三点:
- 什么是场景?”Scenario is a specific sequence of actions and interactions between actors and the system, it is also called a use case instance.”(场景是参与者与系统进行的一个特定的交互行为序列,也被称为是一个用例实例。)
- 这些场景是描述一个参与者使用系统达成目标的过程。既有成功的场景,也有失败的场景。比如,一个顾客想使用美团外卖APP进行订餐,他先打开美团外卖APP,然后点击“美食”栏目进入外卖商家列表,再选中要订的美食分类,选择其中一个商家进入该商家的菜单列表,选择要叫的美食,加入购物车,接着进入购物车并确认结算,进入结算列表,填写收货地址,使用红包,确认信息后,提交订单,接着选择支付方式,跳转完成支付后,返回商家,等待商家确认订单,商家确认后即完成了订餐过程。这样的一个具体的使用美团外卖APP订餐的过程就是一个成功的订餐场景,它包括了一系列参与者与系统的交互行为。其中参与者是顾客,系统是美团外卖APP,达成的目标是订餐。如果在打开美团外卖APP过程中,手机没有连接网络,APP提示无法连接网络,无法继续进行后续步骤。这个就是一个失败的订餐场景,因为最终无法达到订餐的目标。
- 用例是一系列成功和失败场景的集合。用例是集合,这说明用例其实是一个抽象出来的描述,它概括了这个集合内的成功和失败场景。通常,用例名称就是这个抽象的描述,并清楚说明了用例的目标,比如上述的两个场景(一个成功,一个失败)就是属于订餐这个用例。“订餐”是用例名称,也是用户使用美团外卖APP的一个目标。从另一个角度来讲,用例也可以理解成是系统提供的一种服务或功能,订餐是美团外卖APP提供的一种服务,属于它其中的一个功能。
额外地,需要提醒的是,用例中有主场景(也叫基本流)和可选场景(备选流)。主场景即是成功使用系统达成目标的场景,比如上述的第一个场景;而可选场景则是除了主场景外的其他成功或失败场景,比如上述的第二场景就属于可选场景,同时,对于成功订餐场景,如果直接选择历史订单,然后再次订餐的具体过程也是一个可选场景。
另外,用例可以分成多个子用例,比如可以将订餐这个用例分成选择商家、选择美食、提交订单、支付这几个子用例,每个子用例也是一个场景集合,包含了各种场景,比如支付就又包含了微信支付和银行卡支付等等过程场景。
最后,强调一下,用例是以客户角度使用客户术语描述的,与技术无关,并不关注系统内部怎么实现;用例以及其中的场景描述并不是太具体,比如具体到要按下左下角的购物车按钮进入购物车这样的一个步骤,可以说用例描述是一种UI-Free Style,不用去想界面,只关注用户意图来进行简洁描述。
说完用例,接下来就是故事了。简单来讲,故事其实是对用户使用系统来达成目标或期望的需求描述,比如,顾客想使用美团外卖APP来在线订餐,其中“在线订餐”就是顾客使用美团外卖APP的目标需求,“顾客”也当然就是用户。可以发现,故事其实和用例很像。故事中的用户相当于用例中的参与者,故事中用户的目标或期望则相当于用例的名称,比如“订餐”。事实上,两者在理解上可以看成一种偏等价关系。
但是,需要了解的是,两者仍有所不同。用例是多个成功和失败场景的集合,而故事则只是用户对使用系统的目标需求的描述。用例更注重参与者使用系统的交互过程,故事则更关注用户想要系统能提供的有价值的功能(目标需求)。相比之下,用例比故事更加详细,用例中主场景、可选场景都可能转换为故事。
方便于理解Scrum中的Backlog,其实只需要记住,故事的目标或期望可以理解成用例的名称,故事的描述可以理解成用例主场景的更概括性描述;用例可以分成多个子用例,故事也可以分成多个小故事,子用例和小故事互相对应。
Backlog
backlog从根本上说,就是一个需求、或故事、或特性等组成的列表,按照重要性的级别进行了排序。它里面包含的是客户想要的东西,并用客户的术语加以描述。
可以知道,backlog条目罗列了系统产品的故事、需求、特性或者功能,同时它还对这些用户的需求进行了重要性排序。从另一面讲,backlog也表示了系统各用例的重要性程度。
以下是截取书中的示例,是一个产品Backlog的示例:
一个backlog一般包括有以下一些字段(当然也有其他字段):
- ID——统一标识符,是一个递增的数字,用于区分各个故事。
- Name——名称,简短的、描述性的故事名,这里也可以使用用例名称来代替。
- Importance——重要性,用来说明这个故事有多重要。它也是使用数字来表述的,但对连续性和大小范围没有要求,数值越大,说明该故事越重要。这些数字可以是0(不重要)、5(不太重要)、10、30、40、100(重要)、150(很重要)等等。通常,将各个故事之间的重要性数值间隔设置得比较大,方便在增加新故事时,能够有合适的重要性数值。比如添加一个重要性在100和150两个故事之间的新故事项,可以设置重要性为120,但不要设置成101,因为100和101两个故事之间可能会再添加新故事,此时只能选择重要性为100.1或者100.5,这样非常不清晰和美观。
- Initial Estimate——初始估算,表示完成该故事所需的工作量,也即是实现该系统功能所需要的时间。这个可以使用故事点/用例点来衡量,即人-天。比如预估2个人完成某项故事所需的时间是4天,那么故事点就是两个数的乘积8。因为是预估,所以故事点的计算依赖经验,常用的估算依据有API接口数、页面数(部件数)和报表数。
- How to demo——如何演示,描述了在sprint结束前的演示过程。这里可以根据对应用例的主场景描述来进行更具体地描述。
- Notes——注释,相关信息、解释说明和对其它资料的引用等等,比如一些分析工具或技术设计上的注释。一般都非常简短。
产品Backlog
产品backlog是一个Scrum的核心,因为它描述了这个产品“所有”的故事(或功能、或特性)。但是实际在开发过程中,是不可能完全列出所有故事的。通常情况下,产品backlog会尽可能多地罗列系统产品的故事,并在开发过程中,随着迭代进行,不断地进行调整。比如在Inception阶段(UP过程的第一个阶段),只能够列出一些主要的故事,并进行排序;而在Elaboration阶段(UP过程的第二个阶段),则可以对产品backlog进行补充,使其更加完善。
另外,产品backlog通常会有一个额外的字段——Iteration,用于表示估算该故事在哪个迭代内实现完成。
比如,下面是个人学习小组在Inception阶段设计的在线短租平台的产品backlog:
可以看到,最初的产品backlog的故事并不完善,只是列出了主要的故事,同时重要性级别设计不太合理,也没有进行重要性从大到小的排序。另外,对于初始估算以及迭代安排也不确定,只是简单使用随机数字来代替。而实际上,个人的学习小组项目经验也不足,因此该产品backlog出现许多问题。例如:
- 用户登录以及注册分别是两个故事,不应该设计在一起,同时,重要性安排也不应该这么高,可以设计更低的重要性。
- 重要性数值设计间隔太窄,不方便添加新故事。
- 多个相同重要性的故事,实际上重要性并不应该相同,比如“发布房源信息”应该重要于“修改房源信息”和“查看房源信息”,因为前者的优先级更高,对于这个在线短租平台更重要;同时“支付”故事的重要性则应该稍低些。
Sprint Backlog
Sprint backlog是用于一次迭代过程的backlog,在每次Sprint(迭代)开始前进行设计。Sprint backlog是属于产品backlog的一部分,它是从产品backlog中选择故事用于安排在该迭代内完成。通常,一个迭代的Sprint backlog会先选择重要性较高的故事来作为本次迭代的内容(先实现更重要的功能),同时还会根据预估生产率来进行修改。
比如,下面就是书中关于从产品backlog中选择设计出Sprint backlog示例:
一个迭代的预估生产效率等于在该迭代内可以用的故事点(人-天)乘以投入程度。一个迭代周期以三个星期为例,可用的故事点表示在这三个星期内所有团队成员可以为项目投入的人-天之和,假设团队有两个人(实际最好是4~6个),A能抽出一个星期的时间,那么他的人-天为7,B能抽出50%的时间,那么他的人-天为21/2=10.5,所以可用故事点为7+10.5=17.5。而投入程度则等于上一个迭代中实际完成的故事点之和除以上一个迭代实际工作的故事点。比如,上一个迭代实际工作的故事点为20,而在迭代中完成的故事点之和是10,那么投入程度是10/20=50%。所以这个迭代的预估生产率为17.5 * 50%=8.75。同时,这个投入程度可以再进行修改,例如这个迭代时间内,组员有其他重要的任务课题,能投入的时间和精力也会减小,那么可以适当下降投入程度,成40%,那么预估生产率就变成17.5 * 40% =7。
那么在设计Sprint backlog时,选择的故事点之和应该是小于预估生产率的,比如预估生产率(另一个团队)是50,选择的前5个重要性最高的故事的故事点之和为49,而前6个为60,那么这个迭代只安排前5个故事。
实际在设计Sprint backlog过程中,可能会出现前几个故事的故事点之和会远小于预估生成率,而多加一个故事点却又会过大,这往往是因为重要性高的故事往往也是较为复杂的故事。此时,为了充分利用迭代时间,可以选择重新设计故事的优先级别,又可以将故事缩小或拆分成小故事(比如将用例分成多个子用例)。在这个迭代中先实现这个故事的一部分,后下一个迭代再实现这个故事的其他部分。
另外,在开发初期,尤其是第一个迭代中,往往是不能预估出生产率的,这时就可以先预估个大概数值,然后第一次迭代后,就能进行较准确的估计了。
另外一种排序方式
backlog除了按重要性进行排序外,还能够按照需求组织的方式来进行安排,通常就是将一个大故事拆分后的小故事按顺序进行排序,比如下面的例子,将find hotel故事中的子故事find city和find on map等排序到一起,先在开始的迭代中一起实现,有些子故事的重要性并不是最高的:
Sprint
Sprint本意是冲刺,在这里,一个Sprint相当于一个迭代。在每次迭代(Sprint)开始前,需要进行一次计划会议,设计Sprint backlog,而在每次结束前,则会进行回顾,关注这次迭代中有什么可以改进的点。在Sprint过程中,需要了解的是燃尽图,根据燃尽图的反馈,在Sprint过程中对Sprint backlog进行修改以使得Sprint最终能够成功且合理的达成目标。
燃尽图
燃尽图,burn-down chart,用于记录一个Sprint过程的完成情况。燃尽图的横坐标是迭代时间,即一个迭代时间盒是三个星期,那么横坐标则是从三个星期中的第一天日期到最后一天的日期;纵坐标则是剩下的Sprint backlog中记录的需要完成的故事的故事点,最高点即是Sprint backlog中所有故事的故事点之和,比如下图。
团队每经过一天,就会在燃尽图的对应日期上画出当前的进度点(今天过后还剩下需要完成的故事点),并和之前的进度点连线。那么在经过一段时间后,燃尽图就会出现上述的示例情况,蓝色表示实际的进度的连线,虚线表示如果进度速率平均时的的进度线。
分析燃尽图中进度线的表现可以反映出当前团队的进度情况,并适当地对Sprint backlog进行调整:
- 团队进度缓慢,需要适当删除backlog的故事项,否则团队不可能在迭代中达成目标:
- 团队进度太快,为了避免团队后期没有活干,可以适当添加backlog故事条目:
看板
看板,相当于任务板,用于记录一个Sprint中需要完成的所有任务以及完成每个任务对应的小组成员。通常可以将Sprint backlog中的故事拆分成任务,并设计在看板上。其中,需要注意任务与子故事的区别在于故事是可以交付的功能,而任务则是不可交付的,但却是完成一个故事所需要的步骤,比如一个扫码订餐APP的一个故事是订餐,它拆分成子故事是扫码、选择美食、提交订单、支付,而拆分成任务是设计UI、前端编程、后端编程、测试用例设计等等。