针对人类开发者的生产力提升,第 7 部分:软件质量 [译]

作者:

Collin Green,

Ciera Jaspan,

Maggie Hodges,

Jessica Lin

在谷歌,我们常被请求协助团队衡量各种开发者工具和流程对生产力的具体影响。这通常体现为一些团队开发了新的开发者工具,希望证明这些工具能够提升开发者的工作效率。

速度、便利性与质量

尽管如此,提升开发者的工作速度并非唯一追求的目标;我们同样重视打造高质量的产品。实际上,要提高工作效率并不难……比如取消代码审查或测试套件。这种做法看似能加快开发速度,但显然对公司并非良策。因此,我们虽然追求更高的工作效率,但绝不以牺牲软件质量为代价。我们也不会以损害工程师的利益为代价,例如通过加班来提高效率,这无疑是短期利益与长期影响的权衡。

鉴于这些权衡,我们从三个方面来衡量开发者的生产力:速度、便利性和质量。即使我们可能只是希望影响其中一个方面,但衡量所有三个方面仍然很重要,以确保我们不会做出意想不到的牺牲。这种观点并非首次提出;例如,微软采用了 SPACE 框架【1】,其中包含了许多相似的概念。这两种框架都源自 2017 年 3 月在 Dagstuhl 举办的一个研讨会,那里聚集了 27 名来自学术界和工业界的研究人员,共同探讨了开发者生产力的话题【2】。研讨会结束时,我们确定了一系列相似的组件,并将讨论内容发表在一本书中【3】。最重要的是,我们认识到了开发者生产力是一个包含多个相互关联因素的复杂议题,需要对每个因素进行衡量,以获得关于生产力的全面了解。

在本期专栏中,我们将专注探索软件的一个核心要素:质量。在软件的三大核心要素中,质量是最难以衡量的,原因在于其定义本身就颇具挑战。那么,什么才是软件质量呢?对不同的人来说,软件质量的含义各不相同。对一位注重业务的副总裁而言,高质量的软件意味着能吸引用户使用、付费并向他人推荐的产品。对开发者而言,高质量的软件则指代码易于维护和操作。对运维团队来说,它则是指那些可靠、容错、并能抵御安全威胁的网站。这些都是评价软件质量的重要视角。但当这三方讨论“如何提升软件质量”时,他们很可能会在处理方法和成功衡量标准上产生分歧。即便是在 Google,我们也见证了这样的讨论,因此,为了让每个人都有一个共识的软件质量理解,涵盖这些观点及其相互作用,变得尤为重要。

软件质量的四个维度

为了深入理解软件开发者眼中的“质量”含义,我们在 Google 对软件工程师进行了两轮访谈。在第一轮,我们向八位工程师询问了关于代码质量的看法;第二轮则询问了另一组九位工程师关于产品质量的观点。(值得注意的是,我们的访谈对象仅限于工程师,没有特别涉及产品经理、高级管理人员或其他岗位。)

在进行代码质量访谈前,我们深入研究了大量文献,以了解研究领域是如何定义代码质量的。我们探索了与代码质量紧密相关的术语,明确了研究的目标和方法,试图理解研究者对代码质量的基本理论观点。例如,在论文“组织结构如何影响软件质量”中,Nagappan 等人[4]探讨了代码所有权的指标是否能预测软件发布后的失败率,这暗示他们认为缺陷率是软件质量的重要组成部分。而在“程序复杂度指标与程序员观点的关系”中,Katzmarski 和 Koschke[5]研究了复杂度指标与开发者对修改软件难易程度的感知之间的关系,这表明他们认为软件维护能力是关键。在相关文献中,我们发现有七个关于代码质量的核心要素经常被提及:

  • 缺陷率(软件的错误和问题发生频率)

  • 可靠性(软件运行的稳定性)

  • 可维护性(软件的更新和修复的易用性)

  • 可测试性(软件测试的便捷性)

  • 复杂性(软件结构和功能的复杂程度)

  • 可理解性(整体目标和结构的清晰度)

  • 可读性(代码在行或方法层面的清晰度)。

在访谈中,我们首先询问了工程师们对代码质量的定义。我们还探讨了代码质量对他们个人生产力、所参与的项目、相关项目以及整个组织的影响和后果。最后,我们询问了他们在自己的项目中哪些上述提到的代码质量因素影响了他们的满意度。

关于产品质量,我们也进行了类似的访谈。我们询问了九位工程师如何定义产品质量,并提供了以下属性列表,探讨这些属性与产品质量的关系:

  • 满足用户需求的能力(产品是否满足或超出用户期望)

  • 性能和可靠性(产品的运行效率和稳定性)

  • 产品复杂性(产品的功能和设计复杂度)

  • 隐私和安全(保护用户数据的能力)

  • 创新性(产品的创新元素和特点)。

最后,我们询问工程师们代码质量对产品质量的影响程度。

基于我们对软件质量相关文献的研究和一系列访谈,我们提出了一个涉及四种互相影响的质量类型的“质量理论”。图 1 展示了每种质量类型的一些主要指标,但这些指标并不是全部。我们认为,除了这些质量类型,还有其他重要因素影响着软件开发过程的各个方面。如图 1 所示,我们认为这些质量类型之间存在特定的相互作用关系。

图 1. - 描述“软件质量”如何分解为四个组成部分的理论。箭头表示影响的方向,例如认为过程质量会影响代码质量。
图 1. - 描述“软件质量”如何分解为四个组成部分的理论。箭头表示影响的方向,例如认为过程质量会影响代码质量。

过程质量

我们认为,一切都从高标准的开发过程开始。高标准过程的表现包括全面而确定的测试、深入的代码审查、组织一致性以及有效的规划过程等。有许多证据表明这些因素可以有效预测软件的整体质量。实际上,多个研究显示,与现有代码质量指标相比,基于过程的指标对于预测发布后的缺陷更有预测性。4,6,7,8,9 因此,我们认为,当一个组织的过程质量较高时,它通常会导致代码质量的提升,但现有的“代码质量”指标可能并未完全反映代码质量的真实情况。因此,研究文献实际上更多地反映了过程质量对系统质量的影响。

代码质量

提高过程质量的最终目的是提升代码质量。但究竟什么是代码质量?我们的八位代码质量访谈参与者普遍认为,代码质量主要与其可维护性相关,他们将可测试性、易理解性、复杂性和可读性视作可维护性的分支。这与 Börstler 等人近期发表的一项研究一致。10 他们对 34 名开发者的采访发现了几乎一样的结果。

总体来说,我们的开发者认为代码质量关键在于代码的易用性和易理解性,使他们能够轻松地进行修改。他们提到,高质量的代码文件可以让人“立刻明白其目的”,并且“各部分逻辑清晰地组织在不同文件中。”开发者在看到高质量代码时,其实是看到了具有明确目标的代码;这样的代码为开发者提供了一个清晰、连贯的思维模式。正是这种清晰性,使得代码易于理解和后续修改。

代码质量对于提高可靠性和减少缺陷的影响存在一定的争议;只有一半的参与者认为这两者有直接联系。其他人则指出,其他因素也可能影响可靠性和缺陷率(“即使没有明显的错误,代码也可能因外部因素导致故障”),或者认为可靠性并不完全依赖于代码质量(“我见过很多可靠但代码质量差的情况。”)。他们认为,虽然这些因素相关,但并不与“代码质量”完全等同。

开发者指出,代码质量的影响是双重的:一方面,它通过减少缺陷和提升可靠性来提高系统整体质量;另一方面,高代码质量也能提升开发者自身的工作效率。特别是可维护性非常关键,因为正如一位开发者所述:“代码写一次,却被多次阅读——系统中的每个人都必须能够理解并修改它。”我们在之前的研究中也观察到这一联系;我们发现开发者对代码质量的早期感知是他们对开发效率后期感知的早期指标。11 这一发现颇为有趣,因为它表明生产力的三个组成部分(速度、便利性和质量)并非总是相互制约;在某些情况下,它们实际上可以相互增强。

系统质量

系统质量(System Quality)是我们从开发者眼中的“质量”(quality as the developers see it)转变为业务视角下的“质量”(quality as the business sees it)的关键。多数开发者提及“软件质量”(software quality),会想到代码和流程的质量,而高管和产品经理则更关注产品的质量(product quality)。(这一见解源自与高管和产品经理的非正式讨论,而非访谈研究。)这两种视角在系统质量这一概念上交汇。实际上,我们发现在 Google,这两个群体间的大多数讨论最终都聚焦于系统质量。但这两种视角有时会产生断层;比如,一位工程高管可能会要求提高产品质量(以提升顾客满意度),然后对软件开发者提升代码模块化作为回应表示惊讶。我们推测,这些因素通过系统质量相互关联,但对双方来说,这种联系并非显而易见;他们各自只关注自己工作的一部分。

一个高质量的系统表现为高可靠性、高性能和低缺陷率。虽然高代码质量(code quality)是实现高系统质量的必要条件,但还有诸如安全性和隐私保护这样的因素,这些只能在系统层面上进行真正的评估,并且对整体系统质量也有重要影响。同样地,高系统质量是实现高产品质量的必要条件,但还不足够;产品质量层面还有其他因素在起作用。

从我们的经验来看,衡量系统质量最大的难题之一是数据稀缺。系统中断应该且必须是极为罕见的事件。这就意味着,如果一个团队一年内只发生了两次小型中断,然后下一年再无中断,我们很难确定系统质量是否真的提高了。可能提高了,也可能只是统计上的偶然,他们只是比较幸运。同样,安全威胁和隐私泄露事件虽然影响巨大,但也极为罕见。在所有这些指标中,我们的目标都是达到“零”,但判断我们是否在某个项目上真正取得了进步,这是一件困难的事情。

过程和代码质量的度量标准是跟踪决定系统质量的重要指标。这些指标不论是基于实际日志数据的经过验证的度量,还是来源于工程师调查的自报数据,都使工程师能够指出需要改进的领域,以及代码健康对系统的影响。若没有这些中间指标,利益相关方可能会错误地认为,一年中无系统故障就意味着系统质量高,因为他们看不到开发者对代码库的体验,以及这些代码可能如何拖慢他们的工作效率。如果利益相关方错误地将低缺陷率视为高代码质量的保证,他们可能会过分强调推出新功能以提升产品质量,而忽视了改善潜在高风险系统的必要资源投入。

在一个没有系统中断或事件的年份中,可能存在两种不同的现实情况。最糟糕的情况是,开发者可能不得不在一个运行效率低下的系统中,绕开各种弱点以避免出现问题。而在最理想的情况下,开发者可能在一个低缺陷风险的系统中工作,可以自由地专注于改进和开发新功能。如果没有代码质量的度量,管理层就无法确定实际情况,也就不知道如何指导工程团队,以确保长期维持开发效率和产品质量。

产品质量

关于产品质量,它主要体现在客户的使用体验上,但我们也询问了开发者对产品质量的看法。在这些访谈中,开发者认为产品质量的关键要素包括:效用、易用性和可靠性。有趣的是,工程师们认为“创新性”是一个与产品质量不直接相关的独立概念。一位工程师这样解释:“我认为,‘质量’是指产品在实现其功能方面的表现,而‘创新性’则是关于产品的功能本身——它是否有趣、复杂或令人激动。”

工程师们指出,他们主要能够影响产品的可靠性,但他们也会与产品经理、用户体验设计师和研究人员合作,共同提升产品的效用和易用性。他们进一步指出,代码质量与产品质量有直接关联:低代码质量可能导致开发进度放缓,从而延迟产品的改进,甚至让某些改进变得不可行。他们还提到,低代码质量可能增加系统缺陷的风险,进而影响产品质量。

质量类型之间的联系

这四种质量类型并不是完全相互独立的。我们理论上认为,这些质量类型之间存在联系:过程质量影响代码质量,代码质量影响系统质量,而系统质量则影响产品质量。已有研究显示,某些过程质量的指标可以预测系统质量中的缺陷率。然而,这些联系并不牢固,其他研究发现,这种预测能力在不同项目间并不一致(引用 6, 12, 13, 15, 15),且随时间推移其可靠性会下降(引用 6, 14, 16)。比如,Nagappan 等人(引用 12)尝试利用代码质量指标来预测发布后的缺陷,但每个项目中预测缺陷的指标集合都不同。更令人担忧的是 Ekanayake 等人的研究,他们发现即使是对同一项目,指标的预测价值随时间显著减少。我们的领域需要更多研究来理解为什么会出现这样的结果,尽管我们直觉上认为,质量指标应当在不同产品间保持一致,并且对于特定产品应随时间保持稳定。

我们假设这里的问题之一是,现有的代码质量指标实际上并未真正衡量工程师眼中的代码质量基本概念,这可能导致这些指标无法有效预测系统质量。例如,之前的大量研究发现环形复杂度(cyclomatic complexity)实际上与衡量代码行数(lines of code)的效果几乎相同(引用 17),因此研究界现在通常会采取措施控制这种效应。这表明环形复杂度并不是衡量代码质量的好方法,这也可能是为什么许多研究发现它无法有效预测缺陷率或无法准确反映开发者对代码复杂度的看法(引用 10)。这只是其中一个例子,考虑到这个领域的广度和深度,我们还有很多机会可以在这四种质量类型中发展更好的衡量指标。

工程主管如何运用这一理论?

我们的理论为理解软件质量提供了更深层次的视角。我们希望,当讨论如何确保所有参与方都对提高软件质量有共同认识时,这能引导出更佳的结果。如果团队的目标是提升产品质量,这不仅意味着要提高流程和代码的质量,更重要的是要明确,提升产品质量才是最终目标,并且要让所做的改变与产品质量的提升之间的联系变得明确。虽然增加测试覆盖率可能对产品质量有一定帮助,但这种联系相对较弱。更有效的做法可能是专注于改进系统质量,并衡量这些改动的影响。另一方面,如果团队关注的是代码质量,就需要考虑一系列不同的指标,并可能需要重点改善流程质量。根据我们希望提升的质量类型,选择改进软件质量的策略和衡量指标。

在本文中,我们探索了构成软件质量的各个要素。然而,这只是关于生产力这个大话题中的一部分。在接下来的文章中,我们还将探讨速度和易用性的理念,以及它们与生产力的三大组成部分之间的关联。但衡量生产力时最关键的是要认识到,这里涉及多个方面的因素,单独衡量其中一个方面可能会带来意想不到的后果。即便是在质量这一单一方面,我们也能发现质量有多种形态,因此,识别我们要改进的具体质量类型并采用最佳的衡量标准至关重要。