Table of Contents:

开篇词 | 为什么你要关注研发效能?

研发效能的完整定义应该是:团队能够持续地为用户产生有效价值的效率,包括有效性(Effectiveness)、效率(Efficiency)和可持续性(Sustainability)三个方面。简单来说,就是能否长期、高效地开发出有价值的产品。

研发效能的提高,需要整个公司在研发流程、工程方法、个人效能和文化管理等方面进行精心设计。

在这个专栏中,我会从 4 个方面,分 5 个模块与你讲清楚如何做到研发的高效能。

01 | 效能模型:如何系统地理解研发效能?

研发效能的模型是什么?

在我看来,软件开发本质上就是一条超级灵活的流水线。这个流水线从产品需求出发,经过开发、测试、发布、运维等环节,每一个环节的产出流动到下一个环节进行处理,最后交付给用户。
image.png
另外,这条流水线的每个环节都还可以细分。比如,本地开发环节可以细分为下面几个部分:
image.png
瀑布模式就类似于传统流水线的处理方法:它强调每个环节之间界限分明,尽量清晰地定义每一个环节的输入和输出,保证每一个环节产出的质量。但,和传统制造业相比,软件开发又具有超强的灵活性,体现在以下四个方面

  1. 最终产品目标的灵活性。传统流水线的目标确定,而互联网产品的最终形态通常是在不断地迭代中逐步明确,相当于是一个移动的标靶。尤其是最近几年,这一灵活性愈发明显。比如,在精益开发实践中,常常使用 MVP(最小可行性产品,Minimal Viable Product)来不断验证产品假设,经过不断调整最终形成产品。
  2. 节点之间关系的灵活性,比如流水线上的多个节点可以互相融合。DevOps 就是在模糊节点之间的边界,甚至有一些实践会直接去掉某些环节,或者融入到其他环节当中。
  3. 每个节点的灵活性。每一个生产环节都会不断涌现出新的生产方式 / 方法。比如测试,最近十多年就产生了测试驱动开发、Dogfood(狗粮测试)、测试前移等方法;最近又出现的测试右移,开始强调在生产环境中进行测试。
  4. 每个节点上的开发人员的灵活性。跟传统制造业不同,流水线上的每一个工作人员,也就是开发者,都有很强的灵活性,主要表现在对一个相同的功能,可以选择很多不同的方式、不同的工具来实现。 比如,之前我在 Facebook 做后端开发的时候,同样一个代码仓,有的同事使用命令行的编辑环境 VIM/Emacs,有的使用图形界面 IDE,有的使用 WebIDE;在实现一个工具的时候,大家可以自己选择使用 Python 还是 Ruby 还是 PHP。这其中的每一个选择,都很可能影响效能。

02 | 效能度量:效果不好甚至有副作用,怎么回事?

在和技术管理者,尤其是高层管理者聊起研发效能的时候,常常提起效能的度量这个话题。管理学大师彼得 · 德鲁克(Peter Drucker)曾经说过,“一个事务,你如果无法度量它,就无法管理它”(If you can’t measure it, you can’t manage it)。要想提高研发效能,自然要首先解决效能的度量的问题。

研发效能的度量代表一组可量化的数据或参数,用来跟踪和评估开发过程的“健康”状况。 换句话说,研发效能的度量,从应用程序开发的生命周期中获取数据,并使用这些数据来衡量软件开发人员的工作效率

03 | 效能度量:如何选对指标与方法,真正提升效能?

效能度量的指标分类

在我看来,要真正发挥度量的作用,找到合适的度量指标,必须先对指标进行分类。我推荐从团队和个人这两个维度对度量指标进行分类,其中团队维度中又分为速度、准确度和质量 3 类,所以一共是 4 类。

image.png

效能度量的原则

效能度量不与绩效挂钩,是正确使用效能度量最重要的一点,再怎么强调也不为过。所以,我向你推荐的效能度量的原则就是:效能度量不要与绩效挂钩,而应该作为参考和工具,帮助团队提高效能。

因为无法覆盖 100% 的度量指标,把度量与绩效挂钩就一定会产生“做数字”的现象。这时,使用效能度量非但起不到正面效果,还会对公司和团队造成伤害。管理者常常倾向于使用度量与绩效挂钩这种方法,是因为它能具体到数字方便管理。这种错误,我们一定要注意避免。

如果你只能记得这篇文章的一句话,那我希望这句话是“效能度量不要与绩效挂钩”。

21 | 高效工作:Facebook的10x程序员效率心法

第一条原则:抽象和分而治之

虽然我们面对的世界非常复杂,但大脑只能同时处理有限的信息,那怎么平衡这个有限和复杂之间的矛盾呢?
最好的办法是,把一个系统拆分为几个有限的子系统,每个子系统涵盖某一方面的内容,并将其复杂性隐藏起来,只对外暴露关键信息。
这个拆分处理的过程,就是我们常说的分而治之;而用子系统来隐藏一个领域的内部细节,就是抽象
所以,拿到一个任务之后,我们要做的首先就是进行模块的定义,也就是抽象,然后对其分而治之

第二条原则:快速迭代

第一,不要追求完美,不要过度计划,而是要尽快实现功能,通过不断迭代来完善。优秀的架构往往不是设计出来的,而是在实现过程中逐步发展、完善起来的。
Facebook 有一条常见的海报标语,叫作“Done is better than perfect”,意思就是完成比完美要重要
有些开发者过于追求技术,投入了大量时间去设计精美、复杂的系统。这样做没有问题,但一定要有一个度,切忌杀鸡用牛刀。因为复杂的系统虽然精美,但往往不容易理解,维护成本也比较高,修改起来更是不容易。

第二,在设计的实现中,尽量让自己的代码能够尽快运行起来,从而尽快地验证结果。我们常常会先实现一个可以运行起来的脚手架,然后再持续地往里面添加内容。
在工作中,因为往往是在一个比较大的系统里工作,不能很容易地运行新代码。这时,我们可以编写脚本或者单元测试用例来触发新写的代码。通常情况下,我们更倾向于使用后者,因为这些测试用例,在功能开发完成上线之后,还可以继续用于保证代码质量。在我看来,在开发过程中,能触发新写的代码帮助我开发,是单元测试的一个重要功能。

第三,为了能够快速进行验证,一个重要实践是设置好本地的代码检验,包括静态扫描、相关单元测试的方便运行,以及 IDE 能够进行的实时检查等。

第四,代码写好之后,尽快提交到主代码仓并保证不会阻塞其他开发人员
关于实现代码提交的原子性,我还有一个小技巧,就是如果当前编写的代码提交实在不方便马上推送到 origin/master 分支上,我们也可以频繁地 fetch origin/master 的代码到本地,并在本地对 orgin/master 进行 rebase 来解决冲突。这样就可以确保,我们开发的代码是基于最新的主仓代码,从而降低代码完成之后 push 时冲突的可能性

第三条原则:DRY

DRY,也就是不要重复你自己。还简单,但是又很有效的原则,运用的好的话可以发现很多效率问题。
代码逻辑的重复,不仅仅是工作量的浪费,还会大大降低代码的质量和可维护性。
在编程工作中,除了代码的重复外,比较常见的还有流程的重复。比如测试中,我们常常需要重复地产生一些测试数据,运行完测试之后再把这些数据删除。

image.png

22 | 深度工作:聚焦最有价值的事儿

今天,我就和你聊一个看似简单的问题:在任务多、干扰多的现状下,如何最高效地利用时间,去做最重要的事儿,同时有更多的时间来放松和享受生活。
就我个人而言,我也一直在想办法去聚焦最有价值的事儿,也读了不少 GTD(Geting Things Done,尽管去做)的书,尝试了不少方法,积累了不少经验,也踩了不少坑。总结来看,实现深度工作的办法说起来很简单,可以概括为以下三步:
1. 以终为始,寻找并聚焦最重要的任务;
2. 追根究底,寻找最高效的解决方案;
3. 安排时间和精力,高效执行解决方案。

1. 以终为始,寻找并聚焦最重要的任务

第一步,自己定义任务

GTD 的创始人大卫 · 艾伦(David Allen)提出,日常任务可以分为 3 种:

因为,预先计划好的任务的优先级常常会随着情况的改变而改变,而临时产生的任务很可能当时觉得很紧急,但实际上是可以推迟或者甚至不做的。我们根据当前情况决定要做的任务,就可以避免把时间花在低优先级的任务上。

第二步,聚焦目标,以终为始

聚焦目标,以终为始,其实就是在自己定义任务。因为时间有限,为目标服务的任务才最重要。
作为高效开发者,常见的目标包括业务成功、帮助团队,以及个人成长这 3 个。如果能找到三者重合的任务就最好不过了。

我在 Facebook 工作的时候,有个朋友发现日常工作中自己和团队常常要用到面板,而现有的面板系统对他们的场景不够友好。于是,他自己花时间实现了一个基于 Python 的 DSL 的面板系统。他的工作中就会大量使用 Python,所以这个项目对他的个人技术成长很有好处。

工具做好第一版之后,团队成员非常喜欢这个工具,并很快就扩展到其他的很多团队,比如我也用它给我们团队做了一个面板。这个工具非常好用,半年后在公司立项,并由这个朋友主导,逐渐发展为公司最受欢迎的面板系统。

这个面板工具任务,就是一个帮助业务成功、帮助团队和个人成长三者相结合的一个案例。

日常工作中更常见的情况是,三者不能兼得。这时,我们首先应该关注业务成功,因为它是我们工作的最基本目标,是基础。在此之上,我推荐先考虑帮助团队成长。因为帮助团队的同时,往往会给自己带来一些直接或间接的成长机会。

第三步,无情的筛选,少即是多

生命有限,而工作无限,所以我们必须要无情地排优先级。
很多人都有一个倾向,就是贪多,认为越多越好,我曾经也这样。在自己的书单里添加了几百本书,书签页中添加了几百篇要读的技术文章,Todo List 里添加的任务也越来越多,还计划学习这个语言、那个框架。但实际做起来,却因为时间有限,不但只能浅尝而止,还让自己很疲倦。痛定思痛,我下决心去做减法。
在我看来,“数字 3 原则”很有效,也就是强制把要做的事、要达到的目标,都限制在 3 个以内。
这对我帮助非常大,所以我在后续的工作计划中,也强迫自己使用数字 3 原则,无论是三年规划、半年规划、本周规划,还是当天工作,都做一个无情的筛选,找出最最重要的 3 件事儿。

2. 追根究底,寻找最高效的解决方案

开发人员也要对业务有一定的了解。面对任务的时候,多问几个 Why,并与产品经理和团队成员充分沟通,了解它到底要解决什么问题,只有这样,我们才能以解决问题为出发点,找到最高效的解决方案。

3. 安排时间和精力,高效执行解决方案

用番茄工作法来记录深度工作时间

简单地说,番茄工作法就是把时间划分为固定时长的工作时间和休息时间。一个番茄时间包含两部分,25 分钟的工作学习和 5 分钟的休息时间。

番茄工作法的精髓是,在每一个工作时间段,避免干扰、全神贯注。因为只有精力高度集中,减少上下文切换,才能进入深度工作状态,进而最大程度地发挥我们的心智能力,提高个人效能。

用拥抱无聊来控制手机依赖

手机依赖症越来越普遍,我也深受其害,有段时间甚至去卫生间都一定要带着手机。

后来,我发现了一个“拥抱无聊”的方法。具体来说就是,在一些非常碎片化的时间,不要因为无聊就马上抄起手机,去找一些有意思的东西放松或者学习,而是尝试适应无聊。

其实,无聊也是一种不错的状态,试着去享受它,不要让自己的大脑一直处于活跃状态。这样可以让我们得到休息,而且更重要的是,能够比较好地避免自己打扰自己的倾向。所谓“自己打扰自己”,就是会不自觉地去想、去做一些与手上工作不相干的事儿,自己干扰自己。

23 | 效率工具:选对用对才能事半功倍

对于工具一定要选对和用对
选对工具指的是,我们要针对不同的任务,找到合适的工具来提高效率。
而用对工具指的是,我们要分配适量的时间和精力来选择工具,要时刻注意投入产出比

关于用对工具,我推荐一个比较好的方式是,留意工作中经常重复和繁琐的工作步骤,隔一段时间就做些工具方面的调研,看看有没有更合适的工具或者使用方法来优化这些流程。对于一些非常繁琐、执行频率又非常高的操作,如果没有现成的工具,甚至可以考虑自己开发一些工具和脚本进行优化。频次越高的操作,越值得优化。

24 | VIM:如何高性价比地学习VIM的实用技巧?