本文將介紹.Net界堪稱神級的工具 - Resharper。
先強調這絕對不是業配文!
筆者也沒有收取廠商任何廣告費用,
只是希望讓更多人認識這套工具。
Resharper
ReSharper是JetBrains公司發行的一套Visual Studio擴充套件,
提供的擴充功能很多,
以下僅摘述筆者比較常用的功能介紹:
- 原始碼查看
- 程式碼靜態分析
- 快速重構
Price
單純購買擴充套件的話一年需299美元(約9200$ NT),
授權計價皆以年為單位,
但續約的價格會相對便宜許多(計價方案如下圖 - 2018.11.14)。
沒使用過的朋友可以到官網下載30天的試用版,
下載之後進行安裝即可(需先安裝Visual Studio 2017)。
原始碼查看
雖然現在有非常多的套件都是Open Source,
但看個程式碼還要大費周章跑到GitHub總是為令人感到麻煩,
ReSharper整合了自己家的DotPeek(一套免費.Net原始碼查看工具),
讓原始碼查看(快捷鍵F12)功能變的相當輕易,
但真的去用的人還是占少數。
你也許會想:
「Code都寫不完了,哪有時間看原始碼?」
「沒事看原始碼,吃飽太閒嗎?」
「功能好好的,開發也沒問題,幹嘛看?」
那換個情境思考,
假設你帶你的小孩看完醫生後去領藥,
你不會關注藥物過敏或副作用嗎?
同樣的場景,換成了你的程式碼,
我們卻只求「會動就好」。
我們太習慣「從結果推斷過程」的學習方式,
久了就容易不小心地把錯誤的認知當成「常識」。
舉簡單的資料結構而言,
請問以下的程式碼誰執行會比較快?
List<string> stringList = GetStringList();
stringList.LastOrDefault();
string[] stringArray = GetStringArray();
stringArray.LastOrDefault();
以直覺的思考方式來說,
陣列是以索引值取得集合中的元素,
一般串列則只會記得下一個元素的記憶體位置。
所以你就會很自然的推想:
- 陣列是用Array[陣列長度-1]的方式取得最後一筆元素的值,
- 串列則會逐筆尋找,直到沒有下一個元素為止。
再加上使用了最熟也最不熟的LINQ,
就會很自然的認為兩者的效能差距應該會非常大(直接找跟逐筆找的差別)。
但真的是這樣嗎?
我們使用原始碼查看功能來看一下LastOrDefault這段程式碼。
public static TSource LastOrDefault<TSource>(this IEnumerable<TSource> source) {
if (source == null) throw Error.ArgumentNull("source");
IList<TSource> list = source as IList<TSource>;
if (list != null) {
int count = list.Count;
if (count > 0) return list[count - 1];
}
else {
using (IEnumerator<TSource> e = source.GetEnumerator()) {
if (e.MoveNext()) {
TSource result;
do {
result = e.Current;
} while (e.MoveNext());
return result;
}
}
}
return default(TSource);
}
程式內容翻譯概述如下:
LastOrDefault是針對 IEnumerable<TSource>
做擴充,
當被呼叫時會先嘗試轉型為 IList<TSource>
的型別,
如果轉型成功就使用[長度 - 1]的方式回傳元素值,
不能轉型的話才會逐筆呼叫 MoveNext()
。
當然,我們不可能有時間把每個API看過一遍,
但在使用API得到非預期的結果時,
查看原始碼總比你瞎猜來的好。
程式碼靜態分析
這項功能會自動分析我們現有的程式碼,
然後建議我們比較好的寫法。
舉個簡單的範例Demo,
假設我的原始碼長這樣:
var arr = new int[]{ 3, 4, 5, 6, 7 };
var sum = 0;
for (int i=0; i< arr.Length; i++)
{
sum += arr[i];
}
這時ReSharper會很貼心的提醒你。
除了提醒之外,
還可以快速幫你重構。
選擇轉換成LINQ寫法,
一秒幫你轉過去。
按按快捷鍵事情就做完了,
而且還比較好看!
有關程式碼分析的部分有興趣的讀者可以參考官網的介紹。
快速重構
接下來要介紹的是ReSharper的靈魂所在 - Refactor(重構)
Martin Fowler大師對重構的定義:
在不改變軟體外部行為的前提下,改變其內部結構,使其更容易理解且易於修改
重構牽涉的範圍之廣,
推薦大家可以閱讀聖經本重構─改善既有程式的設計,
此書介紹了許多重構的技巧與名詞,
搭配ReSharper的Refactor使用會更有感覺!
下面會有一堆快捷鍵,
真的記不住至少要記住快捷鍵Ctrl
+Shift
+R
- 彈出Refactor的小視窗。
一樣開始之前先來看看我寫的爛Code,
這邊我用了一個完全沒意義的tempVariable來存數字,
List<int> list = new List<int>();
int tempVariable = 10;
list.Add(tempVariable);
Inline
按快捷鍵Ctrl
+Alt
+N
,
可以幫我們將變數內容填到傳入的方法中,
按下確定之後它就幫我們做完了。
在整理程式碼的過程,
如果我覺得我取的變數好像沒什麼意義,
我就會試著inline回去,
然後再看看這樣是不是比較好理解。
詳細的操作流程可以參考官網提供的範例,
我覺得解說還蠻詳細的,
以下僅分享幾個筆者比較熟悉的重構手法:
Introduce
這個手法跟Inline剛好相反,
Inline是把變數回填到方法中,
Introduce則是把方法中值抽取出來。
Introduce可分為以下三種:
- Introduce Parameter:將值抽取成參數 (快捷鍵
Ctrl
+Alt
+P
) - Introduce Filed:將值抽取成欄位(快捷鍵
Ctrl
+Alt
+F
) - Introduce Variable:將值抽取成變數(筆者目前還沒找到快捷鍵,若有大大知道再麻煩分享!)
通常我會在看不懂方法中「傳入值」想表達的意義時使用這個手法,
將其抽取出來,試著搭配命名來解釋「我想幹麻」。
Rename
快捷鍵:Ctrl
+R
+R
重新命名看似最簡單,
其實是最難的事情。
一個好的命名應該明確的表達意圖,
讓別人看你的程式碼就知道「你想幹嘛」,
而不需要任何註解和文件來補充說明。
但要一次命名就到位其實還是需要相當的經驗,
我個人會習慣在進行重構時,
試著以陌生人的角度來看,
只要我覺得不好理解,
或想到更好的命名,
就會把舊的命名給取代掉。
Extract Method
快捷鍵:Ctrl
+R
+M
方法抽取是最常用的重構手法之一,
我通常會先把比較複雜的程式碼抽出來,
然後在針對那團程式碼逐一拆解,
歸納完主要的邏輯之後再看看是否要調整。
也可能把邏輯主幹歸納完之後再將不必要的變數Inline回去。
結語
就在完賽的前一週,
筆者剛好很巧的去上91哥的「重構與TDD實戰」,
也激起我想用「重構」這個主題做結尾的念頭。
講師在上課的過程中,
透過直接Live Coding的方式,
不斷的顛覆我對重構的定義,
「你的重構不是我的重構」
「你以為重構只是Rename跟Extract Method嗎?」
「一段程式碼至少要被重構三次以上」
距離上完課已經三天了,
這些聲音還在我耳邊圍繞。
重構會隨著每個人的功力而有不同的結果,
也許有些人會認為「後面有時間再來重構」,
但通常就不會有然後了。
重構應該要在當下的過程就進行,
否則後面再回來Code Review時,
還要花一次功去理解這段程式碼的含意。
ReSharper對於一個開發者的助益實在頗大,
但在費用上的確是一筆開銷。
最後我想引用91哥的一段話作為結語:
買來擺著不用,你就會覺得貴。
讓它(ReSharper)可以幫你賺錢,你就會覺得便宜。
參考
https://www.jetbrains.com/resharper/features/code_refactoring.html