Content Entry

Google 软件工程实践

导读:Fergus Henderson 已在 Google 工作了 10 年以上,拥有超过 15 年的商业类软件的行业经验。本文梳理并总结了 Google 软件开发中的关键工程实践,并揭示了其成功之道,值得业界各路人马参考借鉴。

PIC

摘要

我们梳理并总结了Google的关键软件工程实践。

关于作者

Fergus Henderson 作为软件工程师已在Google工作已经10年了。1979年,当他还是一个孩子时就开始编程,后来继续在编程语言设计和实现上进行学术研究。他与他的博士导师在墨尔本大学共同创立了一个研究小组,开发了编程语言Mercury(水星)。他是8个国际会议的计划委员会成员,并发布了超过50万行的开源代码。他是Usenet新闻组comp.std.c ++的前主席,并且是ISO C和C ++委员会的官方认可的“技术专家”。他拥有超过15年的商业软件行业经验。在Google,他是Blaze的原创开发人员之一,Blaze是一个目前在Google上使用的构建工具,并致力于语音识别和语音操作(在Siri!之前)的服务器端软件和语音合成开发工作。他目前管理Google的文字转语音工程小组,但仍然撰写和审查了大量的代码。他写的软件安装在十亿多个设备上,每天使用量超过十亿次。

1. 简介

Google已经是一个非常成功的公司了。除了Google搜索和AdWords的成功之外,Google还提供了许多其它杰出的产品,包括Google地图、Google新闻、Google翻译、Google语音识别、Chrome和Android 等。Google通过收购小型公司(如YouTube)获得的产品大幅增强和扩展了大量产品,并对各种开源项目做出了重大贡献。 Google已经展示了一些尚未推出的激动人心的产品,例如自驾车。

Google的成功有着很多原因,包括开明的领导力、伟大的人才、超高的招聘标准,以及在迅速成长的市场中成功利用早期领先优势的财务实力。但其中一个原因是 Google开发了优秀的软件工程实践,帮助它取得成功。这些做法随着时间的流逝,根据地球上众多最有才华的软件工程师积累和凝练的智慧而演变。我们愿与世界分享我们的实践的经验,包括分享我们从错误中学到的一些教训。

本文的目的是梳理并简要介绍Google的关键软件工程实践。然后,其他组织和个人可以将它们与自己的软件工程实践进行比较和对比,并考虑是否自己应用一些实践经验。

许多作者(例如[9],[10],[11])都有分析Google的成功和历史的书籍或文章。但大多数主要涉及商业、管理和文化;只有一小部分作者(例如[1,2,3,4,5,6,7,13,14,16,21])探索了软件工程方面的事情,并且大多数只探索一个方面;而且没有一篇文章提供了Google整体软件工程实践的简要概述,正如本文旨在做的那样。

2. 软件开发

2.1 源代码仓库

Google的大多数代码存储在一个统一的源代码存储库中,并且可供 Google 所有软件工程师访问。 请注意有些例外,特别是两个大型开源项目 Chrome 和Android,它们使用单独的开源仓库,另外一些高价值或安全关键的代码,其读取访问被锁定得更紧,管得更严。但大多数 Google 项目共享相同的存储库。

截至2015年1月,这个86 TB的存储库包含了10亿个文件,包括900多万个源代码文件,包含总共20亿行源代码,历史记录3500万次提交,每个工作日更改4万次提交[18]。控制对存储库的写访问:只有存储库的每个子树的列出的所有者都可以批准对该子树的更改。但一般来说,任何工程师都可以访问任何代码片段,可以检出并构建它,可以进行本地修改,可以测试它们,并可以发送更改供代码所有者审核,如果所有者批准,可以签入(提交)那些变化。在企业文化上,Google鼓励工程师修复他们看到的任何东西,并且知道如何修复它们,不管项目的边界如何。这增强了工程师能力,带来了更高质量的基础设施,更好地满足那些使用它的人们的需求。

几乎所有的开发都发生在仓库的“头 ”,而不是在分支上。这有助于及早识别集成问题,并最大限度地减少所需的合并工作量。它还使得更容易和更快地推出安全修复程序。

尽管这并不总是可行,在测试的传递依赖性中的任何文件每次更改之后,自动化系统总是频繁运行测试。通常在几分钟内,这些系统自动通知作者和审阅者任何导致测试失败的更改。大多数团队通过安装突出的显示屏,甚至安装带有颜色编码的灯(绿色为成功构建和所有测试通过,红色为一些测试失败,黑色为构建失败)使他们构建的当前状态非常显眼。这有助于将工程师的注意力集中在保持构建为绿色状态。大多数更大的团队还有一个“构建警察”,通过与错误的更改的作者合作,以快速解决任何问题或回滚令人不安的更改,负责确保持续通过测试。(构建警察角色通常在团队成员之间或在其经验丰富的成员之间轮流充当)。这种关注保持构建绿色状态,使开发变得实用,即使对于非常大的团队仍然如此。

代码所有权。存储库的每个子树可以具有列出该子树的“所有者”的用户ID的文件。子目录还从父目录继承所有者,但可以选择禁止。每个子树的所有者控制对该子树具有写访问权,如下面的代码审查部分所述。每个子树需要至少有两个所有者,虽然通常有更多的所有者,特别是在地理上分布的团队。通常将整个团队成员列在所有者文件中。 Google的任何人都可以对子树进行更改,而不仅仅是所有者,但必须获得所有者的批准。这确保每个更改由理解所修改软件情况的工程师审核。

有关Google源代码存储库的更多信息,请参阅[17,18,21];以及另一家大公司如何应对同样的挑战,见[19]。

2.2 构建系统

Google使用一个称为Blaze的分布式构建系统,该平台负责编译和链接软件以及运行测试。它提供了用于构建和测试在整个存储库中工作的软件的标准命令。这些标准命令和高度优化的实现意味着, 对于任何Google工程师来说,构建和测试存储库中的任何软件通常非常简单和快捷。这种一致性是一个关键的推动因素,有助于使工程师能够跨项目边界进行更改。

程序员编写“BUILD”文件,Blaze用它来确定如何构建他们的软件。使用相当高级别的 声明式构建规范 声明库,程序和测试等构建实体,为每个实体指定其名称,源文件以及它所依赖的库或其他构建实体。这些构建规范包括称为“构建规则”的声明,每个都指定高级概念,如“这里是一个C ++库,这些源文件取决于这些其他库”,并且由构建系统将每个构建规则映射到一组构建步骤,例如编译每个源文件的步骤和用于链接的步骤,以及用于确定使用哪个编译器和编译标志。

在某些情况下,特别是Go程序,可以自动生成(和更新)构建文件,因为BUILD文件中的依赖性信息是(通常)源文件中的依赖性信息的抽象。但是,它们仍然检入到存储库里。这确保构建系统可以通过仅分析构建文件而不是源文件来快速确定依赖性,并且避免构建系统和用于所支持的许多不同编程语言的编译器或分析工具之间的过度耦合。

构建系统的实现使用Google的分布式计算基础设施。每个构建的工作通常 分布在数百甚至数千个机器上。这使得可以快速构建极大的程序或并行运行数千个测试。

各个构建步骤必须是“气密的”:它们仅取决于他们所声明的输入。强制所有依赖关系正确声明是分发构建的结果:只有声明的输入被发送到运行构建步骤的机器。因此,构建系统可以依赖于知道真正的依赖性。即使编译系统调用的编译器也被视为输入。

单独构建步骤是确定性的。因此,构建系统可以缓存构建结果。软件工程师可以将它们的工作空间同步到旧的更改号码,并且可以重新构建,最终将获得完全相同的二进制文件。此外,该高速缓存可以在不同用户之间安全地共享。(为了正常工作,我们必须消除由构建调用的工具中的不确定性,例如通过清除生成的输出文件中的时间戳)。

构建系统是可靠的。构建系统跟踪对构建规则本身的更改的依赖关系,并且如果生成目标的操作发生变化,即使该操作的输入没有改变,也知道重新构建目标,例如当只更改编译器选项时也是如此。它还正确处理中断构建部分的方式,或在构建期间修改源文件:在这种情况下,您只需要重新运行build命令。没有任何需要运行相当于“make clean”。

构建结果被缓存在“云中”。这包括中间结果。如果另一个构建请求需要相同的结果,即使请求来自不同的用户,构建系统将自动重用它们而不是重新构建。

增量重新构建速度快。构建系统保持驻留在内存中,因此对于重新构建,它可以增量地分析自上次构建以来更改的文件。

预提交检查。 Google提供了在启动代码审查和/或准备向存储库提交更改时自动运行一系列测试的工具。存储库的每个子树可以包含配置文件,该配置文件确定要运行哪些测试,以及是在代码审查时还是在提交之前立即运行它们,还是两种情况下都运行测试。测试可以是同步的,即在发送更改以进行审查之前和/或在将更改提交到存储库之前运行(有利于快速运行测试);或者是异步的,结果通过电子邮件发送到审查讨论线程。 [审查线程是进行代码审查的电子邮件线程;该线程中的所有信息也显示在基于Web的代码审查工具中。]

2.3 代码审查

Google已经建立了完善的基于Web的代码审查工具,并与电子邮件集成,允许作者提出审查,并允许审查者查看并排显示差异(使用漂亮的颜色编码)并对其进行评论。当更改作者发起代码审查时,系统会通过电子邮件通知审查者,并提供指向该网页更改工具网页的链接。当审查人提交审查评论时,系统会发送电子邮件通知。此外,自动化工具可以发送通知,包含例如自动化测试的结果或静态分析工具的结果。

对主源代码存储库的所有更改必须至少由另一位工程师审查。此外,如果更改的作者不是正在修改的文件的所有者,则至少有一个所有者必须审查并批准该更改请求。在特殊情况下,子树的所有者可以在审查之前签入(提交)该子树的紧急更改,但审查者仍然必须命名,并且更改作者和审查者将自动对其进行标记,直到更改生效经过审查和批准。在这种情况下,为解决审查意见所需的任何修改必须单独进行,因为原始更改已经提交。

Google有一些工具可以通过查看正在修改的代码的所有权和作者身份,最近审查人的历史记录以及每个潜在审查者的待审代码数量,自动为特定更改提示审查人。变更所影响的每个子树至少一个所有者必须审查并批准该更改请求。但除此之外,作者可以自由选择审查者,因为他们认为合适做审查。

代码审查的一个潜在问题是,如果审查者的响应太慢,或者过于不愿意批准更改,这可能会减慢开发速度。代码作者选择他们的审查者的事实有助于避免这样的问题,允许工程师避免可能对他们的代码过于占有的审查者,或者发送评论以对较不透彻的评论者进行简单的改变,并且将更复杂的改变发送给更有经验的审查者或几个审查者。

每个项目的代码审查讨论自动复制到项目维护者指定的邮件列表中。任何人都可以对任何更改发表评论,无论他们是否被指名为该更改的审查人,无论是在更改之前还是之后。如果发现错误,通常追踪引入它的更改,并对原始代码审查线程发表评论,指出错误,以便原始作者和审查者知道情况。

还可以向几个审查者发送代码审查,然后一旦其中一个审查者批准(当然作者或第一个作出回应的审查者是所有者,则在其他审查者评论之前)提交改变,随后的审查意见将在后续更改中处理。这样可以减少评论的周转时间。

除了存储库的主要部分, 存储库中也存在一个“实验性”部分,它不强制执行正常的代码审查要求。但是,在生产环境中运行的代码必须位于存储库的主要部分,并且非常强烈地鼓励工程师在存储库的主要部分开发代码,而不是开发实验性代码,然后将其移动到主要部分,当代码是开发时而不是之后,因为代码审查是最有效的。实际上,工程师经常要求代码审查,即使是实验代码也是如此。

Google鼓励工程师坚持每个单独的更改较小的原则 ,较大的更改最好分成一系列较小的更改,审查者可以轻松地一次查看完毕。这也使作者对每篇作品的审查期间提出的主要变化作出反应更容易;非常大的更改通常太僵硬,并阻碍审查者对更改提出建议。鼓励保持更改较小原则的一种方式是代码审查工具标记每个代码审查与更改的大小描述,添加/删除30-99行的更改标记为“中型”和300行以上的更改标记具有越来越不相关的标签,例如““large”(300-999),“freakinhuge”(1000-1999)等(但是,以一个典型的Google式的自娱自乐的方式,每年花上几天用有趣的替代品替换这些熟悉的描述,正如像海盗行侠仗义似谈资。)

2.4 测试

Google强烈鼓励并广泛使用单元测试。生产环境中使用的所有代码都需要进行单元测试,代码审查工具将突出显示是否添加了源文件而没有添加相应的测试。代码审查人员通常要求添加新功能的任何更改都应添加新测试以涵盖新功能。模拟框架(允许构建轻量级单元测试,甚至对于具有对重量级库的依赖的代码)的使用时相当普遍的。

集成测试和回归测试也广泛应用。

如上面的“预提交检查”中所述,测试可以作为的一部分自动执行代码审查和提交过程。

Google还提供用于测量测试覆盖率的自动化工具。结果也作为源代码浏览器中的可选层被整合进来。

在部署之前进行负载测试也是Google的重点。团队需要生成一个表格或图形,显示关键指标(特别是延迟和错误率)如何随传入请求的速率而变化。

2.5 Bug 跟踪

Google使用一个名为Buganizer的错误跟踪系统来跟踪问题:bug,功能请求,客户问题和流程(如发布或清理工作)。错误被分为层次化组件,每个组件可以有一个默认的受托人和默认电子邮件列表到抄送列表(CC)。当发送源代码更改以供审查时,系统会提示工程师将更改与特定的问题编号相关联。

Google的团队通常(但不是通用)定期扫描其组件中的开放问题,确定优先级,并在适当时将其分配给特定工程师。一些团队有一个特定的个人负责Bug分类,其他人在常规团队会议中进行Bug分类。 Google的许多团队都使用Bug标签来指明是否已对Bug进行了分类,以及每个Bug所针对的发布版本。

2.6 编程语言

Google强烈鼓励软件工程师使用以下四种官方认可的编程语言之一进行编程: C ++,Java,Python或Go。最小化所使用的不同编程语言的数量扫平了代码重用和程序员协作的障碍。

另外,每种语言都有 Google 风格指南,以确保整个公司的代码都具有类似的风格、布局、命名约定等。此外,还有一个公司范围的 可读性 培训流程,由经验丰富的工程师关心代码可读性通过检查一个实质性的变化或一系列变化,直到审查人确信作者知道如何用该语言编写可读代码为止,来训练其他工程师如何以特定语言编写可读的惯用代码。每个以特定语言添加不重要的新代码的更改都必须由已通过该语言的“可读性”培训流程的人批准。

除了这四种语言之外,许多 专用的领域特定语言 用于特定目的(例如用于指定构建目标及其依赖性的构建语言)。

这些不同的编程语言之间的互操作主要使用 Protocol Buffers (协议缓冲区)完成。ProtocolBuffers 是一种以高效且可扩展的方式编码结构化数据的方法。它包括一门用于指定结构化数据的领域特定语言以及一个编译器,它接受领域特定语言的描述,并生成C ++,Java,Python中的代码,用于构建、访问、序列化和反序列化这些对象。 Google的Protocol Buffers版本与Google的RPC库集成,支持简单的跨语言RPC,对RPC框架自动处理的请求和响应进行序列化和反序列化。

过程的通用性 是使开发变得容易的关键,即使具有巨大的代码库和多样化的语言也是如此:无论什么项目或语言,有一组命令来执行所有常见的软件工程任务(例如签出、编辑、构建、测试、审查、提交、文件错误报告等)和相同的命令可以使用。开发人员不需要学习新的开发过程,因为他们正在编辑的代码恰好是不同项目的一部分或用不同的语言编写的。

2.7 调试和剖析工具

Google服务器与库相链接,这些库提供了许多用于调试运行中服务器的工具。在服务器崩溃的情况下,信号处理程序自动将堆栈跟踪转储到日志文件,并保存核心文件。如果崩溃是由于堆内存不足,服务器将转储活动堆对象的采样子集的分配站点的堆栈跟踪。还有用于调试的网络接口,其允许检查传入和传出RPC(包括定时、错误率、速率限制等),改变命令行标志值(例如以增加特定模块的日志冗长度)、资源消耗、剖析等等。这些工具大大增加了调试的总体便利性,以至于很少启动传统的调试器(如gdb)来完成调试工作。

2.8 发布工程

在Google,只有几个团队有专门的发布工程师,但对于的大多数团队,发布工程工作都是由一般软件工程师完成的。

大多数软件 频繁发布 ;每周或每两周发布是比较常见的目标,一些团队甚至每天发布。这是通过自动化大多数正常发布工程任务实现的。频繁发布有助于保持工程师的积极性(如果在几个月甚至几年后才发布,那么就很难激发工程师的积极性),并通过允许更多的迭代增加总体速度,从而获得更多的反馈机会和更多在给定时间内响应反馈的机会。

通常通过同步到最新的“绿色”构建(即,所有自动测试通过的最后一个改变)的更改号并进行发布分支,在新的工作区中开始发布。发布工程师可以选择额外的更改以“cherry-picked”,即从主分支合并到发布分支上。然后软件将从头重新构建并运行测试。如果存在任何测试失败,则进行其他更改以修复故障,并将这些附加更改挑选到发布分支上,之后将重新构建软件并重新运行测试。当测试全部通过时,将构建的可执行文件和数据文件打包。所有这些步骤都是自动化的,所以发布工程师只需要运行一些简单的命令,甚至只需在菜单驱动的UI上选择一些菜单项,选中哪些更改(如果有的话)即可。

一旦候选构建已经被打包,它通常被加载到“ 分段(Staging) ”服务器上,以便由小组用户(有时仅仅是开发团队)进行进一步的 集成测试

一种有用的技术涉及将来自生产流量的请求的副本(子集)发送到分段(staging)服务器,但是也将这些相同请求发送到当前生产服务器用于实际处理。来自分段服务器的响应被丢弃,并且来自实况生产服务器的响应被发送回给用户。这有助于确保在将服务器投入生产之前,可以检测到任何可能导致严重问题(例如服务器崩溃)的问题。

下一步是通常推出到正在 处理实况生产流量子集 的一个或多个“ 金丝雀(canary) ”服务器。与“分段”服务器不同,这些是处理和响应真实用户。

最后,该版本可以推广到所有数据中心中的所有服务器。对于非常高流量,高可靠性的服务,这在几天的时间内逐步推出,以帮助减少任何中断的影响,因为新引入的bug没有被任何以前的步骤捕获到。

有关Google发布工程的更多信息,请参见SRE手册[7]的第8章。参见[15]。

2.9 启动批准

启动任何用户可见的更改或重大设计更改需要来自实施更改的核心工程团队之外的许多人员的批准。需要特别的批准(通常需要详细审查),以确保代码符合法律需求、隐私需求、安全需求、可靠性需求(例如,具有适当的自动监控以检测服务器中断并自动通知相应的工程师),业务需求等等。

启动过程还旨在确保在任何重要的新产品或功能启动时通知公司内的相应人员。

Google有一个内部启动批准工具,用于跟踪所需的审查和批准,以确保符合每个产品定义的启动流程。此工具可轻松自定义,以便不同的产品或产品区域可以具有不同的所需的审查和批准。

有关启动过程的更多信息,请参见SRE手册[7]的第27章。

2.10 复盘

每当我们的任何生产系统发生严重停机或类似事故时,所涉及的人员都必须写一份复盘文档。本文档描述了事件,包括标题、摘要、影响、时间表、根本原因、什么正常工作/什么无法工作和行动措施。 重点是问题,以及如何避免它们在未来再次发生,而不是对人或分摊责任。影响部分尝试根据中断持续时间,丢失的查询(或失败的RPC等)数量和收入来量化事件的影响。时间线部分给出了导致中断的事件的时间表,以及诊断和纠正它所采取的步骤。“什么正常工作/什么无法工作”部分描述教训 - 哪些实践帮助迅速发现和解决问题,什么出现错误,采取什么具体行动(最好把错误分配给特定的人)可以采取减少未来类似问题的可能性和/或严重程度。

有关Google复盘文化的更多信息,请参阅SRE手册[7]的第15章。

2.11 频繁重写

Google大多数软件每隔几年就会重写一次

这看起来似乎非常昂贵。事实上,它消耗了很大一部分Google资源。然而,它也有一些关键的好处,这是Google保持敏捷性和长期成功的关键所在。在几年的时间里,随着软件环境和其周围的其他技术发生变化,以及随着技术或市场的变化影响用户需求、愿望和期望,产品的需求通常会发生显著变化。几年前的软件是围绕一组较旧的需求设计的,通常不是以对当前需求最佳的方式设计的。此外,它通常累积了很多复杂性。重写代码减少了所有不必要的累积复杂性,这些复杂性正在解决不再那么重要的要求。此外,重写代码是一种向新的团队成员传递知识和所有权感的方式。这种所有权感对生产力至关重要:工程师自然会更努力地开发特性,并在他们认为是“他们的”的代码在解决问题。频繁的重写也鼓励工程师在不同项目之间的换岗,有助于鼓励想法的异质授粉。频繁的重写也有助于确保代码使用现代技术和方法书写。

3. 项目管理

3.1 20%的时间

Google允许工程师高达20%的时间花在他们选择的任何项目上工作,而无需他们的经理或任何其他人的批准。这种对工程师的信任是非常有价值的,有几个原因。首先,它允许任何人有一个好主意(即使这是一个想法,其他人不会立即认出是值得的)有足够的时间来开发原型,演示或展示示,以证明他们的想法具有价值。其次,它向管理层提供可能隐藏活动的可见性。在没有允许20% 时间的官方政策其他公司中,工程师有时会在不通知管理层的情况下工作在“偷偷摸摸”的项目。如果工程师可以正大光明地从事这样的项目,描述他们在这些项目的工作的正常状态更新,甚至在他们的管理可能不认可项目价值的情况下,这是更好的选择。拥有一个全公司范围的官方政策和支持它的企业文化使这成为可能。第三,允许工程师花费一小部分时间在更有趣的东西上工作,保持工程师的动机和兴奋,他们做什么,并阻止他们被烧毁,这很容易发生,如果他们觉得被迫花费100%他们的时间工作在更繁琐的任务上面。在工作积极性方面,积极性的工程师和烧坏的工程师之间的生产力差异是超过20%。第四,它鼓励创新企业文化。看到其他工程师工作在有趣的实验性的20%项目鼓励大家做同样的事情。

3.2 目标和关键结果(OKR)

Google的个人和团队需要明确记录他们的目标,并评估他们在实现这些目标方面取得的进展。团队制定季度和年度目标,可衡量的关键结果显示在实现这些目标方面取得进展。这是在公司的每一个层面上进行的,一直到整个公司的定义目标。个人和小团队的目标应该与他们所参与的更广泛团队以及整个公司目标的更高级目标保持一致。在每个季度末,记录可衡量的关键结果的进展,每个目标的得分为0.0(无进展)至1.0(完成100%)。 OKR和OKR分数通常在Google整个公司上可见(对于特别敏感的信息,例如高度保密的项目偶尔有例外),但它们不直接用作个人绩效评估的输入。

OKR应该往高设置:期望的目标总平均分是65%,这意味着鼓励团队将大约50%的任务设置为比它们可能实际完成的任务要多。如果一个团队的得分明显高于这个数字,鼓励他们在下一个季度设置更加雄心勃勃的OKR(反之,如果他们得分明显低于这个数字,鼓励他们在下个季度更加保守地设置OKR)。

OKR提供了一个关键的机制,用于沟通公司的每个部分工作,并鼓励员工通过社会奖励良好的绩效…工程师知道他们的团队将有一个会议,OKR将得分,并有自然的驱动力尽管OKR对绩效考核或薪酬没有直接影响,但是尽力取得好成绩。定义客观和可衡量的关键结果有助于确保这种良好表现的人类驱动力被引导到对实现共同目标的进展具有实际具体可衡量影响的事情。

3.3 项目审批

尽管有一个明确定义的启动批准流程,但Google没有明确定义的项目审批或取消流程。尽管已经在Google工作了近10年,现在已经成为一名经理,我仍然不能完全理解如何做出这样的决定。在某种程度上,这是因为在整个公司,这种方法是不统一的。每个级别的经理都对他们的团队工作的项目负责,并且在他们认为合适的时候行使其自由裁量权。在某些情况下,这意味着这种决策是以自下而上的方式进行的,工程师可以自由选择在其团队范围内工作的项目。在其他情况下,这种决策以更自上而下的方式进行,公司高层或中层管理人员决定哪些项目将进行,哪些将获得额外的资源,哪些将被取消。

3.4 机构重组

偶尔,公司高层决定取消一个大型项目,然后许多工程师在该项目上工作可能需要在新的团队上找到新的项目。类似地,偶尔进行“碎片整理”工作,其中分散在多个地理位置的项目被合并到较少数量的地点,其中一些地点中的工程师被要求改变团队和/或项目以实现这一点。在这种情况下,工程师通常可以自由地从他们的地理地点可用的位置中选择他们的新团队和角色,或者在碎片整理的情况下,他们也可以被选择留在同一个团队和项目通过移动到不同的地点。

此外,其他类型的机构重组,如合并或拆分团队和报告链中的变化,似乎是相当频繁的事件,虽然我不知道Google如何与其他大公司比较有啥区别。在一个大型,技术驱动的组织中,可能需要进行频繁的重组,以避免由于技术和需求的变化而导致组织效率低下。

4. 人员管理

4.1 角色

我们将在下面更详细地解释,Google将工程和管理职业发展阶梯分离开,将技术主导角色与管理层分开,将研究嵌入工程,并支产品经理,项目经理和现场可靠性工程师(SRE)支持工程师 。看来,至少有一些做法对维持Google开发的创新文化很重要。

Google在工程中有少量不同的角色。在每个角色中,有一个职业发展有不同的可能发展途径,一系列的水平,以及晋升(与相关的改善薪酬,如薪水)的可能性,以承认在下一个水平的绩效。

主要角色是:

●工程经理

这是此列表中唯一的人员管理角色。具有其他角色的人员(例如软件工程师)可以管理人员,但是工程经理总是管理人员。工程经理通常是前软件工程师,并且总是有相当多的技术专长,以及管理人的技能。

技术领导和人员管理之间有着区别。工程经理不一定领导项目;项目由技术主管领导;技术主管可以是工程经理,但更多时候是软件工程师。项目的技术主管对该项目的技术决策有最终决定权。

经理负责选择技术主管,评估他们团队的表现。他们执行指导和协助职业发展,做绩效评估(使用同行反馈的意见,见下文),并且负责一些薪酬一些方面的事情。他们还负责招聘过程的某些环节。

工程经理通常直接管理3到30人之间,虽然8到12是最常见的。

●软件工程师(SWE)

大多数做软件开发工作的人都是这个角色。 Google的软件工程师的招聘标准非常高;通过聘用特别好的软件工程师,困扰其他组织的许多软件问题被避免或最小化。

Google有着独立的工程和管理职业发展序列。虽然软件工程师可以管理人员或转移到工程经理角色,但管理人员不是升级的要求,即使是在最高级别。在更高层次,显示领导才能是必需的,但可以有许多形式。例如,创建具有巨大影响或被许多其他工程师使用的伟大软件就足够了。这是非常重要的,因为这意味着那些具有很强的技术技能但缺乏管理人的愿望或技能的人仍然有良好的职业发展道路,不需要他们选择管理道路。这避免了一些组织遭受的问题,其中人们由于职业晋升的原因而最终爬上管理职位,但忽略了他们团队中的人的管理。

●研究科学家

这个角色的招聘标准非常严格,并且条件非常高,需要表现出杰出的研究能力,这是出色的出版记录*和*编写代码的能力证明。许多非常有才能的学术界人士,如果能够获得软件工程师的资格,就不能在Google获得研究科学家的资格;Google大多数获得博士学位的人是软件工程师,而不是研究科学家。研究科学家被评估他们的研究贡献,包括他们的出版物,但除此之外,不同的标题,软件工程师和研究科学家在谷歌的作用没有太大的区别。两者都可以做原创研究和发表论文,都可以开发新的产品思想和新技术,并可以写代码和开发产品。 Google的研究科学家通常与软件工程师一起,在相同的团队中在相同的产品或相同的研究上工作。这种在工程中嵌入研究的做法极大地促进了新的研究能够被容纳到运输产品中。

●站点可靠性工程师(SRE)

操作系统的维护由软件工程团队完成,而不是传统的系统管理员类型,但SRE的软件工程技能的招聘要求略低于软件工程职位的要求。 SRE角色的性质和目的在SRE书[7]中有详细的解释,因此我们不在这里进一步讨论。

●产品经理

产品经理负责管理产品;作为产品用户的倡导者,他们协调软件工程师的工作,对这些用户传播重要的功能,与其他团队协调,跟踪Bug和计划,以及确保所需的一切都到位,以产生高质量的产品。产品经理通常 不会 自己编写代码,而是与软件工程师合作,以确保编写正确的代码。

●项目经理/技术项目经理

项目经理的角色与产品经理大致相似,但是他们不是管理产品,而是管理项目、流程或运维(例如数据收集)。技术计划经理相似,但也需要与他们的工作有关的专门的技术专门知识。处理语音数据的语言学。在整个组织中,软件工程师与产品经理和计划管理者的比例不尽相同,但一般较高,例如,在4:1至30:1的范围内。

4.2 设施

Google是以有趣的设施而闻名天下,它具有幻灯片、球技和游戏室等功能。这有助于吸引和留住优秀的人才。 Google优秀咖啡馆对员工免费,提供了那些功能,也巧妙鼓励Google员工留在办公室;饥饿绝不是离开的理由。 “微型厨房”的频繁安置,员工可以享用小吃和饮料,也提供同样的功能,但也作为非正式的想法交流的重要来源,因为许多对话开始在那里展开。健身房、运动和现场按摩帮助保持员工健身、健康和快乐,这提高了生产力和保持。

Google的座位是开放式的,通常相当密集。虽然有争议[20],这鼓励沟通,虽然有时牺牲个人太过集中的利益,但是很经济的。

员工被分配一个单独的座位,但座位重新分配相当频繁(通常由于组织扩展的结果,例如每6-12个月重新分配一次),由管理者安排座位,以促进和鼓励沟通,这是相邻之间或几乎相邻的个体沟通总是很容易。

Google的设施都配备最先进的视频会议设施的会议室,连接到对方预订的日历邀请只是一个点击在屏幕上就可完成。

4.3 培训

Google鼓励员工在许多方面受到教育:

●新的Google员工(“Noogler”)有一个强制性的初始培训课程。

●技术人员(SWE和研究科学家)从“Codelabs”开始:在线短期个人技术培训课程,包括编码练习。

●Google为员工提供各种在线和面对面培训课程。

●Google还支持在外部机构学习。

此外,每个Noogler通常被任命为官方“导师”和一个单独的“伙伴”,以帮助他们入职的速度。非正式指导还通过与其经理、小组会议、代码审查、设计审查和非正式流程的定期会议进行。

4.4 换岗

Google鼓励公司不同部门之间的换岗,以帮助在整个组织传播知识和技术,并改善跨组织沟通。允许在12个月后处于良好状态的员工在项目和/或办公室之间进行转移。还鼓励软件工程师在组织的其他部门进行临时指派任务。例如, SRE(站点可靠性工程)中的六个月“轮换”(临时任务)。

4.5 绩效考核和奖励

Google极力鼓励反馈。工程师可以通过“对等奖金”和“kudos”给彼此明确的积极反馈。任何员工都可以任何其他员工提名“同伴奖金” - 现金奖金100美元,每年最多两次。超越正常的工作职责,只需填写一个网络表单来描述原因。当同伴奖励被授予时,队友也通常得到通知。员工也可以给予“kudos”,形式化的赞美声明,为良好的工作提供明确的社会认可,但没有财政奖励;对于“kudos”,没有要求工作超出正常的职责,并且对它们可以被授予的次数的限制没有限制。

经理也可以发放奖金,包括现金奖金,例如项目完成。和许多公司一样,Google员工根据其绩效获得年度绩效奖金和股权奖励。

Google有一个非常仔细和详细的晋升过程,包括由毛遂自荐或经理提名、自我审查、同行评审、经理评价;然后由促进委员会根据这些意见作出实际决定,结果可以由促进上诉委员会进一步审查。确保正确的人得到晋升对于为员工维持适当的激励是至关重要。

另一方面,绩效不佳则由经理反馈处理,如果有必要,还需要制定绩效改进计划,其中包括制定非常明确的具体绩效目标,并评估实现这些目标的进展情况。如果失败,可能会导致效果不佳,但实际上这在Google上极为罕见。

经理绩效通过反馈调查进行评估; 要求每个员工每年两次填写关于他们的经理业绩的调查,结果被匿名化和聚合,然后提供给经理。这种向上反馈对于维护和提高整个组织的管理质量非常重要。

5 结论

我们简要介绍了Google使用的大多数关键软件工程实践。当然,Google现在是一个庞大而多元化的组织,组织的一些部门有不同的做法。但是这里描述的做法一般由Google的大多数团队遵循。

由于涉及这么多不同的软件工程实践,以及Google成功的许多其他原因与我们的软件工程实践无关,因此很难给出任何定量或客观的证据,将个体实践与改进的结果联系起来。然而,Google的这些做法是经受了时间考验的,在那里他们受到了成千上万的优秀软件工程师的集体主观判断。

对于那些主张使用本文中描述的特定实践的其他组织中的人来说,也许有助于说“对Google来说足够好了”。

致谢

特别感谢Alan Donovan的非常详细和建设性的反馈,并感谢Y aroslav Volovich,UrsHölzle,Brian Strope,Alexander Gutkin,Alex Gruenstein和Hameed Husaini对本文的早期草稿非常有帮助的意见。

参考文献

英文原文

Software Engineering at Google - by Fergus Henderson

comments loading