1.2可视化看板任务管理
看板源于精益生产实践,敏捷将其背后的可视化管理理念借鉴过来,经过一番改造,形成了有自己独特风格的可视化管理工具。曾有人总结过scrum和kanban的使用[1],而很多时候,我们也将它叫作迭代状态墙。
我们先来看看怎样用这个状态墙来管理迭代任务。说起来其实是一个很简单的东西。
通常一个迭代的状态墙反映了某一个迭代的计划和任务进展情况。状态墙按照一个迭代内团队的典型开发活动分成几栏,例如“待开发”、“开发中”、“待测试”、“测试中”、“测试完成”等。在一个迭代之初,我们会将计划在本迭代完成的故事卡放到“待开发”这一栏中。可视化状态墙的一个好处就是所有团队成员都可以实时地了解本迭代的计划和进展情况。开发人员领取任务时,就将他领取的故事卡片从“待开发”移到“开发中”,同时贴上带有自己名字的小纸条。当他开发完成之后,就将故事卡片移到“待测试”一栏。测试人员看到“待测试”栏里有待测的故事卡,就取下一张,移动到“测试中”,然后开始这个用户故事的测试;测试完成后,就将故事卡移动到“测试完成”一栏。如果测试人员发现了一个bug,那么他可以用红颜色的卡片记下这个bug,然后放到“待开发”这一栏中。状态墙上除了用户故事、bug之外,还会有一些诸如重构、搭建测试环境这样的不直接产生业务价值的任务,这三类任务用不同颜色的卡片放到状态墙上统一管理。
这样一个简单的工具,是如何帮助我们消除浪费、解决项目管理中的问题的呢?让我们逐条分析一下看看。
1.2 如何减少返工带来的浪费
返工是软件开发过程中的一大严重浪费。比如说开发人员完成的任务交给测试人员测试的时候,关键流程不能走通,阻碍了测试进程;交付给客户的东西被客户说“这不是我想要的东西”;分析人员将还没分析透彻的任务交给开发人员,在最后验收的时候发现开发人员加入了自己的一些“发挥”。这些都会造成返工。返工意味着没有一次性将事情做对,意味着流程中的上游没有交付高质量的产品,也可能意味着团队成员间的沟通出了问题。
在传统的瀑布流程中,我们往往是期望通过前期细致入微的工作来确保一个阶段的工作被高质量完成之后才移交到下一阶段。后来我们慢慢从失败的经验中学习到,这种方法在变化的需求环境下实在是太脆弱,不仅不能如愿保证质量,而且会造成更大的浪费,交付周期也不能满足要求。于是我们引入了迭代式开发方法[2],一个需求的分析、开发、测试、验收成了一个小粒度的更连续的过程,在这个小的交付循环中,看板帮助我们以更细节的粒度来管理一个任务每个阶段的工作质量。
通常我们是这么做的。当我们把一张故事卡从“待开发”移动到“开发中”时,这张卡片必须是已经分析完成的。也就是说,当开发人员准备真正开始开发这张故事卡之前,我们的需求分析师们必须保证这张卡片所包含的所有内容和细节都已经分析完成,不再有模棱两可的细节,不会留给开发人员过多的自我发挥和想象空间,而且这些细节必须和客户确认过,而不只是团队自己“设计”的结果。
这一道关看似很寻常,实际上很多项目会在这里出问题。很多时候开发人员开始开发的时候,需求还没有分析完成,很多细节尚须澄清确认,实现上的技术风险还没有被完全排除。也有的分析师善于给开发人员留有大量自我发挥空间,需求过于言简意赅。开发人员开始开发这样的需求时,要么做不下去,要么按照自己的理解做下去。做完后分析师发现不对,和想的不一样,于是开发人员返工。最糟糕的情形莫过于最后客户说这不是他当初想要的东西。
由此可见,开发人员挪卡的时候,确保这张待开发的用户故事已经被真正分析完成,是我们准确实现用户需求的第一步。通过规定这一挪卡的前提,同时辅以用户故事的澄清(由分析师向开发人员澄清)或者反向澄清(由开发人员向分析师讲述自己的理解),可以很大程度上减少返工。
还有一种浪费发生在测试过程中。测试人员经常会发现,处于“待测试”状态中的一些故事卡,在测试的时候主要的流程走不通,根本无法进一步展开测试,于是乎不得不将故事卡打回到开发人员手中。而往往这个时候开发人员已经在另一个用户故事上工作了。要么他需要停下手中的任务解决测试的问题,要么让测试人员等到这些问题修复过后再测。无论哪种都是不好的选择。
出现这种问题的一个主要原因是因为开发人员声称他已经“开发完成”,将故事卡从“开发中”挪到“待测试”时,实际上自己并没有对这部分功能进行测试,或者是因为疏忽,或者是因为懒惰,或者是因为过于自信。通过在这个状态转换阶段引入用户故事初验,分析师在挪卡之前先到开发人员机器上看看该故事卡包含的功能是否被实现了,可以很大程度上提升效率,减少浪费。如果分析师在初验过程中发现了问题,那么开发人员马上能以最小的成本进行修复,而不用等到之后测试人员发现时再来修复。而且,分析师初验也提供了一个判断实现是否良好的反馈点,这是我们能够看到一个需求是否被实现并能够真正工作的最早的时间点。
1.2 如何避免多任务并行
多任务之间的频繁切换是一个常见的问题。表现在团队里的成员身上,特别是开发人员,多为会在不同的任务间切换。就像前面的故事中提到的,开发人员可能这一刻还在实现某一个需求,而下一刻可能就会被叫走去修复某一个遗留版本的缺陷;又或者该开发人员手头被分配了多个任务,每个任务都在进行中,而没有一个处于完成状态。任务切换是导致效率降低的一个重要原因[3]。不同任务间的上下文的切换会导致将任务当前状态频繁地在头脑中“压栈”和“出栈”,这些操作会耗费时间。如果完成一个任务一个人需要一天时间,那么两天内这个人可以完成两个任务;但是如果他在第一天开始在这两个任务上并行工作,那么完成这两个任务会需要大于两天的时间。
大家可能已经注意到了,在前面的看板图中,处于“开发中”的所有任务卡片上都有一个小纸条,上面标记着正在这张卡片上工作的人的名字。如果说有两个人结对在一个卡片上工作,那么这张卡片上应该有两个名字。这个小小的实践可以帮助我们随时发现团队内某一时刻,每个人是否只在一个任务上工作。
如果这一简单的规则能够严格被遵循,那么当我们看到一个人的名字出现在多张卡片上的时候,我们就知道这个人此刻可能忙着在多个任务之间切换,而每一个任务都可能不会在估计的时间点内完成。如果我们看到有人的名字没有出现在任何卡片上,那么他目前大概处于休息状态。团队内的每个人的名字都应该对应在一个小纸条上,如果你此刻在某个任务上工作,那么就将自己的名字贴到相应卡片上,如果此刻在该任务上没有工作,就将自己的名字移去。
我们在领取“待开发”状态栏中的卡片时,应该保证每次每人只领一张卡片,不要多领,完成了这张卡片之后,再回来领下一张。当一张卡片被认领之后,我们就会对这张卡片进行跟踪,在站会上谈论它的完成情况,谈论实现过程中碰到的问题。当它的进度和估计的可能进度偏差较大时,我们能够及时察觉而不是在最后一刻才发现,这样可以提供需要的帮助,确保它能够顺利完成。这样一种方式让我们能够将注意力集中到小粒度的需求(例如用户故事)上,来更多地关注这些用户故事的流动速度。而当每个小的用户故事能够顺畅地流动起来时,整个项目的交付也就得到了保障。
当然这一实践并不能自动保证团队内不再出现多任务并发、拖延或者做和任务无关的其它事情等问题。可能有些人在做一个用户故事的过程中,突然中断去做了一些其他事情,但是却没有及时在状态墙上更新自己的状态。重要的是团队要有实现交付目标的共同愿景,能够透明地暴露问题,而且善于利用状态墙来发现和改进自身的问题。对于不成熟的团队,这可能需要一个转变的周期。
如果一个团队的职责共享较好,所有人集体拥有代码,鼓励每个人在代码的不同部分熟悉和工作,那么在这样的团队内就不容易出现把一大块任务事先就明确给某一个人的情况。相反,所有人的工作事先不具体确定,大家会更容易形成某一时刻只领取一张卡片的习惯,避免同时在多个任务上工作。实际上,状态墙的使用也可以帮助团队走向职责共享之路,只需要在领取任务的时候有意地给人们分配一些之前没做过的内容,同时安排好有经验的人与其结对工作,一段时间之后,团队内的人便会逐渐体会到和之前只是专注在一个模块内不同的工作方式。
1.4 如何减少半成品库存,缩短交付周期
一个需求的交付周期(lead time[4])是从它被识别到最终交付给用户手中所耗费的时间。交付周期越短,意味着客户从提出想法到能够在软件中实际使用的时间越短。从客户的角度来看,更短的交付周期意味着自己的软件能够对市场变化更快地响应,因而获得更强的竞争力,同时也意味着能够更快地验证自己的想法。
任务管理的粒度太大会直接导致交付周期变长。最极端的情况是将属于某一模块的任务在一开始就全部交给负责这个模块的人,所有这个模块相关的修改都由他来实现。在一个按模块划分职责、每个人只负责自己具体模块的团队里,通常这个模块的负责人会实现这个模块的所有修改;不然,就是将一个可能需要做两周到一个月的任务分给某个人;或者更好一点的情况是,单个任务本身不大,但是会将相关联的任务成批地分配给某个人。如果你的团队内也是采用大篇的“规格说明书”等Word文档来组织需求的,那么要小心,这种问题很可能在团队内已经存在。整个团队没有小粒度频繁交付的概念,习惯了大批量长时间地交付方式,因为批量大,所以估计常常不准,而且时间跨度长,中间也会有更多地干扰因素出现,这些都导致任务不能在开始承诺的时间点交付。开发周期长同样导致测试活动的滞后,极端地滞后就演变为所有开发工作完成之后才能进行测试,这就是我们熟悉的瀑布模式。最终的影响就是需求的交付周期会很长。
传统团队的一个常见组织方式是按照功能模块划分团队成员,明确分离职责,这也会变相增长交付周期。这样的团队通常倾向于按照功能模块来组织半成品任务,而不是按照可以交付价值的完成品来组织任务。习惯按照功能模块来组织开发的团队通常会阶段性地“联调”,不同模块的人带着自己的代码合在一起调试,由于缺乏频繁地集成,这种联调活动的时间经常不可控。团队在大部分时间内通常只拥有一大堆半成品,后续的测试和验收活动都没有办法进行,而只能等到团队在某一刻组装出一个完整的功能后才能测试,所以交付周期也会比较长。
因此,如果我们的需求都是按照软件的功能模块划分,而不是按照面向用户的价值来划分的,那么我们在交付用户价值这一目标上,一开始就走错了路。采用用户故事能够把需求以用户能够理解的价值组织起来,这一点是我们缩短交付周期的一个重要基础。
我们的状态墙能够揭示需求的交付周期。让我们来看看这样几个场景。
如果我们的需求是按照软件的功能模块划分的,那么通常单个模块的编码完成不可测。例如有的团队喜欢将Web应用的上层页面部分和下层数据库逻辑部分划分到不同的模块组,一个用户的需求也会拦腰切成两截,一部分交给上层团队完成,一部分交给下层团队。这样,即使单个团队的任务完成也不能开展这个需求的测试,于是这些任务就会堆积在“待测试”这一栏。
如果我们的需求很大,以至于开发人员要花费很长的时间(超过1周)才能完成开发,那么这个需求会在“开发中”这一栏停留很久。大家可以猜到,当一个人同时进行多个任务时,这些任务也会比它们被单个依次开发时在“开发中”这一栏停留更久的时间。
任何一栏中的任务其实都是半成品,只有完成测试、交付到用户手中的需求才是完成品。状态墙上的每一栏都好比一个存放着各种零件的仓库,每一栏中的卡片越多,停留得越久,就说明当前半成品的库存越多,是该得到团队认真关注的时候了。状态墙将每个阶段的半成品数量可视化呈现出来,让虚拟的数量通过卡片这种物理介质的数量得以呈现。
通过状态墙,我们可以计算出每一个需求的交付周期大概是多久。状态墙上一个用户故事从放到“待开发”这一栏,到它被移动到“完成”这一栏,这一个时间段是需求的整个交付周期的其中一段,也是很重要的一段。通过优化从“待开发”到“完成”的这一个过程,我们可以缩短需求的交付周期。通过比较需求的交付周期和客户对交付周期的要求,我们可以量化之间的差距,然后指导我们进行改进。
在理解了状态墙是如何呈现一个需求的交付周期后,我们就不难理解瀑布方法是如何让交付周期变长的。在瀑布模型中,全部开发工作完成之后才会进行测试工作,相当于所有的任务卡片都堆积到“待测试”状态之后,才开始逐一测试。所有开发完成的半成品,都会留存在“待测试”这一仓库中,一直等到所有开发活动结束的那一刻。
出现库存堆积的时候,就是我们需要改进的时候。如果“待测试”这一栏有太多的任务卡片,那么就说明我们的测试活动没有跟上,有可能是我们的测试环境出了问题,或者是我们的测试人员人力不足。如果太多的卡片位于“测试完成”状态,说明我们的发布和最终交付过程出了某些问题。如果“待开发”这一栏中任务过多,说明我们的计划有可能超出了当前团队的开发能力,或者说反映了开发人员的不足。还有一种情况是“待开发”这一栏空了很久,这可能说明了另外一个问题,那就是我们的分析师的分析速度匹配不上团队的开发能力。一个良好的团队,必然是各种角色协调配合,并行工作,同时他们之间的任务衔接也能够比较流畅。
1.5 迭代产能的度量、计划及其他
团队在每个迭代所能完成的工作量,通常被称为迭代的速度(velocity),是衡量团队每个迭代产能的一个指标。这个指标能够帮助团队制定迭代计划。根据团队估计任务工作量的方法不同,迭代的velocity的单位也可能不同(例如故事点数)。通常,我们只需要在迭代结束的时候,数一数状态墙上完成的任务工作量就可以了。
当我们经历了若干个迭代以后,通常团队的迭代速度会趋于稳定,我们在做下一个迭代计划的时候,会参考以往迭代的数据。如果上一个迭代完成了15个点,那么下一个迭代我们通常也会计划15个点左右的工作量,将这些卡片放到“待开发”这一栏中。也就是说,每个迭代结束时,我们都会对状态墙进行更新,将即将到来的迭代的卡片放到墙上,而且将一些处于半成品状态的卡片进行适当的调整。
前面提到,状态墙上可能有三种卡片,除了需求,还可能有bug和技术任务。测试人员每次在迭代中测出一个bug,就会将bug写成卡片,放到“待开发”这一栏。当bug不多的时候,团队可以在不太影响原有计划的情况下消化掉这些bug,确保软件的质量持续地得到保证;如果bug太多,则需要做一些计划,将bug分散到几个迭代里去消化。然而到这个时候,团队可能更需要及时反省一下出现这么多bug的原因了。
另一类技术任务也需要和bug以及需求卡片一起被考虑到迭代计划中去。通常技术任务包括诸如搭建持续集成环境、准备测试环境、重构这样的任务。它们虽然不直接给用户带来价值,但是却是保证软件质量、确保团队效率的重要因素。比如重构类的任务,对于工作在遗留系统上的团队来说可能是需要一直考虑的事情,为了保障新需求的顺利实现,可能需要有计划地重构之前的一些遗留代码。
bug和技术任务耗费团队成员的时间资源,但是不直接产生用户价值。如果我们衡量团队每个迭代的总体生产能力,需要在计算迭代速度时考虑这三类任务;但是如果我们只考察团队每个迭代交付的用户价值的量的大小,那么就不应该包含技术任务和bug。当一个团队在迭代中花了过多的时间在技术任务或者修复bug上,那么这个团队就需要反省一下其中的原因,是不是团队的基础设施太差,或者是团队在开发时过于粗心导致太多的bug,抑或是其他的一些原因。