改善 Java 代碼質(zhì)量的工具與方法
我們可能見(jiàn)過(guò)上面的有關(guān)代碼質(zhì)量的圖片,究竟如何衡量一段代碼好壞?
代碼質(zhì)量是什么?為什么它很重要?
作家通過(guò)他的著作來(lái)講述了一個(gè)清晰的、令人信服的故事。他們使用章節(jié)、標(biāo)題和段落等工具來(lái)清晰地組織他們的思想,并輕松地引導(dǎo)讀者。
開(kāi)發(fā)者的工作與作家類(lèi)似,只是使用不同術(shù)語(yǔ)如命名空間、類(lèi)和方法。如果創(chuàng)作者不能有效地使用他們的工具,那么無(wú)論他們的作品是書(shū)還是代碼,讀者都很難讀懂。
回到代碼質(zhì)量這個(gè)話題,好的代碼都應(yīng)該具備如下一系列理想特征:
- 可靠:能夠穩(wěn)定工作,不會(huì)頻繁崩潰。
- 一致的代碼風(fēng)格:遵循該語(yǔ)言一致的代碼風(fēng)格和命名慣例。
- 可維護(hù):易于理解,可維護(hù)的代碼應(yīng)該易于擴(kuò)展及添加新功能。
- 完善的測(cè)試:具備良好測(cè)試的代碼往往 bug 更少。
- 高效:不應(yīng)使用不必要的資源來(lái)執(zhí)行所需的業(yè)務(wù)。
- 安全:應(yīng)防止SQL注入等編碼漏洞。
- 較低的技術(shù)債務(wù):較低的技術(shù)債務(wù)使團(tuán)隊(duì)能夠快速前行和開(kāi)發(fā)新功能,而不會(huì)被低質(zhì)量和不可維護(hù)的代碼拖累。
具備的上述特征越多,代碼的質(zhì)量就越高。根據(jù)項(xiàng)目及客戶的具體情況,其中一些特性可能不是代碼必需的。
當(dāng)面臨交付期限時(shí),編寫(xiě)高質(zhì)量的代碼非常具有挑戰(zhàn),但如果你考慮到代碼的長(zhǎng)期可維護(hù)性,這一點(diǎn)很重要。同時(shí),高質(zhì)量的代碼也會(huì)幫助團(tuán)隊(duì)長(zhǎng)期保持一致的交付速度。
根據(jù)我的經(jīng)驗(yàn),下面是一些在我的項(xiàng)目中對(duì)改進(jìn)和維護(hù)高質(zhì)量代碼非常有效的總結(jié)。
使用靜態(tài)代碼分析器提高代碼質(zhì)量
編譯器可以捕捉和防止語(yǔ)法問(wèn)題,但它們無(wú)法檢測(cè)到類(lèi)似情況:
- 代碼結(jié)構(gòu)不一致
- 社區(qū)已經(jīng)成型的經(jīng)驗(yàn)
- 代碼復(fù)雜性
靜態(tài)代碼分析是一種在代碼運(yùn)行前對(duì)其進(jìn)行檢查的技術(shù)。有一些工具可以進(jìn)行靜態(tài)分析,它的工作原理是根據(jù)多種編碼規(guī)則分析代碼,來(lái)發(fā)現(xiàn)一些違規(guī)行為。這些工具可以集成到構(gòu)建工具中,如 gradle、maven 等,并讓有問(wèn)題的代碼構(gòu)建失敗。
以下是一些可以整合到項(xiàng)目中的工具。
Checkstyle
Checkstyle (1) 是開(kāi)發(fā)中用于檢查 Java 源代碼是否符合編碼規(guī)則的靜態(tài)代碼分析工具。Checkstyle 進(jìn)行的檢查限于代碼的表現(xiàn)形式,這些檢查并不能確認(rèn)代碼的正確性和完整性。
https://checkstyle.sourceforge.io/
使用 Checkstyle 可以確保開(kāi)發(fā)團(tuán)隊(duì)遵循一致的編碼風(fēng)格,使其更容易閱讀和理解。
下面是一些可以使用 checkstyle 進(jìn)行的檢查。
- 屬性和方法的命名慣例
- 函數(shù)參數(shù)的數(shù)量
- 代碼每行最大寬度
- 強(qiáng)制性的文件頭描述,如版權(quán)
- import 和范圍修飾符
- 字符之間的空格
- Class 構(gòu)建函數(shù)的約定
- 多重代碼復(fù)雜度測(cè)量
PMD
PMD(Programming Mistake Detector,編程錯(cuò)誤檢測(cè)器)(1) 是一個(gè)靜態(tài)代碼分析器,它可以報(bào)告在應(yīng)用程序代碼中發(fā)現(xiàn)的問(wèn)題。
https://pmd.github.io/
PMD 可以幫助檢測(cè)代碼中的問(wèn)題,這些問(wèn)題可能會(huì)在代碼交付生產(chǎn)環(huán)境時(shí)引起問(wèn)題。
- 可能的 bug: 空的 try/catch/finally/switch 塊,吞掉原來(lái)異常并拋出一個(gè)新的異常。
- 死代碼:未使用的局部變量、參數(shù)和私有方法。
- 空的 if/while 語(yǔ)句
- 過(guò)于復(fù)雜的表達(dá)式: 不必要的 if 語(yǔ)句,for 循環(huán)可以是 while 循環(huán)。
- 次優(yōu)代碼:浪費(fèi)的 String/StringBuffer 的使用
- 高循環(huán)復(fù)雜度的類(lèi)
- 錯(cuò)誤的 BigDecimal 用法
CPD(復(fù)制/粘貼檢測(cè)器)
CPD (1),顧名思義,是一個(gè)基于拷貝的檢測(cè)器,即使對(duì)于大型代碼庫(kù)來(lái)說(shuō)也是非常高效的。它使用 Karp-Rabin (2) 字符串匹配算法編寫(xiě)。
https://pmd.sourceforge.io/pmd-4.2.5/cpd.html
https://xlinux.nist.gov/dads/HTML/karpRabin.html
它可以被配置為檢測(cè)大于確定數(shù)量的標(biāo)記的重復(fù)。復(fù)制/粘貼代碼是不可取的,因?yàn)樗勾a難以維護(hù),并可能在對(duì)其中一個(gè)地方做了一些改變,而忘記在其他地方也存在相同的代碼的情況下導(dǎo)致 bug。
衡量代碼質(zhì)量
免責(zé)聲明:當(dāng)一項(xiàng)措施成為目標(biāo)時(shí),它就不再是一項(xiàng)好措施。(1)
https://en.wikipedia.org/wiki/Goodhart%27s_law
代碼覆蓋率指標(biāo)
代碼覆蓋率是一個(gè)指標(biāo),可以用來(lái)獲得一些關(guān)于代碼質(zhì)量的信心。說(shuō)了這么多,選擇哪些測(cè)試來(lái)衡量覆蓋率時(shí)要小心。并不是所有測(cè)試金字塔的測(cè)試都是一樣的,像 JaCoCo 這樣的工具可以用來(lái)計(jì)算代碼覆蓋率。
在看代碼覆蓋率的指標(biāo)時(shí),只應(yīng)該考慮單元測(cè)試,因?yàn)閱卧獪y(cè)試是為了測(cè)試代碼是否完成了開(kāi)發(fā)者想要做的事情,執(zhí)行這些測(cè)試是最快的驗(yàn)證方法。
衡量集成測(cè)試的代碼覆蓋率可能是有價(jià)值的,但它應(yīng)該被視為單獨(dú)的結(jié)果,而不應(yīng)該與單元測(cè)試報(bào)告合并。記住集成測(cè)試是為了確保所有的組件一起工作。使用集成測(cè)試來(lái)提高代碼覆蓋率,就像使用大錘來(lái)敲開(kāi)一個(gè)螺母一樣。
毒性圖(Toxicity Chart)
毒性圖(Toxicity Chart) (1),顧名思義是一種展示代碼毒性的方法。這個(gè)圖代表了代碼庫(kù)中每個(gè)類(lèi)的毒性,毒性分?jǐn)?shù)是根據(jù)一系列參數(shù)計(jì)算出來(lái)的,比如文件長(zhǎng)度、方法長(zhǎng)度、循環(huán)復(fù)雜度、嵌套語(yǔ)句等等。這個(gè)圖表可以展示給業(yè)務(wù)人員、管理人員等非技術(shù)人員,幫助他們了解代碼的質(zhì)量。
https://erik.doernenburg.com/2008/11/how-toxic-is-your-code/
示例代碼
下面的 Github 倉(cāng)庫(kù)包含了一個(gè)包含上述所有工具的示例項(xiàng)目。它的結(jié)構(gòu)讓你很容易選擇一些需要的工具來(lái)集成到你自己的項(xiàng)目中。
https://github.com/singhalkul/java-quality-checks
保持代碼質(zhì)量是一個(gè)持續(xù)的過(guò)程,它不能由團(tuán)隊(duì)中的某一個(gè)人來(lái)完成,整個(gè)團(tuán)隊(duì)都有責(zé)任確保編寫(xiě)的代碼是高質(zhì)量的。
雖然上面提到的工具會(huì)幫助確保減少代碼中一些質(zhì)量問(wèn)題,但這不是唯一的方法。團(tuán)隊(duì)?wèi)?yīng)該遵循極限編程實(shí)踐,如配對(duì)編程、測(cè)試驅(qū)動(dòng)開(kāi)發(fā)、代碼審查、持續(xù)集成,以確保高質(zhì)量代碼特征存在于代碼庫(kù)中。
英文原文:
https://medium.com/inspiredbrilliance/improving-code-quality-for-java-projects-5d24ad448109
本文轉(zhuǎn)載自微信公眾號(hào)「高可用架構(gòu)」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系高可用架構(gòu)公眾號(hào)。