sonar掃描——方法重構分析


代碼重構之法——方法重構分析

Intro#

想要寫出比較優秀的代碼,需要時刻警惕代碼中的壞味道,今天想寫一篇文章介紹一下如何分析你的方法是不是需要考慮重構

一個方法通常有三個部分組成,輸入(Input),輸出(Output),方法體(Method Body),我們就從這三個方面來分析一個方法是否該考慮重構

Input#

方法輸入也就是方法的參數,通常來說一個方法的參數基本可以控制在7個以內(僅作參考,可以自己衡量,SonarQube 默認方法最多七個參數),如果你的方法參數過多的話,可能就需要考慮重構一個方法參數了,通常的做法是封裝一個獨立的 model,參數作為 model 的屬性。

舉一個常見的例子,比如一個新聞列表的API,起初可能很簡單,就只需要一個 lastId,一個 count 兩個參數,但是隨着業務需求的增加,可能會增加很多別的參數,比如前端提供一個 keyword 進行全文檢索,提供一個 sortBy 進行排序,根據新聞標題匹配,作者名稱匹配,分類匹配,根據發布時間篩選等等,最后可能會導致這個方法的參數有很多

通常我會新增一個 XxxRequest 的 model,然后方法參數替換成這個 model,然后指定 [FromQuery] 就可以了,可以對比一個修改前后的差異,是不是后面的方式更清爽一些呢

Copy
Task<IActionResult> List(int lastId, int count, string title, string author, string keyword, int categoryId, string sortBy, DateTime? beginTime, DateTime? endTime) 
Copy
Task<IActionResult> List([FromQuery]NewsListQueryRequest request) 

Output#

Output 就是方法的返回值,盡可能返回具體的類型,盡可能避免使用 Tuple 等類型,方法的返回值應該具有明確的意義

使用具體的 Model 代替 Tuple 返回值,尤其是一些 public 的,要被外部訪問的方法更應該返回具體的類型,雖然 C# 7.2 開始支持了 named tuple,會比之前友好很多,支持給 tuple 指定名稱,但是這只是編譯器級別的,實際還是 Item1,Item2 ...,還是比較推薦使用具體的 model,更加明了

Body#

通常一個方法不要太長,曾經在群里看到群友吐槽一個方法兩千多行,這樣的方法維護起來簡直就是災難,不要讓一個方法太長,保持方體體的簡單,一些通用的邏輯通過 Filter 或結合 AOP 來實現

Sonar 有一個分析方法復雜度的一個方法,官方稱之為 Cognitive Complexity

簡單介紹一下,代碼里的 if/switch/for/foreach/try...catch/while 都會增加方法的復雜度,出現一層嵌套則復雜度再加1, Sonar 默認的一個方法的復雜度不能超過 15

來幾個簡單的示例:

下面這個方法的復雜度是 3,有三個 if(else) 分支

Copy
void Method1(int num) {
  if(num > 0)
  {
  } 
  else if(num <0)
  {
  } 
  else
  {
  }
}

下面這個方法的復雜度是 3,foreach 帶來了 1 的復雜度,if 也是1的復雜度,但是因為 if 是嵌套在 foreach 內部的,一層嵌套會導致復雜度增加1

Copy
void Method1(int[] nums) {
  foreach(var num in nums)
  {
    if(num > 0)
    {
    }
  }
}

下面這個方法的復雜度在上面的基礎上增加了兩個 catch,這使得復雜度會加 2,從而變成 5

Copy
void Method1(int[] nums) {
  try
  {
    foreach(var num in nums)
    {
      if(num > 0)
      {
      }
    }
  }
  catch(InvalidOperationException e)
  {
  }
  catch(Exception e)
  {
  }
}

更多示例可以參考官方介紹: https://www.sonarsource.com/docs/CognitiveComplexity.pdf

Reduce Complexity#

前面我們介紹了一些復雜度的分析,如何能夠切實有效的降低方法的復雜度呢:

  1. 方法參數不宜過多,參數過多考慮重構輸入參數,通常可以新建一個 model 來管理輸入參數
  2. 方法返回值不宜使用意義不明的返回值,盡量不用 Tuple 作為返回值
  3. 方法的行數不要太多,利用新語法減少行數,減少 if 判斷,比如使用 null 傳播符代替一系列的 iflist?.FirstOrDefault()?.Name, a ??="test"
  4. 多個方法的相同邏輯使用切面邏輯處理,比如每個方法里都有 try...catch,那我們就可以使用一個復雜 try...catch 的切面邏輯,如果是 mvc/webapi 也可以借助 ExceptionFilter 來實現
  5. 參數校驗使用微軟的 ModelValidator 或者使用 FluentValidation 進行校驗,在代碼里盡量避免使用大量的 if 判斷導致復雜度的增加
  6. 仔細 review 代碼,有些邏輯是否合並在一起,避免在多個 if 里嵌套相同遍歷邏輯
  7. and more...(等你來補充

More#

除了自己主動感知方法的復雜度之外,我們也可以借助一些第三方的靜態代碼分析工具來分析我們的代碼,從而獲得一些修改建議進而保證代碼的高質量。

SonarQube 是目前使用較多的工具,可以方便的和 CI 集成,有一個 SonarCloud 網站提供雲服務,可以輕松為你的開源項目集成靜態代碼分析,有興趣可以看看,地址是 https://sonarcloud.io/,之前還用過 codacy,似乎不太流行,推薦 SonarQube

Reference#

==

 

出處:https://www.cnblogs.com/weihanli/p/13636616.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM