研发效能可以度量么?

taowen

Martin Fowler 告诉我们,不能!
那怎么办?我们可以用以下的过程指标来指导日常的改进:

会议时间

如果 Autonomy 的问题是高沟通成本,那么是否可以直接度量整个沟通成本。例如参与会议的时间,这是一个可能的指标。这样的指标会有什么问题呢? 有没有更好的指标?

度量会议时间会有如下的问题:

  • 会议没有包含全部的沟通成本,包括面对面沟通,IM沟通等
  • 不开会可能是因为没有新需求
  • 开会多可能就是因为需求多,说明业务蒸蒸日上
  • 开会多少只说明了成本的高低,只要最终的效能好不就 OK 了么? 或者换句话说,只要业务赚钱不就 OK 了么?

最有效的当然是总收入,总利润这样的结果指标。但是不能一竿子断定所有的过程指标都没有意义。不可能所有人都背最终的结果指标,也不可能所有的改进都要从结果指标入手。会议时间显然能说明成本构成,只是这个成本是否花得值很难判断。一个劳动者只有8个小时的符合劳动法的工作时间,如果有7个小时都在会议上,显然能够说明一些问题。所以我认为会议时间做为观察性的过程指标还是有一定意义,主要的作用是划个红线,超过了红线说明会议太多了。

会议时间这个指标的问题在于无法指导改进。因为开会多,可能仅仅是需求变多了。

“接口改动” / “实现改动” 比率

我们把文件分为两种类型,负责接口的文件和负责实现的文件。理想的情况下,应该尽可能少的改接口,而是主要去改实现,这样才能减少跨模块的人员沟通。如果一个新需求,需要同时改动N个模块。但是只要不需要改动接口(包括用 Map<string, any> 这样形式搞的隐式接口),仍然是理想的情况。虽然产品经理需要和多个团队沟通每个部分的需求是什么,但是开发团队之间的沟通仍然可以比较少。要每个新需求都只改动一个模块由一个团队负责,这是不太现实的:

  • 新商业玩法往往是破坏性的。我们不要去做提前预测
  • 需求大小是任意的,产品经理分工也是有随机性的。总是有办法把一个需求弄大到全公司只做这么一个需求的地步。

接口完全不修改,开发人员之间完全不沟通也是不可能的。我们要关注的是目前的业务逻辑拆分是不是合理,多个 Git 仓库之间的接口如果需要频繁调整,那么说明 Git 仓库是不是分得过多了,或者边界不是最佳的。要根据新的输入,不断去审视过去做过的拆分决策。而 “接口改动” / “实现改动” 比率可以量化目前业务逻辑拆分是否让每个 Git 仓库有 Autonomy。这个值越小,说明仅改动实现情况占比越高。

为了数据统计比较稳定:

  • 仅做到文件级别的区别。一个文件要么属于接口,要么属于实现。一般通过技术手段都可以做到这样的隔离。
  • 一天无论改了多少次,改了多少个文件都记为“1次”改动。这样避免了分多次提交,或者文件数量多寡引起的数据波动。

极端情况下,我们可以不分 Git 仓库,或者只有两个 Git 仓库,从而让 “接口改动” / “实现改动” 比率比较好看。这个也说明了分 Git 仓库的成本。把业务逻辑拆得越碎,必然会导致跨团队的沟通会上升。Git 仓库不是分得越多就越好,而是满足了团队的并发数就可以了。

这个指标的另外一个问题是日常性的文案修改会导致实现改动非常多。所以我们要以“Consistency”维度的指标去平衡。假设我们已经有了一种统一的文案配置机制。那么需要有一个“文案配置机制”接入率的指标。这样就可以避免日常性的例行修改破坏这个指标的真实性。

《A Philosophy of Software Design》 很重要的一个观点就是 "Modules should be deep",这样的隐喻让人们把注意力放在了静态的结构上。其实作者的本意是接口如果比实现要小很多的话,接口被修改相对于实现被修改的概率也就小了很多。这样我们大部分时候就可以只改实现,而不改接口。“业务逻辑拆分”其成本和收益都要在接下来做新需求的过程中体现,抽离了业务变更的时间轴,静态的代码结构无法度量其好坏。

接入率

不认为去识别“代码重复率”是有意义的指标。代码重复并不一定是问题,很难说今天是一摸一样的代码,明天还会保持一摸一样。不管三七二十一的“复用”反而可能造成耦合,降低团队自主性(Autonomy)。 一个典型的反面案例就是 utils 包,utils 类。没有人说得清楚啥时候要用你抽取出来的这个 utils 类,也说不清楚啥时候不应该用。 如果要抽出可复用的代码,出发点应该是 consistency,是在团队关键成员达成了一致之后的有意识行为。

每个可复用的Git仓库,要定义清楚自己的适用范围。在适用范围内需要度量接入率。如果说不清楚啥情况该复用,啥情况不该复用的东西,就应该当成一次性的业务逻辑,不要让其他Git仓库对其产生依赖关系。 接入率基于代码扫描自动计算,可接入的通过 pattern match 算得,已接入的直接看代码符号的引用关系。

阻断率

当我们使用了 Java 这样的编程语言的时候,Java 会阻断你在代码中使用汇编语言直接操纵 CPU。这是比较典型的“阻断”。 阻断同样是为了保证一致性。

如果使用了 C++ 这样的编程语言,很有可能 Git 仓库之间对什么是一个 string 都没有共识。 这样就必须要在一定范围内(比如某个项目,某个部门),强制要求所有的 Git 仓库都接入同样的 string 库,从而保证互操作的低摩擦。

类似的,一个彼此互相RPC调用的分布式应用,各个进程都用不同的 RPC 协议,用不同的 RPC 实现库来互相通信会导致很多问题。 例如,A调用B又调用C,一旦调用失败,层层加码地去重试,就可能导致最底层模块被反复重试,最终被击垮。 解决办法是需要分布式调用链上的所有进程都遵循同样的重试规则。 如果没有办法“阻断”手撸RPC的实现,看见一个http url,就直接随意找个 http 标准库去调用,那就很难保证重试规则的一致性。

阻断率指所有可接入的地方,有多少处上了强制检查,确保了违规行为会被阻断。

咨询量

当一个定位为“可复用模块”的团队,是孤单寂寞的。如果被拉去参与了某重点项目的 Feature Team,那是莫大的荣耀。 但是为了保证 Consistency,可复用的 Git 仓库,应该努力降低使用者的成本。 使用者的最大成本来自于沟通问询。如果文档不清楚,接入开通方式是手工的,必然会体现在咨询量上。

咨询量这个指标怎么计算就很难说得清楚了。在不同的团队里,咨询量的体现方式各有不同。总之这个指标就是越接近零越好。

工单流转时长

企业的外部用户创建的工单,如果最终发现需要开发来处置,到转到对应的开发手里。这个从工单创建时间,到开发开始处置的时间差,就是工单流转延迟。 度量这个指标主要是为了避免后台模块缺乏对企业最终用户的体验缺乏同情心,减少中间的层次。 这里工单指的是偶发的个案。对于大面积故障造成的工单,一天之内的工单合并为记录为一条。也就是数据采样的时候,一天只抽取一条工单纳入指标。

故障定位时长

孤立的一个进程很难完成所有工作。业务逻辑不可避免地要拆分成多个进程。如何找到出问题的进程。 一个进程也很难仅由一个 Git 仓库构建而来。业务逻辑不可避免地要拆分成多个 Git 仓库。如何找到进程的问题是哪个 Git 仓库造成的。 故障定位延迟是指故障从开始定位,到找到根本原因所花的时间。进程边界,Git 仓库的边界,越不依赖人的经验,越不依赖人的现场沟通,就越可能降低故障定位延迟。

代码集成时长

从修改一行代码,到把这行代码修改和其他进程集成到一起,用真实流量验证,这个端到端的延迟是多少。 开发自己的笔记本能把所有的进程都能启动起来是一种办法。 开发能用单元测试模拟试也是一种办法。 每个小时上一次线也是一种办法。 只要能对刚才改的那行代码,集成起来不出问题有信心就可以。 所以我们没有把“本地开发环境设置时间”做为一个指标,因为能够本地启动进程是手段,而集成到一起测才是实际目的。

业务逻辑拆分模式

以上是我们整理出来的可能有用的指标,全文撰写中 taowen/modularization-examples

阅读 117

taowen
I write code

Go开发者们请加入我们,滴滴出行平台技术部 taowen@didichuxing.com

4.1k 声望
1.1k 粉丝
0 条评论

Go开发者们请加入我们,滴滴出行平台技术部 taowen@didichuxing.com

4.1k 声望
1.1k 粉丝
宣传栏