如何一眼看透效能问题的根因?研发效能度量分析的六种常用方法
The following article is from InfoQ Author 张乐
正如 Douglas W. Hubbard 在他的畅销书《How to Measure Anything》中所指出的那样,“如果一种度量真的很重要,那是因为它必须对决策和行为产生一些可以想象的影响。”如果我们不能确定一个度量指标可否影响决策,以及如何改变这些决策,那么这种度量就没有价值。
对于度量指标的分析,下面我们介绍一些常用的方法:
在度量研发效能的指标时,随着时间推移的改善趋势会比绝对值更有意义。每个组织、每个部门、每个团队、每个人都有不同的起点和上下文背景,对度量指标的绝对值进行横向比较很可能有失偏颇。针对每个独立的个体来说,度量其随时间推移的变化趋势更能获取到有效的信息。
举个例子,下图是在某个部门中推进研发效能分析时绘制出来的趋势图。可以看到,在 2019 年 7 月份之前,随着时间的推移,交付周期持续处于上升趋势,即交付需求越来越慢。在进行复盘时,当时的管理者识别到了这一问题,虽然大家工作看起来很繁忙(资源利用率很高),但从业务或客户的角度来看,研发效率的体验却在持续下降(流动效率降低)。于是,当时管理者就决定指派专人负责研发效能的诊断分析和提升工作,对交付周期问题直接进行干预,通过一系列改进措施扭转这个趋势。在图中红圈位置是一个转折点,交付周期在 2019 年 8 月之后有了明显下降,说明所采取的干预措施是有效果的,在度量的指导下发现并处理了问题,最终该部门效能得到了提升。
下图是另外一个趋势分析的案例。这个部门核心的关注点是线上质量,使用缺陷逃逸率指标来进行度量。可以看到从 2019 年 Q2 到 2020 年 Q3,缺陷逃逸率一直处于下行趋势。但更为重要的是,是采取了什么样的措施和实践才达成了这一目标呢?图中的代码评审覆盖率、单元测试数量和通过率的趋势图正是这一问题的答案。可以看到,因为在背后付出了很多质量内建活动的努力,才让线上缺陷逃逸减少的这一目标得以达成。我们通过趋势分析,看到了多个指标之间的关联性,这种关联性分析方法非常有用,我们将在后文中展开说明。
下钻分析可以帮助我们从宏观到微观,从表象到根因逐层排查问题,找到影响效能的瓶颈点。常见的下钻分析包括按阶段下钻(针对交付周期类指标)、按聚合维度进行下钻、按在制品进行下钻等。下面我们来看一些例子。
按阶段下钻
我们经常看到的现象是,如果产研部门被业务部门抱怨说交付速度太慢,产研部门的管理者头脑中的第一反应很可能是:再多招聘一些开发人员吧!从约束理论的角度来看,交付管道中至少会存在一个约束因素,限制了全局流动效率的潜能。但这个约束具体是在哪个阶段,很可能与我们预想的完全不同。
在下面这个案例中,部门碰到的问题就是交付周期较长。于是,把交付周期按照阶段下钻之后形成了一张柱形图。从图中可以看到,需求的平均开发周期在 5 天左右,其实并不算很长,但开发前有一个等待周期也接近 5 天,另外还有多个阶段的平均耗时接近甚至高于开发周期。比如测试阶段耗时超过 9 天,方案及 PRD 阶段耗时接近 6 天。在精益理论中,我们可以把活动分为三类:增值的活动(如写代码等)、非增值但必要的活动(如测试等)、浪费(如等待、缺陷导致的返工)。我们要最大化增值的活动,优化非增值但必要的活动,消除不必要的浪费。那么在这个案例中,我们就找到了改进的大致方向,再结合其他指标进一步进行问题排查,应该就可以得出有针对性的优化策略了。
按聚合维度下钻
研发效能度量平台在采集到各研发工具产出的效能数据之后,一般会进行自下而上的聚合,比如按照产品、部门、团队、项目、应用等不同的维度聚合,这样就可以提供更高层级的视图进行展示和分析。而我们在分析效能问题时,更多是自上而下进行的,比如先看到整个公司的效能情况、各个部门的横向对比,然后再进行逐层下钻,一直到子部门、团队层级,甚至下钻到数据明细,从而从宏观到微观进行问题根因分析。
在下面这个案例中,首先可以看到左上角的聚合数据报表,它展示了在所选时间范围内(周 / 月 / 季),所选部门与其同级部门的交付周期的横向比较,并且可以进行上一周期和本周期的对比。从这个宏观数据出发,我们可以进一步下钻分析,比如下钻到所选部门的下一级部门、下两级部门、下三级部门的数据图表,最终钻取到具体的明细数据。然后可以按照交付周期的长短对所选范围内的需求进行排序,并查看这些需求的交付过程和状态流转的细节,针对性分析影响效率的问题所在,寻求改善的抓手。
对在制品进行下钻
我们在做效能度量分析的时候,经常会按照固定周期(比如月度或季度)来统计效能数据、出具效能报告。但当每次看到效能报告中统计数据的时候,往往这个周期已经过去了。当我们根据上个周期的数据分析决定采取一些改进措施的时候,需要在下一个周期结束时才能进行效果验证,那么这就带来了一种延迟反馈。
其实,我们也可以采取一些更积极的、更及时的分析和干预方法。比如前文中提到的流负载(或在制品)指标就是一种先导性指标,流负载过高一定会导致后续的交付效率下降、交付周期变长,所以识别到这类问题就要进行及时干预。那么如何干预呢?可以使用一种称为滞留时长报告(Aging Report)的下钻分析方法。
工作项在交付管道中的停滞,会浪费交付过程中的宝贵时间。滞留时长报告显示了在交付管道中,没有完成的工作分别在当前状态滞留了多长时间。在下面这个案例中,我们首先可以看到左下角的流负载报表,它展示了在所选时间范围内(周 / 月 / 季),所选部门人均的在制品数量,并且可以进行上一周期和本周期的对比。从这个宏观数据出发,我们可以进一步下钻分析,比如下钻到所选部门的下一级部门、下两级部门、下三级部门的数据图表,最终钻取到具体的明细数据。这样我们就可以看到这些在制品的详细情况,它们目前分别处于什么样的阶段,在当前阶段已经滞留了多长时间。如果做得更好一些,可以计算出来工作项在每个阶段平均的滞留时长作为参考值,如果发现有些工作项滞留超过了平均时长,就需要特别进行关注,进一步分析是什么因素导致的阻塞,然后迅速采取行动,想办法恢复工作项的流动。
软件研发效能的提升是复杂的,受到诸多因素的影响。这些因素与结果之间存在相关关系而不是因果关系。即使我们发现两组数据之间有关联,也不意味着其中一组必然会导致另一组。例如,如果某个团队 “代码技术债率”指标很高,一般情况下代表着代码中存在的很多问题被暂时搁置,未来持续维护的成本和技术风险很大,那么从较长一段周期的趋势来看,很有可能 “交付周期”的指标会持续增长,即两组指标之间存在相关性。但这并不是必然的因果关系,虽然技术债很多,但很有可能因为人员能力、突击加班等其他因素暂时掩盖了这种问题,表面上冲抵了这种趋势。
但从研发效能分析的角度来看,我们仍然可以从历史数据中分析这种相关性,然后通过实验的方式进行探索,找到能够切实驱动效能提升的因素进行持续干预。比如,想提升线上质量、降低缺陷密度,经验告诉我们应该去加强单元测试的覆盖、完善 Code Review 机制、做好自动化测试案例的补充。但是,这真的有效么?我们通过数据来看,很可能没有任何效果!并不是说这些实践不该做,而是可能做的不到位。也许只是为了指标好看,编写缺少断言的单元测试、找熟人走过场分分钟通过的代码评审、覆盖一些非热点代码来硬凑测试覆盖率目标等等。所以,我们需要实验思维,要不断检视、反思、检讨所采用的实践,哪些实践的确有效,哪些实践效果不大,哪些实践方向正确但因执行不到位所以效果才不及预期。 我们要通过实验找到那些真正有用的改进活动及其与结果之间的相关性关系,有的放矢采取行动才会更有效率和有效果。
在下面这个案例中,我们的目标是降低需求交付周期。根据研发效能领域专家的经验和理论的输入,我们认为研发各阶段耗时、流负载、需求规模、紧急需求插入占比、需求变更率、变更前置时间、代码技术债率、缺陷解决时长、代码复杂度 / 重复度等指标与需求交付周期有正相关关系,而流动效率、需求评审通过率、代码评审通过率、发布成功率等指标与需求交付周期有负相关关系。
然后,我们对过去半年的历史数据进行相关性分析并得到了一份相关性系数的热力图。在图中,正 / 负相关性由从浅到深的颜色进行标识,我们可以看到大部分相关性数据的计算结果与我们的经验和理论是匹配的,但也有个别数据与经验存在一定出入。那么接下来我们的行动思路也就明确了,即对已被数据证明存在相关性的活动和过程指标实施干预,如降低流负载、提升需求稳定性等,以期能够加速需求的交付速度。然后,对数据与经验有出入的指标进行检视与反思,分析是实践无效还是数据失真导致的误判,并在下个周期中进一步增加实验进行持续探查。
以上分析过程 体现了数据驱动、实验性的思维方式,这正是研发效能度量能够有效指导效能改进、促进效能提升的不二法门。
另外,在这个案例中,我们还使用了北极星指标、群星指标与围栏指标的表述方式。上文已经讲到,北极星指标又称为首要关键指标(One Metric That Matters),可以用来指引我们改进的方向。为了进一步分解、分析北极星指标,我们还需要一些辅助性的参考指标,这些指标可能会有多个,分布在北极星指标的周围,我称之为群星指标。而围栏指标的设置是为了避免过度追求北极星指标所带来的潜在负面影响,避免在达成目标的解决方案选择上采取短视的行为。我们在分析一个特定场景时,可以使用由北极星指标、群星指标与围栏指标构成的指标集来进行全面的度量分析。
累积流图分析在上文的下钻分析一节中,我介绍了按阶段下钻的方法,可以把交付周期按照交付管道中不同节点,分解到每个阶段的耗时情况。但这种方法实际统计的是一段周期内的平均值,而平均值无法体现出按时间变化的趋势,只能用于事后分析,无法在过程中进行干预。接下来,让我们来细化和解决这一问题。
累积流图(CFD: Cumulative Flow Diagram) 是一种很有效的度量分析方法,可以很好地反映工作项在每个流程节点的流动情况,观察到不同角色在交付过程中相互协作的情况,并可以很容易地分析出研发过程各个阶段在制品、交付周期、交付效率随时间变化的趋势。
累积流图的 X 轴是日期,通常使用天数作为刻度,Y 轴的是工作项数量。那么 Y 轴从研发过程第一个状态(如“分析”)到最后一个状态(如“完成”)之间的高度,就代表了在制品的数量,高度越高说明在制品堆积越多。X 轴从研发过程第一个状态(如“分析”)到最后一个状态(如“完成”)之间的长度,则代表了从开发启动到完成的周期时间,这个长度越长说明周期时间越长,而这往往是由于在制品堆积造成的。根据利特尔法则,Throughput(吞吐量) = WIP(在制品) / Average Lead Time(平均前置时间)。在累积流图中,“完成”线的斜率就是吞吐量。通过观察“完成”线的斜率变化,就可以直观地看出团队的交付效率的变化。
在理解了以上分析方法后,我们就可以把工作项每个阶段的流动情况,按照时间维度绘制出来累积流图,来识别当前交付的进展、瓶颈、问题和需要进一步探查的内容。
下图给出了研发效能度量平台绘制的四张典型的累积流图。我们来逐个分析一下:
在左上角的累积流图中,我们发现代表”测试中”的红色区域随着时间推移,面积持续扩大,而且这个区域的高度和长度都在快速增长。这说明”测试中”这个状态的在制品堆积变得越来越严重,并且交付周期也在变得越来越长。我们初步可以判定”测试中”阶段可能是当前交付管道中的瓶颈所在。但这个时候还不能武断地认为就一定是测试资源或者测试产能的问题,还可能有各种其他情况。比如,开发提测质量很差导致大量缺陷产生,工作项虽然处于测试中状态但实际是在等待开发修复缺陷。或者是由于不同系统之间的依赖,已完成的部分不具备可独立测试性,需要等待其他系统就绪后才能开展测试等。但无论如何,我们已经找到了瓶颈点所在及其发展趋势,接下来的问题就是如何干预、优化和提升了。
在右上角的累积流图中,我们发现代表了开发、测试、上线的多个阶段、不同颜色的区域都发生了”塌陷”,而工作项总量却保持稳定。这说明可能是多个阶段的状态发生了回退,比如某些需求虽然开发、测试完成,并且最终上线了,但是业务在线上验收的时候发现存在重大问题,或与原始需求目标存在较大差异,要求需求下线并重新进行设计和开发。这是一种严重的返工行为,我们知道这代表着巨大的研发资源浪费。这就是我们为什么要从源头把控好需求的质量,加强对需求的理解,明确需求验收条件的原因。如果是需求存在质量或歧义的问题,可能导致数倍于需求分析工作量的研发和测试工作量产生,这种杠杆作用会让本来就很稀缺的研发资源的有效产出进一步降低。研发效能不仅与效率有关,还关乎到有效性。
在左下角的累积流图中,我们发现代表”开发中”的黄色区域随着时间推移,其高度保持水平,这说明”开发中”这个状态已经陷入了停滞。但代表”测试中”的绿色区域还在持续增长,说明并不是所有工作都停滞了。我们需要进一步探查发生这种情况的原因,由于并不是所有工作都停滞了,我们可以排除放长假的影响。所以,很有可能是开发过程中遇到了重大的技术架构问题,导致开发工作无法继续开展,或者由于出现了突发的紧急状况,需要调拨大量开发人员去进行救火,导致当前开发工作停滞。停滞作为流动的对立面,我们应当及时识别出这种情况,尽快处理。
在右下角的累积流图中,我们看到除了“测试中”阶段出现在制品堆积问题以外,还发现在迭代后期有大量新增需求的情况发生,这有可能是为了响应业务的变化而进行紧急需求插入,也有可能是为了”搭车上线”,赶在发布窗口之前追加一些新的需求。敏捷思维让我们欣然接受需求的变更,但是我们也承认过度的变更会导致开发过程的摩擦。上线前出现大量需要搭车上线的需求也不一定都是合理的,很可能因开发和验证时间不充分导致线上问题,所以我们不能一味地接受,还有要进行合理的权衡。
流效率就是在交付管道中,工作项处于活跃工作状态的时间(无阻塞地工作)与总交付时间(活跃工作时间 + 等待时间)的比率。经验表明,很多企业的流效率只有不到 10%,也就意味着需求在交付管道中有大量时间都处于停滞、阻塞、等待的状态。
我们结合 DevOps 平台中的看板工具,将待评审、就绪(待开发)、待测试、待发布等阶段的属性设置为”等待”,而需求沟通、需求评审、方案设计、开发、测试、发布等阶段的属性设置为”活跃”,这样就可以得到研发过程的基础数据,对流效率指标进行计算。
下图给出了我在一个部门落地流效率度量和分析时的一些实施细节,通过对指定范围内团队的看板进行统一配置,明确各个阶段的准入准出,规范各个团队的操作规范,就可以得到流效率的度量数据。然后,我们通过对在制品数量进行控制、推进小批量交付和一系列最佳实践的引入,优化了研发阶段的等待时间,让流效率获得了一定的提升。
在这里有个问题需要特别注意,就是数据准确性的问题。如果依据看板工具进行各个研发阶段耗时的统计,那么我们就要考虑看板中的工作项状态与实际工作状态如何保持一致的问题。当然,办法还是有的。比如,我们可以依靠规范的宣贯和执行的监控,确保数据相对准确(例如至少在每日站会的时候确保工作项状态及时更新),但更为有效的办法是通过自动化的手段,在工作项与代码关联后,研发人员后续的一系列基于代码的提交、合并、提测、上线等动作可以自动联动更新工作项的状态,关于这部分的内容我们将在下一章中展开说明。
流负载分析流负载是在交付管道中已经开始、尚未完成的工作项的数量,也就是我们经常说的在制品数量。流负载是一个关键的先导性指标,流负载过高一定会导致后续的交付效率下降、交付周期变长,所以识别到这类问题就要进行及时干预。
下图给出了我在一个团队中落地流负载度量和分析时的一个案例,可以看到产研团队流负载比上个统计周期提升了 43%,而相同周期内的产研交付周期环比提升了近 20%。从实际统计数据来看,这两个指标之间存在关联关系,流负载的升高影响了交付周期的上浮。但这两个指标之间并没有像公式一样存在那种精确的数学关系,这是因为影响交付周期的因素本来就很多,我们无法像在实验室中一样屏蔽掉所有其他因素的影响,而只观察这两个指标之间的关系。另外,流负载的升高对于交付周期的上浮存在延迟反馈,积压的需求可能并没有在当前统计周期内完成,也就并没有进入到交付周期的数据统计范围内。但是,我们已经能足够清晰地看到趋势,两个指标之间存在强相关。
看到了问题以后,我们可以使用上文中提到的在制品下钻方法进行具体工作项的排查。我们也可以使用被称为”个人研发日历”的视图进行查看。在下图中可以看到,位于最下面的开发人员在 3 月 15 日~3 月 21 日这周的并行任务非常多,而且都是贯穿整周时间的工作安排。这种大量并行,频繁打断和上下文切换的工作方式,也是研发过程中一种典型的浪费—任务切换浪费。我们应当进一步优化研发计划,控制并行的在制品,让流动变得更顺畅。
如果一种度量真的很重要,那是因为它必须对决策和行为产生一些可以想象的影响。度量指标可以有很多,但如何用好这些指标识别、分析、诊断问题,并做出对效能提升有效的决策、牵引正确的行动才是重点。本文提出了六种常见的效能度量分析方法,虽然文中主要是以管理域的度量分析方法举例,但对工程域的分析(如代码、CI、测试等专项的分析)也是非常必要的,限于篇幅我们暂不展开,后续有机会再做介绍。
研发效能度量的难点不仅是度量指标的设计和度量分析方法的使用,在中大规模企业中落地还有很多需要考虑的因素,下篇文章我就结合近期落地经验,来介绍一些落地过程中具体的实施建议。
之前三篇文章:
作者介绍:
张乐,腾讯 DevOps 与研发效能资深专家,曾长期工作于拥有数万研发的互联网大厂(百度、京东),专注于敏捷与 DevOps 实践体系、DevOps 平台产品设计、研发效能度量体系建设等方向,历任资深敏捷教练、DevOps 平台产品总监、集团级研发效能度量标准化联盟负责人等岗位。长期活跃于技术社区,目前是 DevOps 起源国际组织 DevOpsDays 中国区核心组织者,同时也是国内多个技术峰会的联席主席、DevOps/ 研发效能专题出品人、特邀演讲嘉宾。EXIN DevOps 全系列国际认证授权讲师、凤凰项目 DevOps 沙盘国际授权教练。历任埃森哲、惠普等全球五百强企业资深咨询顾问、技术专家,多年敏捷与 DevOps 转型、工程效率提升和大型项目实践经验。畅销书《独角兽项目:数字化时代的开发传奇》译者。
(当当五折优惠、京东满100减50)
(识别二维码,直接购买)