@Lenciel

技术团队的绩效度量

这是一个关于技术团队效能管理的系列的第一篇,主要讲怎么度量,后面还有怎么提升

最近在 ArchSummit 做了一次关于绩效管理的分享(详情可点击),slide发出去之后,很多朋友希望知道具体讲了啥,就在这里整理一下。

作为技术管理者,我们经常要回答下面这些问题:

  • 作为成本中心为什么还要这么多人?
  • 提个需求怎么折腾这么久不能上线?
  • 我们的研发为什么没有 996? 不够拼啊?
  • 你们究竟怎么说明自己的价值和人效?

每次我们被问到的时候可能心里面都充满了委屈或者辛酸。以「要不要搞 996」为例,本质上这无非是「人月神话」的衍生物:通过增强人手或者工作时间来更快地完成软件系统的开发工作。如果是短期内目标非常明确并且业务发展需要,可以搞一下。如果把它当成灵丹妙药,那就真的只会把团队拖垮,把能干的小伙伴逼走了。

所以,这里我们来尝试讨论一下团队的绩效如何可以科学的进行度量。需要注意这里说的是团队的绩效,在货车帮技术团队的个人绩效是结合 KPI 和 OKR 两种手段来给每个人制定的。

首先是度量

能够被度量的,才是能够被考核,从而有提升的。

但是,要量化互联网行业里技术团队的输出是很困难的。有人可能会争论说,有很多的「手艺活」,比如画画,比如陶艺,仍然是可以通过工时或者计件进行绩效的度量的,为什么软件行业就不行呢?

首先,和生产制造或者销售等工作不同,技术工作的产出是「无形的」,在财务上资本花的时候也是算作无形资产。

其次,虽然在软件工程的早期,这个行业被类比成建筑行业:我们的架构师跟建筑师一样叫做 Architect,瀑布开发流程也明显有很多建筑体系的影子,甚至今天我们还自嘲是搬砖的。但实际上同一个建筑设计图,拿给两个合格的建筑施工队,工期和交付的产出应该都是基本一致的。而同样的需求,两个不同的技术团队不管是工期还是产出物,甚至可以说没有一行代码是一样的。

再次,整个技术工作对工作量的估计和任务的拆解是非常主观的。特别是进入敏捷时代了之后,研发的各个阶段工作并不是顺序发生的。很多时候测试还在进行这个迭代的测试,产品已经在整理下一个迭代的需求了,要把一个周期内的工作量度量清楚,更加困难。并且敏捷流程本身其实也是有代价的。

最后,核心的问题在于,软件本身的复杂度,造成了它的工作量本身就很难被评估。

旧手段的问题

过去我们衡量绩效的核心是放在工作效率(productivity)的衡量上的,它有下面几方面的问题:

  • 关注输出的总功而不是有用功
  • 关注个人的输出而不是团队的
  • 关注 productivity 而不是 performance

下面我们挨个看看最常用的一些手段。

计算代码行数

计算代码行数是国内很多公司,包括华为这样的大公司都常常在用的指标。只要稍微理性一点我们都知道,同样的问题被 10 行代码解决了,要比 1000 行代码好得多。我们每天都说要还技术债,实际上代码本身是最大的技术债:一旦有代码被写出来,它的维护和变更都会产生巨大的代价。但,同样的,另一个极端:用尽量少的代码解决问题,也不值得推荐,因为如果太 tricky 的话,没有人看得懂,可维护性会变差。

计算story points

story points 更多的是一个 velocity,用来衡量团队的 capacity,它本身连 productivity 都说明不了。用它来作为绩效标准会有两个问题:

  1. 它是对某一个团队自身进行衡量的相对值,不能用来作为团队之间的比较。并且同一个团队处于不同的上下文时输出也不一样。
  2. 一旦被当成绩效,团队会把「完成」尽量多的 story 当成目标,可能造成有用功比例降低,甚至是影响团队之间的协作。

记录工时

记录工时等都算是统计资源(包括人和各种别的生产资料)利用率的一个变种。但是高资源利用率意味着团队其实没有时间来响应需求的变更,插入,以及现有系统的优化。

数学里面的排队原理说明,一旦资源利用率达到 100%,lead time 就会趋于无穷大。也就是说,当你资源利用率非常高的时候,很可能你要完成一个事情的时间是趋于无穷大的(到处都是死锁)。

我们怎么度量

好的衡量方式应该有两个关键:

  1. 应该关注整个团队的总体有效输出:比如在过去一个典型的情况是我们对研发衡量他们的产出,对运维衡量他们的稳定性,于是研发把一堆有问题的代码直接扔给运维;运维开始制定一系列规则繁复的上线流程来保障稳定性:最终都影响了作为团队的整体有效输出。
  2. 应该关注有用功,而不是总功。

在找寻符合这些标准的数据的过程中,我们最终锁定了四个指标:

  • delivery lead time
  • deployment frequency
  • mean time to restore service
  • change fail rate

Lead Time

在 Lean Theroy 里面,衡量 lead time 是一个非常核心的概念:它是指从用户提出一个需求,到这个需求被满足的时间。在软件开发的上下文里面,lead time 分两部分:需求被确认,解决方案被设计出来,变成一个产品或者产品的一个功能;功能被开发出来并经过测试验证,并最终上线到用户可用的时间。

前面这部分是很难找到一个比较确认的开始时间的,并且它的输出也是比较模糊的。然而后面这段,设计确认了之后,从实现到测试到发布的时间,是比较好衡量的。

因此目前我们主要是统计代码从提交到真正进入生产环境需要的时间。这个时间越短,就说明我们响应用户需求以及解决线上问题的速度更快:

是一个小时内?一天内?一天到一周?一周到一个月?还是更久?

Deployment Frequency

lean theory 里面还有一个很重要的指标是 batch size。但是因为软件的 batch size 很难衡量,所以我们考察部署的频率:

  • 是按需的
  • 每个小时或者每天一次
  • 每天到每周一次

客户端系统要提高部署的频率,就需要有插件框架,支持不通过应用商店发布版本让用户获取更新。

MTTR

除开通过前面两个指标度量软件发布的能力,我们还需要度量系统的稳定性。传统上这是靠 MTBF(mean time between failures)。但是因为现在的系统复杂度非常高,bug 基本上是无法避免的,所以我们变成了另外一个维度:出问题时,多快可以恢复,也就是 Mean Time To Restore。

Change Fail Rate

最后一个关键指标也是跟质量有关的,就是针对生产环境(包括了灰度环境)的变更(包括 release 和配置两个维度的变更)失败率(是否导致了服务降级,服务失效,需要 hotfix/rollback/patch)。

其他指标

确定了这四个指标,还需要确定一些会对核心指标有影响的可量化指标。

平均进行中任务数

Working In Progress状态的Jira任务/项目人数

一个软件项目里的工程师需要快速地在计划、开发、审查和修复 bug 之间轮转工作角色。如果任务队列过载,队列上的事项就会出现积压,比如工程师开发代码时收到了新的特性请求,或者被要求参加评审会。

建议把这个指标逐步控制到至少 2.0 以下。

进行中任务总数

进行中状态的Jira总数

可以反映出正在同时进行的项目数(可以根据项目 Jira 的拆分力度,看看是统计 story 这一级,还是 epic 这一级)。

代码规模

过去三个月项目repo的commit数量

代码库和代码库里面增加的代码并不是越多越好,也不是越少越好。如果过多,其实就像实体经济一样,你的「库存」就多,代码一旦编写,就需要进行编译、部署和发布,就需要人进行维护。库存里的代码数量如果多到一个程度,对用户真正有用,交付了价值的代码比例必然是低的。

平均功能数

产品环境配置文件数/项目人数

如果说平均进行中任务数主要反应研发人员的「开发」工作量,平均功能数则主要是反应「维护」工作量。如果一个团队的平均功能数过高,工作的质量就会严重下降,公司可以根据这个来调整团队的人数或者是进行项目的分摊。

Bug数

每个项目的Bug总数

这个不用多解释,如果 Bug 多了,「需求消化时间」和「功能迭代时间」自然就上去了。

完成全部挤压需求的预期时间

项目平均「需求消化时间 * 挤压的需求数量

大量积压有三个负面影响。首先,它会不断增加了我们的「需求消化时间」,因为过多的需求堆积,会导致团队无法快速完成工作,而是陷入大量的对优先级的安排和争论中。其次,它降低了我们在未来改变计划的灵活性。最后,它降低了团队成员的积极性。

确定了这些指标之后,我们通过对 Jira/Confluence/ReviewBoard 的打通,来进行工具化、无侵入的指标收集,在不影响大家干活的前提下,形成项目情况的大看板。

敏捷开发的成本

软件工程发展到今天,一共产生了两个比较经典的流程:瀑布和敏捷。

瀑布是一个现实生活里面有的东西,这个类比就变得很好理解。

Don't touch me

敏捷究竟是什么?如果我们忘记那些 story point,站会,sprint,scrum,想一想,「敏捷」这两个字代表什么?

我觉得无非是代表当变化发生的时候,有足够的灵活性。

如果我们以做一双鞋举例。

瀑布可以对应到标准化工厂,每个阶段的专业人士(或者机器)可以用最高的效率进行生产,达到极高的吞吐量。

但是量产的鞋没法满足所有人的需要。比如有的人喜欢脚面宽一点,有的人喜欢鞋带或者鞋帮有一些变化。这个时候如果做鞋的说,都可以满足,那么它就很敏捷。

这通常是一个制鞋的工匠可以做到的:他有大量的工具,足够的技巧,只要多给点时间,可以满足你的各种需求。

工厂的优点很明显是量产的吞吐量,缺点则是生产不同的东西需要花费大量时间来重建机器。 工匠的缺点也很明显,就是生产效率低下,产量低,同时标准化程度低,不能水平扩展。

所以敏捷和效率其实就是跷跷板的两头,因此瀑布和敏捷作为两种侧重点不同的方法论,并没有好坏,也无所谓新旧,两种方法在项目管理的三角形里,一个优化了时间,一个优化了成本。如何选择,其实和软件开发里面大多数时候一样:你得判断做什么样的 tradeoff。在最近的十年,只不过因为软件的发布成本不断降低,复杂度却不断提高,且需求常常不确定,因此程序员倾向于支持更有柔性的敏捷。

理解了敏捷流程的成本有什么意义?

首先要时刻想到,你是牺牲了效率的。要把对效率的影响减小,就要控制项目参与人数,而不是加人。要为这些小团队提供更好的工具和服务,而不是把流程弄得复杂。

其次,要明白即便是推敏捷流程,根据不同项目细节上也可以不同:如果你的团队创建的产品或工具有内外部的用户,使用 Scrum,让他们看到交付的节奏,不要一直干扰开发。相反,如果是提供基础设施或者基础服务,使用 Kanban 等流程来提高 lead time,因为这种情况下用户最在乎的就是效率。

再次,因为敏捷牺牲了效率,光从团队组织架构上做动作,比如把团队规模减小,服务化等等,很难完全把这部分损耗找回来。怎么办?要不断地为更好的工具投资,来对抗复杂度,提高效率。好的工具通常是对问题进行了抽象之后,让关键的信息流动的同时,让关键的步骤被自动化,这其实解决的就是复杂度。

最后,当通过工具提高效率进入瓶颈期时,你可以再尝试从人这方面入手:改进流程,将整个系统或者任务分成更小的部分,让员工成为专家中的专家。同时,良好的流程还有助于并行化工作以提高整体的吞吐量。