除了代码行数、工时,我们还有什么更科学的方式度量研发工作量?
在软件研发领域,我们常常使用“代码行数”、“工时”和“需求数量”等指标来度量工作量。然而,这些方法都存在一些缺点,如果采用单一一种指标来进行度量,都有可能会对项目的真实工作量评估带来误导。
首先,“代码行数”是一个不准确的度量标准。虽然某些情况下,更多的代码可能意味着更多的工作量,但这种关系并不总是线性的。例如,一个复杂的算法可能涵盖了很多行代码,但实际上,它可能比一个简单的界面来得更容易理解和维护。此外,不同的开发人员可能有不同的编程风格和效率,这就使得用代码行数来度量工作量变得困难。
总体来讲,“代码行数”存在以下弊端:
1. 缺乏统一标准:对于代码行数的统计,缺乏统一的标准和规则。不同的编程语言、不同的编程风格、不同的注释方式都会影响代码行数的统计,使得不同项目之间的比较变得困难。
2. 代码行数只是表面上的量化指标,不能真正反映代码的复杂性和价值。
其次,“工时”也存在类似的问题。尽管工时可以反映开发人员的工作时间,但它并不能准确反映实际的工作量。例如,一个经验丰富的开发人员可能比一个新手更快地完成相同的任务。此外,工时还可能受到其他因素的影响,如团队沟通、代码复用等。具体来讲,“工时”存在的问题包括:
1. 无法体现工作价值:不同水平的人做同一件事,往往水平高的人耗时短。
2. 工时度量准确性问题,通常手工填报工时不准确,另外工具上没有及时更新状态等。
3. 忽视了研发工作的复杂性:软件开发和研发是一项高度复杂的工作,涉及到需求分析、设计、编码、测试、调试等多个环节。每个环节都需要投入大量的时间和精力。而“工时”度量方式很难全面反映出这些环节的复杂性和工作量,容易造成不公平和偏差。
4. 虚报数据:如果过度依赖“工时”来度量工作量,为了体现个人贡献,可能会出现被虚报的情况。
5. 缺乏对研发工作成果的有效评估:使用“工时”来度量工作量,很难对研发工作的成果进行有效评估。在很多情况下,投入的工时多并不意味着产出的软件质量就一定高。如果过度关注工时,可能会忽视对软件质量、功能、性能等方面的评估和优化。
6. 不适应软件行业的快速变化:软件行业是一个快速变化的行业,新的技术和工具不断涌现。如果仍然使用传统的“工时”度量方式,很难适应这种变化,也难以提高软件开发的效率和竞争力。
最后,“需求数量”也不能完整地描述研发工作量。需求的多少并不能完全反映出开发难度、技术复杂度等因素。比如,一些功能可能看似简单,但在实施过程中可能遇到了许多隐藏的复杂性。而有些需求可能就比较直观,使得开发过程相对简单。这也引出另一个问题,就是需要在使用“需求数量”作为指标之前,要定义好“需求颗粒度”,而“需求颗粒度”的度量方法也存在难点。总之,将“需求数量”作为度量研发工作量的单一指标,会遇到这些问题:
1. 难以反映真实的工作量:需求数量并不能真实地反映出研发工作量的大小。研发工作量不仅包括需求的实现,还涉及到设计、编码、测试等多个环节。仅仅通过需求数量来度量工作量,会忽视其他重要环节的投入,从而无法对研发团队的工作进行全面评估。
2. 难以制定合理的排期和计划:如果以需求数量作为度量标准来制定研发计划和排期,可能会出现资源分配不均和不合理的情况。这可能导致部分开发人员工作量过大,而其他人员则闲暇时间过多;或者出现部分模块开发进度较快,而其他模块进度滞后的情况。这样的排期和计划很难保证软件项目的整体进度和质量。
因此,使用代码行数、工时和需求数量来度量研发工作量存在局限性。我们需要更全面、更科学的度量方法,以便更准确地评估软件开发项目的真实工作量。
如何更科学地度量研发工作量?
要实现更科学地度量研发工作量,甚至度量更多其他指标,我们就需要引入新的指标与单位,或者你可以管它叫做变量——“代码当量”,这个指标也被中国信通院开源生态监测平台采纳使用了。代码当量也叫开发当量(英文名为 ELOC,Equivalent Line of Code,)下文称”代码当量”,由思码逸原创,是一种对开发者代码工作量进行合理量化和度量的指标。
代码当量的特点是什么?
“代码当量”实际上是可以用来替换掉“代码行数”指标的。我们来举几个例子,你就能明白“代码当量”与“代码行数”的区别了。
首先代码行数指标(LOC,Line of Code)很容易被简单的代码习惯差异所影响。
在下图中,我们删除红色代码,新增绿色代码,实质上只是简单的代码格式变动,并不实际改变基本逻辑和代码质量,却表现为 1 行添加和 4 行删除(总共 5 行更改)。
相比之下,由于纯句法变化对 AST 没有影响,此段代码的新旧 ASTs 是相同的,所以这个操作的代码当量为 0。
另外,代码行数无法区分不同性质的代码的工作量。
考察以下 Python 代码,它的功能是在给定的字典中找到对称对。测试数据 test_dict 和实际功能函数 find_sym_pairs()贡献了相等数量的行数(7 行),这当然不能反映编写这两段代码所付出的不同的工作量。
但是通过为每个 AST 节点类型分配不同的权重,我们可以对不同类型 AST 节点的编辑操作进行更合理的评估,更合理的量化开发过程中的工作量。
总体来讲,与代码行数、提交数等浅层工作量指标相比,代码当量(开发当量)的优势体现在三个方面:
排除源代码级别的噪音,比如空格、死代码等;
大部分程序分析和语义理解技术都是构建在抽象语法树这一数据结构上,相比于解析更靠后阶段的字节码、机器码,抽象语法树更能反映出程序员本身的表达;
可应用编译优化技术,使评估更加准确。
代码当量的计算原理是怎样的呢?
你可能会好奇,代码当量是如何实现的。我们都知道软件开发是一个动态的过程,代码随着提交发生变化,相应的抽象语法树也会演变。代码当量指标正是基于抽象语法树复杂度的计算。这一指标的原型来自思码逸创始团队 2018 年在软件工程顶级会议 FSE 上发布的论文《关于量化代码贡献的开发价值》。
代码当量的计算原理
下图简单演示了这个过程如何从代码的修改计算出代码当量的数值。
首先,将源代码解析为抽象语法树(AST),AST 是源代码抽象语法结构的树型表示。它的“抽象”性质有助于消除测量中不重要的噪音,这个特性可以在以下的例子中体现。
图:代码修改前后的抽象语法树对比
其次,计算新旧树之间的树的差异(树 diff)。树 diff 步骤的输出是一个编辑脚本,由一系列编辑操作组成,正是这些操作一步步将旧 AST 转换成新 AST。编辑操作分为四种类型:插入、删除、移动和更新。例如,插入操作可以将新节点作为 AST 中现有节点的子节点插入;更新操作可以更新现有节点的值。
最后,我们计算所有编辑操作的加权总和,根据编辑操作的类型和此编辑操作的 AST 节点的类型为每个操作分配权重,最终得到代码当量的数值。
总结:从源码到代码当量的基础计算过程如下,一共分三步:
1. 将旧/新源代码解析为 ASTs
2. 通过在旧/新 ASTs 之间进行树状转换来生成编辑脚本
3. 从编辑脚本加权计算代码当量
当“代码当量”与其它指标结合
“代码当量”除了可以作为一个度量指标,还可以作为一个基本单位,结合其它指标能更好地度量、分析当前研发效能。我们来举几个例子。
第一个场景是很多团队都会遇到的,就是“分析当前的团队人效”。首先,很多团队可能会使用工时、事务吞吐量来评估一个团队的人均效能,但是只使用这两个指标来衡量的话,存在一些漏洞。如果将代码当量和事务吞吐量与工时交叉分析,则可以量化研发团队内部的投产比。这样的度量也有助于开发者们更专注于交付结果,而非磨洋工凑时长。
第二个场景“需求颗粒度评估”。在需求进入开发之前,我们可以利用故事点、功能点、工时等方法来评估需求颗粒度;在需求完成开发之后,需求颗粒度可以通过其实际的工作量进行回顾,例如统计对应的实际工时、代码当量等。实际上,贝壳已经引入“代码当量”来评估“需求颗粒度评估”了。他们是怎么来使用“代码当量”的呢?
贝壳使用代码当量指标,来量化每个需求的颗粒度大小(对应多少研发工作量),并分析颗粒度的分布。基于这些分析,贝壳可以了解各业务团队的需求拆分是否合理,且颗粒度相对稳定。在全面了解的基础上,建立起组织级基线,及时识别超出基线、颗粒大小异常的需求点,并给出引导。
在引入代码当量前,贝壳使用两个指标来量化需求的大小:规划阶段的估点大小,和事后统计的交付工时。估点主要还是基于需求分析阶段的主观判断,而交付工时受需求状态流转是否及时的影响,都有可能出现可信度的问题。代码当量也可以用于这两个指标的校准,帮助团队识别故事点预估偏差和工时记录不全不准等问题,进而用多个指标交叉验证需求大小,使效能度量更加可靠。
同理,代码当量也可以用来量化 Merge Request(代码合并请求,GitHub 中称为 Pull Request)的颗粒度,并设定了 MR 颗粒度建议值,改进工程实践,避免 MR 过大带来的问题多、冲突多、测试及 debug 成本高的问题。
最后体验
想试试代码当量计算?可以访问思码逸代码当量游乐场,你可以任意选择语言、调整加权设置、亲手修改代码,体验不同的代码编辑行为所产生的代码当量,可以直观看到自己的操作所带来的当量变化。
如果你希望更进一步了解代码当量的计算原理,那么可以访问思码逸官网的文档中心,查看代码当量相关文档。
评论