KM的博客.

谷歌的软件工程

字数统计: 12.2k阅读时长: 43 min
2022/03/10

谷歌的软件工程

目录

1、简介

2、软件开发

  • 源代码库
  • 系统构建
  • 代码 review
  • 测试
  • Bug追踪
  • 编程语言
  • 调试与分析工具
  • 发布工程
  • 项目启动批准
  • 事故复盘
  • 软件反复重写

3、项目管理

  • 20%时间自由分配
  • OKR 机制
  • 项目批准
  • 项目重组
  • 年度黑客马拉松

4、人员管理

  • 角色分工
  • 办公区域设施
  • 培训
  • 部门间转移
  • 绩效考核和奖励

1 简介

谷歌是一家非常成功的公司。除了 Google 搜索和 AdWords 的成功之外,Google 还提供了许多其他出色的产品,包括 Google 地图、Google 新闻、Google 翻译、Google 语音识别、Chrome 和 Android。 Google 还极大地增强和扩展了许多通过收购 YouTube 等小公司而获得的产品,并为各种开源项目做出了重大贡献。谷歌已经展示了一些即将推出的令人惊叹的产品,例如自动驾驶汽车。

谷歌成功的原因有很多,包括开明的领导、优秀的人才、较高的招聘门槛,以及在快速增长的市场中成功利用早期领先优势所带来的财务实力。但其中一个原因是谷歌开发了优秀的软件工程实践,这帮助它取得了成功。这些实践基于地球上许多最有才华的软件工程师积累和提炼的智慧,随着时间的推移而发展。我们想与世界分享我们的实践知识,并分享我们从一路走来的错误中吸取的一些教训。

本文的目的是对 Google 的关键软件工程实践进行分类和简要描述。然后其他组织和个人可以将这些与他们自己的软件工程实践进行比较和对比,并考虑是否自己应用其中一些实践。

2 软件开发

2.1 源代码库

Google 的大部分代码都存储在一个统一的源代码存储库中,可供 Google 的所有软件工程师访问。 (客户数据受到严格保护,只有源代码可以访问。)使用这个可广泛访问的单一存储库有一些明显的例外,特别是两个大型开源项目 Chrome 和 Android,它们使用单独的开源存储库,以及一些高价值或安全关键的代码片段,它们的读取访问权限被更严格地锁定。

但大多数谷歌项目共享同一个存储库。截至 2015 年 1 月,这个 86 TB 的存储库包含 10 亿个文件,其中包括超过 900 万个源代码文件,总共包含 20 亿行源代码,具有 3500 万次提交的历史记录和每个工作日 4 万次提交的更改率[18]。

对存储库的写访问受到控制:只有存储库每个branch 分支的列出所有者才能批准对该branch 分支的更改。

但通常任何工程师都可以访问任何一段代码,可以检查并构建它,可以进行本地修改,可以测试它们,并且可以将更改发送给代码所有者审查,如果所有者批准,可以接受这些变化commit) 。

从文化上讲,鼓励工程师修复他们看到的损坏的一切并知道如何fix修复,而不管项目边界如何。

这赋予了工程师权力,并带来了更高质量的基础设施,更好地满足使用它的人的需求。

几乎所有的开发都发生在存储库的“master”,而不是branch分支上

这有助于及早的发现和定位到问题,并最大限度地减少所需的合并工作量。

它还使得推出安全修复程序变得更加容易和快捷。

经常运行自动化系统进行测试,通常是在每次更改测试的传递依赖项中的任何文件之后,尽管这并不总是可行的。通常在几分钟内这些系统会自动将测试失败的任何更改通知作者和审阅者。大多数团队通过安装突出的显示器甚至带有颜色编码灯的雕塑(绿色表示成功构建并且所有测试通过,红色表示某些测试失败,黑色表示损坏的构建)来使他们构建的当前状态非常显眼。这有助于将工程师的注意力集中在保持构建绿色上。大多数较大的团队还有一个“构建预警”,负责确保测试继续顺利通过,与有问题的更改的作者合作以快速解决任何问题或回滚有问题的更改。 (构建预警的角色通常在团队或更有经验的成员之间轮换。)这种对保持构建绿色的关注使得开发在头部变得实用,即使对于非常大的团队也是如此。

代码所有权。存储库的每个branch 分支都可以有一个文件,列出该branch 分支“所有者”的用户 ID。子目录也从其父目录继承所有者,尽管可以选择抑制。每个branch 分支的所有者控制对该branch 分支的写访问,如下面的代码审查部分所述。

每个branch 分支都需要至少有两个所有者,尽管通常会有更多,尤其是在地理分布的团队中。整个团队都列在所有者文件中是很常见的。** Google 的任何人都可以更改branch 分支,而不仅仅是所有者,但必须得到所有者的批准。这确保了每一个更改都由了解正在修改的软件的工程师审查。**

2.2 系统构建

Google 使用称为 Blaze 的分布式构建系统,它负责编译和链接软件以及运行测试。它提供了用于构建和测试在整个存储库中工作的软件的标准命令。这些标准命令和高度优化的实现意味着任何 Google 工程师通常都可以非常简单快捷地构建和测试存储库中的任何软件。

这种一致性是一个关键的推动因素,它有助于使工程师跨项目边界进行更改变得切实可行。

程序员编写“BUILD”文件,Blaze 使用这些文件来确定如何构建他们的软件。诸如库、程序和测试之类的构建实体是使用相当高级的声明性构建规范来声明的,这些规范为每个实体指定了它的名称、它的源文件以及它所依赖的库或其他构建实体。这些构建规范由称为“构建规则”的声明组成,每个声明都指定了高级概念,例如“这是一个具有这些源文件的 C++ 库,这些源文件依赖于这些其他库”,构建系统将每个构建规则映射到一组构建步骤,例如编译每个源文件的步骤和链接步骤,以及确定要使用的编译器和编译标志。

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

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

单个构建步骤必须是“封闭的”:它们只依赖于它们声明的输入。

强制正确声明所有依赖项是分发构建的结果:只有声明的输入被发送到运行构建步骤的机器。因此,可以依赖构建系统来了解真正的依赖关系。甚至构建系统调用的编译器也被视为输入。

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

构建系统是可靠的。构建系统跟踪对构建规则本身的更改的依赖关系,并且知道生成目标的操作是否发生了更改,即使该操作的输入没有更改,例如当只有编译器选项发生更改时。它也处理得当

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

增量重建速度很快。构建系统驻留在内存中,以便重建它可以增量分析自上次构建以来已更改的文件。

预提交检查。

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

2.3 代码 review

谷歌建立了优秀的基于网络的代码审查工具,与电子邮件集成,允许作者请求审查,并允许审查者查看并排的差异(带有漂亮的颜色编码)并对其进行评论。当更改的作者发起代码审查时,会通过电子邮件通知审查者,并带有指向该更改的 Web 审查工具页面的链接。审阅者提交审阅意见时会发送电子邮件通知。此外,自动化工具可以发送通知,例如包含自动化测试的结果或静态分析工具的结果。

对主源代码存储库的所有更改必须由至少一名其他工程师审查。此外,如果更改的作者不是被修改文件的所有者之一,则至少有一个所有者必须审核并批准更改。

在特殊情况下,branch 分支的所有者可以在对branch 分支进行review之前接受对该branch 分支的紧急更改的 commit,但仍必须指定审查者,并且更改作者和审查者将自动对其进行讨论,直到更改完成经审查和批准。在这种情况下,必须进行任何修改以解决审查意见在单独的更改中,因为原始更改已经提交。

谷歌有一些工具,可以通过查看正在修改的代码的所有权和作者身份、最近审阅者的历史记录以及每个潜在审阅者的待定代码审查数量来自动建议审阅者进行给定的更改。更改影响的每个branch 分支的至少一个所有者必须审查并批准该更改。但除此之外,作者可以自由选择他们认为合适的审稿人。

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

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

也可以将代码审查发送给多个审查员,然后在其中一个审查员批准后立即提交更改(当然,前提是作者或第一个回复的审查员是所有者),在其他审查员发表评论之前,在后续更改中处理任何后续审查意见。这可以减少评论的周转时间。

除了存储库的主要部分之外,存储库还有一个“实验”部分,其中不强制执行正常的代码审查要求。但是,在生产环境中运行的代码必须在存储库的主要部分中,并且强烈建议工程师在存储库的主要部分中开发代码,而不是在实验中开发然后将其移动到主要部分,因为代码审查在开发代码而不是之后完成时最有效。在实践中,工程师甚至经常要求对实验代码进行代码审查。

鼓励工程师将每个单独的commit保持在较小的范围内,较大的更改最好分解为一系列较小的更改,以便审阅者可以轻松地一次进行审阅。 这也使作者更容易对每篇文章的审阅过程中提出的重大更改做出回应;

非常大的更改通常过于严格和死板,并且会抵制审稿人建议的更改。

鼓励保持较小更改的一种方法是代码审查工具在每个代码审查上标记更改大小的描述,

添加、修改和删除 30-99 行的更改标记为“中等大小”,

并使用 超过 300 行的更改被贴上越来越贬低的标签,例如 “large”(300-999)

“freakin huge”(1000-1999)等

(然而,以一种典型的谷歌方式,通过每年几天用有趣的替代方式替换这些熟悉的描述来保持乐趣,例如 像海盗一样说话。:)

2.4 测试

Google 强烈鼓励并广泛实施单元测试。生产中使用的所有代码都应该有单元测试,如果添加源文件而没有进行相应的测试,代码审查工具会突出显示。代码审查员通常要求任何添加新功能的更改也应该添加新测试以覆盖新功能。模拟框架(即使对于依赖于重量级库的代码也允许构建轻量级单元测试)非常流行。
集成测试和回归测试也被广泛使用。

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

谷歌也有用于测量测试覆盖率的自动化工具。结果也集成为源代码浏览器中的可选层。

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

2.5 Bug追踪

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

Google 的团队通常(尽管不是普遍的)定期扫描其组件中的未解决问题,确定它们的优先级并在适当的情况下将它们分配给特定的工程师。 一些团队有一个特定的人负责错误分类,其他团队在他们的定期团队会议上进行错误分类。 Google 的许多团队都使用错误标签来指示错误是否已被分类,以及每个错误的目标是在哪个版本中修复。

2.6 编程语言

强烈建议 Google 的软件工程师使用 Google 官方批准的五种编程语言之一进行编程:C++、Java、Python、Go 或 JavaScript。减少使用的不同编程语言的数量减少了代码重用和程序员协作的障碍。

每种语言都有谷歌风格指南,以确保整个公司的代码都是用相似的风格、布局、命名约定等编写的。此外,还有一个公司范围内的可读性培训过程,由经验丰富的工程师来关心代码可读性培训其他工程师如何用特定语言编写可读的、惯用的代码,方法是审查一个或一系列的实质性变化,直到审查者对作者知道如何用该语言编写可读代码感到满意。以特定语言添加重要新代码的每项更改都必须得到已通过该语言的“可读性”培训过程的人员的批准。

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

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

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

2.7 调试和分析工具

Google 服务器与库链接,这些库提供了许多用于调试正在运行的服务器的工具。

在服务器崩溃的情况下,信号处理程序将自动将堆栈跟踪转储到日志文件,并保存核心文件。

如果崩溃是由于堆内存不足,服务器将转储活动堆对象的采样子集的分配站点的堆栈跟踪。

还有用于调试的 Web 界面,允许检查传入和传出 RPC(包括时间、错误率、速率限制等)、更改命令行标志值(例如,增加特定模块的日志记录详细程度)、资源消耗、分析 , 和更多。 这些工具极大地提高了调试的整体易用性,以至于很少启动像 gdb 这样的传统调试器。

2.8 发布工程

少数团队有专门的发布工程师,但对于谷歌的大多数团队来说,发布工程工作是由普通软件工程师完成的。

大多数软件都经常发布;每周或每两周发布一次是一个共同目标,有些团队甚至每天发布一次。这可以通过自动化大多数正常的发布工程任务来实现。频繁发布有助于保持工程师的积极性(如果某件事要到几个月甚至几年后才发布,就很难对它感到兴奋),并通过允许更多的迭代来提高整体速度,从而获得更多的反馈机会和更多的机会在给定的时间内响应反馈。

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

一旦一个候选构建被打包,它通常被加载到一个“staging”服务器上,供一小部分用户(有时只是开发团队)进行进一步的集成测试。

一种有用的技术涉及将来自生产流量的请求的副本(子集)发送到staging服务器,但也将这些相同的请求发送到当前的生产服务器以进行实际处理。来自登台服务器的响应被丢弃,来自实时生产服务器的响应被发送回用户。

这有助于确保在将服务器投入生产之前可以检测到任何可能导致严重问题(例如服务器崩溃)的问题。

下一步通常是部署一个或多个处理实时生产流量子集的“canary 金丝雀”服务器。与“staging”服务器不同,这些服务器正在处理和响应真实用户。

最后,该版本可以推广到所有数据中心的所有服务器。对于非常高流量、高可靠性的服务,这是通过在几天内逐步推出来完成的,以帮助减少由于新引入的错误导致的任何中断的影响,而这些错误没有被之前的任何步骤捕获.
有关 Google 发布工程的更多信息,请参阅 SRE 书籍 [7] 的第 8 章。另见[15]。

2.9 启动批准

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

发布过程还旨在确保在任何重要的新产品或功能发布时通知公司内的适当人员。

Google 有一个内部发布批准工具,用于跟踪所需的审核和批准,并确保符合每个产品定义的发布流程。

该工具易于定制,因此不同的产品或产品领域可以有不同的所需审查和批准集。

有关启动过程的更多信息,请参阅 SRE 书籍 [7] 的第 27 章。

2.10 事故报告

每当我们的任何生产系统出现重大中断或类似事故时,相关人员都需要编写一份事后分析文件。

本文档描述了事件,包括标题、摘要、影响、时间线、根本原因、有效/无效以及行动项目。重点是问题,以及将来如何避免这些问题,而不是在人或分摊责任上。

影响部分尝试根据中断持续时间、丢失查询(或失败的 RPC 等)的数量和收入来量化事件的影响。时间线部分给出了导致中断的事件的时间线以及为诊断和纠正它所采取的步骤。什么有效/无效部分描述了经验教训——哪些实践有助于快速检测和解决问题,出了什么问题,以及可以采取哪些具体行动(最好作为分配给特定人员的错误)来减少未来类似问题的可能性和/或严重性。

有关 Google 的事故文化的更多信息,请参阅 SRE 书籍 [7] 的第 15 章。

2.11 软件反复重写

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

这可能看起来非常昂贵。事实上,它确实消耗了谷歌很大一部分资源。

然而,它也有一些重要的好处,这些好处是谷歌的敏捷性和长期成功的关键。

在几年的时间里,随着软件环境和围绕它的其他技术发生变化,以及随着技术或市场的变化影响用户的需求、愿望和期望,产品的需求通常会发生显着变化。几年前的软件是围绕一组较旧的需求设计的,通常不是以最适合当前需求的方式设计的。此外,它通常积累了很多复杂性。

重写代码消除了所有不必要的累积复杂性,这些复杂性正在解决不再那么重要的需求。

重写代码是向新团队成员传递知识和主人翁意识的一种方式。这种主人翁意识对生产力至关重要:工程师自然会投入更多精力来开发功能并修复他们认为“属于他们”的代码中的问题。

频繁的重写还鼓励工程师在不同项目之间的流动性,这有助于鼓励思想的碰撞💥。

频繁的重写也有助于确保使用现代技术和方法来编写代码。

3 项目管理

3.1 20%的时间自由分配

工程师可以将最多 20% 的时间用于他们选择的任何项目,而无需获得经理或其他任何人的批准。

这种对工程师的信任是非常有价值的,原因有很多。

首先,它允许任何有好想法的人,即使这是一个其他人不会立即认为值得的想法,也有足够的时间来开发原型、demo或简单介绍,以展示他们的想法的价值。

其次,它为管理层提供了对可能隐藏的活动的可见性。在其他没有允许 20% 时间的官方政策的公司中,工程师有时会在不通知管理层的情况下从事“臭鼬”项目。如果工程师能够对此类项目持开放态度,并在定期状态更新中描述他们在此类项目上的工作,即使在他们的管理层可能无法就项目价值达成一致的情况下,情况也会好得多。拥有全公司范围的官方政策和支持它的文化使这成为可能。

第三,通过允许工程师将一小部分时间花在更有趣的事情上,它可以让工程师对他们所做的事情保持动力和兴奋,并防止他们感到筋疲力尽,如果他们觉得有必要花费 100% 的时间很容易发生这种情况。他们将时间花在更繁琐的任务上。敬业、积极进取的工程师和精疲力竭的工程师之间的生产力差异远远超过 20%。

第四,鼓励创新文化。看到其他工程师从事有趣的实验性 20% 项目会鼓励每个人都这样做。

3.2 OKRs

Google 要求个人和团队明确记录他们的目标并评估他们在实现这些目标方面的进展。

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

OKR 应该设置得高一些:期望的目标总体平均得分为 65%,这意味着鼓励团队将目标设定为比他们可能实际完成的任务多 50% 的目标。如果一个团队的得分明显高于此值,则鼓励他们为下一个季度设置更雄心勃勃的 OKR(相反,如果他们的得分明显低于此值,则鼓励他们在下个季度更保守地设置 OKR)。

OKR 提供了一种关键机制,用于沟通公司各部门的工作内容,并通过社会激励来鼓励员工的良好表现……工程师知道他们的团队将召开会议,对 OKR 进行评分,并且自然而然地即使 OKR 对绩效评估或薪酬没有直接影响,也努力争取取得好成绩。定义客观和可衡量的关键结果有助于确保将这种人为的良好绩效驱动力引导到对实现共同目标的进展具有真正具体可衡量影响的事情上。

3.3 项目审批

尽管有明确的启动批准流程,但 Google 没有明确的项目批准或取消流程。

尽管在谷歌工作了 10 多年,现在我自己也成为了一名经理,但我仍然不完全理解这些决定是如何做出的。 部分原因是整个公司的处理方法并不统一。 每个级别的经理都对其团队所从事的项目负责,并在他们认为合适的情况下行使他们的自由裁量权。 在某些情况下,这意味着此类决策是以一种自下而上的方式做出的,工程师可以自由选择在其团队范围内从事哪些项目。 在其他情况下,此类决策是以自上而下的方式做出的,由高管或经理决定哪些项目将继续进行,哪些将获得额外资源,哪些将被取消。

3.4 项目重组

有时会做出取消大型项目的行政决定,然后许多一直从事该项目的工程师可能不得不在新团队中寻找新项目。同样,偶尔也会进行“碎片整理”工作,将分散在多个地理位置的项目合并到较少数量的位置,某些位置的工程师需要更改团队和/或项目以实现这一目标。在这种情况下,工程师通常可以从其所在地理位置的可用职位中自由选择他们的新团队和角色,或者在碎片整理的情况下,他们也可以选择通过移动留在同一团队和项目中到不同的位置。

此外,其他类型的公司重组,例如合并或拆分团队以及更改报告链,似乎也相当频繁,尽管我不知道谷歌与其他大公司相比如何。在技术驱动的大型组织中,可能需要进行一些频繁的重组,以避免随着技术和需求的变化而导致组织效率低下。它们可以帮助避免或减轻大型组织中“运送组织结构图”的常见问题,其中软件架构反映了组织的报告结构。

3.5 年度黑客马拉松

谷歌鼓励创新的另一种方式是举办“黑客马拉松”[23]。

在许多谷歌办公室,这采取了为期一周的年度“黑客马拉松”的形式,软件工程师可以在其中抽出时间来处理新的创新项目。在人们可以提出想法的启动会议之后,他们组成小团队,花一周时间根据新想法构建演示或原型,并在周末向观众和评委展示他们的演示,谁为最佳项目颁发(小)奖。然而,最大的回报是认可——以及让一个成功的黑客马拉松项目毕业成为全职真正项目的机会。

尽管所有工程师都获得了他们网站的许可参加此类黑客马拉松,但许多工程师确实发现很难脱离他们的日常职责,因此参与率通常相当低(例如 5-20%),尽管更多人将参加最初的启动和/或最终演示,并可能会从所提出的想法中得到启发。

4.人员管理

4.1 角色分工

正如我们将在下面更详细地解释的那样,谷歌将工程和管理职业发展阶梯分开,将技术领导角色与管理分开,将研究嵌入到工程中,并为工程师提供产品经理、项目经理和现场可靠性工程师 (SRE) . 似乎这些实践中至少有一些对于维持 Google 发展起来的创新文化很重要。
谷歌在工程领域有少数不同的角色。 在每个角色中,都有可能的职业发展,具有一系列级别,以及晋升的可能性(与薪酬相关的改进,例如薪水)以认可下一个级别的绩效。
主要作用如下:

  • 工程经理
    这是此列表中唯一的人员管理角色。其他角色(例如软件工程师)的个人可能会管理人员,但工程经理总是管理人员。工程经理通常是前软件工程师,并且总是拥有相当多的技术专长和人际交往能力。
    技术领导和人员管理是有区别的。

    • 工程经理不一定领导项目;项目由 Tech Lead 领导,他可以是工程经理,但更多时候是软件工程师。
    • 项目的技术主管对该项目的技术决策拥有最终决定权。
    • 经理负责选择技术主管,以及他们团队的表现。
    • 他们执行指导和协助职业发展,进行绩效评估(使用来自同行反馈的输入,见下文),并负责薪酬的某些方面。他们还负责招聘过程的某些部分。
    • 工程经理通常直接管理 3 到 30 人,但最常见的是 8 到 12 人。
  • 软件工程师 (SWE)
    大多数从事软件开发工作的人都有这个角色。谷歌软件工程师的招聘门槛非常高;通过只雇用非常优秀的软件工程师,可以避免或最小化许多困扰其他组织的软件问题。
    像许多现代软件公司一样,谷歌在工程和管理方面有不同的职业发展顺序。尽管软件工程师可以管理人员或转任工程经理角色,但管理人员并不是晋升的必要条件,即使在最高级别也是如此。在更高的级别,需要表现出领导力,但这可以有多种形式。例如,创建具有巨大影响或被许多其他工程师使用的优秀软件就足够了。这很重要,因为这意味着拥有出色技术技能但缺乏管理人员的愿望或技能的人仍然拥有良好的职业发展道路,不需要他们走上管理轨道。这避免了一些组织因职业发展而最终担任管理职位而忽视团队中人员的人事管理的问题。

  • 研究科学家
    这个职位的招聘标准非常严格,而且门槛非常高,需要表现出卓越的研究能力,以出色的发表记录编写代码的能力为证明。学术界许多非常有才华的人能够获得软件工程师职位的资格,但没有资格获得谷歌的研究科学家职位;谷歌大多数拥有博士学位的人是软件工程师,而不是研究科学家。研究科学家根据他们的研究贡献进行评估,包括他们的出版物,但除了这个和不同的头衔之外,谷歌的软件工程师和研究科学家角色之间并没有太大的区别。两者都可以做原创研究和发表论文,都可以开发新的产品理念和新技术,都可以并且都可以编写代码和开发产品。 Google 的研究科学家通常与软件工程师一起工作,在相同的团队中从事相同的产品或相同的研究。这种将研究嵌入工程的做法极大地促进了将新研究纳入运输产品的便利性。

  • 现场可靠性工程师 (SRE)
    操作系统的维护由软件工程团队完成,而不是传统的系统管理员类型,但 SRE 的招聘要求与软件工程师职位的要求略有不同(如果通过专业知识来补偿,软件工程技能要求可能会略低一些 其他技能,如网络或 Unix 系统内部)。 SRE 角色的性质和目的在 SRE 书籍 [7] 中有很好且详细的解释,因此我们不会在此进一步讨论。

  • 产品经理
    产品经理负责产品的管理; 作为产品用户的倡导者,他们协调软件工程师的工作,宣传对这些用户重要的特性,与其他团队协调,跟踪错误和时间表,并确保生产高质量产品所需的一切都准备就绪。 产品经理通常不自己编写代码,而是与软件工程师合作以确保编写正确的代码。

4.2 办公设施

谷歌以其有趣的设施而闻名,包括滑梯、球坑和游戏室等功能。这有助于吸引和留住优秀人才。谷歌优秀的咖啡馆,对员工免费开放,也提供了这种功能,也巧妙地鼓励谷歌人留在办公室;饥饿永远不是离开的理由。员工可以在其中获取零食和饮料的“微型厨房”的频繁放置也起到了同样的作用,但也是非正式思想交流的重要来源,因为许多对话都是从那里开始的。健身房、运动和现场按摩有助于保持员工健康、快乐和快乐,从而提高生产力和保留率。
谷歌的座位是开放式的,而且通常相当密集。虽然存在争议 [20],但这鼓励了交流,有时会以个人注意力为代价,而且是经济的。
员工被分配了一个单独的座位,但座位的重新分配相当频繁(例如,每 6-12 个月,通常是由于组织扩张的结果),由经理选择座位以促进和鼓励沟通,相邻之间总是更容易或几乎相邻的人。

谷歌的所有设施都设有配备最先进视频会议设施的会议室,只需在屏幕上轻按一下即可连接到另一方以获取预定的日历邀请。

4.3 培训

Google 通过多种方式鼓励员工教育:
● 新的 Google 员工(“Nooglers”)必须参加必修的初始培训课程。
● 技术人员(SWE 和研究科学家)从做“Codelabs”开始:个人技术的短期在线培训课程,包括编码练习。
● Google 为员工提供各种在线和面对面培训课程。
● 谷歌还为在外部机构学习提供支持。
此外,每个 Noogler 通常都会被指定一个官方“导师”和一个单独的“伙伴”,以帮助他们快速上手。

非正式指导也通过与经理的定期会议、团队会议、代码审查、设计审查和非正式流程进行。

4.4 部门转移

鼓励公司不同部门之间的转移,以帮助在整个组织内传播知识和技术,并改善跨组织的沟通。

任职 12 个月后,信誉良好的员工可以在项目和/或办公室之间调动。

还鼓励软件工程师在组织的其他部分执行临时任务,例如 SRE(站点可靠性工程)为期六个月的“轮换”(临时分配)。

4.5 绩效考核与奖励

Google 强烈鼓励提供反馈。工程师可以通过“同行奖励”和“荣誉”相互给予明确的积极反馈。任何员工都可以提名任何其他员工获得“同行奖金”——100 美元的现金奖金——每年最多两次,用于超出正常职责范围,只需填写网络表格来描述原因。当授予同伴奖金时,通常也会通知队友。员工也可以给予“荣誉”,正式的表扬表扬,为良好的工作提供明确的社会认可,但没有经济回报;对于“荣誉”,没有要求工作超出正常职责范围,也没有限制可以授予的次数。
经理还可以奖励奖金,包括现场奖金,例如为项目完成。与许多公司一样,谷歌员工会根据他们的表现获得年度绩效奖金和股权奖励。
谷歌有一个非常仔细和详细的晋升过程,包括自我或经理提名、自我审查、同行评议、经理评估;然后,晋升委员会会根据该意见做出实际决定,结果可能会受到晋升申诉委员会的进一步审查。确保合适的人得到提拔对于维持对员工的正确激励至关重要。

另一方面,糟糕的绩效是通过经理的反馈来处理的,如果有必要的话,还有绩效改进计划,其中包括设定非常明确的具体绩效目标并评估这些目标的进展情况。如果失败,可能会因性能不佳而终止,但实际上这在 Google 极为罕见。

通过反馈调查评估经理绩效;每位员工都被要求每年填写两次关于其经理绩效的调查,结果会被匿名化和汇总,然后提供给经理。这种向上的反馈对于维持和提高整个组织的管理质量非常重要。

5 总结

我们已经简要描述了 Google 使用的大多数关键软件工程实践。

当然,谷歌现在是一个庞大而多元化的组织,组织的某些部分有不同的做法。 但此处描述的做法通常为 Google 的大多数团队所遵循。

由于涉及到如此多不同的软件工程实践,以及谷歌成功的许多其他与我们的软件工程实践无关的原因,因此很难提供任何定量或客观的证据将个人实践与改进的结果联系起来。

然而,这些做法在谷歌经受住了时间的考验,并受到了成千上万优秀软件工程师的集体主观判断。

参考

Software Engineering at Google中文版

[1] Build in the Cloud: Accessing Source Code, Nathan York, http://google-engtools.blogspot.com/2011/06/build-in-cloud-accessing-source-code.html

[2] Build in the Cloud: How the Build System works, Christian Kemper, http://google-engtools.blogspot.com/2011/08/build-in-cloud-how-build-system-works.htm

[3] Build in the Cloud: Distributing Build Steps, Nathan York http://google-engtools.blogspot.com/2011/09/build-in-cloud-distributing-build-steps.html

[4] Build in the Cloud: Distributing Build Outputs, Milos Besta, Yevgeniy Miretskiy and Jeff Cox http://google-engtools.blogspot.com/2011/10/build-in-cloud-distributing-build.html

[5] Testing at the speed and scale of Google, Pooja Gupta, Mark Ivey, and John Penix, Google engineering tools blog, June 2011. http://google-engtools.blogspot.com/2011/06/testing-at-speed-and-scale-of-google.html

[6] Building Software at Google Scale Tech Talk, Michael Barnathan, Greg Estren, Pepper Lebeck-Jone, Google tech talk.

http://www.youtube.com/watch?v=2qv3fcXW1mg

[7] Site Reliability Engineering, Betsy Beyer, Chris Jones, Jennifer Petoff, Niall Richard Murphy, O’Reilly Media, April 2016, ISBN 978-1-4919-2909-4.

https://landing.google.com/sre/book.html

[8] How Google Works, Eric Schmidt, Jonathan Rosenberg.

http://www.howgoogleworks.net

[9] What would Google Do?: Reverse-Engineering the Fastest Growing Company in the History of the World, Jeff Jarvis, Harper Business, 2011. https://books.google.co.uk/books/about/What_Would_Google_Do.html?id=GvkEcAAACAAJ&re dir_esc=y

[10] The Search: How Google and Its Rivals Rewrote the Rules of Business and Transformed Our Culture, John Battelle, 8 September 2005. https://books.google.co.uk/books/about/The_Search.html?id=4MY8PgAACAAJ&redir_esc=y [11] The Google Story, David A. Vise, Pan Books, 2008.

http://www.thegooglestory.com/

[12] Searching for Build Debt: Experiences Managing Technical Debt at Google, J. David Morgenthaler, Misha Gridnev, Raluca Sauciuc, and Sanjay Bhansali. http://static.googleusercontent.com/media/research.google.com/en//pubs/archive/37755.pdf [13] Development at the speed and scale of Google, A. Kumar, December 2010, presentation, QCon.

http: //www.infoq.com/presentations/Development-at-Google

[14] How Google Tests Software, J. A. Whittaker, J. Arbon, and J. Carollo, Addison-Wesley, 2012.

[15] Release Engineering Practices and Pitfalls, H. K. Wright and D. E. Perry, in Proceedings of the 34th International Conference on Software Engineering (ICSE ’12), IEEE, 2012, pp. 1281–1284.

http://www.hyrumwright.org/papers/icse2012.pdf

[16] Large-Scale Automated Refactoring Using ClangMR, H. K. Wright, D. Jasper, M. Klimek, C. Carruth, Z. Wan, in Proceedings of the 29th International Conference on Software Maintenance (ICSM ’13), IEEE, 2013, pp. 548–551.

[17] Why Google Stores Billions of Lines of Code in a Single Repository, Rachel Potvin, presentation.

https://www.youtube.com/watch?v=W71BTkUbdqE

[18] The Motivation for a Monolithic Codebase, Rachel Potvin, Josh Levenberg, Communications of the ACM, July 2016. http://cacm.acm.org/magazines/2016/7/204032-why-google-stores-billions-of-lines-of-code-in-a- single-repository/fulltext

[19] Scaling Mercurial at Facebook, Durham Goode, Siddharth P. Agarwa, Facebook blog post, January 7th, 2014. https://code.facebook.com/posts/218678814984400/scaling-mercurial-at-facebook/

[20] Why We (Still) Believe In Private Offices, David Fullerton, Stack Overflow blog post, January 16th, 2015. https://blog.stackoverflow.com/2015/01/why-we-still-believe-in-private-offices/

[21] Continuous Integration at Google Scale, John Micco, presentation, EclipseCon, 2013. http://eclipsecon.org/2013/sites/eclipsecon.org.2013/files/2013-03-24%20Continuous%20Integr ation%20at%20Google%20Scale.pdf

[22] Bazel web site. https://bazel.build/

[23] Unlock your team’s creativity: running great hackathons, Max Saltonstall, Google blog post, Aug 28, 2018. https://www.blog.google/inside-google/working-google/unlock-your-teams-creativity-running-gre at-hackathons/

CATALOG
  1. 1. 谷歌的软件工程
    1. 1.0.1. 目录
    2. 1.0.2. 1 简介
    3. 1.0.3. 2 软件开发
      1. 1.0.3.1. 2.1 源代码库
      2. 1.0.3.2. 2.2 系统构建
      3. 1.0.3.3. 2.3 代码 review
      4. 1.0.3.4. 2.4 测试
      5. 1.0.3.5. 2.5 Bug追踪
      6. 1.0.3.6. 2.6 编程语言
      7. 1.0.3.7. 2.7 调试和分析工具
      8. 1.0.3.8. 2.8 发布工程
      9. 1.0.3.9. 2.9 启动批准
      10. 1.0.3.10. 2.10 事故报告
      11. 1.0.3.11. 2.11 软件反复重写
    4. 1.0.4. 3 项目管理
      1. 1.0.4.1. 3.1 20%的时间自由分配
      2. 1.0.4.2. 3.2 OKRs
      3. 1.0.4.3. 3.3 项目审批
      4. 1.0.4.4. 3.4 项目重组
      5. 1.0.4.5. 3.5 年度黑客马拉松
    5. 1.0.5. 4.人员管理
      1. 1.0.5.1. 4.1 角色分工
      2. 1.0.5.2. 4.2 办公设施
      3. 1.0.5.3. 4.3 培训
      4. 1.0.5.4. 4.4 部门转移
      5. 1.0.5.5. 4.5 绩效考核与奖励
    6. 1.0.6. 5 总结
    7. 1.0.7. 参考