讓 Code Review成爲一種習慣

1. 開篇

5月份的時候突然接到 code.oa.com【騰訊內部的一個代碼管理平臺】 的 summer 的通知, 說廣點通的codereview 參與度在公司各部門中表現出色,而我們小組(廣點通廣告定向小組)的 codereview 綜合表現在全公司的小組中排名第一。這讓我有點意外,有點無心插柳的感覺。 summer 希望我能寫寫我們小組做 code review 的一些心得體驗, 回想我學習使用 codereview 的經歷, 我最先想到的一句話是我幾年前看到的關於 codereview 的一句評述:

The biggest thing that makes Google’s code so good is simple: code review.That’s not specific to Google – it’s widely recognized as a good idea, and a lot of people do it. But I’ve never seen another large company where it was such a universal. At Google, no code, for any product, for any project, gets checked in until it gets a positive review.

這是一段讓我記憶深刻的話, 一個Google 工程師寫的, 我摘錄下來做作爲文章的開始,表達我在騰訊這些年和一些出色的工程師合作的過程中一起學習和實踐 CodeReview 之後, 對CodeReview 文化的一種由衷的認同和尊敬。

2. Rietveld

我 2008 年進入騰訊, 主要呆在 R2參與soso 的開發, 從 2008 ~ 2010 年我都很不屑於 R2 的研發質量管理,覺得做得實在很糟糕:沒有統一的編碼規範、沒有unittest,甚至經歷過有些人不會用 svn, 不太懂代碼的版本控制, 當然我自己也不怎麼懂開發流程中的質量管理, 那時候連 codereview 是什麼都沒聽說過。2010年初, 公司開始在搜索上加大投入, 招聘了一些牛人,尤其是 Google 的一些工程師, 而這些人也把 Google 的一些開發文化帶入了 R2。雖然 soso 最終的命運並不如人所願, 但是在 2010~2013年間, 許多soso 的工程師是學習並經歷了什麼是嚴謹而強大的開發流程,也見過我們曾經山寨的 Google 的技術, 以及山寨的 Google 的開發流程。 而至今爲止,我們和很多同事回憶起來,我們常調侃說我們是見過豬跑也吃過豬肉的。

2010年4月從Google 來到我們部門的一位牛人是 yiwang, 做機器學習的博士, 做了一次 LDA topic modeling 的報告, 令人印象深刻, 接觸了幾次之後,我主動找了 yiwang 一起合作,學習 LDA 並參與並行 topic modeling 的開發。yiwang 讓我做的第一件事就是研究一下 Google 開源的 Rietveld code review 系統, 並找一臺機器把 Rietveld 搭建起來。於是一頓折騰之後, 我們搭建了公司的第一套嚴格意義上的 codereview 系統, 當然那個時候也只是供我們小組內自己使用。 搭建好 Rietveld 之後, 我們做的第二件事就是把 code style 都統一到 Google 發佈的 C++ coding style。 最早在這套系統上進行 codereview 的就是4個工程師 yiwang, leostarzhou, charlieyan, 和我。

所有和 yiwang 合作過的人在 codereview 中都苦不堪言, 他是近乎苛刻的嚴格執行 Google C++ coding style, 我們提交的的 code 中多一個空格,多一個空行;或者是註釋符號 “//” 後面少一個空格, 全都被打回來修改;更別說變量、函數名命名不符合規範,隨意使用變量縮寫這些大的禁區了。對於我們最初的代碼, yiwang 挨個細緻的指出我們違反規範的地方, 在 comment 中貼上Google C++ 規範的具體要求的 URL anchor, 以說明我們爲何違反了規範。 一開始我是有點不以爲然的, 來回幾次之後我自己也不好意思了, 把 Google coding style 從頭到尾仔仔細細的看上3遍, 認真的記住一些細節, 於是很快就開始上手了。

自然, 後續我們合作的工程師逐漸多了起來, 對於 codereview 的必要性,許多人是有質疑和挑戰的, 於是在和yiwang合作的幾年裏, 我反覆聽他說了三個故事。

第一個是關於他自己的,他從小開始 coding, 高中的時候已經拿到工程師的認證,進入 Google 之前 coding 無數, 進入 Google 之後寫的第一個100行的程序, 被貼的 comment 超過了100行。 所以不要抱怨我們的標準嚴格, 嚴格的標準才能產出漂亮的代碼, 我們今天在騰訊做的 codereview 真是不算啥。

第二個是關於Google 內部 codereview 的爭議的, 據說 Google 內部建立 codereview 制度的時候,也是很多工程師不樂意, 尤其是年長的工程師, 寫了多少年代碼了, 被一羣年輕的小屁孩在代碼上指指點點,實在是受不了。 最後說是 Google 的一位極有地位的人物出來說話了:我們要想把工程質量控制好, 無論是資歷深淺,都一定要遵守共同的代碼規範,於是 codereview 制度得以建立。

第三個是解釋爲何要用 Google C++ coding style 的, Google 的代碼規範是一羣頂尖的 coder 制定的, 變量名用小寫, 函數名用駝峯式, 那都是有嚴格的視覺美學講究的,讓人看了很舒服的,甚至是做過視覺對照研究的。雖然我對此存疑, 我還是認同 Google C++ coding style 是我見過的最好的 coding style。 而我們騰訊的一位 HR 在和我閒聊的時候也表示過同樣的觀點 :-)。

Coding style 的規則制定很多都是相對的, 而Google style做得 NB 的地方就是, 他設定的大多數規則的目的他並不是要證明自己是正確的, 而是詳細的列出各規則的優缺點(pros and cons),讓你更深刻的理解這些規則。著名的統計學家 George E.P. Box 在數據建模中說過一句廣爲流傳的話: All models are wrong, but some are useful. 套用這句話到 code review 的 coding style 中, 我想說 All coding rules are wrong, but some are useful。當然 Google style 好的一個額外的原因是 Google 提供了 cpplint 這個工具自動檢查你的 code 中是否有違反規範的地方, 大部分的低級錯誤都會被檢查出來。

3. 推廣 CodeReview

我們小組剛開始把 Google 的 Rietveld 在內部搭建起來並在部門內推廣使用以後, 發現了一些問題, 主要包括:

  1. issue 提交之後如何通過 email 發送到公司的 outlook 帳號
  2. Rietveld 提供的提交 issue 的工具 upload.py 對中文的支持不好
  3. 底層用的文本文件做存儲, 訪問量大的時候,提交 issue 多的時候, 速度不行

前面兩個問題charlieyan 和我對 Rietveld 的 python 源代碼做了一些修改, 很快解決了。 第3個問題我們一直解決得不好。 不過當時來說支撐我們幾個小組的開發還是 OK的。 所以 yiwang 開始繼續推動 Rietveld 在 R2 的使用。 到了 2011 年的時候這套工具已經在 R2 的多個部門被使用了。 下面一張圖是我們曾經統計過的各個部門當時的使用情況


2010 年我們在推廣 codereview 的時候, yiwang 也聯繫了研發管理部的同事, 也就是 code.oa.com 的維護人員, 當時 code.oa.com 並沒有嚴格意義的 codereview 功能。 它提供一個代碼 checkin 之後進行 codereview 的功能, 所以也沒有發送 codereview 的 upload.py 腳本;這個功能自然是有用的,但是事後的 review 往往有缺陷, 很難替代事前的 review。事實上更重要的問題是, 公司內部當時並沒有形成 codereview 的文化。 yiwang 和研發管理部的人交流的時候強烈的推薦了 Rietveld 系統, 不久之後code.oa.com 也仿照 Rietveld 開發了正式的 codereview 功能,而用於提交issue 的 tcr.py 也正是基於Rietveld 的 upload.py 做的修改。

而在搜搜內部,狀況則有些不同。 Google 來的朱會燦帶領的搜索雲平臺(搜索基礎架構部)對 codereview 文化建設做了強力的推動, 基礎架構部門的幾個牛人開始使用這套系統之後, wujie, phong 他們接管了這套 CodeReview 系統, 當時上面提到的第三個問題當時已經成爲了一個嚴重的問題, wujie, phong 開始改進 Rietveld 的性能問題, 把底層的文本文件存儲替換爲 mysql 數據庫, 使用 apache 服務器替換了 Rietvled 基於 Django 的 HttpServer, 所以Rietveld 第三個和性能相關的問題也徹底被解決了。 後續 huanyu 申請了 codereview.soso.oa.com 這個域名專門提供 codereview 服務, 於是直到搜搜和搜狗合併, 搜搜內部的好幾個部門的兄弟們一直基於 Rietveld 系統做 codereview。

4. C++ Readability

搜索廣告部門的情境廣告中心應該是我經歷的 code review 文化建立得最徹底完善的地方。 當時 yiwang 是這個中心的總監,我和 huan 各負責一個小組, 我們中心要負責開發一套 AFC(ads for content) 的情境廣告產品, 和現在廣點通有很多相似之處。 huan, yiwang, 包括我們的 GM paulyan 都是 Google 的工程師, 而 AFC 這個產品幾乎是從零開始開發, 所以很自然的, 許多開發流程都是山寨的 Google 的, 雖然 AFC 這個產品最終由於各種原因並沒有在公司內部成功, 但是許多參與開發的工程師對於我們當時建立起來的開發流程應該是印象深刻的。 當然 codereview 是其中很重要的一個環節。 Huan 借鑑 Google 的CodeReview 流程, 在中心推動了一個 C++ readability 制度的建立。 一個語言的 readability 表示工程師對這個語言和相應的編碼規範的熟悉, 這個 C++ readability 最初只授予有限幾個高職級的工程師。 每一個 codereview issue 至少需要得到一位具有 C++ readabiltiy 的工程師的認可, 這個 issue 才能夠提交到代碼庫中。

而每一個沒有 C++ readability 的工程師要想獲得這個 readability, 需要提交一個 codereview issue 做專門的申請, 這個issue 的標題必須包含 “Apply for C++ Readability”, issue 至少包含三個文件, xxx.cc, xxx.h, xxx_test.cc, 如果這個 issue 通過嚴格的 codereview 被通過了, 就可以授予這個工程師 C++ readability 。 而通常這種申請的 review 過程大家都會特別的認真細緻。

5. 在廣點通 CodeReview


2013年10月, 搜索廣告平臺部併入廣點通成立了SNG 的效果廣告平臺部, 原來AFC 的系統由於這個合併事實上基本廢棄, 只是在開發過程中很多模塊組件被逐步遷移到了廣點通的系統上。 我們剛進入廣點通的時候, 廣點通使用 code.oa.com 平臺做 codereview, 也建立了一些 codereview 的文化, 但是有很多地方是執行不到位的。 coding style 雖然也推崇 Google coding style, 但是執行上不嚴格, 所以整個代碼庫的代碼風格是很不統一的。 這也給我們的 codereview 執行帶來很大的挑戰:

  • 舊的代碼風格不統一,我們如何統一代碼風格, 舊的代碼是否需要基於新的風格重寫?
  • 整個產品都在高速的開發迭代中,老大對於產品功能的開發演進有明確的期望, 產品經理天天在開發人員後面催進度, 我們是否要執行嚴格的 code review ?

廣點通最後還是明確的規定 coding style 統一到 Google C++ coding style, 我們團隊的 CodeReview 也整體轉戰 code.oa.com, 我們自己不再使用 Rietveld(不過這套系統並沒有被廢棄, wujie 2014年一月的時候把這套系統搭建起來服務於微信, 並申請了域名 cr.oa.com), code.oa.com 的 CodeReview 功能經過幾年的改進, 也確實變得很好用。 考慮到產品迭代的節奏, 我們廣告質量中心在推進的過程是漸進的:

  • 所有新提交的文件必須使用 google style
  • 所有新修改的代碼必須使用 google style
  • 在指定的時間範圍內, 重要模塊的 code 必須重構爲 google style

爲了讓 codereview 文化在廣點通能更加徹底的建立起來、執行到位, 幾位總監和架構師也迅速推動 code.oa.com 中實現了 code owner 的機制, 每個目錄下面明確設置 code owner, 每個change issue 要想提交, 必須有 code owner 通過纔可以。 而剛開始執行的時候, 廣告質量中心爲了保證 code review 執行到位, code review 是非常集權的, 所有相關目錄的 owner 只寫上總監。所以質量中心發出的所有 code review issue 只有總監通過了之後纔可以提交, 在一定的時間內這確實影響開發效率, 不過對教育所有開發人員的 code review 意識是高效的。 在經歷了近三週的嚴格控制之後, 目錄的owner 才加上組長, 然後逐步放開到組內的一些骨幹成員。

對於我們小組而言, 有一半是之前 AFC的開發人員, 經歷過嚴格的 codereview 訓練; 有一半是廣點通原來的開發人員,沒有經歷過嚴格的 codereview 訓練。 爲了教育大家的 codereview 意識,在小組的週會上我要反覆的強調 codereview 的重要性;同時我明確的指出每個人的考評是和 codereview 的表現相關的。

對於廣告業務的工程輸出主要包括項目中的設計文檔, 代碼實現, 線上A/B test實驗和實驗結果跟進分析, 以及日常在小組內的分享(平常積極的郵件討論,wiki 建設, 組內的 techtalk 分享等)。 所有的一線工程師, 無論職級高低,最重要的工程輸出原則還是 show me the code, 而 codereview 是最能夠反應這個客觀輸出的。 在小組內部, 我們儘量讓每個人的 codereview 參與狀況都公開透明, 所以我們要求

  • 每個 codereview issue 要明確發送到你的項目合作者, 項目合作者 review 之後才允許提交
  • 每個 issue 都必須全員轉發到小組內所有成員, 小組內的任何人只要願意,都可以去review 其他人的代碼

由於所有的 codereview issue 都會發送到小組內所有成員, 所以我是能夠在 code.oa.com 上看到所有人的 code 產出情況的。我通過給大家做 codereview 判斷小組每個工程師的工程輸出, code.oa.com 上大致是可以看到小組內每個人參與 codereview 的程度的, 包括他發出的 issue, 他給組內成員做的 codereview comments 等等。 code.oa.com 上提供了一個功能, 可以 dump 出所有人的 codereview issue, 所以考評的時候我會檢查每個成員在半年之內的 codereview 輸出狀況,檢查組內成員提交的 issue 的質量。

不過 code.oa.com 上查看每個人的 codereview 參與狀況的功能現在還是太弱, 如果code.oa.com 能提供一個統計分析功能, 使得每個人可以看到自己的一些統計指標, 包括

  • 我修改的文件總數,修改和提交的代碼總行數
  • 我給合作者做了多少次 codereview, 提供了多少次 comments
  • 合作者給我做了多少次 comments

如果小組的組長能夠看到組內成員的這些統計指標,無疑對於考評每一個小組成員的工程輸出會提供很多客觀公正的信息。

6. CodeReview 感悟

做了4年的 CodeReview, 基本上這個流程在我們的團隊已經深入骨髓,成爲了小組工程工作中的種行爲習慣。 如果有一天我離開了騰訊, 我相信我在騰訊所經歷的相對嚴格的 CodeReview 訓練會幫我做好下一個項目的工程質量管理。 爲何要做 CodeReview 網絡上有很多的論證, 之前和 yiwang 合作的時候, 團隊內總結的幾點如下(主要都是 yiwang 總結的):

  • Code Review保證開發質量,整個過程有章可循,無需顧及“面子”,能夠修正很多平時不注意或者明知故犯的小毛病
  • Code Review高效溝通交流,不需電話和視頻會議,讓北京深圳兩地的同事們一起協同工作
  • Code Review幫助知識傳遞,團隊內細粒度的知識分享, 大家一起逐行的點評代碼比用技術交流會以及KM投稿更細緻
  • Code Review保證代碼的可持續使用,代碼風格不一致導致一個系統每次移交負責人都被重寫一次
  • Code Review和敏捷開發相容,而不是相斥,敏捷不是片面追求發佈次數,而是保證質量的發佈
  • CodeReview 是一種社交的途徑, 鼓勵小組成員之間多做技術交流
  • CodeReview 對新人的成長極其有利。 很多新人第一次做 codereview 的時候感覺都是慘不忍睹, 被拍暈了, 我見過的最慘的 issue 被要求修改了20多次之後才被允許提交。然而這種方式對新人的成長非常高效,一個coding 能力不錯的工程師, 幾個 codereview issue 之後, 很快就能寫出合格的代碼。
  • CodeReview 增加團隊內代碼的可維護性, 同一份代碼至少會有兩個人熟悉——代碼的作者和審閱者。

如何建設一個團隊的 code review 文化, 跟隨 Google 的腳步, 也有一些具體的意見:

  • 需要培養合格的reviewer。 建立各種編程語言的readability認證機制,從一組“種子”reviewer開始,讓更多同事獲得認證成爲合格的reviewers
  • 需要細化和公開各種語言的code style。 評註中可以給出建議的出處的URL,使得保持代碼風格和可維護性落到實處
  • 需要建立Code Lab機制。 幫助工程師們入門開發流程和規範
  • 需要建立change approval機制。 鼓勵組內更多工程師改進代碼(敏捷),但是修改在提交前除了必須通過review,還需要相關責任人的approval;在加速開發滾動的同時,保證權責分明
  • 引導輕量 review。我們都經歷過有些工程師發一個 change issue 的時候, 幾十個文件一併發出來, 一個 issue 可能是累積一週的修改, reviewer 看到這種 issue 幾乎都是崩潰的,不可能保證 review 質量。 所以好的 issue 應該是輕量的, 大的 issue 應該拆分爲小的 issue 發送。下圖是 Cisco 公司的codereview 報告中摘出的, 如果一個 issue 的修改代碼行數超過 400, 基本上 reviewer 是不可能認真 review 幫你找出 bug 的 。

  • 明確issue 能否提交是工程師自己的責任。開發人員有時候抱怨別人 review 得慢, 拖延時間。 我們小組內部通常明確指出:一個 issue 能否提交是開發人員自己的責任。 開發人員自己要積極推動合作人員幫忙 review issue, 推動 issue 被通過並及時提交。

7. 結語

學術界的所有高質量論文都是 peer review 之後纔有可能發表的。 寫過 paper 的碩士博士都有一個體會, 接到的各種 review 意見有時候令你非常的痛苦, 然而無論是你拒絕了 reviewer 的意見,還是接受意見修改了文章, 你都會經歷一個認真思考的過程去提升你文章的質量。 高質量的論文是科研人員嚴格 review 出來的, 我相信高質量的 code 也可以通過工程師的 review 產生。 把CodeReview 打造成團隊的習慣,而我們逐漸會發現這種習慣所釋放出來的正能量。 希望有一天, 我們也能做到:

At Tencent, no code, for any product, for any project, gets checked in until it gets a positive review。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章