如何提升软件的交付效率

前言

一个团队的交付效率,体现着这个团队的战斗力。交付效率跟很多因素相关,仅谈效率其实并不全面。我们的最终目的其实是要提升「产能」和「有效性」。产能跟效率与工时有关,有效性跟方向的正确性和成果是否完成兑换有关。

  • 产能:效率、工时

  • 有效性:方向的正确性、成果是否完成兑换


为了不让问题太过宽泛,也为了能讨论的更加细致,本文我们只讨论效率(和有效性)。其他因素方面的讨论,可以独立成文。

本文主要从以下几个方面来介绍:

  • 一些道理

    • 从治河中学习:束水攻沙

    • 让每个排队的人少等一会:利特尔法则

    • 识别最慢的环节:约束理论

  • 应该怎么做

    • 为什么会堵住:风险识别与资源分配问题

    • 及早得到外部反馈:让别人看到并收集意见

    • 远离空想之地:在真实世界中试验

1. 一些道理

1.1 从治河中学习:束水攻沙

束水攻沙」是中国 明末专家 潘季驯 提出来的 治河之策(1565~1592),当时他根据黄河含沙量大的特点,提出了「以河治河,以水攻沙」的治河方策。以前人们在治理河水的时候,都是在不断加固两岸河堤,黄河水的含沙量较大,会导致河堤越加越高,甚至都出现了河水比两岸还要高的情况。这样当河水泛滥时,一旦河堤决口,河水就会奔涌而下,毁坏两岸房屋和农田。


潘季驯 提出来的治河之策,反其道而行,他希望在治河的过程中增加河水流速,让河水能够快速流入大海,这样就不会造成阻塞。此外,增加流速的同时,这些水流会把河中的淤泥和沙子带走,导致河堤内部更低,即使决口造成的危险也更低。



但是这跟交付效率又有什么关系呢?这关系很大。我们可以把河流理解为「软件功能的价值交付流」,河水只有最终流入大海才算完成,软件产品也只有最终交付到用户手中才算完成。如下图,所以交付软件,不就是治河嘛,我们应当向 潘季驯 学习「束水攻沙」,只有增加流速才能减少危害。把河堤垒的越来越高(待办列表越来越长),不能解决根本问题。



  • 在实际开发过程中,我们经常会遇到任务堆积的情况,或者我们依赖了其他人的工作,但是他又迟迟没有完成。这个时候给他增加再多的待办,也是毫无作用的,更多的待办除了给他更大的压力之外,不会让整体交付得更快,反而会变得更慢。因为等待新待办完成的人,也在排队中了(一个环节任务多,会导致依赖这个环节的人都在等,任务越多,等待的人就越多)。这些待办列表(数组),就好像河堤一样,不断的加固和垒高,一旦撑不住了,就会给整个项目带来了极大危害。

  • 这时候应用「束水攻沙」的思路,比较好的办法是,减少待办事项数量,让正在进行中的工作赶紧交付出去,并且暂不接受新的待办排进来。对于依赖这个待办的人而言,也需要调整事项的优先级,而不是处于等待中。处于连环等待过程中的所有人,都会觉得系统卡死了,工作效率非常低。

  • 除此之外,由于待办减少了,任务被切分成了更小的模块,会导致每个环节更容易走到更下游,开发的工作减少后,测试的工作,发布的工作,都会减少,并且用户也可以更早的看到新功能上线(重要的部分先上线)。这是一种被称为 Small MR 的研发理念,采用小步快跑的方式,持续不断的交付功能(增加价值的流速)。

1.2 让每个排队的人少等一会:利特尔法则

排队论 中有一个著名的定律,称为 利特尔法则(Little's law),是由 约翰·利特尔 在 1954 年提出的,公式如下,

1
2
3
4
5
L: 平均滞留人数
λ: 吞吐率(单位时间内进入或离开的人数)
W: 平均等待时间

L = λW
要想缩短平均等待时间 W,只能通过减少平均滞留人数 L,或增加吞吐率 λ 来实现。


而「吞吐率」一般是很难立即提高的,这涉及到系统本身所能提供服务的效率。但是平均滞留人数却可以通过管理手段人为减少。对任何一道工序而言,在不增加工序本身工作效率「吞吐率」的情况下,仅仅减少在制品数量「平均滞留人数」,就可以大幅度的减少「平均等待时间」。 即,限制在制品(work-in-progress)数量,可以有效的缩短平均等待时间,从而提高「产能」。


利特尔法则 是日本丰田汽车 精益生产 的理论基础(去库存,减少浪费),这也是为什么在软件开发中,大家追求持续集成、持续部署 的根本原因(持续交付)。


精益生产 是上世纪 50 年代起,从丰田公司实践中演化出来的生产方式,又被称为「丰田生产方式」。1990 年麻省理工 James P. Womack 等几位教授提炼总结了丰田的实践,出版《改变世界的机器》一书,精益生产的概念才开始为世人所认识和效仿。直至今日,它仍然是最先进的生产制造方式,是制造业共同追求的目标。丰田生产方式之父 大野耐一 说:丰田生产的两大支柱是「准时化」和「自动化」,「看板」是运营这一系统的工具。 —— 看板方法


不幸的是,「看板」这个词在多数情况下都被人误解了。它不是一个「让大家看的板子」,而是一个专有名词「Kanban」。它代表着人们如何通过「观察交付过程,减少平均等待时间,从而提高产能」这一努力的方向,而不是为了压进度、催交付,如果非得说它的精髓,那就是砍需求(减少滞留,赶紧做完)。

Kanban:减少滞留,赶紧做完(束水攻沙) 让大家看的板子:压进度、催交付(修堤筑河)


  • Kanban 的主要思路在于快速交付,左侧 Kanban 上能展示出完整的工序,每个工序都有 WIP/Done 这些标识。我们可以看到,上游的 Done 太多会给下游 WIP 造成阻塞,也就是即使上游某个环节生产效能逆天,也不能让整个系统更快。这就是丰田汽车公司所看到的浪费,轮胎造的太快,车门如果没有生产出来(或产量不足),那也没办法最终得到一辆汽车。并且轮胎生产的那么多,也只能造成库存压力过大(制造业还需要考虑库存成本,软件开发中是任务切换成本)。

  • 而右侧的板子,是大家常用的 Todo/Doing/Done 三列视图,仅能看到自己(当前工序)的任务完成情况,但是看不到上下游,这种板子其实不能说是 Kanban,无法识别哪个环节效率过高导致下游阻塞,也无法识别自己本身是否效率过高,导致上游供货不足。

  • 所以从这种角度来看的话,很多人只是用能看的板子来记录自己的任务,并没有从完整的价值交付链路视角看到全貌。这是社会化大分工、工业革命批量生产 所带来的问题,批量生产可以提高单一工序的效率,但是整体效率会受到库存积压和供货不足的影响。

1.3 识别最慢的环节:约束理论

我并不想推广「看板」方法,我也不是看板方法的忠实信徒。回到主题,我想要做的事情是,通过一切有用的办法,提高软件团队的生产效率,从而提升整个团队的战斗力。


不论是「束水攻沙」还是「利特尔法则」,都有反直觉的成分在里面。也就是说,如果真的要这样做的话,就得应对来自四面八方的舆论压力,因为它所提倡的跟通常的 工作方法/文化 截然不同,甚至有冲突。

  • 具有更短的待办事项列表:是不是工作不饱和?

  • 超快的交付节奏:是不是缺乏深入思考,有没有想好了再做?整体来看是否在浪费时间?

  • 下班时间更早:既然还有那么多时间,为什么还在努力砍需求?


比较容易说服人们的办法是,向大家介绍「木桶原理」和「约束理论」。

一只木桶能盛多少水,并不取决于桶壁上最高的那块木板,而是取决于「最短的那块」。

任何「非瓶颈资源」究竟能使系统赚多少钱,不是由它自己的潜能所决定,而是由系统中的其他制约因素所决定。



在软件生产流程中,单点再快也没有用。代码写的再快,尚未部署上线(或者没有人来使用功能)也是没有用,充其量只是生产了一堆内容和资料。这些内容和资料,必须变成功能被人用,才能产生价值。所以软件开发团队,应该总是致力于两件事:

  • 尽一切可能消除阻塞,让代码变成功能

  • 尽一切可能验证功能的有效性,帮助用户解决问题

以上两点往往是自嘲为「码农」的工程师,最容易被忽略的。软件开发并不是交差就完事了,优秀的工程师具有使命感,总是主动对外释放价值。


木桶原理大家都知道,也知道提高效率要致力于解决最慢的那个环节。但具体怎么做呢?我可以提供两类视角。

  • 一线研发视角
    • 依赖别人的事项,一定要心中有数。催了两次之后,如果还不能完成,那就要考虑上报风险,把手头这件等待中的事情从给自己的待办中移除掉,这样等待自己这件事完成的那些人也会释放。老实说,这个其实挺难的,但其实是正确的做法,应当让全链路所有人认识到阻塞带来的等待成本。

    • 除此之外,自己答应要交付的事情,需要定期在项目会上同步风险,如果不能完成,就得提前在项目组内讨论,可以在约定时间内完成哪些部分,而不是按照自己实现的难易程度来交付。明明会延期而不说,那只有两个结果,要么别人因此也延期,要么到期交付了不是特别重要的那部分工作。

  • 项目管理视角
    • 项目管理者应当努力提高项目的可见性,具体做法就是每周向项目组成员和利益相关方发周报,而不是让组员向自己发周报。在项目周报中,应当明确标定哪些是按照当前进度无法完成的内容,以及为了应对这些风险,所采取的举措。因为有很多风险,是需要继续上升的,项目管理者有时候也难以拍定优先级(需要跟其他项目协调)。

    • 项目管理者应当主要充当砍需求(重排优先级)的角色,别管时间多么紧,总是有最重要的那部分内容,而不是全都要。全都要的结果只能延期,延期并不是加班这么简单,也许还会错过市场窗口,或者无法更早认识到失败的创意。导致整体投入人力超标(超出预算、加班),让一件本来 ROI 较高的事情变得不是那么划算了。

2. 应该怎么做

2.1 为什么会堵住:风险识别与资源分配问题

消除阻塞的办法,其实很简单,但执行起来却比较困难。消除阻塞,只需要识别阻塞点,并疏通阻塞就行了。识别阻塞很容易,疏通困难。在软件开发中,阻塞源于某些事项没有按照预期的时间完成,依赖这件事的人,就会处于等待中,这是一种极其浪费人力的状态。因为阻塞点并不是只阻塞一个人,而可能是阻塞了一连串的事项,或者是一连串的人。大家都处于排队状态,平均等待时间乘以人数,量级会大到吓人。


其实上文对于如何应对阻塞,已经告诉我我们办法了:「束水攻沙」和「利特尔法则」 。我们应当想办法让阻塞之处,赶紧交付,让水流(价值流)畅通。有两个办法:

  • 改变优先级:别的事情不做,先做这个

  • 砍需求:先交付重要的部分



这两个办法有时候,都需要一定的管理手段才能完成。因为调整优先级、砍需求 往往不是做事的人说了算的,而是分配工作的人说了算。所以如何让分配工作的人,认识到项目风险(阻塞)才是关键之所在。这就需要我们提升项目的可见性,甚至不同项目之间还要经常权衡。只有让资源的所有者看到风险,才有可能调整资源投入情况。


自下而上的让一线开发自己来调整,这是不太可行的,因为这会涉及到工作表现问题。

  • 做不完是不是能力差

  • 做不完是不是在偷懒

  • 做不完是不是不够用心


我很想说的是,在任何团队我们都应该建立「科学的项目管理观」,在已经利用好现有 人力/能力 的基础上,就完全可以打造出一个高绩效的团队了。软件开发不是打仗(不是体力劳动),大家不用拼死一战,而是要靠脑子和正确的方法赢得商战。


  • 软件开发过程中的加班现象是非常常见的,加班其实是一个不太好的习惯。它通常意味项目风险管控出了问题,或者说是我们用着比预算更多的时间,才能得到一个比较理想的结果(总 ROI 下降)。从软件团队整体视角来看,人们想做能做的事情,总是有各种选择的。如果对 ROI 评判出了问题,那就没有把力量用在关键之处(忽略了其他 ROI 更高的事项)。其实,当意识到某件事情需要投入更多的人力时,应该考虑这个事情是否仍然划算,是否有其他更划算的事情要做。

  • 那么怎么才能不加班,还能完成工作呢?这是不可能的。我们要么投入更多人力,要么到截止日期时无法完成工作。所以,重要的不是交付,而是在截止日期时交付什么。在仅有的人力投入基础之上,在截止日期时,先交付哪一部分内容。也就是说,不是没有时间,而是缺少优先级概念(There's always time, time is priorities)。但这个优先级不是那么容易达成的,通常需要在多个项目中进行协调。更是需要资源的所有者(赞助商),参与进行讨论。

  • 明明觉得无法完成,还要假设自己能完成,然后在截止日期时,交付一个半成品。这是非常有害的,软件项目如果不加管控,就是这样一个结局(常被称之为「死亡行军」)。有不少团队经历过、经历着这样的「死亡行军」,反正做不完,那就做着吧,我们不是已经在加班了吗。

  • 所以应对加班总共有三种办法,其中前两点都是预算超标的表现,而且还会造成依赖方进行等待:

    • 扩大人力投入
    • 扩大时间投入
    • 优先交付 ROI 更高的部分
  • 优先交付 ROI 更高的部分,就是本文提倡的办法,是消除阻塞的利器。将在制品交付赶紧交付,不要让事项堵在自己这里,当下游开始处理自己的一部分工作时,再继续做剩余的工作,让价值流动起来,不要在任何一个环节有卡顿。

2.2 及早得到外部反馈:让别人看到并收集意见

习惯流水线工作的工程师,对于整个价值交付的全貌是不理解的。这是分工造成的,工程师只要完成编码,不用关心功能是否有用。最终的软件功能,是否用户喜爱,是否能解决用户的问题,这是产品经理的事情。这种思路是非常有害的,甚至有些人会认为,功能如何被用户所使用,是用户应该自学的。后者说,功能如何被用户所知,那是负责宣传工作的人应该做的,不是工程师该考虑的问题。


以上种种问题,就是社会化大分工场景下的窘态,这会导致大家虽然看起来很忙,但其实没有忙到点子上。即便是功能交付的效率再高,不为用户所知,使用起来太难,那会大大折损这件事情的最终价值。


有这样一种观点,认为设计优良的框架,细致考虑并精巧实现的架构自然会被人们重复利用。事实上,即便是最精美,最优雅的框架,可复用性最高的系统,也必须满足下面的条件才可能被复用。

  1. 大家知道它们存在
  1. 大家知道如何使用它们
  1. 大家认识到利用已有资源好过自己动手

—— 《软件架构师应该知道的 97 件事



架构如此,任何软件功能亦如此。提升功能的有效性,首先应该意识到有这个问题,其次才是考虑如何提升。提升有效性的一个常用做法是,建立「反馈循环」(也称为科学方法)。自然科学家们就是用这种方式,不断的打磨/修正 人们对大自然的认识。

  • 细致的观察真实世界的特点

  • 根据观察结果提出假设模型

  • 根据模型预测未来的事件

  • 继续观察并核实预测的准确性

  • 如此反复直到确认预测和观察一致

你敢相信么,以上关于科学方法的描述,居然出自于《算法》这本书。所以强调科学方法,并不是为了标新立异,而是它确实是被实践证明的有效方法。


  • 反馈能加速修正,只有得到多轮修正,才能更快的逼近事实。从这个角度来看,软件更像是一个活的生命体。它不断的从外界接受反馈,不断的调整自己的姿态,最终才能跟外界软件生态融为一体(被用户所使用)。

  • 一个比较棘手的事情是,当今社会每个人的信息带宽是有限的,眼前被各种各样的信息所占满。所以确定一个信息渠道很重要,让目标用户群体通过这个渠道跟成长中的软件进行交互。

  • 最后就是渠道中进行宣传的内容,需要能够吸引眼球,让用户感兴趣。所以有时候,文档比软件功能本身的价值还要高,需求是 交流/碰撞 出来的,而不是想象出来的。

2.3 远离空想之地:在真实世界中试验

如果你实在觉得「科学方法」实在太过学术派,那么在《Scrum:用一半的时间、做两倍的事》中,也曾提到过「PDCA 循环」(它是 Scrum 思想的由来),这是 Scrum 作者在越南接受飞行训练的指导法则:规划(Plan)、执行(Do)、检核(Check)、行动(Act)。

要精确衡量已经完成的工作,以及成果的好坏,并追求「持续改善」。别只改善一次,要持续改善,永远都要找到可供改善之处,永远不要安于现状。


提升功能有效性的办法是,要让自己的想法跟外界产生交互,并持续改善。



每一位有志于提升功能有效性的工程师,都应该读一下《做对产品》这本书。我自己在第一次读这本书的时候,浑身冷汗直冒, 如果一个创意在「空想之地」逗留时间太长,就会陷入由未经证实的恣意判断、信念、偏好 和 预测 组成的谜团之中。


我们无法只通过思考就判断出一个创意是否 “正确的它”,靠你自己的思考做不到,靠别人的思考或观点也不行,靠所谓 “专家” 的思考也是一样。有时候,我们会发现自己原来的预测是对的,但那大部分都是运气使然。


只要你还待在空想之地,就无法把 “正确的它” 给推导出或诱导出来,你只能通过在真实世界中进行试验,来把它发掘出来。


把自己的想法尽快落地,把 Beta 版的软件尽快拿出来,在真实世界中进行试验。不要担心一开始给人们的印象不好,只要能解决问题,我们可以向大家强调,这是为了解决问题而用来「快速试错」的试行版本。谁能比竞品更快的出现在用户视野,谁就有了更多直接的反馈,也就有了更早的机会修正自己的功能设计,最不济,也有了更早的时间点识别失败的创意。


  • 我经历过很多次这样的讨论,几个人在一个房间里,决定了一个想法,于是大家就立马紧锣密鼓的开始做了。或者说,几个人假设用户需要某个功能,或者假设用户想要以某种方式使用它,就决定开始做了。这是非常鲁莽的。

  • 每一次少数人的「密谋」都会导致不良后果,但这样的事情又一直在发生。没有让该知道的人知道,没有让该参与讨论的人讨论,就会在一段时间之后爆发危机(突然有了一个事情,别人不知道怎么来的)。

  • 多年以来大家对软件流程的理解,已经非常深刻的,即便是再小的功能迭代,也不能缺少必要的流程。比如说 需求、设计、技术 评审。如果不讨论需求,势必会在之后的某个阶段,反过头来重新再讨论一次,成本会非常高,导致很多工作重做。如果不讨论设计、技术,也是如此。

  • 软件开发是一个价值流,只有上游符合标准,下游的交付产物才可能有用。如果上游都不符合标准,那就只能在下游交付时才意识到问题,结果就是再重来一遍。《做对产品》书中提到过「预型」这个概念(假设先有这么一个东西,问问真实用户的想法),帮助大家走出空想之地,提前验证无效的想法,免得等产品交付到用户手中,才被意识到。

小结

本文介绍了我对软件交付的理解,以及提升交付效率需要额外关注的两点,

  • 始终致力于消除阻塞

  • 尽早的建立反馈循环

如果你的团队还没有认识到这些,说明整体的战斗力水平还具有很大的提升空间。丰田公司是如何作为后起之秀,成为世界汽车行业巨头的,这都是真实存在的例子。当众多汽车公司,还在沉浸于工业革命所带来的「批量生产」之快感中时,丰田生产方法告诫人们,去库存、减少在制品数量,可以提高产能。


文中以上的想法,并不是来源于我个人,我只是对现在正在经历着的软件行业的革命,进行了一次汇总。「束水攻沙」「利特尔法则」「木桶原理」「约束理论」,这些框架以后一定改变软件工程师的做事准则,将研发效能提升到一个新的境界。