《Software Engineering at Google》, 是 Fergus Henderson(弗格斯·亨德森)在2017年6月发表,并于2019年修订的一篇论文。这篇论文从软件开发,项目管理和人员管理的角度讲述了谷歌的软件工程实践。谷歌作为一家全球顶尖的科技公司,在软件工程方面有着非常出色的实践经历,值得软件工程师们认真品读。
作者Fergus Henderson在谷歌从事了10年以上的软件工程师岗位,从1979年还是个孩子的时候就开始编程,至今已经有了超过40年的编程经历。是谷歌软件构建工具Blaze最初的开发者之一,如今Blaze已经在谷歌内部广泛使用。他写出的软件如今安装在超过10亿台设备上,每天被使用超过10亿次。
以下是我个人的一些思考:
做伟大的产品,服务社会并赚取利润。这大概是每个软件工程从业者的职业目标。
软件服务公司,将人才聚集在一起,用以支撑更大的商业价值。对公司来说,如何组织资源,调动人才,获取最大价值,是值得思考和研究的。这也是公司存在的意义,即整合人才以达到个人难以达到的目标。
要想取得最大价值,需要做好三件事:
- 招募优秀的人才,并把每一个人才放到合适的岗位上。
- 激发人才的内在潜力和创造力。
- 以科学的方法论,指导推动软件工程的实施。
关于人才
谷歌主要采用了以下两种策略来激发人才的潜力
- 20%自由时间
- OKR管理
20%的自由时间
公司许可,工程师们可以花费20%的工作时间做任何项目,无需主管的同意。这个举措的好处非常多。一来可以充分激发员工的创造力,创造力来源于兴趣。二来,这个举措体现了对工程师的足够尊重,让他们充分拥有归属感,认为在谷歌工作可以充分展示才华,而不是乏味的打工。
我自己也深有体会,在工作中,经常会迸发出灵感,或者有非常想做的,想研究的技术点。但通常会为了工作进度而妥协,或者强行挤出休息时间来进行。如果官方提供了20%的时间,相信作为工程师,一定会感到干劲十足。
目标与关键成果(OKR)
对团队来说,方向感是必不可少的。谷歌采用OKR模型来把控方向,O表示Object(目标),KR表示Key Result(关键成果)。目标通常可以分解为3~5个关键成果。个人的OKR,需要和团队的,更高层级的OKR对齐。OKR周期不宜过短也不宜过长,谷歌采用季度作为OKR周期。
很多人用KPI(Key Performance Indicator)和OKR进行对比,并认为两者没有本质区别。的确,这两者在实践上非常容易混淆,但他们的思想确实截然不同的。KPI通常直接用来衡量业绩,决定了你的收入和晋升机会。通常采用团队认领的方式,主管领了KPI之后,将KPI分解给团队成员,整个团队的目标都围绕着如何将KPI完成。由于KPI的完成程度直接等于绩效,在制定KPI的时候,员工会和老板讨价还价,希望制定一个较低的易于完成的KPI,这对于创造力来说是受限的。
OKR则不与绩效直接挂钩,仅作为参考。制定OKR的时候,鼓励充分发挥想象力,高标准的制定。每一个员工自己思考并制定自己的OKR(需要和主管对齐),它更多体现的是一种自底向上的管理模式,对于发挥主观能动性来说,具有很大的优势。
关于软件工程
关于人才管理,就暂时写到这里,我是一名工程师,还是想更多的谈一谈我对软件工程这一块的感受。
原文写的比较散,分别从代码管理,编译构建,测试,缺陷管理,发布版本,上线等必要的环节,讲述了谷歌内部的做法。不得不说,谷歌在软件工程方面做得相当出色,是业界的楷模。
不过我并不打算从每一个环节来谈自己的感受。我希望能够从一个更高的维度来理解这些环节共同解决的目标以及他们之间是如何相互联动的。
软件开发的最终目标是将软件上线并提供服务。评价开发的过程是否成功,我们通常会从成本和收益两个方面考量。以下问题的答案将决定项目是否成功。
- 从项目启动到上线,花费了多长时间
- 项目共计投入了多少工程师,他们的薪水如何。
- 软件在上线后遭遇了多少功能缺陷和性能缺陷,这些缺陷的影响怎么样。
- 修复缺陷和开发新功能的代价有多大。
- 如果团队有成员流失,对项目会造成多大的影响。
- 新成员的加入,需要花多少时间熟悉业务和代码。
当然决定项目成败绝不是仅仅靠技术人员能左右的,还与市场运营,销售能力等密不可分,但现在让我们把视角仅仅放在技术相关的方面。
软件工程如何实施,将直接决定这些问题的答案。但有一点需要注意的是,我们并不能在所有的问题上都取得完美的效果。因为有些指标是互相矛盾的。
比如,投入更多的工程师,可能缩短项目的开发周期,但也意味着投入更多的成本。砍掉代码审核,缺陷测试,可以减少当前的开发成本,并使得项目快速上线。但会造成软件质量的下降,并带来后续更大的维护成本。
《经济学原理》中提到人们面临权衡取舍,是经济学第一大原理。在软件工程领域也同样适用。成本,效率,质量这三者不可兼得。领导者需要根据项目背景做出权衡。
如果软件偏底层,例如操作系统,内核相关,就应该在软件质量和运行效率方面投入更多的经历,因为它们通常被大量的上层应用所使用,一旦出了问题,将会导致极其昂贵的代价。一个典型的例子就是华为的鸿蒙操作系统,它是需要时间去打磨的,不应该推出一个半成品来快速抢占市场。
但处于应用层的软件,策略会有所不同。决策者通常不会拘泥于一个网页的打开速度是1秒钟还是1.1秒钟,他们希望在软件本身没有严重问题的情况下,快速上线抢占市场。至于小缺陷是可以在不断的迭代中修补的。如果失去了市场,即便你把软件打磨的再精品,也很难弥补经济损失。
谷歌的设计哲学
谷歌的软件工程,代表了大型互联网企业的高效运作方式。我们来看一看它背后的设计哲学。
机器比人便宜
雇佣一名工程师的代价是高昂的,知乎的一篇薪酬对比文章里提到谷歌工程师的平均年薪接近20万美元。在工程基础设施上,谷歌愿意动用服务器的强大算力,以节约工程师的时间。内部变异构建系统Blaze就是一个很好的例子。
在谷歌,提交一行代码改动,往往在几秒钟之内就能得到构建好的软件包。而其他公司这个数字可能达到分钟级别。如果魔幻的效率背后,是一个超大型的分布式系统。一旦编译任务被提交,Blaze(内部编译框架)就会迅速计算出,文件的改动导致了哪些产物需要重新生成,生成这些产物可以分解成多少个子过程,并把独立的子过程分布到庞大的集群中并行计算。
中小型公司则更多的使用笔记本电脑或台式机的算力完成编译构建,这种方式虽然也能工作,但时间开销会大不少,工程师的幸福感也会受到影响。
规范大于灵活
独立工作的工程师通常喜欢灵活。因为灵活总能快速的解决遇到的工程问题。他们喜欢自由组织代码,灵活选择依赖包的版本,随意控制编译构建逻辑。但在团队作业,尤其是大型团队中,这种做法会带来高昂的沟通成本。
谷歌有超过10亿行的核心代码存储在一个代码库中,背后依托的是性能强大的分布式文件系统。虽然代码库体量巨大,但工程师并不需要下载全部代码,而是选择自己关注的目录。权限系统的设计也围绕目录展开,每一层目录都可以设置owner和developer,下级目录自动继承上级目录的权限。
中央仓库最大的好处就是内部系统可以完全基于master分支工作。避免复杂的版本管理和版本冲突。通过高效运转的持续集成机制和测试回归机制,保证主干分支的质量。
构建系统Blaze也对使用者提出了一系列的规范要求。以C++为例,这门语言本身设计的非常灵活,在编译时无需告诉编译器代码依赖的头文件的具体路径,只需要告诉编译器去哪里搜索即可。但Blaze强制要求用户显示制定头文件的具体路径。
这看起来似乎在开历史倒车,其实不然。一方面,额外增加的规范使得编译框架更好的掌控编译过程,从而可以最大化的利用分布式的能力解决问题。另一方面,规范也减少了团队的沟通成本,从而使大型项目更加顺滑的开展。
越早发现问题越好
软件工程从写下第一行代码到正式上线,通常要经历编码 -> 构建 -> 测试 -> 部署,这几个步骤,有一种说法是缺陷每迟一个环节被发现,解决成本平均提高10倍。谷歌有一套完整的机制,保障软件的质量,并推动尽早的发现缺陷。
第一道关卡是编译构建和单元测试。工程师提交代码后,通常会自动触发编译构建和单元测试。运行结果很快就会出来,当结果为失败时,系统通过邮件或即时通讯工具告知工程师。工程师需要确保自己的提交在系统上产生一个运行通过的标志,否则需要高优先级解决问题。
第二道关卡是代码审核。代码审核采用人工审核+机器辅助的方式,通常检查逻辑是否有错误,代码是否规范,架构是否合理。谷歌内部有一个自动化的系统,会在工程师提交代码审核后给出推荐的审核人列表,一来避免某些人被分配了过多的审核任务,二来也可以把复杂的改动交给更资深的审核者。本着高效的原则,每次提交的代码量应该控制在300行以内。
第三道关卡是功能测试和集成测试,在这里将对产品的功能有一个完整的检测。谷歌也开发了自动化评估测试覆盖度的工具,负载测试先于上线是Google的一条规范准则。团队应该制作图表展示关键性指标。
总结
这篇读后感就准备写到这里了。谷歌有很多先进的工程理念和优秀的工程实践。但从公司的角度,也要结合实际情况合理借鉴,切不可盲目照搬。决策者应该站在成本,质量,效率的角度综合考虑,既要考虑历史技术负债,又要结合未来团队规模,公司规模等等,这并不是一件简单的事情。
我是一名软件工程师,专注于devops领域,准确说细分领域是编译构建。接下来,我会分享一些在编译构建领域的心得和最佳实践。