image先來看一個令無數(shù)技術(shù)Leader聞風喪膽的項目“死亡”三角,業(yè)務(wù)壓力引發(fā)代碼質(zhì)量下降,代碼質(zhì)量下降引發(fā)開發(fā)效率下降,開發(fā)效率下降又加重了業(yè)務(wù)壓力,最終導(dǎo)致業(yè)務(wù)壓力山大,乃至項目爛尾。如何破解?方法有很多,像精簡業(yè)務(wù)需求、增加開發(fā)人手、升級技術(shù)架構(gòu)等,很多時候需要多管齊下,但凡打掉這個“死亡”三角中的任何一角,就能終止這個惡性循環(huán),甚至逆轉(zhuǎn)為良性循環(huán)。
代碼評審(Code Revew,簡稱CR)的首要打擊目標顯然是“爛代碼”。避免“爛代碼”的最好時機是寫代碼的時候,其次是代碼評審的時候。IBM 的 Orbit 項目有 50 萬行代碼,使用了 11 級的代碼檢查(其中包含代碼評審),結(jié)果是項目提前交付,并且只有通常預(yù)期錯誤的 1%。一份對 AT&T 的一個 200 多人組織的研究報告顯示,在引入代碼評審后,生產(chǎn)率提高了 14%,缺陷減少了 90%。那到底什么是代碼評審?如何進行代碼評審?繼續(xù)往下看。
1 CR 祛魅
我個人認為代碼有這幾種級別:1)可編譯,2)可運行,3)可測試,4)可讀,5)可維護,6)可重用。通過自動化測試的代碼只能達到第3)級,而通過CODE REVIEW的代碼少會在第4)級甚至更高。
—— 陳皓
下面 8 條有關(guān) CR 的闡述,你覺得哪些是正確的?
- 搞形式主義,存粹是浪費時間
- CR 是保證程序正確性的手段
- CR 是保證代碼規(guī)范的手段
- CR 是 Leader 的事,跟我沒關(guān)系
- 我只看指給我的 CR,其他 CR 跟我沒關(guān)系
- 沒有時間 CR,直接 Merge
- CR 必須一行不落從頭看到尾
- CR 必須一次完成
———————————————————————————————— 請仔細思考 60 秒
3...2...1...時間到,你的答案是幾條?很抱歉,在我看來,沒有一條是正確的。1、4、5、6 是送分題,顯然都是錯誤的。7 是眉毛胡子一把抓,CR 就像讀書,不是所有的書都適合精度,也不是所有的代碼都需要評審。8 是任務(wù)心態(tài),為了 CR 而 CR,CR 的目的不是完成 CR,而在于提升代碼質(zhì)量,你寫代碼時也不會一次完成所有功能。比較有爭議的是 2 和 3,誠然,正確性和代碼規(guī)范都是 CR 要關(guān)注的方面,但這并不意味著 CR 要保證正確性和代碼規(guī)范(CR 也沒法保證),保證正確性的主要手段是測試(單元測試,集成測試,契約測試,功能測試,自動化測試等),而保證代碼規(guī)范主要依靠代碼規(guī)范檢查工具(像常用的 checkstyle 和 PMD)。
CR 到底是什么?依我所見,CR 本質(zhì)上是一種討論,一種嚴肅的、專業(yè)的、異步的以文字形式呈現(xiàn)的討論,隨意性和情緒化是 CR 的大忌。什么叫隨意性?未經(jīng)審視的評論。什么叫情緒化?因時而異,因人而異。高水平的 CR 首先要忘掉自己。
2 知:CR 的三重境界
技術(shù)水平?jīng)Q定了 CR 的下限,認知高度決定了 CR 的上限。所以說 CR 水平高不高,最終還是看認知水平。認識 CR 有三重境界,分別是執(zhí)行層、團隊層和文化層。
2.1 執(zhí)行層:昨夜西風凋碧樹,獨上高樓,望盡天涯路
第一層為執(zhí)行層,顧名思義就是通過如何做來認識 CR。以下列舉 CR 時需重點關(guān)注的六個方面,并輔以相應(yīng)的例子便于理解。
1)關(guān)注代碼規(guī)范。命名是第一位的,一個令人費解的命名背后往往隱藏著一個設(shè)計紕漏。其他諸如空白字符、換行、注釋等問題,也會影響代碼的可讀性和可理解性。
2)避免重復(fù)代碼。編程法則第一條,Don't repeat yourself. 重復(fù)代碼是萬惡之首,重復(fù)代碼人人得而誅之!
3)降低圈復(fù)雜度。什么是圈復(fù)雜度?簡單來說就是代碼中 if/case/for/while 出現(xiàn)的次數(shù)。圈復(fù)雜度越高,BUG 率越高。如果一個方法的圈復(fù)雜度達到 3 或者更高,那么 CR 時就要多看兩眼。
4)關(guān)注性能問題。性能問題雖然不常見,可一旦暴雷往往就是大問題。CR 時看到循環(huán),記得多留一個心眼。
5)關(guān)注分布式事務(wù)。涉及遠程服務(wù)調(diào)用,或者跨庫更新的場景,都應(yīng)考慮是否存在分布式事務(wù)問題,以及適用何種處理方式,是依賴框架保證強一致性,還是記錄異常數(shù)據(jù)保證最終一致性,抑或是直接忽略?
6)關(guān)注架構(gòu)設(shè)計。代碼有代碼規(guī)范,架構(gòu)有架構(gòu)規(guī)范。面對一個新功能的 MR(Merge Request),除了檢查架構(gòu)規(guī)范,還應(yīng)推敲其架構(gòu)設(shè)計,比如是否符合整潔架構(gòu)三原則,無依賴環(huán)原則,穩(wěn)定依賴原則,穩(wěn)定抽象原則。
除了線上 CR,還有一種特殊的線下 CR 方法,就是跳過 MR,直接拉取代碼,進行整體 CR,將評審意見在代碼中標記為 TODO 或者 FIXME,然后 @ 相關(guān)開發(fā)進行改進。這樣做最大的好處,就是避免受單個 MR 的影響,掉入只見樹木不見森林的陷阱。
2.2 團隊層:衣帶漸寬終不悔,為伊消得人憔悴
接下來再看第二層,如何從團隊視角認識 CR。前面說了,CR 本質(zhì)上是一種討論,培根說過「讀書使人完整,討論使人完備」,從個人到團隊,CR 分別意味著什么?
提升自我覺察能力:這是從個人視角來看,當你知道你寫的代碼會有另一雙眼睛來審閱,那你寫代碼時就會保持一份警覺,放棄天知、地知、我知、你不知的幻想,認認真真寫好每一行代碼。
建立良好開發(fā)節(jié)奏:這是從團隊視角來看,CR 是團隊的同步器,每個人既是自己 MR 的作者,又是別人 MR 的評審者,從 MR 到 CR,再從 CR 到 MR,構(gòu)成了每個工作日最動聽的樂章。
高頻次的團隊活動:這也是從團隊視角來看,CR 既然是討論,那么就不僅僅是一個人的事,而是一種團隊活動,一種高頻次、高質(zhì)量、低成本的極具性價比的團隊活動。
2.3 文化層:眾里尋他千百度,驀然回首,那人卻在,燈火闌珊處
最后是文化層,CR 既是傳幫帶文化的重要組成,又是工程師文化的日常體現(xiàn)。
傳幫帶文化的重要組成:資深工程師 CR 初級工程師的代碼,可以給予高頻次、高質(zhì)量的指導(dǎo);初級工程師 CR 資深工程師的代碼,可以欣賞、學(xué)習高手如何把玩代碼,取其精華去其糟粕。
工程師文化的日常體現(xiàn):協(xié)作、高效、進取、影響力,這些在各大互聯(lián)網(wǎng)公司的工程師文化中頻頻出現(xiàn)的關(guān)鍵詞,無一不與 CR 緊密相連。不夸張的說,工程師文化香不香,就看 CR 做的好不好。
3 行:CR 高效之法
認識完 CR,我們再來探討一下如何高效的進行 CR。在我看來,高效 CR 首先有賴于以下幾個客觀條件和主觀條件。
客觀上來看,和諧的工程師文化和清晰的代碼規(guī)范是高效 CR 的兩塊基石。所謂和諧的工程師文化,就是說團隊對代碼秉持開放的心態(tài),不藏著掖著,以寫好代碼為榮,以寫壞代碼為恥,持續(xù)關(guān)注代碼質(zhì)量。而清晰的代碼規(guī)范,一方面提高了代碼的可讀性,另一方面也統(tǒng)一了編碼風格,極大的減少了不同代碼風格對評審者注意力的干擾。
主觀上來看,對評審者而言,第一要端正態(tài)度,保持謙卑的心態(tài),人非圣賢孰能無過,擇其善者而從之,其不善者而改之。第二要謹記評審的對象是代碼,而不是人,你寫下的每一條評審意見都應(yīng)基于客觀事實和數(shù)據(jù),做到有理有據(jù),不帶個人情緒。
基于我多年 CR 的實操經(jīng)驗,結(jié)合Google Code Review Developer Guide,我整理了一些高效 CR 的最佳實踐,供你參考:
- 依據(jù)個人偏好每天固定幾個時間段專門用于 CR,我的習慣是出門前和下班前。CR 耗費的腦力絲毫不亞于編碼,甚至更高,CR 過程中需要高度集中注意力。清醒的頭腦和無干擾的環(huán)境,是提出高質(zhì)量的評審意見的秘訣。
- 除了固定時間段,任務(wù)切換期間也是 CR 的好時機。
- 每次 CR 盡量控制在 15~30 分鐘以內(nèi),超過 30 分鐘應(yīng)休息一會。
- 收到 MR 之后,先判斷一下 MR 的性質(zhì),如果是 Bug Fix 類型的 MR,應(yīng)盡快評審,如果是新功能 MR,則可以等待下一個 CR 窗口。
- 從收到 MR 到 CR 結(jié)束,最長不要超過 1 個工作日。
- 開始 CR 之前先要搞清楚 MR 要解決的問題背景。
- CR 就像讀書,先看目錄(改動的文件列表),再精讀重點章節(jié)(包含核心業(yè)務(wù)邏輯的代碼),最后掃讀剩余章節(jié)。
- 如果改動的文件數(shù)量較多,可以打開 IDE,切換到源分支,方便在 CR 過程中隨時打開相關(guān)代碼進行閱讀。
- 評審核心代碼時,如果發(fā)現(xiàn)嚴重問題,應(yīng)立刻終止 CR,找 MR 提交者當面討論。
- 如果 MR 提交者對評審意見提出異議,評審者應(yīng)找提交者當面討論,避免在評論區(qū)互踢皮球。
- 合并代碼之前應(yīng)確保所有評審意見都被妥善處理。
- 記得點贊。CR 不是只能提意見,看到優(yōu)雅的代碼不要吝嗇你的表揚。
4 小結(jié)
2019 年 Stack Overflow 的一份調(diào)查報告顯示,超過 7 成的程序員會把 CR 當做日常工作的一部分,近 1/3 的程序員每周在 CR 上花費 2~3 個小時,還有 1/3 的程序員每周花費 4~5 個小時。心里默默算一下,你是在拖后腿還是領(lǐng)路者?如果你還沒做過 CR,那么趕緊行動起來;如果你已經(jīng)在 CR,很好,請繼續(xù)保持。一花一世界,一葉一菩提,碼中自有乾坤。CR,走起!