
13.2 解决方案和实施步骤
如果作为软件团队的领导者或者团队成员的你,也曾被上述问题所困扰的话,那么看板的思想和工具或许能够帮助你让团队规划更加富有成效。在介绍如何使用看板之前,让我们先从理解看板开始。
要理解看板,本章开头超市的例子就是最好的例证。超市的存货分为两类,一类是在货架上的展示商品,另一类是超市现场库房中为数不多的存货。顾客去超市很难发现超市的货架上出现商品空缺的原因,就在于当货架上的商品出现空缺时,可以立即用现场库房中的存货补上,同时再下订单给生产商补充库房存货。同时,超市也不会储备过多的存货在库房,从而免去了规划和维护过多库存的浪费。对于超市来说,这个过程非常高效且成本最优,同时,对于客户来说,总是能够买到新鲜的商品,且不必担心喜欢的商品会出现缺货,好处显而易见。
把超市例子中的原则,应用到敏捷软件开发中,可以总结出下面四条看板原则和实施步骤。
原则1:让工作流可视化(Visualize Workflow)
在上面超市的例子中,顾客和超市的理货员总是可以通过观察货架得出商品是否缺货的判断;类似地,看板第一条原则就是可视化。与其他商业流程不同,看板并没有定义一个标准的工作流。在看板中,工作流随具体的应用场景不同而有不同的抽象,唯一的要求就是工作流需要可视化出来。可视化的工作流是看板的基础,以及后续发挥看板威力的重要依托。
在实际操作中,第一步就是基于现有的工作流进行抽象。图17就是一个典型的敏捷软件开发的工作流。正如下面即将看到的,看板思想中可视化工作流的优势在于,可以非常直观地通过可视化看到流程、进度、问题,发现瓶颈和价值。

图17 可视化工作流
实际上,无论是敏捷理论,还是当前非常热门的DevOps理念中,团队信息的透明化(Transpancy),以及基于透明化的信息所获得的及时和快速的反馈,都是非常重要的成功因素之一。例如,在敏捷理论中,团队的燃尽图(Burndown Chart)、每日例会(Daily Stand),以及信息展示板(Radiator),目标都是为团队和产品经理提供透明的关于团队工作进展的信息。同时,如果能够以非常低的成本快速获得团队工作进展的信息,那么管理所带来的额外开销也能够降低。看板实践的第一条原则就是让工作流可视化,这不仅能够为团队提供信息的透明化,也能够为管理者提供透明化的信息,从而降低管理的额外开销。例如,团队管理者希望获得关于团队工作进展的信息,如果没有看板,那么管理者需要通过与相关的团队成员面谈以获得信息,而这些面谈不仅占用了团队成员的工作时间,还会打断团队成员的工作(研究显示,人们在进行一项工作的时候,如果被打断思路,平均需要20分钟时间才能重新恢复到被打断之前的效率)。而如果有了看板,那么管理者就可以自己通过看板获取所需的工作进展的信息。
原则2:对“开始但是未完成的工作”设限(limit work in progress)
“精益软件开发”中总结的软件开发七大浪费,其中非常重要的一个就是“开始但是未完成的工作”。在看板中,工作流中那些“开始但是未完成的工作”(如货架上还没有销售出去的商品)的数量是受到限制的(称为Work in Progress(WIP)limit),只有当看板中的工作在工作流中流动之后,后续的新工作才能被“拉入”工作流并被开始,就如货架上的商品被客户购买走,进入“工作流”的下一阶段,才会引发存货从库房进入货架。
这样做的优点在于:首先,新工作进入工作流的前提在于已经在工作流中的工作有了进展,可以进入工作流的下一步进行处理,因此避免了同时开始一系列工作所造成的工作流瓶颈。其次,由于只有专注在完成已经开始的工作,才能有机会让更多工作进入工作流,团队的注意力会集中在如何减少“开始但是未完成的工作”,因此可以大大降低无谓的浪费。图18展示了在典型的敏捷软件开发工作流上加入WIP数量限制的一个Kanban的例子,其中“需求分析”阶段可“容纳”的开始但未完成的工作限制数量为3,这就意味着最多只能有三个工作“停留”在此阶段,如果有第四个工作希望进入这个阶段,那就要求敏捷团队群策群力,完成至少一个“需求分析”阶段的工作,并将其移入“代码开发”阶段。很显然,正是由于在工作流的每个阶段都有了对开始但未完成工作的数目限制,才使得团队聚焦如何将开始的工作尽快完成,而不是不断开始新的工作,从而造成很多“未完成的工作”的浪费。

图18 对“开始但未完成的工作”设限
原则3:关注看板中工作的流动,而非完美的计划
当前两条原则被实施之后,团队的注意力应该聚焦于不同工作在看板上的流动(从看板的左手边进入工作流,并最终进入最右边的“完成”),而不是仅仅停留在一份完美的计划上。
具体来说,对于一个使用看板实践的敏捷开发团队而言,所有从产品经理(Product Owner)那里得到的工作,只需要在进行了初步的分解和工作量大小估算之后,就可以直接加入看板中最左边“待办(To-Do)”一栏。接下来,团队在看板中可以按照优先级,在有需要“拉入”更多工作时,按照优先级顺序在“待办”任务中选择待开始的工作即可。
Agilistic的创始人克里斯蒂娜(Christiaan Verwijs)总结了以下6招拆分用户故事的非常实用的方法。
用户故事拆分法1:按照工作流(Workflow)
如果一个大的用户故事包含一个工作流的话,那么可以考虑按照工作流中的步骤将用户故事进行拆分。下面是一个客户创建的内容管理系统的用户故事。
作为内容管理员,我需要在企业网站上发布新闻。
这事儿听起来不大,直到我们深入了解发布一个新闻的工作流程。才发现原来只是为了在公司网站上发布几句话的新闻,也需要通过编辑审核,以及法律审核,并且还需要在测试站点上做最终评审。因此,可以按照工作流步骤将这个比较大的用户故事拆分为一系列小的用户故事。
子用户故事1:我可以直接在企业网站发布新闻。
子用户故事2:我可以发布经过编辑评审的新闻。
子用户故事3:我可以发布经过法律评审的新闻报道。
子用户故事4:我可以查看测试站点上的新闻。
……
子用户故事N:我可以将测试站点的新闻报道发布到产品站点。
用户故事拆分法2:按照业务规则(Business Rules)
很多用户故事会涉及一些显式或者隐式的业务规则,可以根据这些业务规则对用户故事进行拆分。例如:
作为用户,我可以灵活的搜索航班日期。
深入挖掘“灵活的日期”揭示了几个不同的业务规则,每个里面都包含一个故事。
子用户故事1:作为用户,我希望能够在x和y之间的n天搜索航班。
子用户故事2:作为用户,我希望能够在×月的一个周末搜索航班。
子用户故事3:作为用户,我希望能够在x和y之间的n天前后搜索航班。
用户故事拆分法3:按照主要工作(Major Work Item)
根据主要投入或工作量来拆分故事。有时一个故事可以分为几部分,大部分的工作将用于实现第一个故事。例如,一张信用卡处理的故事。
作为一个用户,我可以用维萨、万事达、大来卡或美国运通支付航班费用。
这个故事可以分成四个故事,每个卡型作为一个故事。但是首先实现第一种信用卡付费的工作量最大。一旦第一种信用卡能付费,再增加其他信用卡,其工作量就小很多。所以信用卡处理基础设施应该以支持第一个故事为目的进行构建,以后添加更多的功能则相对简单。因此,我们只需要拆为以下两个用户故事。
子用户故事1:我可以使用一种信用卡付费(维萨、万事达或美国运通中的一种)。
子用户故事2:我可以使用所有三种信用卡付费(假定其中一种已经支持了)。
这两个新的故事仍然不是独立的,但要比为每种卡的类型写一个故事依赖关系更清晰。
用户故事拆分法4:按照接口可变性(Input Options/Platform)
对于需求中业务流程和逻辑规则相同,仅涉及接口不同,也就是获取数据的渠道和方式不同,我们可以基于接口的差异进行故事拆分。
例如下面这个用户故事:
作为微信用户,我可以添加好友以便扩大朋友圈。
根据接口可变性拆分如下。
子用户故事1:……我可以通过摇一摇方式添加好友。
子用户故事2:……我可以通过扫二维码方式添加好友。
子用户故事3:……我可以通过手写输入方式添加好友。
用户故事拆分法5:按照典型业务操作(Operations)
很多用户故事都设计有一些典型的业务操作——CRUD,即:Create(增加,创建), Delete(删除), Update(更改), Read(查询)。可根据这些操作对用户故事进行拆分。例如:
作为系统管理员,我希望能够管理使用系统的用户。
通过与系统管理员沟通,了解到他希望能够增加使用系统的用户,也能够将不再使用系统的用户(如离职、更换部门等)删除,那么我们可以将用户故事拆分成下面几个更小的故事。
子用户故事1:我希望能够添加新用户,使其使用系统。
子用户故事2:我希望能够查询当前系统有哪些用户。
子用户故事3:我希望能够修改用户的信息,方便管理用户。
子用户故事4:我希望能够删除用户,保证只有必要的人在使用系统。
用户故事拆分法6:按照正常和异常场景(happy、unhappy scenario)
在我们讨论用户故事时,往往仅关注那些正常的场景,而忽略了那些异常的场景。但是,一个完整的用户故事,其实需要包括正常和异常的场景。因此,我们可以按照正常和异常场景对用户故事进行拆分。例如:
作为用户,我希望登录我的账户,从而能够看到被密码保护的页面信息。
对这个用户故事,我们可以按照正常和异常的场景将其拆分为几个子用户故事:
子用户故事1:(正常)作为用户,当我用正确的用户名和密码登录账户时,能够登录成功,从而看到被密码保护的页面信息。
子用户故事2:(异常)作为用户,当我无法用用户名和密码登录时,我希望能够重置我的密码,从而让我再次进行登录。
子用户故事3:(异常)作为用户,当我无法用用户名和密码登录时,我希望能够有提供注册新账户的选项,从而让我重新注册用户登录系统。
子用户故事4:(异常)作为用户,当我连续三次登录失败时,我希望能够对我的用户进行防黑客保护。
子用户故事x…
原则4:持续提升,不断改进看板
看板绝对不是一旦完成就可以宣告成功而无须任何改变,相反,完成了上述三步之后,看板仍然需要持续的监控和分析,去发掘更好的改进措施。对于一个敏捷软件开发团队而言,外界环境、资源情况、客户需求,以及团队内部的调整都会随时发生,因此对看板中工作流的持续监控和分析,不断寻找并移除可能存在的阻碍敏捷团队提升工作速率(velocity)的因素,才是发挥看板最大作用的不二法则。
在实际操作中,团队会在使用看板之后,定期进行回顾。通过讨论下列2个问题,团队可以发掘可能的改进方向。
(1)基于团队的反馈和团队工作速率(velocity)数据,有什么地方看板给我们带来了提升,我们需要继续保持?
(2)如果我们希望进一步优化工作流并提升工作速率,还有什么可能的改进?
图19就是团队在运行一段时间后,对图18中的看板进行改进的例子。在这个例子中,针对“需求分析”和“代码开发”完成速率不匹配的问题(通常情况下,“需求分析”比“代码开发”需要的时间少,因此,会有一些需求分析完成的工作堆积,没法进入代码开发阶段;而由于需求分析的WIP limit,造成了没法开始新的需求分析工作),团队在工作流内部进行了细分:在“需求分析”和“代码开发”中,加入了“进行中”和“已完成”两个子阶段,并且为每个子阶段制定了相应的WIP limit。在增加了子阶段进行“缓冲”之后,团队的等待减少了,从而提升了整体的工作速率。

图19 改进后的看板