追求代碼質(zhì)量(2)-監(jiān)視圈復(fù)雜度-Java開發(fā)Java經(jīng)驗(yàn)技巧_第1頁
追求代碼質(zhì)量(2)-監(jiān)視圈復(fù)雜度-Java開發(fā)Java經(jīng)驗(yàn)技巧_第2頁
追求代碼質(zhì)量(2)-監(jiān)視圈復(fù)雜度-Java開發(fā)Java經(jīng)驗(yàn)技巧_第3頁
追求代碼質(zhì)量(2)-監(jiān)視圈復(fù)雜度-Java開發(fā)Java經(jīng)驗(yàn)技巧_第4頁
追求代碼質(zhì)量(2)-監(jiān)視圈復(fù)雜度-Java開發(fā)Java經(jīng)驗(yàn)技巧_第5頁
已閱讀5頁,還剩3頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、追求代碼質(zhì)量(2):監(jiān)視圈復(fù)雜度-編程 開發(fā)技術(shù)追求代碼質(zhì)量(2)監(jiān)視圈復(fù)雜度原文出處:ibm中國每位開發(fā)人員對代碼質(zhì)量的含義都冇著自己的看法,并且大多數(shù)人對如何查找編 寫欠佳的代碼也有口己的想法。甚至術(shù)語代碼味道(code smell) ?也已進(jìn)入大 眾詞匯表,成為描述代碼需耍改進(jìn)的一種方式。代碼味道通常由開發(fā)人員直接判定,有趣的是,它是許多代碼注釋綜合在一起的 味道。一些人聲稱公正的代碼注釋是好事情,而另一些人聲稱代碼注釋只是解釋 過于復(fù)雜的代碼的一種機(jī)制。顯然,javadocs?很有用,但是多少內(nèi)嵌注釋才足 以維護(hù)代碼?如果代碼已經(jīng)編寫得足夠好,它述需要解釋自己嗎?這告訴我們,代碼味道是

2、一種評估代碼的機(jī)制,它具冇主觀性。我相信,那些聞 起來味道糟透了的代碼可能是其他人曾經(jīng)編寫的最好的代碼。以下這些短語聽起 來是不是很熟悉?是的,它初看起來冇點(diǎn)亂,但是您要看到它多么可擴(kuò)展!或者它讓您感到迷惑,但顯然您不了解它的模式。我們需要的是客觀評估代碼質(zhì)量的方法,某種可以決定性地告訴我們正在查看的 代碼是否存在風(fēng)險(xiǎn)的東西。不管您是否相信,這種東西確實(shí)存在!用來客觀評佔(zhàn) 代碼質(zhì)量的機(jī)制已經(jīng)出現(xiàn)了一段時(shí)間了,只是大多數(shù)開發(fā)人員忽略了它們。這些 機(jī)制被稱為代碼度量(code metric)。代碼度量的歷史幾十年前,少數(shù)幾個(gè)非常聰明的人開始研究代碼,希望定義一個(gè)能夠與缺陷關(guān)聯(lián) 的測量系統(tǒng)。這是一個(gè)

3、非常有趣的主張:通過研究帶bug代碼中的模式,他們 希望創(chuàng)建止式的模型,然后可以評估這些模型,在缺陷成為缺陷捕獲它們。在這條研究z路上,其他一些非常聰明的人也決定通過研究代碼看看他們是否可 以測量開發(fā)人員的生產(chǎn)效率。對每位開發(fā)人員的代碼行的經(jīng)典度量似乎只停留在 表面上:joe生產(chǎn)的代碼要比bill多,因此joe生產(chǎn)率更高一些,值得 我們花錢聘請這樣的人。此外,我注意到b訂1經(jīng)常在飲水機(jī)邊閑 黒我認(rèn)為我們應(yīng)該解雇bill。但是這種生產(chǎn)率度量在實(shí)踐屮是非常令人失望的,主要是因?yàn)樗菀妆粸E用。一 些代碼測量包描內(nèi)嵌注釋,并且這種度量實(shí)際上受益于剪切粘貼式開發(fā) (cut-and-paste style

4、 development)。joe編寫了許多缺陷!其他每條缺陷也都是由他間接造成的。我們 不該解雇b訂1,他的代碼實(shí)際上是免檢的??梢灶A(yù)見,生產(chǎn)率研究被證實(shí)是非常不準(zhǔn)確的,但在管理團(tuán)隊(duì)(mariagcrncrit body) 廣泛使用這種生產(chǎn)率度量以期了解每個(gè)人的能力的價(jià)值z前,情況并非如此。來 自開發(fā)人員社區(qū)的痛苦反應(yīng)是有理由的,對于一些人而言,那種痛苦感覺從未真 正走遠(yuǎn)。未經(jīng)雕琢的鉆石盡管存在這些失敗,但在那些復(fù)雜度與缺陷的相互關(guān)系的研究屮仍然有一些美 玉。大多數(shù)開發(fā)人員忘記進(jìn)行代碼質(zhì)量研究已有很長一段時(shí)間了,但對于那些仍 正在鉆研的人而言(特別是如果您也正在為追求代碼質(zhì)量而努力鉆研),會

5、在今 天的應(yīng)用中發(fā)現(xiàn)這些研究的價(jià)值。例如,您曾注意到一些長的方法有時(shí)難以理解 嗎?是否曾無法理解嵌套很深的條件從句小的邏輯?您的避開這類代碼的本能 是正確的。一些長的方法和帶有大量路徑的方法渥?難以理解的,有趣的是,這 類方法容易導(dǎo)致缺陷。我將使用一些例子展示我要表達(dá)的意思。數(shù)字的海洋研究顯示,平均每人在其大腦中大約能夠處理7 (±2)位數(shù)字。這就是為什么 大多數(shù)人可以很容易地記住電話號碼,但卻很難記住大于7位數(shù)字的信用卡號 碼、發(fā)射次序和其他數(shù)字序列的原因。此原理還可以應(yīng)用于代碼的理解上。您以前大概已經(jīng)看到過類似清單1中所示 的代碼片段:清單1.適用記憶數(shù)字的原理if (entit

6、ylmplvo != null) list actions = entitytmplvo. getentilies();if (actions = null) actions = new arraylist();iterator enltr 二 actions, iterator();whi 1 e (enttr. hasnext () entityresultvalueobject arvo = (entityresultvalueobject) actionltr.next ();float entityresult = arvo. getactionresultido ;if (asso

7、cpersoneventlist. contains(actionresult) assocpersonflag 二 true;if (arvl. getbyname( appconstants. entity_result_denial_of_service).getid(). equals(entityresult) if (actionbasistd. equal s (actiontmplvo. getactionbasistdo) assocflag = true;if (arvl. getbyname(appconstants. enttty_result_tnvol_servtc

8、e) gctid(). equals(entityresult) if (!reasonld. equals (arv0. getstatusreasonld() assocflag = true;elseentitylmplvo = oldentitylmplvo;清單1展示了 9條不同的路徑。該代碼片段實(shí)際上是一個(gè)350多行的方法的 一部分,該方法展示了 41條不同的路徑。設(shè)想一下,如果您被分配一項(xiàng)任務(wù), 要修改此方法以添加一項(xiàng)新功能。如果您該方法不是您編寫的,您認(rèn)為您能只做 必要的更改而不會引入任何缺陷嗎?當(dāng)然,您應(yīng)該編寫一個(gè)測試用例,但您會認(rèn)為該測試用例能將您的特定更改在條 件從句的海

9、洋中隔離起來嗎?測量路徑復(fù)雜度圈層雜友?是在我前面提到的那些研究期間開創(chuàng)的,它可以精確地測量路徑復(fù)雜 度。通過利用某一方法路由不同的路徑,這一基于整數(shù)的度量可適當(dāng)?shù)孛枋龇椒?復(fù)雜度。實(shí)際上,過去幾年的各種研究已經(jīng)確定:圈復(fù)雜度(或cc)大于10的 方法存在很大的岀錯風(fēng)險(xiǎn)。因?yàn)閏c通過某一方法來表示路徑,這是用來確定某 一方法到達(dá)100%的覆蓋率將需要多少測試用例的一個(gè)好方法。例如,以下代碼(您可能記得本系列的第一篇文章中使用過它)包含一個(gè)邏輯缺陷:清單2. pathcoverage有一個(gè)缺陷!public class pathcoverage public string pathexample

10、(boolean condition)string value = null;if(condition) value 二""+ condition + " ;return value. trim();作為響應(yīng),我可以編寫一個(gè)測試,它將達(dá)到100%的行覆蓋率:清單3. 一個(gè)測試產(chǎn)生完全覆蓋!import junit. framework. tcstceisc;public class pathcoveragetest extends testcase public final void testpathexample() pathcoverage clzzunder

11、tst 二 new pathcoverage();string value = clzzundertst. p3thexeimple(true); assertequals (''should be truez truez value);接下來,我將運(yùn)行一個(gè)代碼覆蓋率工具,比如cobertura,并將獲得如圖1中 所示的報(bào)告: 圖 l cobertura 報(bào)告10 1if(condition)11 1value = h " + condition +12 j13 1return value匸rimf);14 15 file edit view go bookmarks

12、 tools helpcoverage report - com. van ward.co verage.example2.pathcoverageclasses in this fileline coveragebranch coveragecomplexitypathcoveraqe1dd%1 2reports generated by cobertura,done哦,有點(diǎn)失望。代碼覆蓋率報(bào)告指示100%的覆蓋率,但我們知道這是一個(gè)謀導(dǎo)。二對二注意,清單2屮的?pathexample()?方法有一個(gè)值為2的cc (一個(gè)用于默認(rèn)路 徑,一個(gè)用于?if?路徑)。使用cc作為更精確的覆蓋率測量尺

13、度意味著第二個(gè) 測試用例是必需的。在這里,它將是不進(jìn)入?if?條件語句而采用的路徑,如清單 4 屮的?testpathexamplefalse () ?方法所示:清單4.沿著較少采用的路徑向下import junit. framework. testcase;public class pathcoveragetest extends testcase public final void testpathexample() pathcoverage clzzundertst 二 new pathcoverage();string value 二 clzzundertst. pathexample

14、(true); dssertequals("should be tvalue);public final void testpathexamplefalse() pathcoverage clzzundertst 二 new pathcoverage ();string value 二 clzzundertst. pathexample(false);assertequals("should be false", "false", value);正如您可以看到的,運(yùn)行這個(gè)新測試用例會產(chǎn)生一個(gè)令人討厭的?nullpointerexception0

15、在這里,有趣的是我們可以使用圈復(fù)雜度岡是? 使用代碼覆蓋率來找出這個(gè)缺陷。代碼覆蓋率指示我們己經(jīng)在一個(gè)測試用例之后 完成了此操作,但cc卻會強(qiáng)迫我們編寫額外的測試用例。不算太壞,是吧?幸運(yùn)的是,這里的測試屮的方法冇一個(gè)值為2的cco設(shè)想一下該缺陷被隱藏在 cc為102的方法中的情況。祝您好運(yùn)找到它!圖表上的ccjava開發(fā)人員可使用一些開放源碼工具來報(bào)告圈復(fù)朵度。其小一個(gè)這樣的工具 是javancss,它通過檢查java源文件來確定方法和類的長度。此外,此t具 還收集代碼庫中每個(gè)方法的圈復(fù)雜度。通過利用ant任務(wù)或maven插件配置 javancss,可以生成一個(gè)列出以下內(nèi)容的xml報(bào)告:每個(gè)

16、包中的類、方法、非注釋代碼行和各種注釋樣式的總數(shù)。每個(gè)類中非注釋代碼行、方法、內(nèi)部類和javadoc注釋的總數(shù)。代碼庫小每個(gè)方法的非注釋代碼行的總數(shù)和圈復(fù)雜度。該工具附帶了少量樣式表,可以使用它們來生成總結(jié)數(shù)據(jù)的html報(bào)告。例如, 圖2闡述了 maven生成的報(bào)告:圖2. maven生成的javancss報(bào)告此報(bào)告中帶冇?7b刀30 functions containing the most akss?標(biāo)簽的部分詳細(xì) 描述了代碼庫中最長的方法,順便提一句,該方法幾乎總欝與包含最大圈復(fù)雜度的方法相關(guān)聯(lián)。例如,該報(bào)告列出了?dblnsertqueue?類的?updatepcensus()? 方法

17、,因?yàn)榇朔椒ǖ姆亲⑨屝锌倲?shù)為283,圈復(fù)雜度(標(biāo)記為ccn)為114。正如上面所演示的,圈復(fù)雜度是代碼復(fù)雜度的一個(gè)好的指示器;此外,它還是用 于開發(fā)人員測試的一個(gè)極好的衡量器。一個(gè)好的經(jīng)驗(yàn)法則是創(chuàng)建數(shù)量與將被測試 代碼的圈復(fù)雜度值相等的測試用例。在圖2屮所見的?updatcpccnsuso?方法 屮,將需要114個(gè)測試用例來達(dá)到完全覆蓋。分而治之在面對指示高圈復(fù)雜度值的報(bào)告吋,第一個(gè)行動是檢驗(yàn)所有相應(yīng)測試的存在。如 果存在一些測試,測試的數(shù)量是多少?除了極少數(shù)代碼庫以外,幾乎所冇代碼庫 實(shí)際上都有114個(gè)測試用例用于?updatcpccnsus()?方法(實(shí)際上,為一個(gè)方法 編寫如此多的測試用

18、例可能會花費(fèi)很長時(shí)間)。但即使是很小的一點(diǎn)進(jìn)步,它也 是減少方法中存在缺陷風(fēng)險(xiǎn)的一個(gè)偉大開始。如果沒有任何相關(guān)的測試用例,顯然需耍測試該方法。您首先想到的可能是:到 重構(gòu)的時(shí)間了,但這樣做將打破第一個(gè)重構(gòu)規(guī)則,即將編寫一個(gè)測試用例。先編 寫測試用例會降低重構(gòu)小的風(fēng)險(xiǎn)。減少圈復(fù)雜度的最有效方式是隔離代碼部分, 將它們放入新的方法屮。這會降低復(fù)雜度,使方法更容易管理(因此更容易測試)。 當(dāng)然,隨后應(yīng)該測試那些更小的方法。在持續(xù)集成環(huán)境屮,夠7辦刃變化?評估方法的復(fù)雜度是有可能的。如果是第一次 運(yùn)行報(bào)告,那么您可以監(jiān)視方法的復(fù)雜度值或任何相關(guān)的成長度(growth)。如 果在cc中看到一個(gè)成長度,那

19、么您可以采取適當(dāng)?shù)膭幼鳌H绻骋环椒ǖ腸c值在不斷增長,那么您冇兩個(gè)響應(yīng)選擇:確保相關(guān)測試的健康情況仍然表現(xiàn)為減少風(fēng)險(xiǎn)。評估重構(gòu)方法減少任何長期維護(hù)問題的對能性。還要注意的是,javancss不是惟一用于java平臺促進(jìn)復(fù)雜度報(bào)告的工具。pmd 是另一個(gè)分析jewel源文件的開源項(xiàng)目,它有一系列的規(guī)則,其中z就是報(bào)告 圈復(fù)雜度。checkstyle是另一個(gè)具冇類似的圈復(fù)雜度規(guī)則的開放源碼項(xiàng)目。p1d 和checkstyle都有ant任務(wù)和maven插件(請參閱?參考資料,從那里獲得 關(guān)于至此為止討論的所有工具的更多信息。)使用復(fù)雜度度量因?yàn)槿?fù)雜度是如此好的一個(gè)代碼復(fù)雜度指示器,所以測試驅(qū)動的開發(fā) (test-driven development)和低cc值z間存在著緊密和關(guān)的聯(lián)系。在編寫測 試時(shí)(注意,我沒有暗示是第一茨),開發(fā)人員通常傾向于編寫不太復(fù)朵的代碼, 氏、人復(fù)雜的代碼難以測試。如果您發(fā)現(xiàn)自己難以編寫某一代碼,那么這是一種警 示,表示正在測試的代碼可能很復(fù)雜。在這些情況下,tdd的簡短的“代碼、 測試、代碼、測試”循環(huán)將導(dǎo)致重構(gòu),而這將繼續(xù)

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論