代码变多不等于软件变多:一份大样本研究的三个度量口径问题

一、读这类研究,第一件事是拆”产量”这个词
据公开报道,一项跨数年的大样本编程实践研究发现,人工代码审查是编程工具整体效率的一大瓶颈,导致几乎没有证据表明企业引入相关工具能提高软件产量或减少就业;研究的工作事件规模覆盖数百家软件公司、数十万员工与上亿条提交与合并请求一类的事件。这些规模数字在本篇只出现一次,不作为任何一条判断的依据,也不外推到行业整体。我们关心的是另一件更朴素的事:当一个结论里出现”产量”这个词,它到底是被怎么算出来的。
这不是抬杠。同一批数据,按提交数量、按合并请求数量、按交付出去的功能数量算,会得到三种答案,而且三种答案都可能同时成立。研究用的口径我们无法指定,但我们自己的内部指标可以指定——这恰恰是问题所在:多数团队把”AI 写码之后产出了多少”这类问题交给一个从版本库里直接数出来的数字,而这个数字的失真方式正好和工具的行为变化耦合在一起:工具让同一件事被拆成更多次提交,于是提交数上升,净改动未必上升,价值更未必上升。用会随工具行为一起变的量去度量工具的效果,是最常见的自证。
所以本篇的写法是这样:先把三种口径各自的失真说清楚,再讲工作事件数据的共同盲区与分母问题,然后给出”评审是瓶颈”这句结论在我们自己系统里应该怎么测,最后落到把外部结论搬进组织前的准备动作。中间不讨论工具该不该用。
二、三种口径的三种失真
| 产量口径 | 它真正在度量什么 | 失真来源 | 被”优化”之后的样子 | 仍可用在什么地方 |
|---|---|---|---|---|
| 提交数量 | 变更被写入版本库的次数 | 一次大改动拆成多次或反之;生成式工具天然产出分段结果 | 出现大量无人细看的碎提交,次数上升而风险与价值不变 | 观察提交粒度是否突变,作为结构信号而非效果信号 |
| 合并请求数量 | 进入评审通道的工单数 | 受拆分策略与评审文化影响,团队改习惯而不是改效率 | 把一件事开成多条请求分摊评审压力,单条更浅 | 观察队列入口与出口是否失衡 |
| 交付功能数或变更前置时间 | 对外的可见结果与其等待时间 | 功能粒度定义不稳定,跨团队不可比;前置时间受需求大小分布影响 | 把功能定义得越来越细,或把大需求长期挂起不启动 | 在同一业务线内做自身前后比较 |
三行里第三行的坑最少被承认:交付功能数需要稳定的粒度定义。一个团队眼里的”一个功能”可能是另一个团队眼里的”一个模块”。粒度不固定时,功能数就无法跨团队比,也无法跨年比,只能同团队同口径做自身对照。而变更前置时间有个更隐蔽的问题:它是分布的函数而不是均值的函数,如果这段时间里需求类型的构成变了(小修补占比上升),前置时间必然下降,与效率无关。
还有一个方向性失真值得单独说:分母口径的选择会决定你看到”变多”还是”变少”。按提交数看,工具让改动数量上升;按缺陷修复周期看,可能不变;按线上事故与返工看,可能变差。三种读数都来自同一段真实工作。因此任何”产量提高了”的内部汇报,都应该同时给出它用的是哪一种口径,以及另外两种口径下发生了什么。
三、工作事件数据有一块共同的盲区
事件型数据的取材方式是”系统里留下的记录”,这决定了它看不见的那部分恰好是工作量里最贵的部分。四类不进计数:从未合并的分支(大量探索性工作停在分支上,一次都没进入主干);废弃的草稿与生成后未被采纳的结果(它们只在工具自己的会话记录里,不在版本库里);被回滚掉的改动(合进去又被撤出来,提交数照计,净产出为零甚至为负);评审之后要求的返工(同一条变更被反复修改,计数只看合并请求数量时看不到轮次)。
这四类的共同特征是:它们代表”做了但没有留下”和”留下了但不是成果”。工具介入之后,前两类的量会显著上升——生成的候选变多,被丢弃的候选自然变多。如果只数进入主干的部分,会得出效率提升的结论;如果只数候选总量,会得出工作量暴增的结论。两个结论都不成立,因为正确的分母需要包含被丢弃与被回滚的部分。
我们要求项目补的记录动作很轻:在变更上标注意图是否达成、被丢弃的候选数量按会话或按人汇总一次、回滚与修复性提交单独归类、返工轮次作为字段而不是从评论里猜。这四项目的不需要新工具,多数版本库与工单系统本来就留了位置,只是没人填。填了之后,前一小节那张表里的”被优化之后的样子”就不再是推测,而是能查到的分布。
四、分母本身在变:同期对照为什么不可省
同一组织在采用工具前后的团队构成、任务类型和需求吞吐量都在变,这构成所有内部比较的根本困难。如果不设同期对照,很容易把结构变化当工具效果。四类典型的混淆来源:
- 团队构成变化:新人占比上升时,同样的产出量意味着不同的单位效率;而新人比例变化往往和工具引入是同一个管理决策带来的。
- 任务类型变化:把技术债清理、迁移、合规整改这类低可见度工作排开之后,剩下的需求类工作自然更快,与工具无关。
- 需求吞吐变化:上游给了更多小需求,前置时间下降,因为需求本身变小了。
- 评审文化变化:换了一位更宽松的评审人,合并通过率上升,看起来像工具改善了质量。
处理办法不是造一个完美的实验,而是把可比性写明:至少固定”同一业务线、同一粒度口径、同一评审规则”这三条,并说明采用的判定阈值与观察窗口。做不到同期对照时,用前后自身对照就必须把上面四类混淆来源逐一声明是否发生在窗口内。这份声明不是形式主义,它是别人判断你这份数据能不能引用的唯一依据。
五、”评审是瓶颈”要测的是分布,不是均值
这句结论对我们是可以直接行动的,前提是把它换成可测的量。要看的东西有五项:评审排队时长(从标记为待评审到有人首次响应)、评审人负载(同一时刻挂在一个人身上的条数)、单评审人带宽(单位时间能给出结论的条数与其波动)、返工轮次(一条变更被要求修改的次数)、从提交到合并的时间分布。
关键的动作是使用分位数而不是均值。评审时长这类数据的形状是长尾:绝大多数几分钟,少数几天。均值会被长尾拉高或被大量秒过拉低,两个方向都可能误导。至少看三个位置:中位数说明日常体验,高分位说明谁被卡住,超时长尾占比说明结构性堵塞。一个团队中位数很好但高分位很差,说明问题不在整体带宽而在少数复杂变更上,处置方式是找对这些变更有判断力的人,不是给所有人加评审要求。
均值还有一个更具体的坑:它会把”没人评审所以一直挂着”和”评审很快但要求很低”这两种完全相反的状态算成同一个数。这两种状态在分位图上形状不同:前者长尾极重,后者曲线很扁但没有修改意见。所以我们要求把评审意见的结构也记下来,按类型分(意图不清、边界漏项、与既有约定冲突、可读性),类型分布是判断评审质量比时间更直接的证据。
这一节和容量改造是两件事。把评审队列当容量问题去加人、改并发、调门禁,是结构改造;本节讲的是怎么先测出”到底卡在哪一段”。没有前者可以做,但不测就做,很容易把资源投到不是瓶颈的那一段。
六、搬结论之前:结果指标与反证指标要成对出现
把一个外部结论搬进自己的组织,第一步不是买工具或定推广计划,而是先写清楚”更多软件”在我们这里指什么。这句话写不出来,后面所有读数都没有解释力。写出来之后,选一两个能对外解释的结果指标,并且给每一个结果指标配一个反证指标——这是本篇最想留下的那份清单。
| 结果指标(会变好的方向) | 配对的反证指标(防止被单优化) | 为什么配它 |
|---|---|---|
| 合并请求吞吐量 | 缺陷逃逸率与生产事故数 | 吞吐上升常来自评审放松,代价延后到线上暴露 |
| 交付前置时间 | 回滚率与修复性提交占比 | 快可能是因为错了就撤,而不是因为一次做对 |
| 单位人力完成的变更数 | 返工占比 | 生成变多、返工也变多时,人力节省是假的 |
| 变更粒度(单条行数下降) | 二定位可用性 | 拆得细若无独立意图,回滚与二分定位反而更难 |
| 评审首次响应时间 | 评审停留时间与意见密度 | 响应快但意见稀薄,等于把瓶颈推到后面 |
反证指标的作用不是否决改进,而是让”改进”这个词必须同时通过两道判据。单指标一定会被优化,这不取决于团队动机,而是它的定义只覆盖了一个维度。
内部实验的最小纪律只有三条,但缺一条就整份数据作废:保留同期对照或明确声明前后自身对照并列出混淆来源;预设判定阈值(什么变化算成功、什么变化算无效),不能事后从读数里挑;约定观察节奏与停止条件(多久看一次、看到什么程度就停),避免把一次采用变成无限期的指标追逐。这三条要写在实验开始前的一次评审里,由不是执行人的人确认。
最后交代一句我们自己的立场。洹拓在做研发度量类项目时,把口径定义当成一份独立交付物,与指标看板同时验收:先有”每一种口径在度量什么、失真在哪、被怎样优化”的书面说明,再看数字。这个顺序反过来,就会得到一份漂亮但无法复用的报表,以及一场关于工具到底有没有用的、永远争不完的会。