?
摘
要
Code Review
是一種通過(guò)復(fù)查代碼提高代碼質(zhì)量的過(guò)程,在
XP
方法中占有極為重要的地位,也已經(jīng)成為軟件工程中一個(gè)不可缺少的環(huán)節(jié)。本文通過(guò)對(duì)
Code Review
的一些概念和經(jīng)驗(yàn)的探討,就如何進(jìn)行
Code Review
和
Code Review
中應(yīng)該注意什么提出一些建議。
本文中涉及的問(wèn)題大部分針對(duì)
JAVA
類(lèi)代碼。同時(shí)本文不涉及
Code Review
過(guò)程和組織。
關(guān)鍵詞:
Code Review
,
JAVA
,
XP
,代碼質(zhì)量
,軟件工程
凡事知其然還要知其所以然
,
我們首先需要知道什么是
Code Review
和我們使用它的目的是什么。
Code Review
是一種用來(lái)確認(rèn)方案設(shè)計(jì)和代碼實(shí)現(xiàn)的質(zhì)量保證機(jī)制,通過(guò)這個(gè)機(jī)制我們可以對(duì)代碼,測(cè)試過(guò)程和注釋進(jìn)行檢查。
Code Review
主要用來(lái)在軟件工程過(guò)程中改進(jìn)代碼質(zhì)量,通過(guò)
Code Review
可以達(dá)到如下目的:
在項(xiàng)目早期就能夠發(fā)現(xiàn)代碼中的BUG
幫助初級(jí)開(kāi)發(fā)人員學(xué)習(xí)高級(jí)開(kāi)發(fā)人員的經(jīng)驗(yàn),達(dá)到知識(shí)共享
避免開(kāi)發(fā)人員犯一些很常見(jiàn),很普通的錯(cuò)誤
??? 保證項(xiàng)目組人員的良好溝通
??? 項(xiàng)目或產(chǎn)品的代碼更容易維護(hù)
知道了
Code Review
的目的,我們就可以看看如何做
Code Review
了,但在做
Code Review
前我們還有事要做,所謂預(yù)則立,不預(yù)則廢,就是說(shuō)如果在進(jìn)入
Code Review
之前我們不做些準(zhǔn)備工作,
Code Review
很容易就變得沒(méi)有意義或是流于形式,這在我們周?chē)怯泻芏嗬拥陌 _M(jìn)入
Code Review
需要檢查的條件如下:
a)
??????
Code Review
人員是否理解了
Code Review
的概念和
Code Review
將做什么
如果做
Code Review
的人員不能理解
Code Review
對(duì)項(xiàng)目成敗和代碼質(zhì)量的重要程度,他們的做法可能就會(huì)是應(yīng)付了事。
b)
?????
代碼是否已經(jīng)正確的
build
,
build
的目的使得代碼已經(jīng)不存在基本語(yǔ)法錯(cuò)誤
我們總不希望高級(jí)開(kāi)發(fā)人員或是主管將時(shí)間浪費(fèi)在檢查連編譯都通不過(guò)的代碼上吧。
c)
?????
代碼執(zhí)行時(shí)功能是否正確
Code Review
人員也不負(fù)責(zé)檢查代碼的功能是否正確,也就是說(shuō),需要復(fù)查的代碼必須由開(kāi)發(fā)人員或質(zhì)量人員負(fù)責(zé)該代碼的功能的正確性。
d)
?????
Review
人員是否理解了代碼
做復(fù)查的人員需要對(duì)該代碼有一個(gè)基本的了解,其功能是什么,是拿一方面的代碼,涉及到數(shù)據(jù)庫(kù)或是通訊,這樣才能采取針對(duì)性的檢查
e)
??????
開(kāi)發(fā)人員是否對(duì)代碼做了單元測(cè)試
這一點(diǎn)也是為了保證
Code Review
前一些語(yǔ)法和功能問(wèn)題已經(jīng)得到解決,
Code Review
人員可以將精力集中在代碼的質(zhì)量上。
好了,進(jìn)入條件準(zhǔn)備好了,有人在這些條件中看到
Code Review
這也不負(fù)責(zé),那也不檢查,不禁會(huì)問(wèn),
Code Review
到底做什么?其實(shí)
Code Review
主要檢查代碼中是否存在以下方面問(wèn)題:代碼的一致性、編碼風(fēng)格、
代碼的安全問(wèn)題、代碼冗余、是否正確設(shè)計(jì)以滿(mǎn)足需求(性能、功能等等),下邊我們一一道來(lái)。以下內(nèi)容參考了
《
Software Quality Assurance: Documentation and Reviews
》一文中的代碼檢查部分。
3
.
1
完整性檢查(
Completeness
)
代碼是否完全實(shí)現(xiàn)了設(shè)計(jì)文檔中提出的功能需求
代碼是否已按照設(shè)計(jì)文檔進(jìn)行了集成和
Debug
代碼是否已創(chuàng)建了需要的數(shù)據(jù)庫(kù)
,
包括正確的初始化數(shù)據(jù)
代碼中是否存在任何沒(méi)有定義或沒(méi)有引用到的變量、常數(shù)或數(shù)據(jù)類(lèi)型
代碼的邏輯是否符合設(shè)計(jì)文檔
代碼中使用的格式、符號(hào)、結(jié)構(gòu)等風(fēng)格是否保持一致
??????
代碼是否符合制定的標(biāo)準(zhǔn)
??????
所有的變量都被正確定義和使用
??????
所有的注釋都是準(zhǔn)確的
??????
所有的程序調(diào)用都使用了正確的參數(shù)個(gè)數(shù)
3
.
4
可修改性檢查(
Modifiability
)
??????
代碼涉及到的常量是否易于修改
(
如使用配置、定義為類(lèi)常量、使用專(zhuān)門(mén)的常量類(lèi)等
)
??????
代碼中是否包含了交叉說(shuō)明或數(shù)據(jù)字典,以描述程序是如何對(duì)變量和常量進(jìn)行訪(fǎng)問(wèn)的
??????
代碼是否只有一個(gè)出口和一個(gè)入口(嚴(yán)重的異常處理除外)
??????
代碼所用的開(kāi)發(fā)語(yǔ)言是否具有定義良好的語(yǔ)法和語(yǔ)義
??????
是否代碼避免了依賴(lài)于開(kāi)發(fā)語(yǔ)言缺省提供的功能
??????
代碼是否無(wú)意中陷入了死循環(huán)
??????
代碼是否是否避免了無(wú)窮遞歸
??????
代碼是否采取措施避免運(yùn)行時(shí)錯(cuò)誤(如數(shù)組邊界溢出、被零除、值越界、堆棧溢出等)
??????
程序的每個(gè)功能是否都作為一個(gè)可辯識(shí)的代碼塊存在
??????
循環(huán)是否只有一個(gè)入口
??????
代碼是否對(duì)每個(gè)程序進(jìn)行了唯一標(biāo)識(shí)
??????
是否有一個(gè)交叉引用的框架可以用來(lái)在代碼和開(kāi)發(fā)文檔之間相互對(duì)應(yīng)
??????
代碼是否包括一個(gè)修訂歷史記錄,記錄中對(duì)代碼的修改和原因都有記錄
??????
是否所有的安全功能都有標(biāo)識(shí)
??????
注釋是否足夠清晰的描述每個(gè)子程序
??????
是否使用到不明確或不必要的復(fù)雜代碼,它們是否被清楚的注釋
??????
使用一些統(tǒng)一的格式化技巧(如縮進(jìn)、空白等)用來(lái)增強(qiáng)代碼的清晰度
??????
是否在定義命名規(guī)則時(shí)采用了便于記憶,反映類(lèi)型等方法
??????
每個(gè)變量都定義了合法的取值范圍
??????
代碼中的算法是否符合開(kāi)發(fā)文檔中描述的數(shù)學(xué)模型
??????
代碼中的實(shí)現(xiàn)技術(shù)是否便于測(cè)試
以下是在實(shí)踐中建立的檢查列表
(
checklist
),
通過(guò)分類(lèi)和有針對(duì)性的檢查項(xiàng)
,
保證了
Code Review
可以有的放矢。
1
JAVA
編碼規(guī)范方面檢查項(xiàng)
檢查項(xiàng)參照
JAVA
編碼規(guī)范執(zhí)行
,
見(jiàn)《
JAVA
編碼規(guī)范
(
Java Code Conventions
)
》
這幾點(diǎn)的范圍都很大,不可能在本文展開(kāi)討論,有專(zhuān)門(mén)的書(shū)籍介紹這方面問(wèn)題,當(dāng)然在
Code Review
中主要靠經(jīng)驗(yàn)來(lái)判斷。
A)
??????
類(lèi)設(shè)計(jì)和抽象是否合適
B)
???????
是否符合面向接口編程的思想
C)
??????
是否采用合適的設(shè)計(jì)范式
性能檢查在大多數(shù)代碼中都是需要嚴(yán)重關(guān)注的方面,也是最容易出現(xiàn)問(wèn)題的方面,常常有程序員寫(xiě)出了功能和語(yǔ)法沒(méi)有絲毫問(wèn)題的代碼后,正式運(yùn)行時(shí)卻在性能上表現(xiàn)不佳,從而不得不做大量的返工,甚至是推倒重來(lái)。
A)
??????
在海量數(shù)據(jù)出現(xiàn)時(shí),隊(duì)列,表,文件,在傳輸,upload等方面是否會(huì)出現(xiàn)問(wèn)題,有無(wú)控制,如分配的內(nèi)存塊大小,隊(duì)列長(zhǎng)度等控制參數(shù)
B)
??????
對(duì)hashtable,vector等集合類(lèi)數(shù)據(jù)結(jié)構(gòu)的選擇和設(shè)置是否合適,如正確設(shè)置capacity,load factor等參數(shù),數(shù)據(jù)結(jié)構(gòu)的是否是同步的
C)
??????
有無(wú)濫用String對(duì)象的現(xiàn)象
D)
??????
是否采用通用的線(xiàn)程池、對(duì)象池模塊等cache技術(shù)以提高性能
E)
??????
類(lèi)的接口是否定義良好,如參數(shù)類(lèi)型等,避免內(nèi)部轉(zhuǎn)換
F)
??????
是否采用內(nèi)存或硬盤(pán)緩沖機(jī)制以提高效率
G)
??????
并發(fā)訪(fǎng)問(wèn)時(shí)的應(yīng)對(duì)策略
H)
??????
I/O方面是否使用了合適的類(lèi)或采用良好的方法以提高性能(如減少序列化,使用buffer類(lèi)封裝流等)
I)
????????
同步方法的使用是否得當(dāng),是否過(guò)度使用
J)
????????
遞歸方法中的疊代次數(shù)是否合適,應(yīng)該保證在合理的??臻g范圍內(nèi)
K)
??????
如果調(diào)用了阻塞方法,是否考慮了保證性能的措施
L)
???????
避免過(guò)度優(yōu)化,對(duì)性能要求高的代碼是否使用profile工具,如Jprobe等
?
對(duì)于
JAVA
來(lái)說(shuō)由于存在垃圾收集機(jī)制,所以?xún)?nèi)存泄漏不是太明顯,但使用不當(dāng),仍然存在內(nèi)存泄漏的問(wèn)題。而對(duì)于其它的語(yǔ)言,如
C++
等在這方面就要嚴(yán)重關(guān)注了。當(dāng)然數(shù)據(jù)庫(kù)連接資源不釋放的問(wèn)題也是廣大程序員最常見(jiàn)的,相信有很多的
PM
被這個(gè)問(wèn)題折磨的死去活來(lái)。
A)
??????
分配的內(nèi)存是否釋放,尤其在錯(cuò)誤處理路徑上(對(duì)非
JAVA
類(lèi))
B)
???????
錯(cuò)誤發(fā)生時(shí)是否所有的對(duì)象被釋放,如數(shù)據(jù)庫(kù)連接、
Socket
、文件等
C)
??????
是否同一個(gè)對(duì)象被釋放多次(對(duì)非
JAVA
類(lèi))
D)
??????
代碼是否保存準(zhǔn)確的對(duì)象
reference
計(jì)數(shù)(對(duì)非
JAVA
類(lèi))
線(xiàn)程安全問(wèn)題實(shí)際涉及兩個(gè)方面,一個(gè)是性能,另一個(gè)是資源的一致性,我們需要在這兩方面做個(gè)權(quán)衡,現(xiàn)在就是到了權(quán)衡利弊的時(shí)候了。
A)
??????
代碼中所有的全局變量是否是線(xiàn)程安全的
B)
???????
需要被多個(gè)線(xiàn)程訪(fǎng)問(wèn)的對(duì)象是否線(xiàn)程安全,檢查有無(wú)通過(guò)同步方法保護(hù)
C)
??????
同步對(duì)象上的鎖是否按相同的順序獲得和釋放以避免死鎖,注意錯(cuò)誤處理代碼
D)
??????
是否存在可能的死鎖或是競(jìng)爭(zhēng),當(dāng)用到多個(gè)鎖時(shí),避免出現(xiàn)類(lèi)似情況:線(xiàn)程
A
獲得鎖
1
,然后鎖
2
,線(xiàn)程
B
獲得鎖
2
,然后鎖
1
E)
???????
在保證線(xiàn)程安全的同時(shí),要注意避免過(guò)度使用同步,導(dǎo)致性能降低
A)
??????
循環(huán)結(jié)束條件是否準(zhǔn)確
B)
???????
是否避免了死循環(huán)的產(chǎn)生
C)
??????
對(duì)循環(huán)的處理是否合適,如循環(huán)變量,局部對(duì)象,循環(huán)次數(shù)等能夠考慮到性能方面的影響
很多
Code Review
人員在面對(duì)代碼中涉及到的數(shù)據(jù)庫(kù)可移植性和提高數(shù)據(jù)庫(kù)性能方面的沖突時(shí)表現(xiàn)的無(wú)所適從,凡事很難兩全其美的啊。
A)
??????
數(shù)據(jù)庫(kù)設(shè)計(jì)或SQL語(yǔ)句是否便于移植(注意和性能方面會(huì)存在沖突)
B)
??????
數(shù)據(jù)庫(kù)資源是否正常關(guān)閉和釋放
C)
??????
數(shù)據(jù)庫(kù)訪(fǎng)問(wèn)模塊是否正確封裝,便于管理和提高性能
D)
??????
是否采用合適的事務(wù)隔離級(jí)別
E)
??????
是否采用存儲(chǔ)過(guò)程以提高性能
F)
???????
是否采用PreparedStatement以提高性能
A)
??????
socket通訊是否存在長(zhǎng)期阻塞問(wèn)題
B)
??????
發(fā)送接收的數(shù)據(jù)流是否采用緩沖機(jī)制
C)
??????
socket超時(shí)處理,異常處理
D)
??????
數(shù)據(jù)傳輸?shù)牧髁靠刂茊?wèn)題
9
JAVA
對(duì)象處理方面檢查項(xiàng)
這個(gè)檢查項(xiàng)的基礎(chǔ)是對(duì)
JAVA
對(duì)象有較深的理解,但現(xiàn)實(shí)是很多看過(guò)《
Thinking in Java
》的程序員,仍然在程序中無(wú)法區(qū)分傳值和傳引用,以及對(duì)象和
reference
的區(qū)別。這或許就是理論和實(shí)踐難以結(jié)合的問(wèn)題啊。正所謂知而不行,非真知也。
A)
??????
對(duì)象生命周期的處理,是否對(duì)象的reference已經(jīng)失效,能夠設(shè)置為null,并被回收
B)
??????
在對(duì)象的傳值和傳參方面有無(wú)問(wèn)題,對(duì)象的clone方法使用是否過(guò)度
C)
??????
是否
大量經(jīng)常的創(chuàng)建臨時(shí)對(duì)象
D)
??????
是否盡量使用局部對(duì)象(堆棧對(duì)象)
E)
???????
在只需要對(duì)象reference的地方是否創(chuàng)建了新的對(duì)象實(shí)例
JAVA
中提供了方便的異常處理機(jī)制,但普遍存在的是異常被捕獲,但并沒(méi)有得到處理。我們可以打開(kāi)一段代碼,最常見(jiàn)的現(xiàn)象是進(jìn)入某個(gè)方法后,一個(gè)大的
try/catch
將所有代碼行括住,然后在
catch
中將異常打印到控制臺(tái),而且該異常是
Exception
對(duì)象。
A)
??????
每次當(dāng)方法返回時(shí)是否正確處理了異常,如最簡(jiǎn)單的處理,記錄日志到日志文件中
B)
???????
是否對(duì)數(shù)據(jù)的值和范圍是否合法進(jìn)行校驗(yàn),包括采用斷言(
assertion
)
C)
??????
在出錯(cuò)路徑上是否所有的資源和內(nèi)存都已經(jīng)釋放
D)
??????
所有拋出的異常都得到正確的處理,特別是對(duì)子方法拋出的異常,在整個(gè)調(diào)用棧中必須能夠被捕捉并處理
E)
???????
當(dāng)調(diào)用導(dǎo)致錯(cuò)誤發(fā)生時(shí),方法的調(diào)用者應(yīng)該得到一個(gè)通知
F)
???????
不要忘了對(duì)錯(cuò)誤處理部分的代碼進(jìn)行測(cè)試,很多代碼在正常情況下執(zhí)行良好,而一旦出錯(cuò),整個(gè)系統(tǒng)就崩潰了
A)
??????
方法的參數(shù)是否都做了校驗(yàn)
B)
???????
數(shù)組類(lèi)結(jié)構(gòu)是否做了邊界校驗(yàn)
C)
??????
變量在使用前是否做了初始化
D)
??????
返回堆對(duì)象的
reference
,不要返回棧對(duì)象的
reference
E)
???????
方法
API
是否被良好定義,即是否盡量面向接口編程,便于維護(hù)和重構(gòu)
A)
??????
對(duì)命令行執(zhí)行的代碼,需要詳細(xì)檢查命令行參數(shù)
B)
???????
WEB
類(lèi)程序檢查是否對(duì)訪(fǎng)問(wèn)參數(shù)進(jìn)行合法性驗(yàn)證
C)
??????
重要信息的保存是否選用合適的加密算法
D)
??????
通訊時(shí)考慮是否選用安全的通訊方式
A)?????
日志是否正常輸出和控制
B)
???????
配置信息如何獲得,是否有硬編碼
三、
總結(jié)
通過(guò)在項(xiàng)目中實(shí)施
Code Review
將為我們帶來(lái)多方面的好處,表現(xiàn)在提高代碼質(zhì)量,保證項(xiàng)目或產(chǎn)品的穩(wěn)定性,開(kāi)發(fā)經(jīng)驗(yàn)的積累等,具體的實(shí)施當(dāng)然也要看項(xiàng)目的實(shí)際情況,因?yàn)?/span>
Code Review
也是需要成本的,這方面屬于
Code Review
過(guò)程的問(wèn)題,將在其他文章中進(jìn)行探討。
四、
參考資料
Java
語(yǔ)言編碼規(guī)范
(Java Code Conventions)? SUN
Software Quality Assurance: Documentation and Reviews? Dolores R. Wallace,Wendy W. Peng, Laura M. Ippolito
快速軟件開(kāi)發(fā)
斯蒂夫
電子工業(yè)出版社
五、
關(guān)于作者
陳建華
,
從事移動(dòng)互聯(lián)方面的應(yīng)用開(kāi)發(fā)
,
郵件地址
: cqbbs@yeah.net