-
Notifications
You must be signed in to change notification settings - Fork 0
CHAPTER 7 Measuring Engineering Productivity
谷歌是一家以数据为导向的公司。我们的大多数产品和设计决策都有可靠的数据支持。数据驱动的决策文化,使用适当的指标,有一些缺点,但总的来说,对数据的依赖往往使大多数决策变得客观而不是主观,这往往是一件好事。然而,收集和分析人类方面的数据,也有其自身的挑战。具体来说,在软件工程方面,谷歌发现拥有一个专注于工程生产力的专家团队本身是非常有价值和重要的,因为公司规模扩大,可以利用这样一个团队的洞察力。
让我们假设你有一个蓬勃发展的业务(例如,你经营一个在线搜索引擎),并且你想扩大你的业务范围(进入企业应用市场,或云市场,或移动市场)。据推测,为了增加你的业务范围,你也需要增加你的工程组织的规模。然而,随着组织规模的线性增长,通信成本呈四次方增长。增加更多的人对增加你的业务范围是必要的,但通信开销成本不会随着你增加人员而线性扩展。因此,你将无法根据你的工程组织的规模来线性地扩大你的业务范围。
不过,还有另一种方法可以解决我们的扩展问题:我们可以让每个人的生产力更高。如果我们能提高组织中单个工程师的生产力,我们就能扩大业务范围,而不会相应地增加通信开销。
谷歌不得不迅速发展新的业务,这意味着要学习如何使我们的工程师更有效率。为了做到这一点,我们需要了解是什么让他们富有成效,找出我们工程流程中的低效率,并解决所发现的问题。然后,我们将根据需要在一个持续改进的循环中重复这个循环。通过这样做,我们将能够在需求增加的情况下扩大我们的工程组织。
然而,这种改进循环也需要人力资源。如果每年需要50名工程师来理解和解决生产力的障碍,那么每年提高10名工程师的生产力是不值得的。因此,我们的目标是不仅要提高软件工程的生产力,而且要有效地做到这一点。
在谷歌,我们通过建立一个致力于了解工程生产力的研究团队来解决这些权衡问题。我们的研究团队包括来自软件工程研究领域的人员和普通的软件工程师,但我们也包括来自不同领域的社会科学家,包括认知心理学和行为经济学。来自社会科学的人员的加入使我们不仅可以研究工程师生产的软件工件,还可以了解软件开发中人的一面,包括个人动机、激励结构和管理复杂任务的策略。该团队的目标是采取一种数据驱动的方法来衡量和提高工程生产率。
在本章中,我们将介绍我们的研究团队如何实现这一目标。这要从分流过程开始:软件开发有许多部分我们可以测量,但我们应该测量什么?在一个项目被选中后,我们将介绍研究团队如何确定有意义的指标,以确定该过程中的问题部分。最后,我们看一下谷歌是如何使用这些指标来跟踪生产力的改进。
在本章中,我们遵循谷歌的C++和Java语言团队提出的一个具体例子:可读性。在谷歌存在的大部分时间里,这些团队一直在管理谷歌的可读性过程。(关于可读性的更多信息,请参见第3章。)可读性过程是在Google的早期建立的,当时自动格式化器(第8章)和阻止提交的锁存器还没有普及(第9章)。这个过程本身的运行成本很高,因为它需要数百名工程师为其他工程师进行可读性审查,以便授予他们可读性。一些工程师认为这是一个古老的欺凌过程,不再具有实用性,这也是午餐桌旁最喜欢争论的话题。来自语言团队的具体问题是:花在可读性过程上的时间是值得的吗?
在我们决定如何衡量工程师的生产力之前,我们需要知道什么时候一个指标甚至值得衡量。测量本身是昂贵的:它需要人去测量过程,分析结果,并将其传播给公司的其他部门。此外,测量过程本身可能是繁琐的,会拖累工程组织的其他部门。即使它不慢,跟踪进度也可能改变工程师的行为,可能会掩盖潜在的问题。我们需要聪明地测量和估计;尽管我们不想猜测,但我们也不应该不必要地浪费测量的时间和资源。
在谷歌,我们想出了一系列的问题来帮助团队确定是否值得首先测量生产力。我们首先要求人们以具体问题的形式描述他们想要测量的东西;我们发现,人们能够使这个问题越具体,他们就越有可能从这个过程中获得好处。当可读性团队找到我们时,它的问题很简单:一个工程师经历可读性过程的成本是否值得他们可能为公司带来的利益? 然后,我们要求他们考虑其问题的以下几个方面。
- 你期望的结果是什么,以及为什么?
尽管我们可能想假装我们是中立的调查员,但我们不是。我们确实对应该发生什么有先入为主的观念。通过一开始就承认这一点,我们可以尝试解决这些偏见,防止对结果进行事后解释。
当这个问题被提给可读性小组时,它指出它并不确定。人们确信在某个时间点上的成本是值得的,但是随着自动格式化和静态分析工具的出现,没有人完全确定。越来越多的人认为,这个过程现在成了一种欺负人的仪式。尽管它可能仍然为工程师们提供了好处(他们有调查数据显示人们确实声称有这些好处),但不清楚它是否值得作者或代码审查者付出时间。 - 如果数据支持你的预期结果,将采取什么行动?
我们这样问是因为如果不采取任何行动,那么测量就没有意义。请注意,如果没有这个结果,有一个计划中的变化会发生,那么行动实际上可能是 "维持现状"。
当被问及这个问题时,可读性团队的回答很直接:如果好处足以证明这个过程的成本是合理的,他们会把研究和关于可读性的FAQ上的数据联系起来,并进行宣传以设定期望。 - 如果我们得到一个阴性结果,是否会采取适当的行动?
我们问这个问题是因为在许多情况下,我们发现一个负面的结果不会改变一个决定。在一个决定中,可能有其他的投入会超过任何负面的结果。如果是这样的话,可能首先就不值得测量。这也是阻止我们研究团队进行的大多数项目的问题;我们了解到决策者对了解结果感兴趣,但由于其他原因,他们不会选择改变方向。
然而,在可读性的案例中,我们有一个来自团队的强有力的行动声明。它承诺,如果我们的分析显示成本大于收益,或者收益可以忽略不计,团队就会扼杀这个过程。由于不同的编程语言在格式化和静态分析方面有不同的成熟度,这种评估将在每个语言的基础上发生。 - 谁将决定对结果采取行动,以及他们何时采取行动?
我们这样问是为了确保要求测量的人是被授权采取行动的人(或直接代表他们采取行动)。归根结底,测量我们的软件过程的目的是帮助人们做出商业决定。重要的是要了解这个人是谁,包括什么形式的数据能说服他们。尽管最好的研究包括各种方法(从结构化访谈到日志的统计分析),但为决策者提供他们需要的数据的时间可能有限。在这些情况下,最好的办法是迎合决策者的要求。他们是否倾向于通过从观点间获取的故事来做出决策?他们是否相信调查结果或日志数据?他们对复杂的统计分析感到舒服吗?如果决定者原则上不相信结果的形式,那么衡量这个过程也就没有意义了。
在可读性方面,我们对每种编程语言都有一个明确的决策者。有两个语言团队,即Java和C++,积极向我们寻求帮助,其他的则在等待,看这些语言先发生什么。决策者相信工程师们自我报告的经验,以了解快乐和学习,但决策者希望看到基于日志数据的速度和代码质量的 "硬数字"。这意味着,我们需要对这些指标进行定性和定量分析。这项工作没有一个硬性的截止日期,但有一个内部会议,如果有变化的话,这个会议将成为一个有用的公告时间。这个期限给了我们几个月的时间来完成这项工作。
通过问这些问题,我们发现在许多情况下,测量根本不值得......这也是可以的!有许多很好的理由不测量一个工具或过程对生产力的影响。下面是我们看到的一些例子。
- 你现在没有能力改变流程/工具
可能有时间上的限制或资金上的制约,使之无法进行。例如,你可能会确定,只要你切换到一个更快的构建工具,就能每周节省几个小时的时间。然而,转换意味着在每个人都转换的时候暂停开发,而且有一个重要的资金截止日期即将到来,你无法承受这种中断。工程上的权衡不是在真空中评估的--在这样的情况下,重要的是要意识到,更广泛的背景完全可以证明延迟采取行动的结果。 - 任何结果很快就会因其他因素而失效
这里的例子可能包括测量一个组织在计划重组前的软件流程。或者测量一个被废弃的系统的技术债务量。
决策者有强烈的意见,而你不太可能提供足够多的正确类型的证据,来改变他们的信念。 这就需要了解你的受众。即使在谷歌,我们有时也会发现一些人由于他们过去的经验而对某一主题有坚定的信念。我们曾发现一些利益相关者从不相信调查数据,因为他们不相信自我报告。我们也发现一些利益相关者,他们最容易被由少量访谈得出的令人信服的叙述所动摇。当然,也有一些利益相关者只被日志分析所动摇。在所有情况下,我们都试图用混合方法对真相进行三角测量,但如果利益相关者只限于相信不适合问题的方法,那么做这项工作就没有意义。 - 这些结果将只被用作虚荣的指标,以支持你无论如何都要做的事情。
这也许是我们在谷歌告诉人们不要测量软件过程的最常见的原因。很多时候,人们计划一个决定是出于多种原因,而改善软件开发过程只是多种好处中的一种。例如,谷歌的发布工具团队曾经要求对发布工作流程系统的计划变更进行测量。由于这个变化的性质,很明显,这个变化不会比目前的状态差,但他们不知道这是一个小的改进还是一个大的改进。我们问团队:如果结果只是一个小的改进,无论如何你会花资源来实现这个功能,即使它看起来不值得投资?答案是肯定的! 这个功能碰巧提高了生产力,但这是一个副作用:它也更具有性能,降低了发布工具团队的维护负担。 - 唯一可用的衡量标准不够精确,无法衡量问题,而且可能被其他因素所干扰
在某些情况下,所需的指标(见即将到来的关于如何识别指标的章节)根本无法获得。在这些情况下,使用其他不那么精确的指标(例如,编写的代码行)进行测量是很诱人的。然而,这些指标的任何结果都是无法解释的。如果这个指标证实了利益相关者预先存在的信念,他们最终可能会继续执行他们的计划,而不考虑这个指标不是一个准确的衡量标准。如果它没有证实他们的信念,那么指标本身的不精确性就提供了一个简单的解释,利益相关者可能再次继续他们的计划。
当你成功地测量你的软件过程时,你并不是为了证明一个假设的正确与否;成功意味着给利益相关者提供他们做出决定所需的数据。如果这个利益相关者不使用这些数据,那么这个项目就总是失败的。只有在根据结果做出具体的决定时,我们才应该衡量一个软件过程。对于可读性团队来说,有一个明确的决定要做。如果衡量标准显示这个过程是有益的,他们将公布这个结果。如果没有,这个过程就会被废除。最重要的是,可读性小组有权力做出这个决定。
当我们决定要衡量一个软件过程时,我们需要确定使用什么指标。显然,代码行(LOC)是不行的,但我们如何真正衡量工程师的生产力呢?
在谷歌,我们使用目标/信号/指标(GSM, Goals/Signals/Metrics)框架来指导指标的创建。
- 一个目标是一个期望的最终结果。它的措辞是你想在高层次上了解什么,不应该包含衡量它的具体方法。
- 信号是你如何知道你已经实现了最终结果。信号是我们想要测量的东西,但它们本身可能是无法测量的。
- 衡量标准是信号的代理。它是我们实际上可以测量的东西。它可能不是理想的测量,但它是我们认为足够接近的东西。
在创建度量衡时,GSM框架鼓励几个理想的属性。首先,通过首先创建目标,然后是信号,最后是度量,它可以防止路灯效应。这个词来自于 "在路灯下找你的钥匙":如果你只看你能看到的地方,你可能没有找对地方。在衡量标准方面,当我们使用容易获得和容易衡量的标准时,就会出现这种情况,不管这些标准是否适合我们的需要。相反,GSM迫使我们思考哪些指标能真正帮助我们实现目标,而不是简单地考虑我们有哪些现成的指标。
其次,GSM通过鼓励我们在实际测量结果之前,采用有原则的方法,提出一套合适的衡量标准,从而有助于防止衡量标准的蠕变和衡量标准的偏差。考虑一下这样的情况:我们在没有原则性方法的情况下选择衡量标准,然后结果没有达到利益相关者的期望。这时,我们面临的风险是,利益相关者会建议我们使用他们认为会产生预期结果的不同指标。因为我们一开始就没有根据原则性的方法进行选择,所以我们没有理由说他们是错的。相反,GSM鼓励我们根据其衡量原始目标的能力来选择指标。利益相关者可以很容易地看到这些指标与他们的原始目标相吻合,并事先同意这是衡量结果的最佳指标集。
最后,GSM可以告诉我们哪里有测量覆盖,哪里没有。当我们运行GSM程序时,我们列出所有的目标,并为每个目标创建信号。正如我们在例子中所看到的,并不是所有的信号都是可测量的--这也没关系!通过GSM,至少我们确定了哪些是可测量的。通过GSM,至少我们已经确定了哪些是不可测量的。通过识别这些缺失的指标,我们可以评估是否值得创建新的指标,或者甚至值得测量。
重要的是要保持可追溯性。对于每一个指标,我们应该能够追溯到它所要代理的信号,以及它所要测量的目标。这可以确保我们知道我们正在测量哪些指标,以及我们为什么要测量它们。
一个目标应该用所期望的属性来写,而不是参考任何指标。这些目标本身是不可测量的,但是一套好的目标是每个人都能同意的,然后才是信号和度量。
为了使其发挥作用,我们首先需要确定一套正确的目标来衡量。这看起来很简单:团队肯定知道他们工作的目标!但是,我们的研究团队发现,他们的目标并不明确。然而,我们的研究团队发现,在许多情况下,人们忘记了将所有可能的权衡纳入生产力范围,这可能导致错误的测量。
以可读性为例,我们假设团队太专注于使可读性过程快速和简单,而忘记了关于代码质量的目标。团队为通过审查过程所需的时间以及工程师对该过程的满意程度设置了跟踪测量。我们的一个队友提出以下建议。
我可以让你的审查速度非常快:只要完全取消代码审查。
虽然这显然是一个极端的例子,但团队在测量时总是忘记核心的权衡:他们太专注于提高速度而忘记了测量质量(或者反过来)。为了解决这个问题,我们的研究团队将生产力划分为五个核心部分。这五个部分是相互权衡的,我们鼓励团队考虑每一个部分的目标,以确保他们不会在无意中提高一个部分,而使其他部分下降。为了帮助人们记住所有五个组成部分,我们使用了 "QUANTS "的记忆法。
- 代码的质量 (Quality of the code)
产生的代码的质量如何?测试用例是否足够好,以防止回归?架构在减轻风险和变化方面的能力如何? - 工程师的注意力 (Attention from engineers)
工程师达到流动状态的频率如何?他们在多大程度上被通知分散了注意力?一个工具是否鼓励工程师进行上下文切换? - 智力的复杂性 (Intellectual complexity)
完成一项任务需要多大的认知负荷?所解决的问题的内在复杂性是什么?工程师是否需要处理不必要的复杂性? - 节奏和速度 (Tempo and velocity)
工程师能多快完成他们的任务?他们能以多快的速度把他们的版本推出去?在给定的时间范围内,他们能完成多少任务? - 满意度 (Satisfaction)
工程师对他们的工具有多满意?一个工具能在多大程度上满足工程师的需求?他们对自己的工作和最终产品的满意度如何?工程师是否感到疲惫不堪?
回到可读性的例子,我们的研究团队与可读性团队合作,确定了可读性过程的几个生产力目标。
- 代码的质量
由于可读性过程,工程师们写出了更高质量的代码;由于可读性过程,他们写出了更一致的代码;由于可读性过程,他们向代码健康文化致敬。 - 来自工程师的关注
我们没有为可读性制定任何关注目标。这是好的! 并非所有关于工程生产力的问题都涉及所有五个方面的权衡。 - 知识的复杂性
工程师们通过可读性过程了解谷歌代码库和最佳编码实践,他们在可读性过程中接受指导。 - 节奏和速度
由于可读性过程,工程师们更快、更有效地完成工作任务。 - 满意度
工程师们看到了可读性过程的好处,并对参与该过程有积极的感受。
信号是我们知道我们已经实现目标的方式。并非所有的信号都是可衡量的,但这在现阶段是可以接受的。信号和目标之间不是1:1的关系。每个目标都应该至少有一个信号,但它们可能有更多的信号。有些目标也可能共享一个信号。表7-1显示了可读性过程测量的目标的一些信号示例。
表7-1. 信号和目标
目标 | 信号 |
---|---|
由于可读性过程,工程师们会写出更高质量的代码。 | 被授予可读性的工程师判断他们的代码比没有被授予可读性的工程师的质量更高。可读性过程对代码质量有积极影响。 |
工程师们通过可读性过程了解谷歌的代码库和最佳编码实践。 | 工程师们报告说从可读性过程中学习。 |
工程师在可读性过程中接受指导。 | 工程师们报告了与经验丰富的谷歌工程师的积极互动,他们在可读性过程中担任审查员。 |
由于可读性过程,工程师更快、更有效地完成工作任务。 | 被授予可读性的工程师判断自己比没有被授予可读性的工程师更有生产力。被授予可读性的工程师所写的修改比未被授予可读性的工程师所写的修改审查得更快。 |
工程师们看到了可读性过程的好处,并对参与这一过程有积极的感受。 | 工程师认为可读性过程是值得的。 |
衡量标准是我们最终确定如何衡量信号的地方。衡量标准不是信号本身;它们是信号的可测量的代理。因为它们是一个代理,所以它们可能不是一个完美的测量。出于这个原因,一些信号可能有多个指标,因为我们试图对基本信号进行三角测量。
例如,为了衡量工程师的代码在可读性之后是否得到更快的审查,我们可能会使用调查数据和日志数据的组合。这两个指标都没有真正提供潜在的真相。(人类的感知是易变的,而日志指标可能没有测量出工程师审查一段代码所花时间的全貌,或者可能被当时未知的因素所干扰,比如代码修改的大小或难度)。然而,如果这些指标显示出不同的结果,就表明可能其中一个指标是不正确的,我们需要进一步探索。如果它们是一样的,我们就更有信心,我们已经达到了某种真理。
此外,有些信号可能没有任何相关的度量标准,因为这个信号在这个时候可能根本无法测量。例如,考虑一下测量代码质量。尽管学术文献已经提出了许多代码质量的代用指标,但没有一个能真正抓住它。对于可读性,我们必须做出决定,要么使用一个糟糕的代理,并可能根据它做出决定,要么干脆承认这是一个目前无法测量的点。最终,我们决定不把这一点作为一个量化的衡量标准,尽管我们确实要求工程师对他们的代码质量进行自我评价。
遵循GSM框架是一个很好的方法,可以明确你为什么要测量你的软件过程的目标,以及它将如何被实际测量。然而,仍然有可能所选择的指标并没有说明完整的故事,因为它们并没有捕捉到所需的信号。在谷歌,我们使用定性数据来验证我们的指标,并确保它们捕捉到了预期的信号。
举个例子,我们曾经创建了一个衡量每个工程师构建延迟中位数的指标;目的是为了捕捉工程师构建延迟的 "典型经验"。然后我们进行了一项经验抽样研究。在这种研究方式中,工程师在做一项感兴趣的任务时被打断,以回答一些问题。在工程师开始构建后,我们自动向他们发送了一份关于他们对构建延迟的经验和期望的小调查。然而,在一些情况下,工程师们回答说他们还没有开始构建!结果发现,自动化工具开始了构建。事实证明,自动化工具正在启动构建,但工程师们没有被封锁在这些结果中,所以没有 "计入"他们的 "典型经验"。我们随后调整了指标,以排除这种构建。
定量指标是有用的,因为它们给你力量和规模。你可以在很长一段时间内测量整个公司的工程师的经验,并对结果有信心。然而,它们并不提供任何背景或叙述。定量指标不能解释为什么一个工程师选择使用一个过时的工具来完成他们的任务,或者为什么他们采取了一个不寻常的工作流程,或者为什么他们绕过了一个标准流程。只有定性研究才能提供这些信息,也只有定性研究才能为改进流程的下一步提供见解。
现在考虑一下表7-2中的信号。你可以创建什么指标来衡量其中的每一个?其中一些信号可以通过分析工具和代码日志来测量。其他的只能通过直接询问工程师来衡量。还有一些可能不是完全可衡量的--例如,我们如何真正衡量代码质量?
最终,在评估可读性对生产力的影响时,我们最终采用了三个来源的衡量标准的组合。首先,我们有一个专门针对可读性过程的调查。这个调查是在人们完成这个过程之后进行的;这使我们能够得到他们对这个过程的直接反馈。第二,我们使用了一个大规模的季度调查来跟踪那些不是专门关于可读性的项目;相反,它们纯粹是关于我们预期可读性应该影响的指标。最后,我们使用了来自我们的开发者工具的细粒度的日志指标来确定日志中所说的工程师完成特定任务所需的时间。表7-2列出了完整的指标清单及其相应的信号和目标。
表7-2. 目标、信号和指标
QUANTS | 目标 | 信号 | 衡量标准 |
---|---|---|---|
可读性调查。报告说参与可读性过程改善了其团队的代码质量的工程师比例 | |||
作为可读性过程的结果,工程师们写出的代码更加一致。 | 工程师在代码审查中由可读性审查员提供一致的反馈和指导,这是可读性过程的一部分。 | 可读性调查。报告可读性审查员的意见和可读性标准不一致的工程师比例。 |
回顾我们在本章中的最初目标:我们要采取行动,提高生产力。在对某一主题进行研究之后,谷歌的团队总是为我们如何继续改进准备了一份建议清单。我们可能会建议给一个工具增加新的功能,改善工具的延迟,改善文档,删除过时的流程,甚至改变工程师的激励结构。理想情况下,这些建议是 "工具驱动"的:如果工具不支持工程师改变他们的流程或思维方式,那么告诉他们这样做是没有用的。相反,我们总是假设,如果工程师有适当的数据和合适的工具 可以使用,他们会做出适当的权衡。
对于可读性,我们的研究表明,总体上是值得的:实现了可读性的工程师们对这个过程感到满意,并认为他们从中学到了东西。我们的记录显示,他们的代码审查得更快,提交得也更快,甚至不再需要那么多审查员。我们的研究还显示了过程中需要改进的地方:工程师们指出了可以使过程更快、更愉快的痛点。语言团队采纳了这些建议,并改进了工具和流程,使其更快,并使其更有说服力,从而使工程师有一个更愉快的体验。
在谷歌,我们发现配备一个工程生产力专家团队对软件工程有广泛的好处;与其依靠每个团队制定自己的路线来提高生产力,一个集中的团队可以专注于解决复杂问题的广泛基础。这种 "以人为本"的因素是出了名的难以衡量,而且鉴于改变工程流程所涉及的许多权衡都难以准确衡量,而且往往会产生意想不到的后果,因此专家们必须了解正在分析的数据。这样的团队必须保持数据驱动,并致力于消除主观偏见。
- 在测量生产力之前,问一下结果是否可操作,无论结果是积极还是消极。如果你对这个结果无能为力,它很可能不值得测量。
- 使用GSM框架选择有意义的衡量标准。一个好的指标是你试图测量的信号的一个合理的代理,并且它可以追溯到你的原始目标。
- 选择涵盖生产力所有部分的衡量标准(QUANTS)。通过这样做,你可以确保你不会以牺牲另一个方面(如代码质量)为代价来改善生产力的一个方面(如开发人员的速度)。
- 定性指标也是一种衡量标准。考虑建立一个调查机制,以追踪关于工程师信念的纵向度量。定性指标也应该与定量指标一致;如果它们不一致,很可能是定量指标不正确。
- 争取创建内置于开发人员工作流程和激励结构的建议。即使有时有必要推荐额外的培训或文档,但如果将其纳入开发人员的日常习惯,则更有可能发生变化。
CHAPTER 1 What is Software Engineering?
CHAPTER 2 How to Work Well on Teams
CHAPTER 4 Engineering for Equity
CHAPTER 7 Measuring Engineering Productivity
CHAPTER 8 Style Guides and Rules
CHAPTER 16 Version Control and Branch Management
CHAPTER 18 Build Systems and Build Philosophy
CHAPTER 19 Critique: Google’s Code Review Tool
CHAPTER 21 Dependency Management
CHAPTER 22 Large-Scale Changes
CHAPTER 23 Continuous Integration
CHAPTER 24 Continuous Delivery