關於程式碼質量度量和分析的一些總結

2023-12-10 21:03:27

最近團隊做CMMI3認證,這期間涉及到了程式碼質量度量。花了點時間做了總結,分享給大家。

先看一張整體的圖,然後逐個指標展開說明。

 一、單元測試覆蓋率

單元測試覆蓋率(Coverage)是一個度量單元測試覆蓋了多少程式碼的指標。它是一種衡量測試質量的方法,用來指示我們的測試用例覆蓋了程式碼的多大部分。 覆蓋率的計算方式通常包括以下幾種: 行覆蓋率(Line Coverage):測試覆蓋了多少程式碼行。 分支覆蓋率(Branch Coverage):測試覆蓋了多少if、switch等決策點的所有可能路徑。 函數覆蓋率(Function Coverage):測試覆蓋了多少個函數或方法。 語句覆蓋率(Statement Coverage):測試覆蓋了多少個語句。 覆蓋率越高,表示的測試用例覆蓋的程式碼越全面,程式碼的質量可能越好。但是,這並不意味著覆蓋率100%就一定沒有問題,因為覆蓋率只是告訴我們測試了哪些程式碼,而不是告訴我們測試的質量如何。另外,有些程式碼可能很難達到高覆蓋率,例如例外處理程式碼等。 一般來說,覆蓋率應該儘可能的高,一般認為80%是一個比較好的目標。
 
二、程式碼複雜度
Cyclomatic Complexity(圈複雜度)和 Cognitive Complexity(認知複雜度) 都是軟體度量中的複雜度度量指標。其中: 1. Cyclomatic Complexity圈複雜度在數量上表現為程式碼獨立執行路徑條數。 例如,每個「if」語句就會新增了一條額外的程式碼路徑。圈複雜度越高,程式程式碼的判斷邏輯就越複雜。此外,路徑越多,就需要編寫更多的測試用例來實現更高的程式碼覆蓋率。 每個函數的平均圈複雜度是一個指標,可以比較程式之間的複雜性。 圈複雜度在一定程度上展示了程式程式碼的「可維護性」。 2. Cognitive Complexity(認知複雜度)是SonarQube提出的一種新的複雜度度量方法,它試圖量化程式碼對人類理解的難度,而不僅僅是程式碼的結構複雜度。認知複雜度的計算考慮了程式的結構複雜度(如迴圈、判斷分支等),以及程式的可讀性(如程式碼的冗餘性、是否遵守最佳實踐等)。例如,一個包含巢狀迴圈和條件判斷的函數,其認知複雜度會高於只包含順序執行程式碼的函數。另一個例子是,使用了難以理解的短變數名或者包含冗長的函數和類,這些都會增加程式碼的認知複雜度。
 
三、程式碼重複度
程式碼重複度是指在程式碼庫中有多少程式碼是重複的,也就是相似或完全相同的程式碼塊出現的次數。 1. 程式碼重複通常是由於複製和貼上程式設計(也稱為「剪貼簿程式設計」)導致的,這種情況下,開發人員可能會複製一個函數或一段程式碼,然後稍作修改以滿足新的需求。雖然這種方法可以快速解決問題,但它通常會導致維護困難和錯誤的增加。如果在原始程式碼中發現了一個錯誤,那麼所有複製的程式碼都需要進行相同的修復。。 程式碼重複度 = (重複的程式碼行數 / 總程式碼行數) * 100% 這個比例越高,表示程式碼重複的程度越嚴重。 在防止程式碼重複方面,通常的最佳做法是使用函數或類來封裝重複的程式碼,並在需要的地方呼叫這些函數或類。這樣,如果需要修改程式碼,只需要在一個地方進行修改,而不需要在多個地方進行相同的修改。
 
四、程式碼壞味道
"Code Smells"或"程式碼壞味道"是一種程式碼質量度量,用來形容那些在程式碼中可能存在問題的程式碼片段。它並不一定表示程式碼有錯誤,而是表示程式碼的設計可能存在問題,這些問題可能會使得程式碼難以理解、難以維護、難以修改。 以下是一些常見的程式碼壞味道的例子: 複雜的條件邏輯:如果一個函數或方法中存在過多的if/else或switch語句,可能表示這個函數或方法承擔了過多的責任,需要進行重構。 長方法:一個方法過長,可能難以理解和維護。一般來說,一個好的方法應該只做一件事情,並且做得好。 重複的程式碼:如同前面提到的程式碼重複度,程式碼重複是一種常見的程式碼壞味道,應該通過提取函數或類來消除。 神祕命名:如果變數、函數或類的命名不清楚,可能會導致理解和維護的困難。好的命名應該清晰表達其目的和用途。 過大的類或模組:如果一個類或模組過大,可能表示它承擔了過多的責任,需要進行分解。 
 
五、安全漏洞
Vulnerabilities或稱為安全漏洞,是指在程式碼中可能存在的安全風險。這些風險可能被攻擊者利用,從而對系統的資料和功能構成威脅。 SQL隱碼攻擊:如果程式碼中直接拼接SQL語句,而沒有對使用者輸入進行適當的處理,那麼攻擊者可能會通過輸入惡意資料來篡改SQL語句,從而進行非法查詢或修改資料。 跨站指令碼(XSS):如果網站直接輸出使用者的輸入,而沒有進行適當的跳脫或過濾,那麼攻擊者可能會通過輸入包含JavaScript程式碼的資料,從而在其他使用者的瀏覽器中執行這些程式碼。 路徑遍歷:如果程式碼中使用了使用者的輸入來構造檔案路徑,那麼攻擊者可能會通過輸入特殊的路徑(如"../")來存取到不應該被存取的檔案。 不安全的反序列化:如果程式碼接受並反序列化了使用者提供的資料,那麼攻擊者可能會通過提供惡意的資料來執行任意程式碼。 ......
 
六、技術債務
Technical Debt,或稱為技術債務,是一個比喻,用來描述因為選擇了快速或簡單的解決方案,而非最佳的解決方案,從而在未來需要付出更多的工作來解決這些問題的情況。這就像財務債務一樣,如果不及時償還,隨著時間的推移,"利息"會越來越多。 技術債務是一個重要的度量指標,用來估算修復所有程式碼壞味道所需的時間。例如,如果一個程式碼壞味道需要花費30分鐘來修復,那麼這個程式碼壞味道就會產生30分鐘的技術債務。所有程式碼壞味道的技術債務累加起來,就是整個專案的技術債務。 技術債務可以幫助團隊理解和量化程式碼質量問題的影響,從而做出更好的決策。團隊可以基於技術債務來決定是否需要對某部分程式碼進行重構,或者在新功能開發和技術債務償還之間做出權衡。 需要注意的是,技術債務並非都是壞事,有時候為了滿足業務需求,適當的接受一些技術債務是可以接受的。關鍵在於,團隊需要意識到技術債務的存在,並且制定計劃來及時償還技術債務,防止其無限制的增長。
 
七、阿里、微軟、Google這些世界級軟體公司的程式碼質量度量值 
從公開的程式設計實踐和程式碼質量標準中得到一些啟示。這些公司通常都非常重視程式碼質量,並採取各種措施來保證程式碼質量,例如嚴格的程式碼審查流程、強制的單元測試和程式碼覆蓋率要求、詳細的程式設計規範和最佳實踐等。此外,他們還經常使用自動化的程式碼質量檢查工具,如靜態程式碼分析工具,來自動檢測程式碼中的問題。 單元測試覆蓋率:這些公司通常都要求程式碼有良好的測試覆蓋率。例如,Google在其測試部落格上提到,他們的一些專案要求程式碼的單元測試覆蓋率達到80%以上。 對於程式碼複雜度,一般來說,每個函數或方法的複雜度應該儘可能的低。有些組織可能會設定一個具體的閾值,例如,圈複雜度不得超過10。這意味著每個函數或方法的控制流程不應該有超過10個不同的路徑。但是,這並不是絕對的,有時候為了實現複雜的功能,函數或方法的複雜度可能會較高。 對於程式碼重複度,一般來說,應該儘可能的低。有些組織可能會設定一個具體的閾值,例如,程式碼重複度不得超過5%。這意味著在所有程式碼中,不應該有超過5%的程式碼是重複的。但是,這也並不是絕對的,有時候為了程式碼的可讀性和維護性,可能會有一些必要的程式碼重複。
對於程式碼壞味道,它是一種主觀的度量,取決於團隊對什麼是「好的」程式碼的看法。一般來說,程式碼壞味道的數量應該儘可能地少。有些團隊可能會設定一個閾值,例如,每1000行程式碼中不應該有超過10個程式碼壞味道。然而,這並不是絕對的,有時候為了滿足特定的需求,可能會接受一些程式碼壞味道。 對於技術債務,它是一種估算修復所有程式碼壞味道所需的時間。一般來說,技術債務應該儘可能地低。有些團隊可能會設定一個閾值,例如,每1000行程式碼的技術債務不應該超過10小時。然而,這也並不是絕對的,有時候為了快速交付功能,可能會接受一些技術債務。
 
八、研發度量指標大全

 

九、業內做程式碼掃描和度量分析的專業軟體

SonarQube is a self-managed, automatic code review tool that systematically helps you deliver Clean Code. As a core element of our Sonar solution, SonarQube integrates into your existing workflow and detects issues in your code to help you perform continuous code inspections of your projects. The product analyses 30+ different programming languages and integrates into your Continuous Integration (CI) pipeline of DevOps platforms to ensure that your code meets high-quality standards.

 程式碼質量閥

 十、Azure Devops中整合SonarQube程式碼分析和上報

 

 當然,程式碼質量閥是可以定義的