七招掌控軟件的代碼質(zhì)量
譯文【51CTO.com快譯】眾所周知,業(yè)界常把低質(zhì)量的程序代碼稱(chēng)為“技術(shù)債”。它們不但會(huì)影響軟件構(gòu)建的效率,而且會(huì)在軟件交付和運(yùn)行中,出現(xiàn)嚴(yán)重的服務(wù)質(zhì)量問(wèn)題。可見(jiàn),軟件質(zhì)量的重要性是不言而喻的。本文將和您討論在自動(dòng)化的代碼質(zhì)量控制流程中,有關(guān)代碼樣式、正確性、復(fù)雜度、設(shè)計(jì)、安全性、覆蓋率、以及審查等關(guān)鍵要素。
1.代碼的樣式
常言道:您的代碼觀感,直接反映了您對(duì)代碼的關(guān)心程度。此言不虛,即使是那些代碼段上的縮進(jìn)不一致,也可能為代碼的后期分析帶來(lái)一場(chǎng)噩夢(mèng)。更不用說(shuō)由此產(chǎn)生的,不同開(kāi)發(fā)團(tuán)隊(duì)在聯(lián)調(diào)程序過(guò)程中的各種沖突了。
幸運(yùn)的是,我們可以使用諸如Idea和Eclipse之類(lèi)IDE工具,來(lái)自動(dòng)化檢查代碼樣式的方式,進(jìn)而修復(fù)并提高代碼的準(zhǔn)確性。具體而言,開(kāi)發(fā)團(tuán)隊(duì)中的每個(gè)成員首先應(yīng)當(dāng)使用相同的代碼樣式定義,將其設(shè)置為共享的.editorconfig文件、或特定于某個(gè)IDE的配置之中。其次,我們需要通過(guò)將樣式檢查集成到構(gòu)建的過(guò)程中,以確保每個(gè)成員都能遵循代碼樣式規(guī)則。我們可以在每次將代碼的更改推送到存儲(chǔ)庫(kù)時(shí),通過(guò)Checkstyle的方式,采用Jenkins插件、Maven、以及Gradle的腳本來(lái)實(shí)現(xiàn)。
2.代碼的正確性
代碼掃描向來(lái)是一項(xiàng)耗時(shí)且繁瑣的工作,有時(shí)甚至難免有所疏漏。對(duì)此,我們可以使用一些免費(fèi)的工具,其中包括:SpotBugs(它是已廢棄的FindBugs項(xiàng)目的繼承者)、PMD、Error Prone、以及SonarQube。其中的一些還可以識(shí)別出重復(fù)性的代碼,并發(fā)現(xiàn)潛在的性能問(wèn)題。與Checkstyle相似,我們可以將這些工具集成到自己的IDE中,輕松地檢查出目標(biāo)代碼中的缺陷。
此外,您也可以使用Checker Framework來(lái)增強(qiáng)Java系統(tǒng)的代碼檢查,以及防范潛在問(wèn)題的能力。當(dāng)然,您可能需要對(duì)其進(jìn)行一些額外的手工配置。
值得注意的是,我們需要讓這些工具在項(xiàng)目構(gòu)建的過(guò)程中就事先運(yùn)行起來(lái),以免在將代碼推送到存儲(chǔ)庫(kù)之前,忘記讓它們“把關(guān)”了。
3.代碼的復(fù)雜度
在前面的討論中,我們主要關(guān)注的是發(fā)現(xiàn)代碼中的常見(jiàn)編程缺陷。下面,讓我們聚焦代碼的復(fù)雜度。顯然,沒(méi)有人愿意閱讀和使用那些難以推理、維護(hù)和擴(kuò)展的代碼。通常,我們可以使用如下指標(biāo),來(lái)衡量代碼的復(fù)雜度:
- Cyclomatic和NPath復(fù)雜度 — 是基于控制流的復(fù)雜度計(jì)算方法。換句話(huà)說(shuō),它顯示了在測(cè)試中,應(yīng)當(dāng)涵蓋的不同路徑的數(shù)量(可測(cè)試性)。我們可以使用的工具包括:Checkstyle、SpotBugs和PMD。
- 認(rèn)知復(fù)雜度- 衡量的是代碼對(duì)于人類(lèi)理解能力的難度(可讀性)。我們可以使用的工具包括:SonarQube和SonarLint的IDE插件。
4.代碼的設(shè)計(jì)
下面,讓我們來(lái)看看如何使用靜態(tài)代碼分析工具,來(lái)發(fā)現(xiàn)目標(biāo)代碼在設(shè)計(jì)上的缺陷。目前,許多面向?qū)ο蟮脑O(shè)計(jì)實(shí)踐,都可以通過(guò)自動(dòng)化的源檢查(source checks),以發(fā)現(xiàn)繼承層次(inheritance hierarchy)過(guò)高、以及上帝類(lèi)(God class)等設(shè)計(jì)問(wèn)題。對(duì)此,Checkstyle和PMD都提供了一整套檢查工具。其中包括:Source code file、Class、Method、以及Parameter list。它們都能夠根據(jù)基本設(shè)計(jì)規(guī)則,對(duì)代碼進(jìn)行全面檢查。
除了上述基本的設(shè)計(jì)檢查,我們還可以通過(guò)如下靜態(tài)分析工具實(shí)現(xiàn)更深層次的檢查:
- PMD的LawOfDemeter可用于減少各個(gè)類(lèi)之間的緊密耦合。
- Checkstyle的DesignForExtension,實(shí)現(xiàn)了由Joshua Bloch撰寫(xiě)的《Java高效編程(Effective Java)》第三版的第17章:針對(duì)繼承或禁止繼承的設(shè)計(jì)和文檔(Design and document for inheritance or else prohibit it)。
- PMD的CouplingBetweenObjects,通過(guò)唯一屬性、局部變量、以及返回類(lèi)型的數(shù)量等信息,來(lái)檢測(cè)難以測(cè)試、分析和擴(kuò)展的緊密耦合類(lèi)。
- jPeek,可衡量類(lèi)的內(nèi)聚性,進(jìn)而保持各種類(lèi)、模塊、以及包的高內(nèi)聚性。
- embold,包含了大量針對(duì)耦合和內(nèi)聚的有關(guān)高級(jí)設(shè)計(jì)缺陷的檢查功能。
- CodeScene是從開(kāi)源項(xiàng)目Code Maat處演變而來(lái)的。通過(guò)分析版本控制系統(tǒng)中有關(guān)歷史代碼的更改,它不僅可以發(fā)現(xiàn)潛在的設(shè)計(jì)問(wèn)題,還能夠發(fā)現(xiàn)開(kāi)發(fā)中的瓶頸問(wèn)題。
值得注意的是,最后兩款工具僅對(duì)于開(kāi)源項(xiàng)目是免費(fèi)的。
5.代碼的安全性
在開(kāi)發(fā)過(guò)程中,為了確保代碼的安全性、可擴(kuò)展性、以及可維護(hù)性,我們需要持續(xù)檢索CVE數(shù)據(jù)庫(kù),以避免第三方的依賴(lài)項(xiàng)出現(xiàn)安全漏洞。此外,您也可以從如下資源處獲取有關(guān)代碼安全的各種實(shí)踐:
- 通用安全編碼規(guī)則--OWASP TOP 10
- 特定技術(shù)安全編碼規(guī)則--Oracle Java的安全編碼準(zhǔn)則
- 最常見(jiàn)的安全漏洞--Mitre CWE Top 25,SANS TOP 25
作為補(bǔ)充,下面是幾種具有自動(dòng)化執(zhí)行功能的,代碼安全性檢查工具:
- FindSecBugs,是SpotBugs的插件,可用于審核Web應(yīng)用中Java程序的安全性。您不但可以將其集成到Maven或Gradle之類(lèi)的構(gòu)建過(guò)程中,還可以在使用IDE插件進(jìn)行編碼時(shí)用到它。
- SonarQube是一個(gè)多合一的安全性檢查工具。其母公司SonarSource在2020年收購(gòu)了RIPS Technologies后,進(jìn)一步提升了Sonar的安全檢測(cè)能力。
此外,各種第三方的依賴(lài)項(xiàng)和Docker鏡像,也能夠在代碼質(zhì)量控制的過(guò)程中,實(shí)現(xiàn)各項(xiàng)安全性的掃描。
6.代碼的覆蓋率
常言道:如果沒(méi)有大量的自動(dòng)化測(cè)試,就無(wú)法驗(yàn)證代碼是否能夠按期運(yùn)行;如果沒(méi)有自動(dòng)化的回歸測(cè)試,就無(wú)法安全地重構(gòu)代碼。那么,我們又該如何在保證具有高質(zhì)量的代碼置信度的基礎(chǔ)上,盡可能涵括更多的流程,檢查并提高代碼的覆蓋率呢?顯然,我們需要事先充分地準(zhǔn)備好如下不同的測(cè)試覆蓋率相關(guān)指標(biāo):
- 語(yǔ)句與指令的覆蓋率,即:程序中有多少條語(yǔ)句已被執(zhí)行。
- 代碼行覆蓋率,即:已測(cè)試了多少行源代碼。
- 分支覆蓋率,即:已經(jīng)執(zhí)行了目標(biāo)控制結(jié)構(gòu)中的多少個(gè)分支。
- 方法與功能覆蓋率,即:定義了多少種方法。
在工具方面,我們可以使用IntelliJ IDEA的Coverage、Eclipse的JaCoCo等具有IDE的流行工具。
- 通過(guò)將Coverage工具集成到構(gòu)建過(guò)程中,我們能夠通過(guò)上述指標(biāo),來(lái)了解具體涵蓋了代碼的哪些部分,進(jìn)而發(fā)現(xiàn)測(cè)試中的不足。
- JaCoCo可謂Java領(lǐng)域最流行的代碼覆蓋率工具。您可以通過(guò)Maven、Gradle、甚至是Ant,將其集成到構(gòu)建的過(guò)程中。JaCoCo既提供了開(kāi)箱即用式的支持,又可以從遠(yuǎn)程流程中收集到覆蓋率的相關(guān)信息。同時(shí),它也能協(xié)助我們將端到端的測(cè)試,包括在代碼覆蓋率的最終報(bào)告中。值得一提的是,Sonar也使用JaCoCo來(lái)監(jiān)控那些隨時(shí)間變化的代碼覆蓋率。您還可以針對(duì)新的代碼覆蓋率級(jí)別過(guò)低的情況,自定義質(zhì)量門(mén)(Quality Gates)的通知與警報(bào)。
- OpenClover除了提供一組基本的覆蓋率度量標(biāo)準(zhǔn)與集成之外,還包含了一組旨在提高代碼覆蓋率的度量標(biāo)準(zhǔn)。
- Cobertura曾經(jīng)是Java最受歡迎的代碼覆蓋工具,不過(guò)目前已不再被維護(hù)與更新。
7.半自動(dòng)化的代碼審查
在整個(gè)代碼管控的過(guò)程中,最復(fù)雜、且最難實(shí)現(xiàn)自動(dòng)化的環(huán)節(jié),當(dāng)屬代碼審查。由于部分需要依賴(lài)手動(dòng)來(lái)實(shí)現(xiàn),因此該過(guò)程往往取決于審查者的技能、資歷、甚至是態(tài)度,而且其結(jié)果也不盡相同。
例如,SonarQube僅在其付費(fèi)版本中,提供了針對(duì)合并與拉取式請(qǐng)求的靜態(tài)自動(dòng)化分析。據(jù)此,您可以在打開(kāi)某個(gè)合并式請(qǐng)求(Merge Request)時(shí),登錄到SCM,并在代碼中直接查看到靜態(tài)代碼分析的結(jié)果。
而開(kāi)發(fā)人員則主要會(huì)從如下方面開(kāi)展代碼審查:
- 功能性需求審查
- 特定項(xiàng)目的需求審查
- 高級(jí)設(shè)計(jì)或架構(gòu)審查
- 代碼復(fù)雜度和性能審查
因此,為了使代碼審查的過(guò)程更能保持一致性,我們應(yīng)準(zhǔn)備好一份代碼審查清單,以事先約定好手動(dòng)代碼驗(yàn)證的詳細(xì)內(nèi)容。對(duì)此,您可以參考Google的《代碼審查之開(kāi)發(fā)者指南,Code Review Developers Guide》。它在“代碼審查”部分給出了一個(gè)簡(jiǎn)短的審查清單,以便實(shí)現(xiàn)整個(gè)團(tuán)隊(duì)在審查過(guò)程中的統(tǒng)一性。
原文標(biāo)題:How To Keep Code Quality Under Control In 7 Steps,作者:Artur Kluz
【51CTO譯稿,合作站點(diǎn)轉(zhuǎn)載請(qǐng)注明原文譯者和出處為51CTO.com】