八卦 Google 的前端開發方式及流程

pythontab發表於2014-07-30

話說本人從畢業到現在一直在某 B 公司工作,前些年折騰過不少開發方式和工具,但總覺得或許有更好的方案,所以很好奇其它公司內部是如何工作的,我曾經瀏覽過某 Y 公司內部無所不包的 TWiki,也拜訪過某 F 總部瞭解他們的開發流程,但對某 G 公司卻瞭解不多,只零零碎碎知道一些,這兩天抽空梳理了之前收集到的各種資料,希望能給 FEX 後續改進提供參考。

注意:以下內容主要資訊來自網上收集、『In The Plex』這本書及閒聊,純粹為了技術交流和討論,僅代表個人觀點,本人從未在某 G 工作過,不受 NDA 限制,但大部分資訊無法確認真偽,加上某 G 很大,每個部門都有可能不一樣,所以這裡的資訊也是比較片面的,歡迎大家提供更多參考資訊。

分工協作

首先,某 G 大部分產品線都不區分前端工程師和後端工程師,一個人需要用從前到後都負責開發,儘管這幾年似乎有變化,能看到專門的Front End 職位了,但應該是很少數產品線的做法。

N 年前有人去 G 面試過,和他閒聊後瞭解到某 G 要求應聘者必須至少要會 C++ 和 Java 中的一種,只會 Python/PHP 是不夠的,要是隻懂 JS 就更不行了。這個資訊很關鍵,能用來解釋一些內部現象,後面我會提到。

我個人認為前端工程師確實應該瞭解基本的後端知識,某 B 公司以前很多前端工程師都只負責模板(比如 Smarty)開發,這導致一個很嚴重的問題,那就是前端工程師往往不知道如何搭建環境,開發時需要依賴後端工程師提供環境和資料,嚴重影響了開發效率, 這也是為什麼 FIS 還內嵌了本地服務功能。

另外國內有公司還對前端工程師做進一步細分,按照職能分為寫 HTML/CSS 和 JS 的,對於我所屬的團隊,我個人並不贊同這種做法,因為 HTML 和 JS 是密切相關的,這樣分工將不利於程式碼管理與最佳化,尤其是互動複雜的頁面,因為 JS 很依賴 HTML,拆分反而增加溝通成本,但或許在重運營的網站這麼做會更好。

程式碼管理方法

以下是一些零碎瞭解到的幾點:

內部所有人都能看到程式碼

據說在 09 年時某國家的 office 有例外(來自『In The Plex』第 6 章,內容比較不和諧,這裡就不展開了)

提交程式碼需要相關人員的 review

這使得某 G 內部工程師可以很方便地切換專案,很少一個人只負責一個專案

程式碼只有最新版(trunk),沒有 release 版本,沒有版本號

一般大家喜歡新增介面

如果要修改原有的介面,就必須通知所有使用方,不過因為所有人都能看到所有程式碼,所以很容易找到有誰使用

據瞭解某 F 也是這樣的

有個程式碼的搜尋引擎

我認為這種方式比讓工程師寫文件靠譜多了,因為絕大部分呼叫這個庫的程式碼都是相似的,所以直接給出例子能讓別人更容易上手

估計和下線的 Code Search 比較像(好像還是某高管寫的,不過我忘記在哪看到的了)

如果想使用某個基礎庫,最好的方法是搜尋使用到這個庫的相關程式碼,抄過來

程式碼依賴是透過全域性的方式統一管理的

我猜應該很類似 Chromium 中的 GYP,熟悉 node 的同學可以理解為 npm,不過是支援多語言的

之前在某 G 工作過的 iOS 工程師也在某篇後來刪除的文章中透露程式碼中不放 Xcode 專案檔案,而是由工具生成出來(話說這篇文章挺有價值的,可惜老外不喜歡轉帖,導致現在找不到了)

這種依賴管理方式讓人想起某 A 公司(賣書那個,不是賣水果的)內部完善的 SOA 機制,不過某 A 喜歡基於 service 來重用,而某 G 看起來喜歡程式碼級別的重用

很少使用第三方庫

只能選用內部維護的版本,比如類似這個 MySQL

會將第三方庫的編譯工具改成內部的,比如 Chromium 中都改成 GYP 方便管理

據說想申請用某個新第三方庫需要稽核,週期比較長

程式碼管理軟體用的 Perforce

這個程式用了 17 年,有 2 千萬次 changelist(可以理解就是 ci 數量)

最大的 client 有 6 百萬個檔案(應該絕大部分是資料吧,要知道 chromium 專案也就不到 30 萬個檔案)

文件及相關資料檔案也放上面

Reivew 工具叫 Mondrian(確認就是 Rietveld 的前身)

某 G 直接將這個公司買下了(未確認,但下面那篇論文是在某 G 網站上的,所以我感覺訊息可靠),Perforce 的員工為某 G 內部定製了一套程式碼管理工具

另外我找到一篇 Perforce 的效能最佳化的論文,這裡面透露了很多 G 公司內部的程式碼情況(發表時間是 2011 年 5 月),以下資訊取自這篇論文:

整體來說某 G 的程式碼管理方式有很多可取之處,尤其是程式碼開放,能最大程度地調動開發人員的主動性與協作意識,從而創造出更大的價值。不過沒有版本管理這點是個雙刃劍,我也沒想好是否這樣會更好。

feature flag

因為沒有分支,程式碼只有一份,所以要實驗新功能就得透過 flag 來控制的,這個 flag 由線上 Borg 系統來管理,能做到針對某一部分的 Cookie 開啟不同的 feature,方便進行對比抽樣。

如果某個功能最終不上線,後續需要手工刪除相關程式碼。

這個 flag 開關功能在某 F 也有,我認為這是大型網站是必備功能,但需要注意,這個系統本身會成為關鍵節點,之前某 F 的類似系統掛過,直接導致整個網站大部分功能都關閉了,所以一旦出問題後果很嚴重。

嚴格的程式碼檢查

據說某 G 工程師大部分時間在寫單元測試,單元測試可以保證 UI 無關程式碼的質量,但對於頁面測試就很難了,雖然可以使用 selenium,但某 G 內部大家都不願意寫,我個人認為這個問題確實無解,頁面隨便一改就導致大量測試失效,我還沒見任何一家公司解決(某 F 說他們用的是 Watir,但主要用於保證登入等基本功能可用),目前看來唯一可行的就是自動頁面截圖 diff,某 G 在 Consumer Surveys 這個產品中也在嘗試。

據說某 G 的專案大多沒有嚴格的上線時間點,所以不能以專案緊急為藉口來不寫單元測試,這點和天朝不太一樣,大家更傾向犧牲質量來追求速度。

另外國外公司一般對瀏覽器相容性問題都不怎麼關注,因為現代瀏覽器中的相容性問題比以前好得多,這點某 G 和某 F 公司一樣,只支援高版本的 IE。

因為只有主幹,所以提交程式碼很謹慎,需要經過 3 個主要階段:

程式碼風格檢查

應該主要參考這個文件

非常嚴格,據說還會檢查命名什麼的

有段子說 Python 作者 Guido van Rossum 寫的 Python 程式碼無法透過檢查,所以一直沒提交。。。我認為這是假的,因為他老人家寫的 rietveld 還是挺符合某 G 規範的

單元測試檢查

程式碼 owner 的 Review

提交一旦出錯可能會導致影響其它人的工作(因為每個人都依賴主幹啊),甚至遭到其它國家 office 工程師的指責,所以大家對於程式碼提交都非常謹慎,再三確認,壓力不小。

在單元測試、程式碼風格和 review 的執行上,某 G 做得很徹底,這點值得學習,國內大家似乎更喜歡開發效率而不是質量。

前端如何開發

除了 Gmail、Maps、Plus 這樣的特例,基本上都是由後端模板生成頁面,很少專案使用 JS 來寫介面,更少使用 MVC 框架,這點其實在很多公司都差不多,比如某 B 也是一樣的,除了地圖及廣告管家等產品,其它產品基本上都是透過模板生成的。

某 G 的頁面是通常是由 Java 或 C++ 語言所寫的模版引擎生成的,而且開源出來了,分別是 Closure Templates 和 CTemplate,話說某 B 在幾年前也自己寫了個 C++ 的模板引擎,但目前基本被淘汰了。

對某 G 來說,「前端」工程師要寫 Java 和 JavaScript,而「後端」服務主要是 C++(某些地方開始使用 Go 了,比如這個)。

前面說到招人時都要會 Java,這帶來的結果是大多數團隊成員更瞭解 Java 而不是 JavaScript,於是在這種背景下很自然地誕生了 GWT 這個神奇的東西,它在內部很多地方使用,按照內部人士的說法,主要的考慮是:

能自動生成跨瀏覽器瀏覽器程式碼

結構規範,透過編譯器就能提前發現很多問題

能使用強大的 IDE 來提高效率(重構、自動完成、方便跳轉到定義等)

對於專業做前端的同學,看到 GWT 多半不喜歡,感覺就是多此一舉,但如果是 Java 出身的工程師其實是很容易接受的,尤其是對於習慣了 Java 的程式碼組織方式及強型別語言的人,反而會很不習慣 JavaScript 這種弱型別的語言,覺得太難控制太容易出錯了,比如拿到一個變數,在 Java 程式碼中透過它的型別就能知道它的資料結構,但 JavaScript 就不行了,只能在執行時 console.dir 出來或找相關實現的程式碼,從我個人體會來看,對於陌生程式碼,JavaScript 版本的理解難度要明顯高於 Java 版本。

話說某 G 曾經弄過一個叫 Wave 的產品,後來產品失敗後就將程式碼開源出來了,我認為這個程式碼能反應出 G 內部在使用 GWT 時的開發風格,我用 cloc 統計了一下它的程式碼情況,結果如下:

神奇吧,這麼複雜的前端互動應用,只有 1 個 56 行的 JS 檔案,而且其實這個 JS 還是無關緊要的,所以你可以理解為什麼某 G 只招懂 Java 或 C++ 的工程師了吧。

後來某 G 的 Lars Bak 大神推出了 Dart,在我看來就是用來取代 GWT 的,前面說到的 GWT 優點在 Dart 都有,而且在 I/O 2012 有一個演講題目是 Migrating Code from GWT to Dart,赤裸裸啊。

另外其實某 G 內部也不是所有人都喜歡 GWT,比如 Plus 就沒使用,而是直接基於 Closure 開發,並使用 Closure template。

說到 Closure,就不得不提它的起源:Gmail,在 WebApps 2010 會議上,有篇 PPT 介紹了 Gmail 程式碼的情況,以下摘抄其中幾個資訊:

2004 年就有 9400 行程式碼了,還有個 JS 編譯器(Closure compiler 的前身)來壓縮程式碼、檢查錯誤等

2005 年有 22000 行程式碼,10000 行註釋

2006 年有 52000 行程式碼,23000 行註釋,開始使用物件導向,並初步形成 Closure library

2007 年重寫,程式碼達到 90000 行,註釋居然有 97000 行(太厲害了。。。),開始出現模組化機制,而且出現了 Closure Templates

隨後開始內部使用,並最終對外推出了 Closure 系列工具

演講人認為 Type-checking is important and possible

有報導說在這個會議中演講人還透露 Gmail service 也是用 JS 寫的,程式碼有 443000 行

對於這個訊息,我不確定是否真實,但確實是有可能,08 年時 Stevey Yegge 也說過某 G 的規範有漏洞,沒說 JS 只能用在前端,而且他還真這麼做過。

最後插一句我的觀點:對於我所處的團隊及使用者類產品來說,GWT 沒有意義,而 Dart 雖然比起 GWT 要好得多,但和 JS 互動實在太麻煩,導致它的使用場景很有限,語法有明顯變化,使得難以讓大部分前端工程師接受(Lars Bak 就在 I/O 2013 上吐槽工程師太糾結語法,看起來大神在內部推廣時肯定遇到不少阻力)。對於型別檢查的好處,我個人是比較贊同的,因此我更喜歡 TypeScript 這 種增強形方案,因為它可以逐步適應,既有型別支援的優勢,又能直接使用現有程式碼。

內部工作流程

以下是打聽到的某個產品專案開發流程:

PM 或工程師提出某個想法,UX 做原型 mock

PM 申請專案稽核(透過率不高)、工程師開發 UX 無關部分

工程師完成開發

線上小流量實驗

PM/工程師分析實驗結果,完成報告,申請全量上線(透過率不高)

透過資料來證明這個功能是有價值的

需要解釋這些資料的變化原因

分批逐步上線,這個過程中還會有很多稽核

最終確定是否要上線(透過率不高)

一般整個專案週期很長(至少一季度),專案最終上線時間點無法確定,大部分的專案最終都無法正式上線。

最大的特點是完全靠資料說話,而不是由某個 PM 決定一切,以前有個視覺設計師在離開 G 後就在部落格上吐槽這點,他認為這會導致無法進行大膽的介面改版。

這個流程和我們搜尋產品幾年前的開發流程很類似,對於成熟的搜尋引擎來說這麼做確實有它的道理,畢竟隨便改個什麼都很可能影響收入,當然要十分謹慎了,但這種開發方式並不適合面向使用者類的產品,如社群、遊戲等,因為開發週期太長了,很容易錯過時機。

某人一天的工作

這裡拿 Matt Welsh 來舉例介紹一個工程師在某 G 一天的工作,雖然他不是做前端開發的,但他目前在 Chrome 團隊負責移動 Web 效能最佳化,所以還是比較相關,而且最重要的是他比較喜歡寫部落格,有意無意地透露了很多資訊,所以我比較好公開談。

另外話說他之前還是哈佛的計算機終身教授(!!!),八卦很多,比如差點說服小扎同學不要搞什麼社交網路了,還是好好學習拿畢業證照。。。

這這篇文章裡,Matt Welsh 介紹他的一天是如何度過的(另外還提到了在哈佛當教授是如何度過的,也很有意思),我摘抄如下:

9:00,到公司,查郵件

9:30-10:15,寫程式碼,增加功能,編寫單元測試,發起 changelist 程式碼 review,喝無糖可樂

10:15-11:00,切換 git 分支到其它專案,檢視同事 review 程式碼的結果,回覆評論併發新版本 changelist

10:00-11:30,再次切換 git 分支,提交一個要執行 3 小時的 MapReduce 任務分析網路延遲日誌

11:30-12:00,和山景城的團隊成員開視訊會議

12:00-12:35,午餐

12:35-14:00,檢查郵件,檢查 MapReduce 任務執行狀態,回覆程式碼 review 的評論,再次提交程式碼,然後檢視任務列表確定接下來的工作

14:00-15:00,和在劍橋(有評論指出這裡是波士頓的劍橋,不是英國那個)、山景城等多個地區的團隊成員開專案會議

15:00-16:00,喝紅牛,這時 MapReduce 任務已經跑完了,生成圖表,分析資料中不符合預期的部分,整理程式碼,準備下一次 MapReduce

16:00-17:00,喝蘇格蘭威士忌(scotch)並玩吉他英雄(Guitar Hero)

17:00,收拾筆記本回家

看完後我的幾點體會是:

前面提到的程式碼只有 trunk 並不準確,當然每個部門確實可能不一樣

程式碼 review 做得很認真

看起來任務很明確,所以雖然工作時間是 9-5,但效率挺高,這點我最為好奇的,怎麼做到將工作安排這麼具體?

除了寫程式碼,分析資料也是每天的重要工作,具體分析什麼可以透過他的論文了解,看得出來是很細緻的

內部工具

2008 年前的內部工具情況可以透過這篇文章和這個 PPT 瞭解,不過之後就不清楚了,看起來很多外部工具都有內部版本(Docs、Mail、Talk、Calendar 等)。

這裡說一下 Chromium 專案中我看到的工具使用情況:

網站是基於 Sites 搭建的

設計文件喜歡使用 Docs,因為可以線上編輯和評論功能,所以多人協作會很方便

https://codereview.chromium.org/

在 Groups 中進行討論

使用 code 來管理 issues

Buildbots 來進行編譯和整合測試

搭建了各種檢測工具來保證質量,具體細節推薦讀這本書,看完這本書我最大的體會是沒什麼神奇的東西,完全靠細心的工作

可用的石頭

以下是我認為可以借鑑的地方:

原始碼不分版本,對內部所有人公開

在 FEX 內部已經是這樣了,但我們應該推動更廣泛的開放與共享

嚴格的程式碼規範及單元測試機制

FEX 所有專案將接入 Travis CI

程式碼規範及單元測試的強制檢查

程式碼 owner 的 review 機制

透過實際例子來使用,甚至不用看文件

加強對 demo 及 example 的要求,不能是簡單的 hello,而最好是從產品線實際使用案例中抽取出來

文件及相關資料和程式碼放一起

這能保證找起來很方便

如果由於種種原因不能放一起,至少也要放連結

外部產品有內網版,比如 Docs

典型的 Eating your own dog food

在內網提前測試外部產品的新功能,而且一般內部人員都會很積極地吐槽,對產品改進很有幫助

GWT 的靜態檢查機制

整理這篇文章時我發現 TypeScript 也已經接近 1.0 版本了,看起來時機快成熟了,後續計劃嘗試 TypeScript


相關文章