做者: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 感興趣的童鞋,歡迎指點。