【干货】谷歌软件工程技术实践总结:软件开发、管理和人员调配(20PDF)

【新智元导读】作者 Fergus Henderson已在Google工作了10年以上,拥有超过15年的商业类软件的行业经验。本文梳理并介绍了Google 软件开发中的关键步骤,并从工程设计的思路上阐述了这样做带来了什么好处。之前尚且没有一篇文章提供了Google整体软件开发实践的简要概述。

本文梳理并介绍了Google软件开发中的关键步骤。

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

以下是新智元对整份报告的重点翻译。

目录

摘要

关于作者

1.概述

2.软件开发

2.1.源码库

2.2.编译系统

2.3.代码审查 2.4.测试

2.5.Bug追踪

2.6.编程语言

2.7.调试和分析工具

2.8.工程发布(Release Engineering)

2.9.验收

2.10.复盘

2.11.频繁修改

3.项目管理

3.1.20%时间

3.2.目标和关键结果

3.3.项目验收

3.4.团队重组

4.人员管理

4.1.角色

4.2.设施

4.3.培训

4.4.人员变动

4.5.表现评估与奖赏

5.结论

致谢

参考书目

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月,这个86TB的存储库包含了10亿个文件,包括超过900万个源代码文件(总共包含20亿行源代码),具有3500万提交的历史和每工作日4万提交的变化率[18]。对存储库的写访问是被控制的:只有存储库的每个子树的listed owner可以批准对该子树的更改。但一般来说,任何工程师都可以访问任何代码段,可以检查,构建,可以进行本地修改,可以测试,并可以发送更改供代码的owner审核。如果所有者批准,就可以写入那些变化。在企业文化上,我们鼓励工程师修复他们看到的任何东西,并且去获知如何修复,而无所谓项目的界限。这强化了工程师的能力,并导向了更高质量的基础设施,以更好地满足使用它的人的需求。

几乎所有的软件开发都发生在存储库的“头”,而不是在分支上。这有助于及早识别集成问题,并最大限度地减少所需的合并工作量,同时也便于更快推出安全修复程序。

尽管不是每次都可行,一旦带有传递依赖性的文件发生变化,系统会频繁地自动运行测试。一般在几分钟内,这些系统会自动通知作者和审阅者测试失败的任何更改。大多数团队通过显示标记甚至含有特定含义的光来表明他们的工程状态(绿色表示构建成功,所有测试通过;红色说明一些测试是失败的;黑色则表明整体构建已经坍塌)这有助于将工程师的注意力集中在保持绿色状态。大多数更大的团队还有一个“构建警察”,通过与更改的作者合作,快速解决任何问题或消除令人不安的更改,从而确保测试持续通过 (这一警察角色通常由全部团队成员或是经验丰富的成员轮流担任)。即使对于非常大的团队,这种对于变化的关注也有助于保持整个构建的绿色状态,使整个开发始终保持可行性。

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

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

2.3 代码审核(Code Review)

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

对主源代码存储库的所有更改必须至少由另一位工程师审核。 此外,如果更改人不是正在修改的文件的所有者,则至少有一个所有者必须审核并批准该更改。

2.4 测试(Testing)

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

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

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

Google还提供用于衡量测试覆盖率的自动化工具。结果也被集成为源代码浏览中。

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

2.5. Bug 追踪(Bug tracking)

Google使用一个叫 Buganizer 的错误跟踪系统来跟踪各种问题:错误、功能需求、客户问题和流程(如发布或清理工作)。错误被分为层次化组件,每个组件有一个默认的负责人和默认电子邮件列表以便CC。当发送源更改以供审查时,系统会提示工程师将用问题的关联编号提示工程师。

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

2.6.编程语言(Programming languages)

强烈鼓励 Google 的软件工程师使用以下四种官方认可的编程语言之一进行编程:C++,Java,Python 或 Go。尽可能少地使用的不同编程,这能减少了代码重用和程序员协作的障碍。

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

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

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

过程的通用性是使开发变得容易的关键因素,即使具有巨大的代码库和多样化的语言:有一组命令来执行所有常见的软件工程任务(例如check out, edit, build, test, review, commit, file bug report 等),并且无论什么项目或语言都可以用相同的命令。开发人员不需要因为他们用的代码是不同项目的一部分或用不同的语言编写的,而学习新的开发过程。

2.7.调试和分析工具 (Debugging and Profiling tools)

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

2.8. 发布工程(Release engineering)

有几个小组有专门的发布工程师,但对于 Google 的大多数小组,发布工程工作都是由通常的软件工程师完成的。

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

最后,该发布可以推广到所有数据中心中的所有服务器。对于非常高流量,高可靠性的服务,会在几天的时间内逐步推出,以帮助减少因为新引入的错误没有被发现而带来的影响。

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

2.9. 批准发布(Launch approval)

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

2.10. 事故分析(Post-mortems)

当任何生产系统发生严重停机或类似事故时,所涉及的人员都必须写一份事后分析文档。本文档描述事故,包括标题、摘要、影响、时间表、根本原因、什么工作/什么没有和行动项目。文档的重点是问题本身,以及如何在未来避免他们,而不是针对人或分摊责任。 有关Google事故分析文化的更多信息,请参阅SRE手册[7]的第15章。

2.11. 频繁重写(Frequent rewrites)

大多数Google的软件每隔几年就要重写。

这看起来非常昂贵。确实,它消耗了Google资源的很大一部分。然而,它也带来了一些重要的好处,这是谷歌的敏捷性和长期成功的关键。在几年的时间里,随着软件环境和周围的其他技术发生变化,以及随着技术或市场的变化影响用户需求、愿望和期望,产品的需求通常会发生显著变化。

几年前的软件是围绕一套老的需求设计的,通常不是以当前需求的最佳方式设计的。此外,它通常积累了很多复杂性。重写代码消除了所有不必要的累积复杂性,这些复杂性只是解决了不再那么重要的需求。另外,重写代码可以向新的团队成员传递知识和所有权感。这种所有权感对生产力至关重要:工程师自然会更努力地开发特性,并在“他们的”的代码中解决问题。频繁的重写也鼓励工程师在不同项目之间的移动,有助于鼓励想法的杂交。频繁的重写也有助于确保代码使用现代技术和方法编写。

3.项目管理

3.1. 20% 的时间

工程师被允许花高达20%的时间在他们选择的任何项目上工作,而无需他们的老板或任何其他人的批准。

3.2. 目标和关键结果 (Objectives and Key Results -OKRs)

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

3.3. 项目批准(Project approval)

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

3.4. 公司重组(Corporate reorganizations)

少数情况下,执行者决定取消一个大型项目,然后该项目的工程师可能需要在新的团队上找到新的项目。

4.人员管理

5.结论

我们简要介绍了大部分在Google使用的重要软件工程实践。当然,Google现在是一个庞大而多样化的组织,它 的某些部分有不同的做法。但是这里描述的做法通常被大多数团队遵循。

由于涉及这么多不同的软件工程实践,以及Google成功的许多其他方面的原因,因此很难给出任何定量或客观的证据,将个人做法与结果改进联系起来。然而,这些做法是经受了谷歌时间考验的,成千上万的优秀软件工程师的集体遵守它。

对于那些在其它组织被倡导的实践,正好在本文中也被描述了,或许可以辅助说明“这对Google来说足够好了”。

原文发布于微信公众号 - 新智元(AI_era)

原文发表时间:2017-02-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏EAWorld

普元DevOps5.2版本新特性发布

伴随新版本的发布,我们团队也对这次迭代做了些回顾,有值得分享的新特性与设计,也有一些需加强的能力,借此与大家分享。

2874
来自专栏熊二哥

《大型网站技术架构》学习笔记-01概述

李智慧老师的大型网站架构已经买了两年了,之前大体看过一次,不过还未内化为自己的本领,最近项目空闲,决定尽力掌握这部分的知识,以跟上大师的节奏。今天是儿童节,祝自...

2775
来自专栏领域驱动设计DDD实战进阶

DDD实战进阶第一波(二):开发一般业务的大健康行业直销系统(搭建支持DDD的轻量级框架一)

本系列文章 DDD实战进阶第一波(一):开发一般业务的大健康行业直销系统(概述) DDD实战进阶第一波(二):开发一般业务的大健康行业直销系统(搭建支持DDD的...

3985
来自专栏Java学习网

程序员需谨记的8条团队开发原则

  当你从学校出来,找到第一份软件开发工作的时候,你就不再是一个单独作战的程序员了,你将会有一个团队,你的一举一动也将直接影响团队的效率和产出。下面这8条团队开...

3305
来自专栏SEO

什么样的网站更值得百度去收录?

2688
来自专栏大数据文摘

超贴心 :一份简单明了的营销分析软件包测评

2105
来自专栏云计算D1net

云原生机制的三个核心思想及其未来之路

摆脱临时性自动化方案之定位,发挥优势以实现可预测功能。 ? 您能否以每周为单位向客户发布各类新功能?甚至进一步达到以每天乃至每小时为单位?新晋开发人员能否在上班...

2634
来自专栏腾讯移动品质中心TMQ的专栏

腾讯TMQ沙龙|移动互联网APP应用的服务端测试方案和实践

移动互联网APP应用的服务端测试方案和实践 活动时间:2016年9月8日 QQ群视频交流 活动介绍:TMQ在线沙龙第八期分享 本次分享的主题是介绍移动互联网AP...

2195
来自专栏腾讯大讲堂的专栏

王者荣耀、NBA突发支撑

2837
来自专栏携程技术中心

干货 | 携程运维工作流平台的演进之路

作者简介 徐豪杰,携程旅行网技术保障中心流程工具团队资深软件工程师,于2013年加入携程,主要负责携程工作流平台架构设计与建设,在流程建设方面有着比较丰富的积累...

6099

扫码关注云+社区

领取腾讯云代金券