Google的软件工程概述

1. 介绍

Google已经是一个非常成功的公司。正如在搜索和竞价广告方面的成功一样,Google也提供了许多其他突出产品,包括Google地图,Google新闻,Google翻译,Google语音识别,Chrome和Android。Google还通过购买小公司大大增强和扩展了许多产品,例如YouTube,并对多种多样的开源项目做出了重大贡献。Google也展示了一些尚未投入市场的惊人产品,如自动驾驶汽车。

Google的成功有很多原因,包括开明的领导力,技术牛人,高标准招聘,以及成功带来的经济实力,可以在非常迅速增长的市场早期进行介入。但其中一个原因是谷歌开发出的优秀软件工程实践,这帮助谷歌走向成功。这些实践基于全球最有才华的软件工程师的大量积累和提取的智慧,随着时间的推移而不断演化。我们想跟全球各地的人们分享我们的知识与实践以及我们从中学到的一些教训。

本文的目的是记载并简要介绍Google的关键软件工程实践。其他组织和个人可以进行比较和对比,并考虑是否应用一些做法。

许多作者(例如[9],[10],[11])都有书籍或文章来分析Google的成功历史。但大多数主要涉及商业,管理和文化;只有一小部分(例如[1,2,3,4,5,6,7,13,14,16,21])谈到了软件工程方面的内容,大多数只探讨一个方面;并且没有从整体上提供一个简短的、书面的关于谷歌软件工程实践的概述,本文目的正在于此。

2. 软件开发

2.1 源码存储库

大多数Google代码存储在一个统一的源代码存储库中,Google的所有软件工程师都可以访问。有一些值得注意的例外,特别是两个大型开源项目Chrome和Android,分别使用了独立的开源代码存储库,以及一些高价值或关键的安全代码有更严格的访问限制。但大多数Google项目共享相同的存储库。自2015年1月起,这个86 TB的存储库包含了10亿个文件,包括超过900万个源代码文件,20亿行源代码,具有3500万个版本修改的历史记录和每工作日提交的4万个版本修改的变更率[18]。存储库的写访问是受控的:只有存储库的每个子分支列出的所有者才可以批准修改该分支。但一般来说任何工程师都可以访问任一代码段,可以签出并构建,可以进行本地修改,可以测试它们,并可以发送变更以供代码所有者审核,如果所有者同意,可以签入(提交)这些变更。在文化上,鼓励工程师修复他们看到的任何有问题的知道如何修复的软件,无论项目边界如何。这鼓励了工程师并带来了更高质量的基础设施,更好地满足了使用它的人的需求。

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

频繁运行测试的自动化系统,通常在每次更改任何文件,进行传递性依赖测试之后进行,虽然这并不总是可行的。这些系统自动通知作者和审阅者测试失败的任何变更,通常都在几分钟之内完成。大多数团队通过安装使构建的当前状态突出显示,甚至用颜色编码来表示(绿色为建立成功和所有测试通过,红色表示有一些测试未通过,黑色表示失败的构建)。这有助于工程师集中精力注意保证构建通过。大多数更大的团队也有一个“构建巡警”负责确保测试的持续通过,通过与作者合作,不期望的变更能快速修复或回滚。(构建巡警角色通常在团队或其经验丰富的成员之间轮流承担。)这种专注于保持构建通过的做法使开发在头部进行具有实用性,即使是规模非常大的团队。

代码所有权。存储库的每个分支都可以有一个列出分支“所有者”用户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已经建立了完善的基于网络的代码审查工具,<

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值