谷歌是如何构建Web框架的

图0:谷歌是如何构建Web框架的

根据谷歌对外公布的数据,它的20亿行代码都部署在同一个代码仓库里,通过基于基线的方式进行开发工作中的代码共享。

图1:谷歌是如何构建Web框架的

从上面这张图可以看到,一共有文件10亿个,源文件数量达到900万个,源代码行数达到20亿行,提交代码的深度可以挖掘到3500万次提交,平均每个工作日提交4万次,数字真是恐怖。

从大众的眼光来看,特别是那些谷歌公司外部的人,他们会觉得这种单一代码仓库的管理方式,尤其是代码量这么恐怖的前提下,这种管理方式很不正常,但是它真的很有效,而这种有效是由管理方式决定的,而不是单纯让它自然生长。

Rachel Potvin和Josh Levenberg编写的一篇文章里是这么描述的:

谷歌的代码库由全球数十个办公的超过2.5万名软件开发工程师所共享,平均每天他们会提交1.6万次代码修改请求,全文地址可以点击这里

图2:谷歌是如何构建Web框架的

只有一个版本

正如下面这张图所显示的,在谷歌,你看不到代码分支,拉代码分支是很多公司的习惯做法,在开发阶段这个很方便,相当于一个个独立的Docker镜像,但是等代码合并的时候就不是这么好玩了。

图3:谷歌是如何构建Web框架的

对于只有一个源码仓库的开发模式来说,你不可能出现应用程序FooBar使用AngularDartV2.2.1版本,而另一个应用程序BarFoo使用2.3.0版本的情况。两个应用程序必定需要使用同一个版本。这其实是将多版本之间的完全兼容性测试由出现问题转移到了代码提交环节。

每次提交74000个测试用例

我们这里以AngularDart框架为例,它目前有1601个测试用例。当你向谷歌的代码库提交一次AngularDart代码时,会自动为所有依赖于AngularDart框架的工程运行测试用例。也就是说,差不多有74000个测试用例(视依赖的工程数量而定,这里只是举一个例子,有些流行的框架可能测试用例会更多)。

图4:谷歌是如何构建Web框架的

我们举个例子,也许你修改代码的数量很少,例如“&& random.nextDouble() > .05”,你只是增加了这么一个判断条件,它并没有触发1601个测试用例里面的任何一条,但是因为你增加了这个判断,它可能会对框架的使用方造成问题。

真正的价值在于,提交代码时所作的测试时针对真实的应用程序的。不仅仅测试的量级很大,针对使用方的测试也可以反应你的框架是如何被开发者所使用的。这就好比我们自己写框架的人,写出来的测试用例都是符合我们思考方式的,但是你无法左右你的客户如何使用你。

对于生产环境下的应用程序,我们应该明白它们和测试环境的示例程序存在巨大的区别,你当前支撑得好,他们才会一直使用下去,这种做法也是为了更好地支持后续的开发活动。

你制造麻烦,你修复它

正如标题所说,如果AngularDart的作者引入了一个改变,哪怕只是一行代码的改变,他们都需要直接去为客户解决问题。也正是由于谷歌只有一个代码库,所以AngularDart作者可以直接修复问题。

所有的修改代码和针对客户的修复措施代码,它们都需要同时被提交带代码库,当然,还需要所有相关方的代码评审完成之后才能提交。

我们举个例子。当AugularDart团队的成员想要做代码修改,而这次的代码修改会影响AdWords这个应用程序的代码,那么AugularDart团队的成员需要直接进入AdWords的源代码,然后修复问题。他们可以运行AdWords已存在的测试用例,也可以自己增加一些新的用例。然后他们把所有的改变写入改变列表(change list)并提交评审。因为他们的change list涉及到框架(AngularDart)和调用方(AdWords)的代码,所以系统会自动请求来自双方面的成员进行代码代码审核和批准请求。

当然,业界也有其他的批评,认为AngularDart开发者仅关注了谷歌内部的使用方,例如AdWords,而没有关注外部的使用方,例如Workivas、Wrikes,以及StableKernels。

大规模改变

如果AngularDart准备进行一次大规模的改变,例如从2.x升级到3.0,是否真的需要为所有的使用者(框架依赖方)修复缺陷、运行测试用例,答案是:Yes。

当类Foo里的一个方法从bar()变为baz(),你可以构建一个工具,这个工具可以遍历整个Google代码库,自动搜索所有的Foo类及其子类的实例,直接把它们修改为baz()。

图5:谷歌是如何构建Web框架的

性能指标

除了关注功能,谷歌还要求框架提供方关注提交代码后出现的性能问题。谷歌会自动为每一个使用方生成性能测试结果,这个性能测试是针对生产环境的,绝对真实。

图6:谷歌是如何构建Web框架的

Hermetic构建工具

对于大量的测试用例,开发人员当然不可能一个一个去运行,一个个修复缺陷,他们使用的是Bazel(开源构建代码工具)。在这个量级下你不可能使用一系列的shell脚本构建工程,你需要的是hermetic构建工具。

hermetic在这里的意思有点类似于“纯正”,你构建的步骤不能有单边影响(例如temo files、changes to PATH这些修改),修改需要是可以判断的(例如输入什么导致输入改变)。你可以在自己的机器上通过hermetic工具先运行测试用例,相当于你机器上的客户端,运行通过后把改变代码提交到服务器上并行构建它们。

总结

通过这种类似于提供方作为责任方的制度,让谷歌的软件开发人员对于每一行代码的提交都会非常谨慎,但是也对生产环境的程序稳定性、性能提供了充分的保障,此外,通过这种方式也会影响开发人员对于产品的开发思维,让他们可以站在用户的立场上思考如何更好地构建自己的框架,这其实也是在一定程度上推动技术和产品的发展。

本文文字及图片出自 InfoQ

余下全文(1/3)
分享这篇文章:

请关注我们:

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注