/ Agile

用敏捷的方式翻译敏捷经典《User Stories Applied》(三)

厄…一不小心,这最后一部分拖了这么久才写,得先自我检讨检讨。这最后的部分其实是此次翻译中最重要的一部分。这篇我将分析为什么这次翻书会比较成功。当然,这个成功的定义来自于出版社的反馈,较高的质量以及如期的交付。

首先,我们是一个分布式的团队。曾经有段时间我在美国出差,Bill也经常在国外飞来飞去,而且我们都是兼职来做这个翻译,几乎不怎么见面。那么我们是怎么解决沟通协调的问题呢?

  • 我们使用了看板,其实也就是一个Excel表格。但是就这么简单的一个东西提供了一些项目的可见性,更重要的是它帮助我们协调任务。我们可以很容易的避免两个人做重复的任务。
  • 每周的同步会议。从中我们可以知道,现在项目的状况。同时,大家要对未来一个星期做出commitment,即下个星期要做什么。然后是提出遇到的困难,大家一起沟通商量解决方案。其实也就是Scrum中Daily Scrum每个人要回答的三个问题。最后就是Retrospective,回顾一下我们现在项目中有什么需要改进的。
    • 如果说看板是一个需要主动检视项目状况的工具,那么每周的同步会议似乎就是被动的将项目状况推到的你的面前,确保大家都知道现在项目的状况。另外,还同步会议还提供了一个社会功能,Peer Pressure,即大家给每个人无形的压力。在会上,每个人都要说这个星期你做了些什么,如果说你这个星期什么都没有做,或进度很少,其他人可能会询问出了什么问题,即使没有问,你说的时候自己也会有心理压力。而这个压力自然而然会让你在这个星期经可能的做出一些产出。
    • 同步会议是一个学习的机会。在讨论遇到的问题和回顾项目时,这些都是学习的机会。比如,团队此时碰到一些术语的翻译问题,可以此时讨论并统一翻译,把以前同样的术语翻译统一起来,下次碰到就可以直接翻译了。再比如,在翻译过程中,获得了新的知识,发现以前的翻译有问题,此时大家可以讨论,即使修正。快速的失败可以减少成本。
    • 同步会议让团队变成了自我组织的团队。在会议上,大家一起处理问题,安排协调任务。大家互相帮助,使团队随时都是朝着同一个目标前进。同时团队还不断的调整工作流程(Done Definition的演化)和策略(模糊角色,Reviewer参与翻译)。
  • Continuous Integration本质上说是一个沟通工具,帮助团队沟通现在项目状况。我们用CI来发送邮件,提高了通知的实时性,弥补了周会的信息延迟。
  • Email当然是最直接的沟通。
有了良好的沟通,还需要计划与跟踪来控制项目。
  • Small batch size。我们将整本书按章节划分成一个一个的“故事”。这样更容易帮助我们衡量项目进度,从而使项目可见性和可预测性提高。Small Batch提供更多的协调机会,减少流程瓶颈,产出自然提高。同时,可以通过快速的失败,降低修正问题的成本,避免了以后类似的失败。另外,还有一个好处就是,我们随时可以发布我们已完成的部分,而不必等到整本书翻完。
  • Chapter point。用户故事用故事点,类似的,我们这里使用了“章点”量化工作量的大小。由于每个章节大小都差不多,最多差别2-3倍,去细究每个章节大小的差别所带来的价值相比带来的成本不是很大,于是我们将所有章节都估算为一个Chapter point。
  • Commitment based。前面说了在周会中,每个人需对下个星期做的事做一个承诺。这个承诺将带来Peer Pressure来促使你完成每周的进度。
  • Frequent check point。每一周的周会成为我们的学习点和同步点。每周一定更新的Burndown反映现在的进度和理想进度的距离,从中我们也会获得进度的压力迫使我们尽快赶上理想进度。还有就是Burndown只有一个章节完全符合了我们的Done Definition的标准才会减掉一个点。这样才能保证我们的做完是真正的DONE。
  • Visualize the work。看板让我们看到所有需要完成的工作,同时还明晰了我们各自的职责。
image

image

前面说了这么多我们是怎么做的,下面来点理论的,Queue Theory,即排队理论。

举个大家身边的例子吧,相信在上海生活的朋友都有体会,在午饭和晚饭时间段,去餐馆总会看到领号排队的。我们把餐馆看作是一个系统,向customer提供service。现在是用餐高峰时期,供小于求,即系统的处理速度或者叫吞吐量小于客户增加的速度。作为餐厅经理,我们要怎么减少排队呢?最直接的办法,扩容!加大店面容量,招揽更多的员工,系统处理速度上去了,自然排队就减少了。但是这是一个不太现实的解决方案。寸土寸金的商业区,不一定有地方给你扩容,即使有你要投入大量的资金租地,装修和招募员工,只是为了解决高峰时段的排队问题,这对一般餐馆来说都是不太现实的,或者说性价比太低,ROI(投资回报率)太低。那还有没有其他的解决方案呢?当然有!

在排队理论中有一个重要的Little定律:

任务完成周期(Cycle Time)= (正在同时处理的任务数) / (平均任务完成率)。

Wiki中的原话是:

The long-term average number of customers in a stable system L is equal to the long-term average arrival rate, λ, multiplied by the long-term average time a customer spends in the system, W, or:

L = λW

即在一个稳定的系统中长期的平均客户数L等于长期的平均到达率λ乘以一个客户在系统中花费的长期的平均时间W。(在稳定的(即满负荷)系统中,到达率与完成率是一样的。好比在餐馆,要有一桌走了才能进下一桌的人。)

任务完成周期越小意味着系统的处理速度越快。我用我小学数学深厚的底子,很容易得出两种方法加快系统处理速度:

  1. 减少同时处理的任务数。
  2. 提高平均任务完成率。
具体有哪些策略呢?
  • 限制正在处理的任务数,即控制WIP(Work In Progress),这是精益和看板的重要原则。我们在翻书的时候,不会一章还没有翻完,又去翻新一章,这是不行的。一定要确保这一章真正的DONE了,再开始新一章。(当然为了最大限度的利用资源,我们将正在翻译的章节数控制在2章。)再说餐馆这个例子,系统已经蛮负荷运作了,你还会让新的客人进来么?当然不会,你一定是等一桌客人走了,再让下一桌客人进来。再说一个极端情况,一个餐馆桌子很多,但是相对的人力资源不够(可能突然有部分员工辞职或请假)。现在餐馆没有坐满,但是已经让所有的服务员和厨师忙个不停了,外面还有客人在排队。这时,如果看还有空位置,让客户进来只会让这个系统性能更低,让客人在餐馆里花费的平均时间更长,排队的客人等的时间更长。客人在你的餐馆里待的时间更长,不能给你带来更多的收益,反而,你要更多的成本来维持这些客人,也不能让新的客人进来(这才是你的收益)。这也就是所谓的等待成本。这个道理听起来比较简单,很多餐馆却一味的只想着让新的客人进来,这反而可能不能赚到更多的钱,还使等待客人的队列更长,甚至失去了这些客人。其实真正在软件开发过程中,也很少有团队能做到这一点。
  • 提高平均完成率。加人,也就是开始餐馆例子中的扩容,这个对很多团队来说可能不大现实。我们翻书也是一样,团队就这4个人了(再说,总不至于以后书的封面上长长的译者名字列表,后面还加一“等等”吧)。那么就要让现有资源发挥更大的作用。例如流程中的一些潜在压力,如Peer Pressure,Progress Pressure,至少让人不好偷懒。优化工作流程,像我们使用CI通知大家有新的更新,如果Reviewer看到有新的章节翻译好了,他马上可以开始review了。再比如,有的餐馆发现客人经常找服务员要调羹,服务员总是被客人叫过去了,然后又回到厨房去拿调羹,再交给客人。于是他们让服务员随时身上放有一个调羹,这样不论送菜或点单的时候,就随时可以给客人调羹,节省了时间。但是,记住千万不要让资源过载,就像前面说的那样,指挥让系统更慢,效率和质量都会下降。让团队去承诺他的工作量,量力而为。
  • 定制小一点的任务。小一点的任务意味着处理时间更少。餐馆里,客人一个人吃饭总是很快吃完了就走,而一桌客人吃饭的时间可就长多了。当然,这不是餐馆自己能决定的。但幸运的是,我们翻书,做软件开发,这确实我们能决定的。我们翻书的时候用一章来做为一个任务,方便计划跟踪。同样,做软件开发时,小任务意味着更容易实现,更容易估算其大小,因为其复杂度相对较低,不确定性也相对较小。而且一件事情分成两个任务和分成10个任务,工作量是不同的。CFD4这是一个CFD(Cumulative Flow Diagram),我也不知道翻译成中文该怎么说,就CFD吧。下面我们从另一个更直观图来说明CFD。

    CFD1

    左边斜率较大的线代表着任务到达的数量和时间的关系,右边这个效率较小的线代表着任务离开(即完成)的数量和时间的关系。中间的面积为工作量。下图是一个软件开发的CFD图:

    CFD6

    下面我们来比较大任务划分和小任务划分的区别。

    CFD2 CFD3

    很明显大任务划分所须的工作量更大。当然我们比较倾向于小任务了。这时,有的人可能会问了,既然小任务好,为什么我们翻书时不以小节为任务单位,那不是更好?其实任务也不是越小越好的。任务小也是需要成本的。比如我们用小节为任务单位,翻译时可能你一节,我一节这样翻,这样每个人翻的时候可能就跳着小节翻,上下文就丢了,还得去读一遍前面的小节,不停的切换上下文,效率就相对比较低了。而且更容易导致小节之间翻译风格的不一致,在做完这些小节,还要花费成本将其整合。大任务也是有开销的,大任务自然在系统中待的时间比较长,这个维护成本也是比较高的。而且任务在系统中是不会产生价值的,只有出了系统即完成了才能带来价值。好比生产汽车,你先生产了一些零件,如轮胎,底盘,引擎等,放在仓库里只会增加维护成本,只有将其组装成汽车卖出去才能带来价值。还有Internet上的数据传输也是这个道理,大文件传输不是整个文件一次性发过去,而是分成固定字节的小数据包来传输,这个包太小或太大都会影响传输性能,要寻找一个平衡点。这个任务大小与成本的关系如下图所示:

    CFD5

    小任务还有一个好处就是减少平均任务到达和处理的变化性。使用小任务长期的看,任务的到达是均匀的,处理起来也是比较均匀的,不会有大起大落。


  • 为一个队列增加更多的server。这个例子最好说了,大家都有到银行排队的经验吧。现在银行一般都有个排队系统,大家拿号排队,然后有多个窗口服务。当一个窗口空闲时就叫下一个号过去处理。这个就是一个队列对应多个server的例子。这种队列就是First In First Out。大家再想想以前银行没有这个排队系统时,我们是找哪个窗口人少,就去排哪个。但是这个却不一定是最快的,有可能别的窗口处理的更快,别人后来的,可能还比你先走。这种队列就是First In Maybe Out。FIFO

    很明显,使用Push的这种队列,系统负载是不均衡的,Pull就比较均衡,系统的利用率更高。再来说回餐馆的例子,一般热门的餐馆排队都是门口一排人领号的,这是Pull。但是,也有一些老餐馆,客人都是自己进去找座位,看到哪桌吃的差不多了就在旁边等着,也有可能后来的人一来碰到一桌刚吃完就马上坐下来。现实中很多时候,我们都不能完全实现Pull队列,我们会有其他的紧急通道,使得Pull模型演变成FIMO。比如医院的急诊就是这样的,因为这样的紧急customer的等待成本是非常高的。因此我们在做软件开发时,要对story排优先级。

    在软件开发和翻译过程中,team的成员就是server,任务就是customer。那么我们如何为任务的Queue加server呢,当然不是加人,而是角色模糊。什么意思呢?我们的一个功能一般先从等待队列中到开发人员手中,开发人员做完了代码,功能进入等待测试的队列中,然后QA从中拿到功能进行测试,测试通过后,这个功能就完成了。假如一个team有4个人,2个dev和2个QA。那么就有两个server对应着一个等待开发的队列,两个server对应着等待测试的队列。如何在不增加人员的情况下,增加队列对应的server呢?很简单,让QA能做dev的事,dev能做QA的事,即角色模糊,这样等待开发和等待测试的队列都对应着4个server了。当然这是一个比较理想的状况,实际情况是一般QA不可能完全胜任dev的工作,dev也不能完全胜任QA的工作。但是,这可以是我们的一个努力的方向,可以通过其他的手段来弥补工作质量问题。在我们翻书的过程中,我们为了应对进度压力,就采用了角色模糊,Reviewer可以做Translator的事,Translator可以做Reviewer的事。系统性能一下就可以提高不少。因为不论是Reviewer和Translator都很了解我们各自要做的事,不存在什么技能的差异。要是软件开发团队中能做到这样就太好了!也就是在团队中培养“通才”。下面我说一个软件开发比较实际的例子,在开发团队中,有的开发人员可能比较擅长写UI,javascript,CSS等;有的开发人员可能比较擅长写算法;有的开发人员可能比较擅长做数据库方面的。而实现一个功能,这些技能可能都会用到。通常大家都拿各自擅长的任务,有时UI的任务比较重,做UI的人比较忙;算法的任务比较少,做算法的人比较闲。这时系统负载是不均衡的,我们应该尝试让团队成员成为“通才”,让他们这些任务都能做,只是比较擅长做某一类。然后通过代码审查,结对编程等方法来解决代码质量问题。同时这样加快知识分享,牛人带新人,团队成长比较快。

最后,总结一下我们用到的工具:
  • Excel:用来做看板和Burndown图。
  • Subversion:用来做Repository,同时可以提供history和版本控制。
  • CruiseControl.Net:CI实时更新项目状况。
  • Skype:每周周会,语音会议。
  • Email:一般沟通。
那么我们还能做的更好么?
  • 帮助PO(出版社编辑)使用这样的开发方法,使他们能更多的参与到这个过程中来。至少他们不至于那么惊奇我们按时保证质量完成,结果他们来不及印刷。这样我们更快更及时的得到PO的反馈。
  • PO了解了这个开发方法后,我们就可以随时发布我们已经翻译好的部分。每翻译完一章,我们就可以叫给出版社编辑审校排版。以一章最终能直接拿来印刷,作为一章DONE的标准。这样等到我们做完最后一章的时候就是可以直接印刷出书的时候啦。听说,国外有些出版社做到了这点,甚至他们有类似CI的东东,可以做检查,可以做nightly build,每天能发布beta电子书!
  • 在CI中加入一些自动检查的功能,如检查术语是不是统一翻译等。
我们从这次翻译活动中学到了些什么呢?
  • 敏捷不仅仅在软件开发上可以应用。许多敏捷实践改变人们做事的行为;敏捷工具可以帮助我们解决很多问题。
  • 我们成功的因素:
    • 确保良好的沟通;
    • 快速的反馈,不断的学习;
    • 自组织的团队非常好。避免了局部优化,改进队列。责任共享;
    • 倾向使用简单的工具;
    • 不断的观察与调整。
这篇文章比较长,破纪录了,呵呵。还算是比较有意义的一篇文章。鼓励一下自己:)
Jackson Zhang

Jackson Zhang

Odd-e敏捷教练,主要涉及组织,团队,产品,技术,工程实践等,曾为多家知名企业提供教练与培训服务。译有《用户故事与敏捷方法》,《.NET单元测试的艺术》和《实例化需求说明》。擅长工程实践(如测试驱动开发,单元测试,重构,持续集成等),产品探索(Impact Mapping,Pretotyping,Lean Startup等)与团队协作。zbcjackson AT gmail.com

Read More