怎麼樣看code的品質或好壞,通常程式碼複雜度也是其中一個頗重要的因子。
但不完全代表,複雜度低,就是品質好或好維護的 Code。複雜度高,就是代表品質不好或可讀性低的 Code。但是,複雜度還是可以像健康檢查一樣,反應出程式裡面是否有哪裡可能有問題。
今天要介紹的 SourceMonitor,是免費的,而且支援的程式語言包括:C++, C, C#, VB.NET, Java, Delphi, Visual Basic (VB6) or HTML.
[如何提升系統品質]系列文章連結
前面提到了許多重構的文章,這邊要介紹的是品質量測的工具,可以快速的幫助我們找出,哪些程式是需要被重構,可能是品質較低,未來較不好維護的。
下載網址:
SourceMonitor
Features介紹:
1.Collects metrics in a fast, single pass through source files.
2.Measures metrics for source code written in C++, C, C#, VB.NET, Java, Delphi, Visual Basic (VB6) or HTML.
3.Includes method and function level metrics for C++, C, C#, VB.NET, Java, and Delphi.
4.Saves metrics in checkpoints for comparison during software development projects.
5.Displays and prints metrics in tables and charts.
6.Operates within a standard Windows GUI or inside your scripts using XML command files.
7.Exports metrics to XML or CSV (comma-separated-value) files for further processing with other tools.
Size:安裝完在C槽佔3.81MB。
可搭配 SubVersion 跟 Continue Integration Server 一起運作,當 SubVersion 有更新時,自動掃瞄最新的程式碼,產出 Report。
而 SourceMonitor 採用的複雜度是 cyclomatic complexity(循環複雜度),主要是針對每一個 Method 裡所有可能執行的路徑來定義複雜度。
也就是 if、for、while、and、or、else 等有判斷邏輯導致路徑分歧,都會增加複雜度。
以人的角度來看,就是腦袋需要更多的空間來暫存可能會跑那些情況。(也就是 SourceMonitor 所定義的『複雜』)
使用方式
使用方式相單簡單,只要給 Source Code 的路徑,就會把裡面的檔案都抓出來,就可以進行掃瞄分析。
1.執行 SourceMonitor 程式後,新建一個專案,選好語言。(上方的框框也有步驟的說明與引導)
2.指定要掃瞄的 Source Code 路徑,可選擇全部或是只掃瞄部分資料夾底下的 Code。
3.給這個 SourceMonitor Project 一個名字,並決定是否要忽略 Comment
4.決定 SourceMonitor Project 位置
5.是否直接執行第一次 checkpoint,以及是否允許 parse UTF-8 的檔案
6.最後的 confirm
以上就是操作過程,其實幾乎就只是給了路徑,下一步下一步到結束。
接著我們來看分析的結果。
分析結果
先選好要掃瞄的相關檔案,一開始的清單是 filter 後的結果。
點下OK!就會出現掃瞄後的結果。
右鍵清單可以看分析後的detail資訊以及圖表
View Checkpoint Files
Summary
Detail的分析結果,建議可以匯出成csv,再匯入Google Doc或用excel開啟,就能使用排序、filter等功能找到自己需要的資料。
還有一些其他功能就不細部解說了,有興趣朋友自己可以去玩玩看囉。
結論
程式碼分析軟體,就像健康檢查報告一樣,檢查出來異狀,並不一定代表有問題。但要瞭解該數據是否為自然現象,是否需持續觀察。
對了,之前公司規定建議複雜度是在10以內,算是良性。50以上叫做無法維護....
補充
有人反應什麼情況下,不同寫法可以做到同樣的效果,而且複雜度下降。在什麼樣的情況『複雜度』與『可維護性』,不一定複雜度低就好維護。
我先舉個例子,例如最常見的把1~10用”;”串起來。思考邏輯可能是最後一個10後面不加『分號』。
string result = string.Empty;
for (int i = 0; i < 10; i++)
{
if (i == 9)
{
result += (i + 1).ToString() ;
}
else
{
result += (i + 1).ToString() + ";";
}
}
上面這例子,複雜度就是3。常寫code的人碰到這需求,就可能會習慣性寫成這樣:
string result2 = string.Empty;
for (int i = 0; i < 10; i++)
{
result2 += (i + 1).ToString() + ";";
}
result2 = result2.TrimEnd(';');
這樣複雜度就只有1。會比較好維護嗎? 不一定,見仁見智。
再舉個例子,哪一種寫法比較好懂
//第一種,一行幹掉
string myViewState =(string)this.ViewState["myViewState"] ?? string.Empty;
//第二種,if+else
string myViewState2="91";
if (this.ViewState["myViewState2"] == null)
{
myViewState2 = string.Empty;
}
else
{
myViewState2 = this.ViewState["myViewState2"].ToString();
}
再舉另外一個例子,哪一種好?如果連未來擴充性也納進來,那就不一定誰好誰壞了…
public bool ReadOnly { get; set; }
//第一種
if (this.ReadOnly)
{
this.txtipLoginID.Enabled = false;
}
else
{
this.txtipLoginID.Enabled = true;
}
//第二種
this.txtipLoginID.Enabled = !this.ReadOnly;
想要降低 SourceMonitor 複雜度,其實也很簡單,把判斷的片段抽出去當 void 就可以了,但是這樣程式碼就會被切的碎碎的,好維護嗎?也不一定。
一直抽到最後,一個 method 原本只呼叫深度為2的 Statck ,為了降低複雜度搞到深度變成8,值得嗎?這也有待商榷。
如何抓好 Balance ,因應不同的適用狀況來 Refactoring ,這才是寫出好 Code 的必要條件。
[註]SourceMonitor一次僅能針對某一種語言掃瞄,也就是假設專案裡面,有VB也有C#,便無法一次全分析完。