译者注
原文参见 https://arxiv.org/pdf/1702.01...,本译文参考作者@东方之既白(gh_cab525c87299)的工作,并加以校对修改而成,⚠️作为小组交流学习使用⚠️。
摘要(Abstract)
本文中,我们整理并描述了Google的核心软件工程实践经验。
作者简介(Biography)
Fergus Henderson已在Google从事十余年的软件工程开发工作。在1979年,还在孩童时期的他就开始学习程序设计,后来在学校研究计算机程序语言的设计和实现。他和他的博士生导师在墨尔本大学共同创建了一个研究小组,该小组开发了程序设计语言Mercury。他是八个国际程序委员会的委员,目前已经开放了超过50万行的开源代码。他曾是Usenet newsgroup comp.std.c++的早期版主,也是ISO C和C++的标准委员会的公认专家。他拥有超过15年的商用软件行业经验。在Google,他是Blaze的早期开发者之一。目前,Blaze作为构建工具目前已经在Google广泛使用。他曾从事语音识别、voice action(比Siri还早的语音助手)和语音合成等产品的服务端软件开发。目前,他负责管理Google的语音合成工程团队,但他依然奋斗在一线,开发和审阅大量代码。他写的代码已经安装在数十亿计的设备上,每天使用超过数十亿次。
1 综述(Introduction)
Google已经成为了一家非常成功的公司。除了Google搜索和AdWords之外,Google还发布了一系列卓越的产品,如Google地图、Google新闻、Google翻译、Google语音识别、Chrome浏览器和Android。Google还极大地增强并拓展了通过收购兼并的小公司的产品(例如Youtube),并且为一系列开源软件和项目做出了突出的贡献。Google还有一些尚在研发还未发布的非常酷炫的产品,如自动驾驶。
Google的成功有很多原因,包括开明的领导、杰出的人才、高标准的招聘门槛和其在非常快速增长市场中通过领先地位积累的财务实力。但其中还有一个原因是Google积累了卓越的软件工程实践经验,这同样助力了Google的巨大成功。这些实践由全世界最杰出最才华横溢的工程师积累、提炼,并随着时间不断演进完善。现在我们想向大家分享我们软件工程实践经验,也分享一路走来从错误中汲取的教训。
本篇文章的目的是整理和简要描述Google的核心软件工程实践经验。这样,其他的组织或者个人可以比较、对比他们自己的软件工程实践经验,并考虑是否应用其中一些工程实践经验到他们开发中。
许多作者( [9], [10], [11])都写书或者文章分析Google的成功和历史,但其中大多数都在围绕着商业、管理和文化进行分析,仅有一小部分作者([1, 2, 3, 4, 5, 6, 7, 13, 14, 16, 21])研究软件工程对Google成功的贡献,在这一小部分之中,很多又仅在单个层面上分析。目前还没有关于Google软件工程实践的既全面又概要的性的综述,这就是本文的目的。
2 软件开发(Software development)
2.1 代码仓库
在Google,绝大多数的代码都统一存储在一个代码仓库中,Google所有的工程师都可以访问该仓库。(用户数据是严格加密的,只有源码可见)其中有个别例外,典型的如两个大型的开源工程Chrome和Android,这两个项目使用单独的开源的代码仓库,并且对于其中高价值和高安全级别的代码,设定了严格的读取权限。尽管如此,Google的大部分工程还是共享一个代码仓库。截至2015年一月,该代码仓库总共86TB,包含10亿个文件,其中900万个为源代码文件,包含20亿行源代码,共计3500万次代码提交,平均每个工作日产生4万个提交[18]。该代码仓库的写权限是受控的,仅该子树的所有者才可以批准在该子树的代码上修改。但一般来讲,在Google的任何工程师可以都可以访问、下载、编译该代码仓库中的任何一段代码,并可以做本地的修改、测试,并发送相关的修改到代码所有者,如果代码所有者同意修改,则该修改就可以准入合并。从公司文化角度讲,公司鼓励工程师解决那些他们知道如何解决的代码仓库中的任何有问题的代码,而不要在意项目之间的边界,这鼓励了工程师在使用中修改相关代码以服务他们的需求,从而成就了更高质量的基础代码。
所有的开发代码修改都发生在代码仓库的头部(HEAD),而不是分支。这有助于在早期发现代码的集成问题,并减少代码合并的工作量。同时,这让安全补丁的提交也更容易、更快。
自动化测试系统会频繁地运行测试,一般发生在该测试依赖的代码有所改动时,但是这种方式不一定适用于所有情况。这些测试系统一般会在几分钟内自动通知代码修改者和代码审阅者,代码的改动没有通过哪些测试。大多数团队会将当前的构建进度明显的标记出来,或使用显示器,或使用不同的颜色标记(绿色表示构建成功并且所有的测试都通过了,红色表示有的测试失败了,黑色表示构建过程出了问题),这样可以帮助工程师集中注意力使所有的构建变绿(通过)。大多数大团队还有”构建警察“,负责与代码作者协作解决问题或回滚有问题的修改,从而确保所有的测试继续通过(构建警察通常是由小组成员或者小组中的资深成员轮流担当)。关注构建过程的持续顺利通过,使得仅在代码仓库头部开发成为可能,即使在非常大的团队开发中也同样奏效。
代码所有权。代码仓库中的每个子树中均有一个文件记录该子树所有者的用户ID。子文件夹从父目录中继承所有权设置,但是也可以按需修改。如上文所述,子树的所有者控制该子树的写权限,每个子树至少需要两个所有者,但是实际中一般子树会拥有更多的所有者,尤其是地理上比较分散的团队。一种常见的做法是在所有者记录文件中,包含团队的所有成员。除了代码所有者,Google所有的人都可以在子树上进行修改,但是需要得到所有者的同意,这确保了每个修改都会由负责该子树代码并理解该代码的所有者进行审阅。
如需了解更多的关于Google代码仓库的知识,请参考[17, 18, 21], 如需了解其他大公司如何解决该问题,请参考[19]。
2.2 构建系统
Google使用分布式的构建系统Blaze(对外开源版本名为Bazel),Blaze负责编译、链接和测试。Blaze在整个代码仓库上提供了标准的构建和测试命令,标准化的命令和高效的实现意味着对于Google的任意一个工程师,构建和测试代码仓库中的任何软件都是非常容易且快速的。这种一致性是工程师们能够进行跨项目的代码修改的关键性因素。
在Blaze中,工程师通过写”Build”文件告诉Blaze如何去构建他们的软件。构建的实体例如链接库、程序、测试都通过高层次的声明性的构建规范进行声明,指定每一个实体、其名字、源代码文件、链接库和其需要依赖的其他实体。构建的规范由一系列”build rule”组成,每一条都描述了高层次的概念,例如“这里有一个C++库,它依赖哪些源代码文件,依赖哪些其他的库”。构建系统会将每个”build rule”映射为一系列的构建动作,例如编译源代码的动作、链接的动作、决定使用哪个编译器和编译时的参数。
在一些情况下,典型的如Go语言,”Build”文件可以自动生成和更新,因为可以从Go语言源代码的依赖信息抽象出其Build文件的依赖信息。虽然如此,自动生成的这些Build文件仍然会提交到代码仓库。这确保了构建系统可以迅速的由Build文件而非源代码确定依赖关系,对于Blaze支持的众多不同编程语言来说,也避免了构建系统和编译器或分析工具之间的过度耦合。
该构建系统通过Google分布式计算的基础设施得以实现。一般来说,每一个构建工作都分布在数百台甚至上千台机器上完成。这使得快速构建极其庞大的程序或并行运行成千上万的测试成为可能。
单一的构建动作必须是“封闭”的,即它仅依赖Build文件中声明的输入。分布式构建要求所有依赖必须正确声明,因为只有声明了的输入才会被发送到相应的执行构建动作的机器上。这样,才可以依赖构建系统得出正确的依赖关系。在该构建系统中,构建相关的编译器也被当作输入。
单一的构建动作必须是确定的。这样,构建系统才可以缓存构建的结果。软件工程师可以同步他们的工作区到一个旧的修改编号,并可以重新构建得到相同的二进制文件。此外,不同的用户之间还可以安全的共享缓存(为了确保以上操作生效,我们必须消除由编译工具引起的不确定性,例如去掉输出文件中的时间戳信息)。
构建系统必须是可信的。构建系统跟踪构建规则变化时的依赖,并且在构建目标项目的动作变化时进行重新构建,即使输入并没有变化(例如只有编译选项变化时)。构建系统也需要正确处理构建中断时和在构建中修改源代码的情况,在这些情况下,你只需要重新运行build命令即可,而并不需要去执行类似”make clean”的命令。
构建结果在云端缓存,包括中间结果。如果一个构建需求需要相同的结果,构建系统将自动重用相同的结果而非重新构建,即使构建的需求是来自不同的工程师。
增量式的编译非常迅速。构建系统会驻在内存,所以它可以增量式地仅分析相比上次构建发生修改的文件。
提交前检查。当向代码仓库提交一个代码修改或者一个代码审阅时,Google有一系列的自动化工具做检查。代码仓库中的每一个子树都有一个配置文件,其中决定了做哪个测试,在代码审阅还是代码提交时作测试(或者都做)。这些测试可以是同步的,即在向代码仓库发送修改审阅请求或者提交修改之前(优点是快速测试);也可以是异步的,测试的结果会通过邮件在代码审阅会话的讨论中通知)[代码审阅会话是和代码审阅相关的邮件会话,在该会话中的所有信息都可以通过一个基于web的代码审阅工具展示]。
2.3 代码审阅
Google开发了基于web的强大的审阅工具,并与邮件集成。其允许代码作者发起审阅请求,允许审阅者通过边到边的对比视图查看修改(用不同的颜色标记),同时还可以评论。当修改代码的作者发起一个审阅请求时,审阅者会收到邮件通知,该邮件中有该修改在web审阅工具中的链接。当审阅者提交他们的评论时,也会有邮件通知。除此之外,自动化的工具也会发送邮件通知,如自动化测试的结果、静态分析工具的结果等。
所有代码仓库中的修改【至少】要有一个非修改者的工程师审阅。除此之外,如果修改者不是相关文件子树的所有者,那么至少要有一个所有者审阅和批准修改。
在特殊情况下,子树的所有者可以在代码审阅完成之前,提交非常紧急的修改,但仍需提名一个审阅者,不然代码修改者就会持续收到自动通知,直至相应的修改被审阅和批准。在该情况下,由于审阅者评论引发的代码修改都必须在另一个单独的修改中,因为原始的改动已经合并了。
对于修改,Google的工具会自动推荐代码审阅者。该功能基于查找待修改代码的所有者和原始作者,以及历史上最近的审阅者,也会考虑潜在的代码审阅者目前还未完成审阅的代码数量。对于代码修改影响到的每个代码子树,至少要有一个所有者审阅和批准修改。除此之外,代码修改者可以任意指定他们认为合适的代码审阅者。
代码审阅一个潜在的问题是审阅者响应太慢,或者审阅者太过冗余,这可能会减缓开发速度。事实上,代码修改者可以通过选择审阅者避免该问题,如尽量不要选择对自己代码控制欲过强的审阅者,对于简单的改动选择较少的审阅者,对于复杂改动选择更多更资深的审阅者。
每个项目的代码审阅评论会自动复制到项目维护者指定的邮件列表。所有人都可以自由在任意修改上评论,而不用在意自己有没有被提名为审阅者,且在修改提交前后均可以评论。如果发现了bug,通常操作是追踪导致该bug的修改,并在该修改上进行评论,指出该修改的错误,这样代码修改者和审阅者都会了解到该bug。
也可以把代码审查发给几个审阅者,然后在其中一个审阅者批准后,提交修改(当然,前提是修改者或第一个响应的审阅者是代码所有人),这会在其他审阅者发表评论之前提交修改,任何后续的审查意见都将在后续修改中处理。这样可以减少代码审阅的交互时间。
代码仓库中除了主体分支之外还有实验分支,实验分支不强制进行正常的代码审阅。但是,产品线上的代码必须是代码仓库中主体分支的代码,并且我们强烈鼓励工程师在主体分支上进行开发,而非先在实验分支上开发随后移动到主体分支,因为在开发中进行代码审阅比在开发完成后进行要更为高效。实际中,即使在实验分支工程师依然频繁使用代码审阅。
鼓励工程师使用尽可能小的修改,鼓励将大的修改拆分为一系列小的修改,这样审阅者可以容易地完成一次审阅。小修改也使修改者在回应审阅者的建议时更加容易,巨大的改动通常更难接受审阅者的修改建议。鼓励小修改的一种方式是,代码审阅工具会根据提交修改量分类标记该提交,30-99行的增/删/移除会被标记为”medium-size”(中型修改),超过300行以上会被打上不太友好的标记,例如”large”(大型修改,300-999),“freakin huge” (太**大的修改,1000-1999)等。(而且,在更为Google的方式中,为了保持趣味性,每年隔上一些天就会为这些标签换一个更有趣的描述,如talk-like-a-pirate day(国际海盗语言日) :)。
2.4 测试
Google强烈推荐并广泛使用单元测试。所有生产上的代码都需要有单元测试,代码审阅工具会突出显示没有相应测试的源代码文件。代码审阅者会要求工程师为修改中新增的功能添加相应的覆盖新功能的测试。Mocking framework(该框架允许构建轻量级的单元测试,即使针对有复杂依赖库的代码)非常流行。
Google也广泛使用集成测试和回归测试。
如上文所提到的预提交检查,强制执行自动化测试是进行代码提交和审阅的一部分。
Google也开发了自动化评估测试覆盖度的工具,该工具的分析结果可以作为源代码浏览时的可选的一层。
负载测试先于上线是Google的一条规范准则。团队应该制作图表展示关键性指标,特别是延迟和错误率随着请求数量的变化情况。
2.5 Bug跟踪
Google使用bug跟踪系统Buganizer跟踪issue,包括bug,新增feature的请求,用户问题和过程(如发布或清理工作)。Bugs会被分类成分层的组件,每个组件都会有默认的委托人和默认邮件CC列表。当发送一个源代码的审阅请求时,工程师可以立即关联到相应代码修改的问题编号。
通常Google的团队会定期查看在他们组件中处于”open”状态的问题,设定问题的优先级,并将问题分配给恰当的工程师。一些团队有特定测试人员负责bug定级,另一些在他们的日常会议中为bug定级。在Google,许多团队都在bug上打标签,标明已定级的bug、在未来哪次发布修复哪些bug。
2.6 程序设计语言
Google强烈鼓励工程师使用官方批准的5种程序设计语言C++、Java、Python、 Go或JavaScript之一进行编程。减少编程语言的种类可以减少代码复用和代码合作上的障碍。
对于每种程序设计语言,Google都有其编码风格规范,鼓励公司所有的代码都有相近的风格、布局、命名规范等。此外,Google还有全公司范围的代码可读性培训,关心代码可读性的资深工程师会培训其他工程师如何去写可读性高、符合阅读习惯的代码。通过审阅修改者的大量修改或一系列修改,直至审阅者满意、修改者知道如何去写高可读性的代码。对于使用某个语言新增的重大代码,都必须经过一个通过该语言的代码可读性培训的工程师的批准。
除了以上5种语言,也会使用有特殊的领域特定语言(domain-specific languages,DSL)。例如,用于指定构建目标和构建依赖的构建专用语言。
不同语言之间的互操作主要使用Protocol Buffers。Protocol Buffers是一种可扩展的、编码结构化数据的方式。它包括一个定义数据结构的DSL和一个编译器。编译器输入定义好的数据结构描述,自动生成该数据结构对应C++, Java, Python代码,代码中提供构造、访问、序列化、反序列化这些对象的功能。Google的Protocol Buffers和Google的RPC库深度集成产生了一个简单的跨语言的RPC(gRPC),请求和响应的序列化和反序列化操作都由该RPC框架自动处理。
过程的通用性是使开发容易的关键性因素,即使在由庞大的代码库和多种程序语言的情况也是如此。在Google仅有一个简单的命令集执行日常软件开发的所有任务(如更新、编辑、构建、测试、审阅、提交、bug报告等),该命令集也适用任何项目和语言。开发者无需因为他们刚好要修改的代码是另一种语言或者代码而学习新的开发流程。
2.7 调试和分析工具
Google服务链接到提供一系列调试运行时服务的工具库。在服务崩溃的情况下,一个信号处理器会自动把栈调用写到日志文件,并且会存储core文件。如果崩溃是由于堆内存耗尽造成的,服务器将采样实时堆对象,转储该采样子集的 allocation site的堆栈跟踪。并且还有调试的web接口,其允许检查进入和外出的RPCs(包括时间、错误率、速度限制等)、修改命令行参数(如增加特定模块的日志级别)、资源消耗、分析等。这些工具极大地降低了整体调试的难度,甚至很少需要去启动一个传统调试工具,如GDB。
2.8 发布工程
一些团队拥有全职投入的发布工程师,但在Google的大多数团队,发布工作由普通的软件工程师完成。
对大多软件来说,会频繁进行发布。一周一次或者两周一次的发布是很常见的目标,有的团队甚至每天都有发布。将绝大多数普通的发布任务自动化使频繁的发布成为可能。频繁的发布有助于保持程序员的积极性(不然,在以月计甚至以年计的发布周期中很难保持兴奋),并提升整体迭代的速度,在给定的时间内也就增加反馈和响应反馈的机会。
通常,一个发布始于一个全新的工作区,通过同步最新的“绿色”构建的修改ID(最新的通过所有自动化测试的修改),并且制作一个发布分支。发布工程师可以选择其他的改动进行”cherry-picked”操作,例如从主分支合并到发布分支。随后,软件会从头开始构建和测试。如果有失败的测试,需要相应的修改去修复这些失败的测试,这些修改也要”cherry-picked”到发布分支。之后,会重新进行构建和测试。当所有的测试都通过后,构建的可执行程序和数据会被打包。所有的这些过程全部都是自动化的,发布工程师只需要运行几个简单的命令,甚至仅需要在菜单驱动的界面上选择选项和必要的cherry pick的改动即可。
代码打包完成后,通常会先加载到”staging”(临时)服务器进行进一步小规模用户(有时仅是部署团队)集成测试。
一个有用的方式是除了向”staging”服务器发送生产流量的副本(或者一部分)请求,还会将其发送到当前生产服务器进行实际处理。来自staging服务的响应将会被丢弃掉,而来自目前生产服务器的响应会返回给用户。这有助于确保在投入生产之前发现严重问题(如服务崩溃)。
下一步通常是部署一个或者多个”canary“(金丝雀)服务器,该服务会处理生产上的一部分流量。和”staging“服务不同,这里既会处理也会响应真实用户。
译者注:
金丝雀发布一般先发 1 台,或者一个小比例,例如 2% 的服务器,主要做流量验证用,也称为金丝雀 (Canary) 测试(国内常称灰度测试)。以前旷工开矿下矿洞前,先会放一只金丝雀进去探是否有有毒气体,看金丝雀能否活下来,金丝雀发布由此得名。
简单的金丝雀测试一般通过手工测试验证,复杂的金丝雀测试需要比较完善的监控基础设施配合,通过监控指标反馈,观察金丝雀的健康状况,作为后续发布或回退的依据。
如果金丝测试通过,则把剩余的 V1 版本全部升级为 V2 版本。如果金丝雀测试失败,则直接回退金丝雀,发布失败。
优势和适用场合
优势:
用户体验影响小,金丝雀发布过程出现问题只影响少量用户
不足:
发布自动化程度不够,发布期间可引发服务中断
适用场合:
对新版本功能或性能缺乏足够信心
用户体验要求较高的网站业务场景
缺乏足够的自动化发布工具研发能力
最后,该发布会在所有数据中心全部部署。对于高请求量、高可靠性的服务,会在几天时间内逐渐部署,这有助于减少由于之前步骤没有发现的bug而引起的故障的影响。
想要了解更多的关于Google发布工程的信息,请参考SRE[7]的第8章,也可以参考[15].
2.9 发行许可
对于任何用户可见的修改或者巨大的设计修改的发行,需要得到该修改的核心开发团队之外的很多人的批准。特别是需要获得批准(需要更为详细的审阅)去保证编译代码符合法律要求、隐私要求、安全要求、可靠性要求(如有合适的自动监测机制,检测服务故障,并自动通知合适的开发者)、商业要求等。
发行过程也需要确保当有重大产品或者特性发行时,会通知公司内相关的人。
Google内部都有发行时的许可工具,它可以跟踪各个产品必要的审阅和许可,以确保该产品的发行和规定的发行过程一致。这个工具很容易定制,因此不同的产品或者产品线都可以根据需要定制不同的审阅和许可。
想要了解更多的关于发行过程的信息,请参考SRE第27章。
2.10 事故分析
无论何时当产线系统发生严重故障,或者与之相近的错误时,相关的员工需要写一个事故分析文档。该文档中描述事故的标题、总结、影响、时间线、事故的根本原因、哪些解决方法有效哪些无效、行动项目。该文档聚焦在问题本身和以后如何避免相同问题,而不是人或者问责。影响部分要尽量量化事故的影响,包括故障持续时间、丢失的查询数量(或者失败的RPC等)和经济损失。时间线部分要给出导致故障的各个事件和分析、修复故障步骤的时间线。哪些解决方法有效哪些无效部分要描述汲取的教训——什么实践有助于快速发现和解决该问题,什么是错的,可以采取哪些具体的行动(最好是类似bug分配给特定人)在以后降低类似问题的概率或者严重程度。
想要了解更多的关于事故分析的信息,请参考SRE第15章[7]。
2.11 频繁重写
Google的大多数软件每隔几年就会重写。
表面上看起来这样代价非常高,实际上,它也确实消耗了Google的一大部分资源。但是,它同样有重大的意义,是Google保持敏捷和长期成功的关键性因素。在几年内,产品的需求通常会发生重大的改变,软件开发环境及其周围相关的技术也会改变,并且技术或者市场上的改变会影响用户需求、渴望和期望。几年以上的老软件是基于旧的需求集合开发的,通常不是根据当前需求的最优设计。而且,通常也积累了很多复杂性。重写代码避免了为了解决不再重要的需求引入的累积复杂性。除此之外,重写代码还是一种迁移学习知识的方式,也能让新的团队成员找到归属感。归属感对生产力非常重要:工程师天然的会在他们感觉是“自己的”代码上投入更多的精力开发和修复问题。频繁重写也鼓励了在不同项目间流动,这有助于鼓励思想的交叉碰撞。频繁重写也有助于确保代码是使用现代的技术和方法论开发的。
3 Project management(项目管理)
3.1 20%时间
Google允许员工花费20%的时间去做他们选择的任何项目,而无需经过他们主管或其他人的允许。这种对工程师的信任极其重要,有如下几点原因。第一,允许任何有好想法的人(即使他的想法在其他人当前看来并不是有价值的),可以有足够的时间去开发一个原型、示例或者演示去展示他们想法的价值。第二,提供了管理上的透明性,否则员工会隐藏这类活动,在其他没有正式政策允许20%时间的公司,员工有时会从事“地下“项目而不会让主管知道。如果工程师对这些项目持开放态度,这样会好很多,即使他们的主管并不认同该项目的价值,也可在日常更新时描述他们在这些项目上做的工作。在全公司范围内有正式的这样一个政策和文化,使得这成为可能。第三,允许工程师在更加有趣的工作上花费一小部分时间,可以使工程师保持主动和兴奋,避免他们变的疲惫不堪,特别是员工感觉被迫花费100%的时间在繁琐的工作任务上的疲惫。拥有高效生产力、热爱工作、充满动力的工程师和疲惫不堪的工程师之间的差距远远大于20%。第四,鼓励创新文化,看到其他工程师在20%时间做好玩的实验项目会激励每个人都这么做。
3.2 目标和关键结果(OKRs)
Google要求个人和团队都要明确文档化他们的目标和评估达成这些目标的进度。团队设定季度和年度目标,并给出可量化的关键结果以显示目标进度。这在全公司各个层面上展开,直至整个公司的目标。个人和小团队的目标要和他们所属大团队或整个公司的更高层次的目标一致。在每个季度末,会记录每个可量化关键结果的进度,每个目标都会给出一个0.0(零进度)到1.0(100%完成)的打分。OKR和OKR的打分通常是全公司可见的(特别敏感如高度机密的项目是少数例外),但是打分并不是用于员工的个人绩效评定。
OKR应该设定较高的目标,理想的目标设定是总体平均完成度在65%,也就是鼓励团队设定比他们可能完成工作量多大概50%的目标。如果一个团队的得分比0.65高很多,则鼓励他们在接下来的一个季度中设立更高的OKRs(相反的,如果得分比0.65低很多,则鼓励他们在下个季度设立相对保守的OKRs)。
KRs提供了一个关键的机制,用于沟通公司每个部门正在进行的工作,并通过社会激励来鼓励员工的良好表现...尽管OKR对绩效评估或报酬没有直接影响,工程师们知道他们的团队将在会议上对OKR进行评分,并有一种自然的动力去努力取得好成绩。定义有目标和可量化的关键结果有助于确保员工做真正对目标有可量化影响的工作。
3.3 项目批准
虽然Google有完善的发行批准过程,但是却没有一个完善的项目立项或取消的过程。尽管我已经在Google工作了十年,目前也成为了一名管理者,但是我仍然不完全理解这些项目决策是根据什么。部分原因是全公司也没有一个统一的规范。各个职级的管理者对他们团队要做的项目负责,并根据他们的判断进行他们认为合适的项目。在一些情况下,这意味着许多决定都是自底向上建立的,因为工程师被充分给予了在他们的团队内自由选择项目的自由。在另一些情况下,决定是自顶向下建立的,由管理层或者管理者决策进行哪些项目,给哪些额外的资源,哪些项目要被取消。
3.4 公司重组
有时当管理层决定要取消一个大的项目时,这时在该项目工作的许多工程师要在新的团队寻找新的项目。同样,有时要进行资源“整合”,即将分散多个地区的的项目整合在几个少数地区,这时为促成整合,其他地区的工程师也要改变团队和项目。在这种的情况下,公司通常会让工程师在他们地区可选范围内自由选择团队和角色,或者在“整合”的情况下,他们也可以选择更换办公地点从而继续留在原来的团队。
除此之外,其他形式的公司重组,例如合并或分解团队,改变汇报线等,在Google都很常见,尽管我不知道Google和其他的大公司相比算不算多。在一个技术驱动的大公司,一定程度上的频繁重组是必要的,可以避免因技术和需求改变时导致的组织低效。频繁重组可以帮助避免或减轻大型组织中常见的 “暴露组织结构图 "的问题,即软件架构反映了公司的汇报结构。
3.5 年度hack week
谷歌鼓励创新的另一种方式是举办 "黑客马拉松"[23]。许多谷歌办公室采取了每年为期一周的 "黑客马拉松 "的形式,软件工程师可以从他们的正常日程安排中抽出时间来研究新的创新项目。在启动会议上,工程师们可以提出想法,然后他们组成小团队,用一周的时间根据新的想法制作演示或原型,并在一周结束时向观众和评审团演示,评审团为最佳项目颁发(小额)奖品。不过,最大的奖励是认可——以及让成功的黑客马拉松项目成为全职的真实项目的机会。
尽管所有的工程师都得到了他们公司领导的许可参加这样的黑客马拉松,但许多工程师确实发现很难从他们的日常职责中分离出来,因此参与率通常相当低(例如5-20%),更多的人将参加最初的启动仪式或最后的演示,并可能从提出的想法中得到启发。
4 人员管理(People Management)
4.1 角色
我们将在下文讲到,Google区分了工程师和管理者的职业发展路径,将技术主管从管理者中区分开来,将研究工作并入工程,并通过产品经理、项目经理和网站可靠性工程师(site reliability engineers, SREs)支持工程师的工作。目前看来,至少其中的一些实践对于维持Google已经发展的创新文化至关重要。
Google工程师分为少数几个角色。在每个角色内,都有职业进一步发展的机会,其通过一系列的等级和晋升机会(有相应的报酬如薪金等的提高)以认可下一级别的表现。
主要的角色有:
- 工程师主管(Engineering Manager)
这是这个序列中唯一的管理者角色。其他的角色如软件工程师可能也管理人,但是Manager(工程师主管)一定扮演着管理人的角色。Manager通常在早期也是软件工程师,而且是全面的技术专家,有卓越的个人技能。
技术主管和管理者有一个主要区别。Manager并不一定要领导项目。项目通过Tech Lead(技术主管)领导,技术主管可以是Manager,但更常见的是软件工程师。项目的Tech Lead有该项目的技术决策的发言权。
Manager的责任是选择Tech Lead,并负责他们团队的绩效。他们指导和协助职业发展,进行绩效评估(通过同事反馈),并在一定层面上负责薪酬,也在负责招聘中的一部分。
Manager一般直接管理3~30个人,但8~12个更为常见。
- 软件工程师(Software Engineer, SWE)
从事软件工程开发工作的大多数人都是这个角色。Google招聘软件工程师的门槛非常高。通过只招聘特别优秀的软件工程师,很多困扰其他组织的软件问题都被避免或减少了。
像许多现代软件公司一样,Google区分工程师和管理者的职业发展序列。尽管一个工程师可以从事管理工作或者转岗到一个Manager职位,但是对于晋升来讲,管理才能不是必须的,即使是在非常高的级别。高级别的工程师职位需要有一定的领导能力,但它可以有多种形式,例如创造了产生了巨大的影响或者被很多其他工程师使用的软件,对晋升来讲就足够了。这一点非常重要,因为它意味着,对于拥有卓越技术能力但缺乏管理欲望和技巧的人仍然可以有很好的职业发展,并不一定要求这类人走管理者的发展道路。这避免了在其他组织中身处于管理职位,却忽视团队管理,从而失去上升空间的工程师的痛楚。
- 研究科学家(Research Scientist)
该角色的招聘标准非常严格,招聘的门槛极其的高,要求候选者拥有发表一系列文章的经历以证明其出色的研究能力,并且还要求写代码的能力。许多在学术届非常有才华的人,他们或许有能力符合Google软件工程师的角色,但不一定符合研究科学家的角色。在Google,大多数博士都是软件工程师而非研究科学家。研究科学家通过其研究贡献包括文章发表等评定,但除了头衔之外,Google的软件工程师和研究科学家并无太大的区别。他们都可以做原始的研究并发表论文,都可以贡献新的产品想法和新的技术,都可以写代码开发产品。在Google,研究科学家和软件工程师在一起工作,即在相同的团队做相同的产品或者研究。将研究科学家嵌入到工程中对在将发布的产品中融入新研究成果影响巨大。
- 网站可靠性工程师 (Site Reliability Engineer, SRE)
系统的运维由软件工程师团队负责,而非传统的系统管理员。但SRE的招聘需求和其他软件工程师职位略有不同(如果有非常专业的其他技术如网络或unix系统管理等弥补,软件工程师相关的技巧可以稍微降低一些)。SRE角色的性质和角色在SRE的书[7]中已经很好很仔细的解释了,这里我们就不继续讨论了。
- 产品经理(Product Manager)
产品经理负责产品的管理。作为产品用户的代理人,他们协调工程师的工作,宣传对用户重要的新产品特性,协调与其他团队的沟通,跟踪bug和协调时间,并确保一个高质量的产品所需的所有资源一切就绪。产品经理通常并不亲自写代码,但是会和软件工程师协作,以确保写出适合产品的代码。
- 项目经理/技术项目经理(Program Manager / Technical Program Manager)
项目经理的角色与产品经理大致相同,但并不管理一个产品,而是管理项目、流程和操作(例如数据采集)。技术项目经理也类似,但是需要他们工作相关的特定技术专长,例如,处理语音数据的语言学知识。
软件工程师与产品经理/项目经理的比例因不同团队而异,但一般来讲该比例较高,一般在4:1到30:1之间。
4.2 设施
Google因其有趣的设施而出名,如滑滑梯,球球堆和游戏室,它有助于吸引和保留人才。Google一流的咖啡免费向员工开放,这也有相似的功能,并且巧妙的鼓励员工留在办公室,饥饿从来不是离开的理由。员工们更常去的地方“微厨房“,可以拿零食和饮料,也有同样的功能,并且这里还成为一个重要的、非正式的交换想法的地点,许多聊天都始于这个地方。健身房、运动项目和便利的按摩椅帮助员工保持健康快乐,也提高了生产力和人才保留率。
Google的工位是开放空间的,并且通常是密集的。尽管有争议,但这鼓励了沟通(尽管有时会以分散个人的注意力为代价),也很经济。
每个员工分配了一个独立的工位,但是工位的重新分配相当频繁(如6~12月,通常是组织扩张的结果),主管会重新安排座位以便利和促进沟通,相邻的人之间总是更容易沟通。
Google的设施中均有拥有一流的视频会议设备的会议室,和其他组织的开会仅需点击接入屏幕上的一个预先组织好的会议邀请即可。
4.3 培训
Google通过多种方式鼓励员工教育。
- Google新员工(”Nooglers”)有强制的入职培训。
- 技术类员工(SWE和研究科学家)从完成“Codelabs”训练开始:这是一个短期的关于个人技术的编码在线培训课程。
- Google提供一系列的在线和线下培训课程。
- Google也提供在外部机构学习的支持。
除此之外,公司通常都会为每个”Noogler”分配一个正式的导师(Mentor) 和独立的伙伴(Buddy)以帮助他们更快的适应。非正式的指导也发生在和主管的例会、团队会议、代码审查、设计审查和其他非正式的工作流程中。
4.4 转岗
鼓励在公司不同的部分之间转岗,这有助于知识和技术整个公司传播,提高跨组织沟通。在同一个岗位工作满12个月后就可以在不同项目和办公室间转岗。鼓励软件工程师做其他组织内的临时性工作,例如,SRE (Site Reliability Engineering)中的六个月的“轮岗”(临时工作)。
4.5 绩效评定和奖励
Google非常鼓励反馈。工程师可以通过“同事奖金”(peer bonuses)和“勋章”(kudos)来给彼此明确的积极反馈。任何员工都可以提名其他人获取”同事奖金“——100美金的现金奖励,每年最多两次,以奖励其超额完成任务,仅需要通过网页填写并描述原因即可。在颁发“同事奖金”时,通常也会通知团队成员。员工也可以给其他人“勋章”,即正式的表扬声明,为良好的工作提供明确的社会认可,但没有经济奖励;对于 "勋章",没有要求工作超出正常的职责范围,也没有对授予次数的限制。
管理者也可以颁发奖金,包括即时奖金(例如,完成了一个项目后)。而且和许多公司一样,谷歌员工根据他们的表现获得年度绩效奖金和股权奖励。
谷歌有一个非常谨慎和详细的晋升过程,其中包括自我或经理提名、自我审查、同行审查、经理评估;然后由晋升委员会根据这些意见做出实际决定,其结果可由晋升上诉委员会进一步审查。确保合适的人得到晋升,对于保持对员工的正确激励至关重要。
另一方面,对于表现不佳的员工,我们会通过经理的反馈来处理,如果有必要,我们会制定绩效改进计划,其中包括制定非常明确的具体绩效目标,并评估实现这些目标的进展。如果失败了,就有可能因业绩不佳而被解雇,但实际上这在Google是极为罕见的。
Manager的表现是通过反馈调查来评估的;每个员工都被要求填写一份关于其Manager表现的调查表,每年两次,结果被匿名汇总,然后提供给Manager。这种向上的反馈对于保持和提高整个组织的管理质量非常重要。
5 总结
我们已经简要介绍了Google使用的大部分关键软件工程实践。当然,Google现在是一个庞大而多样化的组织,组织的一些部分有不同的实践。但这里所描述的实践通常被Google的大多数团队所遵循。
由于涉及到各种不同的软件工程实践,并且很多Google成功的其他原因与我们的软件工程实践无关,要将个别实践与改进结果联系起来,给出定量或客观证据是非常困难的。然而,这些实践在谷歌经受住了时间考验,它们经受着成千上万的优秀软件工程师的集体主观判断。
致谢
特别感谢Alan Donovan的极其详细和建设性的反馈,感谢Yaroslav Volovich、Urs Hölzle、Brian Strope、Alexander Gutkin、Alex Gruenstein、Hameed Husaini、Glen Shires, Niall Murphy, Ranjit Mathew, Emma Soederberg 在本文初稿时给出非常有用的评论意见。
引用
[1] /Build in the Cloud: Accessing Source Code/, Nathan York, http://google-engtools.blogsp...
[2] /Build in the Cloud: How the Build System works/, Christian Kemper, http://google-engtools.blogsp...
[3] /Build in the Cloud: Distributing Build Steps,/Nathan York http://google-engtools.blogsp...
[4] /Build in the Cloud: Distributing Build Outputs,/Milos Besta, Yevgeniy Miretskiy and Jeff Cox http://google-engtools.blogsp...
[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.blogsp...
[6] /Building Software at Google Scale Tech Talk,/Michael Barnathan, Greg Estren, Pepper Lebeck-Jone, Google tech talk.
http://www.youtube.com/watch?...
[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/sr...
[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/bo... 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/bo... [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.googleuserconte... [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/pa...
[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...
[18] /The Motivation for a Monolithic Codebase/, Rachel Potvin, Josh Levenberg, Communications of the ACM, July 2016. http://cacm.acm.org/magazines... single-repository/fulltext
[19] /Scaling Mercurial at Facebook,/Durham Goode, Siddharth P. Agarwa, Facebook blog post, January 7th, 2014. https://code.facebook.com/pos...
[20] /Why We (Still) Believe In Private Offices/, David Fullerton, Stack Overflow blog post, January 16th, 2015. https://blog.stackoverflow.co...
[21] /Continuous Integration at Google Scale/, John Micco, presentation, EclipseCon, 2013. http://eclipsecon.org/2013/si... 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/insid... at-hackathons/