Code Review 程序員的寄望與哀傷

來自:https://zhuanlan.zhihu.com/p/21478902

一個程序員,他寫完了代碼,在測試環境通過了測試,然後他把它發佈到了線上生產環境,但很快就發現在生產環境上出了問題,有潛在的 bug。

事後分析,是生產環境的一些微妙差異,使得這種 bug 場景在線下測試中很難被發現。畢竟想要在測試環境完美的複製生產環境的所有情況也是不太可能的,導致出現了疏漏。對於這類情況,我們在想是否可以通過在線下做一些 Code Review(代碼審查)假想線上的環境差異,通過在頭腦中的假想上線運行來獲得一些概念驗證,這樣是否能夠減少上線後出現 bug 的概率呢?

感性

Code Review 是很多軟件工程理論和方法學中的重要一環,而且程序員們大多都感性的認識到 Code Review 對於提升代碼質量和減少 bug 有幫助,但在我過去工作的這些年裏,經歷了幾家公司,數個不同的團隊,卻幾乎沒有把 Code Review 作爲必要的一環去執行的團隊。

過去,總是在線上出現一些奇怪的疑難問題後,我們一羣程序員才圍坐一堆,打開相關代碼來逐行分析,根據線上現場的屍檢來做事後分析和推導,這樣的代碼審查和分析實際上根本不是 Code Review,也完全違背了 Code Review 的初衷。Code Review 的初衷是在代碼進入生產環境前經過同行評審來減少代碼出現 bug 的概率。這一點程序員都好理解,提前的 Code Review 就像雷達掃描我們重點關注的代碼領地,以期發現或明顯或隱藏的威脅因素。

想必很多人都看過一部叫《火影忍者》的漫畫,裏面有一種忍術技能——白眼。根據忍者能力強弱白眼能觀察的距離不同,雖然白眼有近 360° 的觀察範圍,依然存在觀察死角。不是所有的程序員都擁有類似「白眼」的技能,我們在寫程序時力求思考的全面,不留死角或盲點,但實際死角或盲點總是存在,隨着程序員經驗或經歷的成長,思考和認識的越發全面(越發接近 360°),擁有了近乎「白眼」的能力,但像白眼一樣依然存在盲點。

我們看不到自己的後腦勺,所以假如在我們的後腦勺放上一個夥伴的眼睛,他的視角就彌補了我們自己的盲點。世上沒有兩片完全一樣的樹葉,也許也不會有兩個認知視角完全重疊的人。

像 Code Review 或結對編程這樣的實踐正是基於這樣的感性認知,試圖找出盲點區域的 bug,但到底這樣的做法能降低多少出現 bug 的概率呢?

理性

有人對 Code Review 的作用進行了更理性且量化的分析,來自 Wikipedia(維基百科)。

卡珀斯·瓊斯(Capers Jones)分析了超過 12,000 個軟件開發項目,其中使用正式代碼審查的項目,發現潛在缺陷率約在 60-65% 之間,若是非正式的代碼審查,發現潛在缺陷率不到 50%。大部份的測試,發現的潛在缺陷率會在 30% 左右。

一般的代碼審查速度約是一小時 150 行程式碼,對於一些關鍵的軟體(例如安全關鍵系統的嵌入式軟體),一小時審查數百行程式碼的審查速度太快,可能無法找到程式中的問題。代碼審查一般可以找到及移除約 65% 的錯誤,最高可以到 85%。

也有研究針對代碼審查找到的缺陷類型進行分析。代碼審查找到的缺陷中,有 75% 是和計算機安全隱患有關。對於產品生命週期很長的軟件公司而言,代碼審查是很有效的工具。

從上面的實驗分析結果看,Code Review 對於發現潛在缺陷很有用(相比測試能發現的缺陷率高一倍),但也需要投入巨大的時間成本(一小時審查 150 行代碼,再快就不利於發現潛在缺陷了),而且更適用於長生命週期的產品。

所以,有個現象就容易理解了。我發現在同一家公司做 Code Review 較多的都是研發通用底層技術產品或中間件的團隊,而做業務開發的團隊則較少做 Code Review。一方面是底層技術產品或中間件的需求較穩定,且生命週期長,而業務項目(特別是嘗試性的新業務)需求不穩定,時間要求緊迫,而生命週期很多都偏短。

困難

通過了理性的分析我們可以看出 Code Review 是有很大好處的,但適用的場景和花費的成本也需要去平衡。除了這點,也許還有一些關於如何實施 Code Review 的困難。

如果把 Code Review 作爲一個必要環節引入到研發流程中,也許會引發下面一些問題:項目 deadline 已定,時間緊迫,天天加班忙成狗了,誰還願意搞Code Review?這是一個最常見的客觀阻礙因素,因爲 deadline 很多時候都不是我們自己確定的。

即使強推下去,團隊認識不到其好處,也不夠重視,每次走個過場,Code Review 的效果如何能保障?如果你是一個父親,爲自己的孩子制定一個最簡單的規則,比如說:飯前洗手。你如何保障這個規則的實施效果,你當然可以每次喫飯前檢查下孩子的手是否乾淨,但你也很難每頓飯都和孩子一塊兒喫,所以你就檢查不到了。要是孩子有個智能的碗,當孩子喫飯時手一接觸到碗就能檢測細菌是否超標,然後發出提醒和拒絕措施,這樣是否就保障了這個規則與你在或不在的實施有效性。而 Code Review 顯然是個更復雜的規則,需要的智能工具支持也更復雜。

團隊人員結構搭配不合理,新人沒經驗的多,有經驗的少。天天安排經驗多的少數人幫助 review 多數新人的代碼,新人或有收穫,但對高級或資深程序員又有多大裨益?一個好的規則或制度總是需要既符合多方參與者的個體利益又能滿足組織或團隊的共同利益,這樣的規則或制度才能順暢的實施和運轉。

若你的團隊中存在一些自信超強大的程序員,覺得自己的寫的代碼絕對沒 bug,不需要別人來給我 review。這樣的人未必就很差,他寫的代碼甚至確實出 bug 的概率比普通人更低,但肯定依然存在潛在 bug。這樣團隊成員的存在,也會成爲 Code Review 的一個障礙。

路徑

Code Review 確實存在很多各種各樣的困難,導致很多團隊都能認識到它的好處卻實施不下去。尤其在國內,我幾乎沒聽說過嚴格把 Code Review 作爲一項研發制度或規則要求的公司。

但在大洋的另一端,無論是老牌大公司如 Google 或是新近崛起的創業公司如 Airbnb 都把 Code Review 作爲上線進入生產環境前強制且必須的一環。在一篇介紹 Google Code Review 的實踐文章中說道,在 Google 任何產品,任何工程的代碼,在被進行嚴格或者明確的審查(Code Review)之前,是不允許提交的。你看,Google 通過工具控制在進行 Code Review 前甚至是無法提交代碼的。

Google 以一種強硬的姿態來制定關於 Code Review 的且應用於全公司範圍內的規則,對任何人都不例外。即使面對團隊中超自信且強大的程序員也無例外,要麼遵守規則,要麼離開組織。這一點從 C 語言和 Unix 的發明者、圖靈獎得主、最具傳奇性的程序員 Ken Thompson 在 Google 的趣事——作爲 C 語言發明者之一因爲沒有參加 Google 的編程語言能力測試所以無法在 Google 提交 C 代碼——從中可以一窺 Google 規則的強硬性。

所以像 Google 這樣的公司對於 Code Review 屬於高度認可且有公司制度和規則的強硬支持,再輔助自動檢測和控制工具的嚴格執行,方能如此。這也屬於一種嚴格的同步 Code Review,所謂同步就是必須要等待 Code Review 有了結果並無異議後方能提交或上線代碼。

但要實施如此嚴格的同步 Code Review 似乎對大部分國內公司又感覺過於無奈,這需要公司制度、團隊文化和技術工具三方面的支持。而在大部分以業務目標、KPI和績效導向的公司,不說在制度和文化方面得到支持,能不被反對就不錯了。關於這一點陳皓(@左耳朵耗子)寫過一篇文章《從 Code Review 談如何做技術》其中寫到了在阿里實施 Code Review 遇到的各種文化上的阻礙和反對。而阿里已是國內頂級互聯網公司,可見實施同步 Code Review 的路徑並不簡單。

如果實施同步 Code Review 如此困難,那麼是否可以退而求其次,設計一種異步的 Code Review 方式呢?就像我們提升系統性能一樣,把一些同步的串行調用變成異步的並行調用,按這個思路 YY 了以下場景。

程序員完成編碼,提交測試,測試通過後就去上線發佈,另一方面也組織並行的 Code Review。畢竟測試通過只能證明測試覆蓋的場景無 bug,但可能代碼實現並不優化和合理,而並行的 Code Review 即使發現了潛在問題依然來不及阻止本次上線,但可以爲下次上線提供優化點或方向。另外在制度上把 Code Review 作爲工程師的日常 KPI,比如:要求每週對其他同事的代碼變動做 1~2 次 Review。

而 Review 的方式除了閱讀代碼,也可以爲 Review 的代碼提供 Unit Test 間接達到了結對編程的目的。爲了確保代碼確實被 Review 過需要工具支持,對 Review 過的代碼進行簽名,對不同的 Review 形式(簽名表示讀過,Unit Test 表示不僅讀過還白盒測試過)進行分類統計,發佈 Code Review 統計排行榜和覆蓋分析。

以類似這樣的方式,逐步培養起交叉 Code Review 的文化和氛圍,同時也顯性將 Code Review 納入了程序員的工作業績之中。一開始不必像同步 Code Review 一樣對所有上線進行了阻塞,帶來巨大的陣痛。當然這也依然是一個理想化的 YY 場景,實施起來依然需要克服不少困難和準備前提工具。

在另外在一篇叫《谷歌是如何做代碼審查的》文章中,一位 Google 的工程師對 Code Review 的認識是:

代碼審查的最大的功用是純社會性的。

還有一個非常重要的好處,代碼審查能傳播知識。

而防止 bug 混入,這反倒是它最不重要的一點。

第一點是這麼理解的,如果你在編程,而且知道一定將會有同事檢查你的代碼,那麼你編程的姿勢和態度都會完全不同。之間的微妙差異可類比於你是在爲公司的內部系統編程,還是在給開源軟件貢獻代碼。這是一個很有趣的視角,它其實反應了公司的制度和文化。

現實

以前嘗試過要在團隊內部做 Code Review,聽說兄弟團隊搞得不錯,然後就一起交流經驗,最後交流的重心就落在了應該選個什麼好用的 Code Review 工具來做,如今想來這完全是捨本逐末了。

這就像以爲有了好的編輯器(或 IDE)就能寫出好的代碼一樣,事實就是有很多好用的 Code Review 工具我們依然做不好 Code Review。古龍小說《陸小鳳》中有一段描述,記憶尤深:

西門吹雪:此劍乃天下利器,劍鋒三尺七寸,淨重七斤十三兩。

葉孤城:好劍。

西門吹雪:的確是好劍。

葉孤城:此劍乃海外寒劍精英,吹毛斷髮,劍鋒三尺三,淨重六斤四兩。

西門吹雪:好劍。

葉孤城:本就是好劍。

劍是好劍,但最好先成爲像西門吹雪或葉孤城這樣的好劍客,再來居高俯視、吹毛斷髮的談劍是否是好劍。

即使在最差的環境下,完全沒有人關心 Code Review 這件事。一個有追求的程序員依然可以做到一件事,自己給自己 review。就像寫文章,我寫完一篇文章從來不會立刻發佈,而是從頭腦中放下(unload),過上一段時間(也許是幾小時、也許是幾天)再自己重新細讀一遍,改掉其中必然會出現的錯別字或文句不通暢之處,甚或論據不充分或不準確的地方,因爲我知道不管我寫了多少文字,總還會有這些 bug,這就是給自己的 review。

即使如此,有時發出去的文章還是依然存在 bug,但總會比不 review 少了些。程序員在估算開發任務時也最好加上自己給自己 review 的時間,給自己 review 是一種自省,自我的成長總是從自省開始。

...

我提交了一段代碼,卻沒人給我 review,稍後我自己給自己 review 了,得到了一段更好的代碼和一個更好的自己。

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