八招幫你執(zhí)行快速代碼審查
譯文【51CTO.com快譯】如果您有過代碼審查的經(jīng)驗(yàn),一定經(jīng)歷過高頻、耗時(shí)且繁瑣的拉取請求、提交確認(rèn)、以及批準(zhǔn)等過程。為了避免凌晨5點(diǎn),您還在孤獨(dú)地審查著從團(tuán)隊(duì)分配來的代碼,我們走訪了該領(lǐng)域的專家與用戶,收集到了如下小貼士,以方便您快速高效地完成任務(wù)。
1、審查較小部分
通常而言,更小的提交會導(dǎo)致更小、且更易于管理的代碼審閱。人們往往需要花較長的時(shí)間,去理解由大塊代碼的修改所涉及到的大量依賴項(xiàng)。而小塊的修改不僅能夠節(jié)省代碼審查的時(shí)間,而且能夠減輕審查人員的認(rèn)知負(fù)擔(dān),方便審查過程的流暢開展。可以說,將工作量分成較小的部分,往往可以使團(tuán)隊(duì)成員加深對于變更意圖與方式的了解。
有調(diào)查表明:一次性審查約400行代碼的效果是最佳的。否則,過多的代碼量,會直接導(dǎo)致審查者發(fā)現(xiàn)問題能力的下降。當(dāng)然,我們也可以根據(jù)實(shí)際使用的平臺、以及開發(fā)的語言,略作調(diào)整。如今大家都在談?wù)?ldquo;長期主義”。一開始,大家可能會不太適應(yīng)這種較小的審查提交方式,但是如果能長此以往地堅(jiān)持下去,它的好處將非常明顯。
2、時(shí)限要求
與代碼測試相比,代碼審查環(huán)節(jié)往往被要求在有限的時(shí)間內(nèi)完成并提交。為了能夠及時(shí)地發(fā)現(xiàn)代碼本身、及其架構(gòu)和時(shí)序等相關(guān)問題,審查人員往往需要對代碼具有充分的了解。因此,在這種“時(shí)間緊、任務(wù)急”的情況下,團(tuán)隊(duì)需要對待代碼的審查重點(diǎn)排定優(yōu)先級。例如,我們可以針對如下方面,根據(jù)實(shí)際情況進(jìn)行審查:
- 條件判斷語句或其他邏輯是否合理?
- 代碼中的字符串是否已格式化?
- 是否在不必要之處使用了同步或鎖的操作?
- 是否采用了原子變量?
- 是否使用了不必要的線程,且是否安全?
- 數(shù)據(jù)結(jié)構(gòu)是否安全且高效?
根據(jù)上述要點(diǎn),我們整理出一份審查清單(下文將會提到),以方便團(tuán)隊(duì)合理地安排時(shí)間與精力。當(dāng)然,即使在項(xiàng)目進(jìn)度緊迫,無法進(jìn)行完全代碼審查的情況下,我們也需要保證新的、關(guān)鍵性的、具有依賴關(guān)系的代碼部分,能夠被審查到。
3、對事不對人
代碼審查講求的是以”對事不對人”的態(tài)度,全面提高代碼的質(zhì)量。例如:倘若甲發(fā)現(xiàn)了乙的代碼中存在著問題,這并不意味著甲的編程能力強(qiáng),而乙的能力弱。我們更不能據(jù)此去懲罰乙(當(dāng)然,獎(jiǎng)勵(lì)甲是應(yīng)該的)。否則,甲可能因?yàn)楹ε缕茐牧伺c團(tuán)隊(duì)中其他成員的關(guān)系,而不愿在審查中指出真實(shí)潛在的問題,進(jìn)而導(dǎo)致代碼的審查效果失真。
此外,有些團(tuán)隊(duì)會將代碼審查的任務(wù)集中在某個(gè)專人身上。這樣除了會造成人員安排上的單點(diǎn)風(fēng)險(xiǎn)以外,還會造成其工作量上的繁重和認(rèn)知度上的局限性。
4、共享編碼與審查準(zhǔn)則
既然不合適將代碼審查任務(wù)固定地托付給一個(gè)人,那么我們勢必要構(gòu)建一個(gè)團(tuán)隊(duì)或小組。而為了保證集體智慧“在線”,我們需要讓所有參與者都事先了解相關(guān)的審查準(zhǔn)則。例如:
- 規(guī)范化針對代碼添加的注釋,闡明代碼修改的原因,以方便后續(xù)者的解讀。
- 修正編碼風(fēng)格,尤其是一些關(guān)鍵性的數(shù)據(jù)結(jié)構(gòu)、以及方法的命名規(guī)則。
- 審查是否充分考慮到了變量或異??赡艹霈F(xiàn)的所有情況。
當(dāng)然,對于不同的編程語言與平臺,我們可以采取略有不同的編碼與審查準(zhǔn)則,并記錄在案。下面是在社區(qū)里被廣泛采用的代碼樣式標(biāo)準(zhǔn)。它們可以促進(jìn)和加速新的成員,在代碼風(fēng)格上盡快地融入團(tuán)隊(duì)。
- Ruby - http://www.caliban.org/ruby/rubyguide.shtml
- Community-driven - https://github.com/bbatsov/ruby-style-guide
- Github’s style - https://github.com/styleguide/ruby
- SO Answer - http://stackoverflow.com/questions/616037/ruby-coding-style-guidelines
- Rubydoc - http://ruby-doc.com/docs/ProgrammingRuby/
- Javascript - https://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml
- Crockford’s guide - http://javascript.crockford.com/code.html
- Felix’s Node style - https://github.com/felixge/node-style-guide
- Mozilla - https://developer.mozilla.org/en-US/docs/JavaScript_Tips
- Idiomatic.js - https://github.com/rwaldron/idiomatic.js
- Python - http://google-styleguide.googlecode.com/svn/trunk/pyguide.html
- Guido’s PEP8 - http://legacy.python.org/dev/peps/pep-0008/
- python-guide.org - http://docs.python-guide.org/en/latest/writing/style/
- PHP - https://developer.wordpress.org/coding-standards/wordpress-coding-standards/php/
- Pear - https://dev.topear/
- PHP-FIG - http://www.php-fig.org/
- PSR-0: Autoloader Standard - https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
- PSR-1: Basic Coding Standard - https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md
- PSR-2: Coding Style Guide - https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md
5、審查清單
常言道,“按圖索驥,效率最高”。我們可以參考如下清單,來逐條檢查并提高代碼審查的流程與效率。
編程習(xí)慣方面
- 是否刪除了每行代碼尾部的多余空格。
- 是否存在從未被用到的變量。
- 是否針對變量、方法、以及類采用了相同的命名規(guī)則。
- 對于括號、循環(huán)、if語句等是否采用了統(tǒng)一的格式。
- 是否將常量寫在了獨(dú)立的常量類中。
- 是否針對不同的異常(exception),采用了不同的捕獲(catch)語句。
- 是否避免了單個(gè)方法過于冗長。
- 為了避免一條語句過長,且超過編輯工具的可視區(qū)域,是否按需對其進(jìn)行了拆分。
- 是否給各種方法添加了適當(dāng)?shù)脑L問控制,而非一律采用public。
- 是否合理地用到了靜態(tài)工廠方法,而非重載構(gòu)造函數(shù)。
功能方面
- 如果某個(gè)邏輯會被多次使用到,那么就應(yīng)該將它寫成幫助類或是API,以便被頻繁調(diào)用。
- 不同語言的代碼不應(yīng)被相互混用。例如,在JSP中就不應(yīng)包含Java代碼。
安全方面
- 任何代碼在未經(jīng)轉(zhuǎn)義之前,都不應(yīng)直接執(zhí)行用戶的輸入。例如JavaScript中的eval函數(shù),以及SQL語句。
- 在代碼級別上,禁止那些在較短時(shí)間內(nèi),被大量提交的IP請求。
- 是否為每個(gè)類、變量、以及方法都設(shè)置了正確的訪問域。
性能方面
- 是否能及時(shí)地關(guān)閉不需要的數(shù)據(jù)庫實(shí)例、以及文件的操作句柄。
- SQL語句的用法是否規(guī)范。
- 是否按需創(chuàng)建了immutable的類。
- 是否避免使用了heavy對象。
- 是否將全局信息保存在“application context”中。
文檔方面
- 是否說明了代碼中的每一個(gè)類、方法、及其基本邏輯。
- 是否提供了針對復(fù)雜的HTML、JavaScript、以及CSS等相關(guān)文檔說明。
- 是否為代碼文件的頭部添加了相關(guān)的版權(quán)信息。
- 如果是對某個(gè)缺陷的修復(fù),是否分配了對應(yīng)的缺陷ID。
與此同時(shí),您可以參考諸如:DRY、SRP、KISS、YAGNI、Smell等原則, 以及如下三種審查清單模板:
- http://www.codeproject.com/Articles/593751/Code-Review-Checklist-and-Guidelines-for-Csharp-De
- http://courses.cs.washington.edu/courses/cse403/12wi/sections/12wi_code_review_checklist.pdf
- https://www.liberty.edu/media/1414/%5B6401%5Dcode_review_checklist.pdf
6、使用自動(dòng)化協(xié)同審查工具
在處置Git存儲庫里的頻繁提交等場景時(shí),光靠一雙眼睛式的人工審查方式,顯然是非常低效且耗時(shí)的。為了發(fā)揮團(tuán)隊(duì)的優(yōu)勢,我們需要引入?yún)f(xié)同審查工具,以實(shí)現(xiàn)更快速、更自動(dòng)化、更全面的合作式審查。目前,Github、Bitbucket和GitLab都能夠通過拉取式請求的特性,提供內(nèi)置的代碼審查工作流。當(dāng)然,我們也可以用到諸如:CheckStyle、PMD、FindBugs、Upsource、以及Codacy等工具。
7、使用短路
如果您時(shí)間非常緊迫,并且無法去逐行檢查代碼的內(nèi)容,那么請采用“抓大放小”漸進(jìn)的方法。畢竟,那些在函數(shù)調(diào)用時(shí)可能引起緩沖區(qū)溢出的問題,以及在生產(chǎn)環(huán)境中會導(dǎo)致程序崩潰的潛在缺陷,比起一眼可以看出的代碼樣式問題,要重要得多。您可以在代碼檢查中,插入所謂短路(short-circuiting)元素,以事先處置和糾正重大的問題,而將較小的缺陷,留待將來時(shí)間充沛時(shí),再予以更正。
8、提交與確認(rèn)
從某種意義上說,代碼審查旨在提高開發(fā)者的編程能力,讓其從自身犯過的錯(cuò)誤中吸取教訓(xùn),從他人的修改思路中學(xué)習(xí)進(jìn)步,而應(yīng)當(dāng)避免其產(chǎn)生抵觸或反感情緒。
值得注意的是,代碼審查人員不應(yīng)以交付時(shí)限為由,針對其發(fā)現(xiàn)的問題,直接對代碼進(jìn)行修改,甚至予以重構(gòu),而應(yīng)當(dāng)提請代碼開發(fā)人員進(jìn)行確認(rèn)。此方法不但可以確認(rèn)問題是否真實(shí)存在,并共同獲取最佳解決方案;而且可以讓代碼作者深入了解其自身的不足,協(xié)助其不斷進(jìn)步。作為參考,您可以通過鏈接--https://www.kernel.org/doc/Documentation/SubmittingPatches,借鑒一下Linux內(nèi)核是如何指導(dǎo)其開發(fā)社區(qū)進(jìn)行問題的提交與處置的。
原文標(biāo)題:Top 10 Ways to Perform Fast Code Reviews,作者:Gustavo Silva
【51CTO譯稿,合作站點(diǎn)轉(zhuǎn)載請注明原文譯者和出處為51CTO.com】