做者:Filip Hracek <br/>
编译:胡子大哈 react
翻译原文:http://huziketang.com/blog/posts/detail?postId=58abfab1204d50674934c3a9 <br/>
英文原文:How Google builds web frameworksgit
转载请注明出处,保留原文连接以及做者信息github
众所周知,Google 使用单一仓库来共享全部代码——20亿行代码,而且这个仓库是采用基于 trunk 的开发方式。web
(这毫无疑问是世界上最大的代码仓库。)算法
对于 Google 公司之外的开发者来讲,这是使人惊讶的,也是反直觉的,可是它确实运做良好。(所给的连接 文章 中已经给了很好的例子,这里就不累述了)编程
Google 的代码库在 Google 在全世界几十个办事处,共 25000 多名软件工程师之间共享。在一个普通的工做日里,就有 16000 屡次代码提交。安全
这篇文章主要讲述构建一个开源 Web 框架(AngularDart)的开发过程。服务器
(“Human users” 意味着谷歌的软件工程师提交代码)angular2
当你在一个单仓库项目中使用基于 trunk 的开发模式时,你的全部东西都只有一个版本。例如, Google 不会发生一个叫作 FooBar 的 App 使用 AngularDart 2.2.1 版本,而另外一个叫作 BarFoo 的 App 使用 2.3.0 版本。全部的 App 都用同一个版本——并且是最新版本。框架
(基于 trunk 的开发模式时示意图,来源:trunkbaseddevelopment.com )
这就是为何 Google 的工程师说全部的 Google 软件都活在“失血边缘”。
若是如今你的内心在大喊“太危险了!”,那就对了。在你的生产环境代码里面依赖另一个库的 trunk(至关于 git 里面的 master)分支上面的代码听起来确实很危险,可是你要知道,故事在这以前还有别的情节。
AngularDart 定义了 1601 个测试(这里)。可是当你要提交一个改动到 Google 仓库中的 AngularDart 源代码时,全部依赖于 AngularDart 的测试都会被跑一遍。这时,大概有 74000 个测试(这依赖于你的改动有多大——系统会知道你影响了哪些测试,而且会启发式地跳过这些测试)。
测试越多越好。
例如,我仅仅是作了一个小改动,用来在变化检测插入验证算法中作一个模拟某种场景的竞争状况(我添加了&& random.nectDouble() > .05
到 这条 if 语句 中)。当我运行它的时候(运行一次),AngularDart 自己的1601个测试并不须要跑,可是这个改动却命中了一堆的客户端测试。
这里面体现出真正的价值是,这些测试都是真实产品的测试。这些测试不只数量庞大,同时它们也反映了开发者是如何使用的这个框架(不只仅是框架的做者使用)。这样作的意义是:框架的做者并不老是可以正确地预估别人是怎么使用他的框架。
对正在生产环境运行的 App 也是有好处的,毕竟上面每月有数十亿美圆的流水。开发者不是在一个业余时间拿来玩玩的 Demo App 上使用框架,而是一个成千上万人投入在上面的线上产品使用。若是 Web 是和将来息息相关的,那么做为 Web 框架开发者,咱们更应该更好地支持后者的开发。
因此,若是一个框架致使依赖于它的一些 App 崩溃,会发生什么?
若是 AngularDart 的某位成员引入了一个引发崩溃的改动,那么他必需要为他们的用户修复它。由于你们都使用单一的仓库,所以 bug 很容易被发现,而且能够立马修复它。
由于 bug fix 的时候可能带来新的 bug,所以 bug 和 fix 有多是同时入代码库。固然,在入库以前它们都会被作代码审查。
咱们来给一个具体的例子。当 AngularDart 团队里的某个成员修改了代码影响了 AdWords 程序的运行,那么他们就要跑到 AdWords 去修复它们。在修复代码过程当中,他们会跑 AdWords 已有的测试,也能够新建测试。而后他们会把测试和 bug fix 都放入变动列表,而且申请代码检查。由于这个变动列表中包含了 AngularDart 代码和 AdWords 的代码,所以系统会自动地将代码发送到两个团队进行审查,只有两边都经过了才能被提交入库。
这是一个很好的防止闭门造车的方法。AngularDart 框架的开发者们能够访问到数以百万计行的代码,这些代码都依赖于该框架。他们不须要去假想其余人会怎么使用这个框架。(固然他们只能访问到 Google 的代码,而访问不到世界上其余依赖于 AngularDart 的代码。)
别人用你的框架,可是你要升级别人的代码,这样听起来会使得开发变慢。可是也没想象中那么慢(能够看一下 AngularDart 10月份的进度),可是也确实让开发进度慢了一些。这是一把双刃剑,怎么来看待这个问题取决于你想要从这个框架中得到什么。等下咱们再来讨论这个问题。
因此,若是有个 Google 的家伙跟你说,他们 Alpha 版本的库已经稳定了而且能够应用到生产环境了,你就知道是什么回事了。
那么,若是 AngularDart 要作一个大规模的变更(如版本从 2.x 升级到 3.0)而且会命中 74000 个测试该怎么办呢?团队要修复全部的问题吗?难道他们要去更改上千个跟根本就不是他们写的源文件吗?
是的。
一个好的 类型安全系统 会使你的工做更有效率。例如,在一个类型安全的 Dart 中,类型安全能够保证全部变量都有一个肯定的类型。那么你进行重构的时候不少东西均可以作到自动化,而不须要开发者手工确认。
当类 Foo 中的一个方法bar()
变成了baz()
,你能够建立一个工具,它能够遍历整个 Google 仓库,找到全部 Foo 类的实例以及它子类的实例,而且把全部的bar()
改为baz()
。有了类型安全,你能够肯定这个改动不会使任何地方崩溃。若是没有类型安全,甚至这么一个简单的修改均可能变得很是麻烦。
(根据 Dart 代码规范,一键格式化代码)
另一个对于大规模改动颇有帮助的是 dart_style, Dart 的默认格式器。全部 Google 的 Dart 代码都是经过这个工具进行格式化的。在你的代码被 push 到代码审查人员以前,就经过 dart_style 进行格式化了,因此不存在像要不要把新的一行放在这或者放在那这样的问题。这也被应用到大规模的代码重构。
正如我上面所说的,AngularDart 得益于依赖于它的产品的测试。但仅仅只是测试还不够,Google 对于 App 的性能要求的很严格,几乎全部的产品都有基准测试套件。
因此,若是 AngularDart 引入了一个致使 AdWords 加载慢了 1% 的改动,上线这个改动以前他们都会知道。若是十月份 AngularDart 团队宣布他们自从八月份以来 AngularDart App 比原来体积小了40%,速度快了10%的时候,他们并非在讨论什么 TodoMVC 这样的小事。他们谈论的是真实世界中里面上百万级别用户的产品和上兆字节的业务逻辑代码。
你可能会好奇,在 AngularDart 引入了一个 bug 后,在这么庞大的内部仓库里面,应该去跑哪些测试呢?固然不会手动的在 74000 个测试去挑测试来跑,固然也不会把 Google 全部的测试都跑一边。答案在于一个叫作 Bazel 的玩意儿。
在这种代码规模下,你不可能写 Shell 脚原本编译全部文件,这样作会很不靠谱并且会慢的使人发指。这时候你须要的是一个封闭式编译工具。
“封闭式”(Hermetic)的意思有点相似于函数式编程里面纯函数的”纯“。也就是说,你的编译过程不能有反作用(如临时文件,改变环境变量 PATH 等),他们也必须是肯定性的(相同的输入必须获得一样的输出)。这样的话无论你何时在你的机器上编译和运行测试,你会获得一致的输出结果。你不须要make clean
。所以你能够发送你的编译/测试到编译服务器上并行编译。
Google 花费了数年的时间开发这个编译工具。近些年将其开源了,就是 Bazel。
多亏了有这样的基础设施,内部测试工具才可以本身来决定编译和测试哪些受影响的部分,而且在恰当的时候运行他们。
AngularDart 的目标很是明确,就是要在构建大型 Web 应用领域,作到一流的效率、性能和可靠性。这篇文章所讲述的就是后一个部分——可靠性。同时也解释了为何 Google 的关键产品,如 AdWords 和 AdSense 都使用这个框架。不是 AngularDart 本身吹嘘本身有多么厉害的用户,就正如上面所说的——就是由于有这么多的内部用户,AngularDart 几乎不可能引入一些随意的变动。这也使得这个框架更加的可靠。
(若是你以为这些听起来太商业化了,你能够看一下个人非商业化 AngularDart 项目 自动化的特朗普 或者 Prime Finder)
若是你想要一个每几个月就有一次大的改版或者重大功能升级的框架,很明显 AngularDart 并非你要找的。即便咱们想这么干,你看完这篇文章就只知道,这么严格的开发流程是不可能开发出这样的框架的。但咱们真心相信,一个不是很流行可是却很稳定的框架确定会它有发展和生存的空间。
在我看来,如何判断一个开源技术会不会获得长期的维护和支持的,那么你就看看这个技术是否是维护者的公司业务的重要组成部分。能够拿 Android,dagger,MySQL 或者 git 做为例子。这就是我为何我很是高兴地看到 Dart 有一个首选它的 Web 框架(AngularDart)、一个首选它的组件库(AngularDart Components)、一个首选它的移动框架(Flutter)——全部的这些都被用 Google 的商业产品中。
我最近正在写一本《React.js 小书》,对 React.js 感兴趣的童鞋,欢迎指点。