[Book] 重構:改善既有程式的設計
Refactoring: Web Edition @ informit
Book Refactoring @ Gitlab
Chapter 6:第一組重構
Extract Function(提取函式)
時機
作者認為,提取函式的時間不是依照程式碼的長度、也不是只有在程式碼會被重複使用時,才來做提取函式的動作,而是「如果你必須費心查看一段程式碼才能了解它究竟在做什麼,你就應該把它拆出來,並且以它的目的來命名。」
"Separation between intention(what) and implementation."
做法
建立一個新函式,並且根據函式的目的來為它命名(根據 what 而不是 how 來命名)。
Inline Function(將函式內聯)
時機
「當程式碼本身的內容和函式名稱一樣清楚時」就不需要額外做內聯,因為多這一層反而增加認知負擔。
作法
將原本函式中的程式碼,直接放回執行它的地方,而不在包這一層函式。
Extract Variable(提取變數)
時機
當只看某個邏輯、運算式或判斷式沒辦法立即瞭解其意義時
做法
將比較複雜的邏輯命名,以讓其他開發者更容易理解
許多編輯器都有提供了 Refactor 的功能,方便開發者做到將程式提取成變數的動作。
VSCode 能將所選的程式碼抽取成變數:
Goland 能將所選的程式碼,以及相同的程式碼片段,同時抽取成變數:
Inline Variable(內聯變數)
時機
運算式或程式碼本身已經能清楚傳達訊息,不需要額外提取成變數,以避免額外負擔
做法
幫變數的程式碼貼回使用它的地方
Change Function Declaration(修改函式宣告式)
時機
發現函式的名稱不易理解時
做法
改善名稱的一個好方法是:「寫下註解來說明函式的用途,再把註解變成一個名稱」:
- 修改函式名稱:讓名稱能夠更清楚該函式做了什麼
- 修改函式參數:傳入整個物件或特定屬性
修改函式或變數名稱時,請善用 Editor/IDE 提供的 refactor 的功能(預設是按 F2),它會自動幫你修改所有參照到這個變數的地方。
如果我們希望將這個函式的名稱從 circum
改為 circumference
:
func circum(radius float64) float64 {
return 2 * math.Pi * radius
}
但因為使用這個函式的地方非常多,可能沒辦法一次全部取代,所以我們暫時先同時保留兩個函式:
func circum(radius float64) float64 {
+ return circum(radius)
+}
+
+func circumference(radius float64) float64 {
return 2 * math.Pi * radius
}
在有使用到這個函式的地方,陸續進行替換,知道全部替換完畢後,在移除舊有的函式。
思考
在傳遞函式參數的時候,經常會碰到要傳遞整個物件或只有使用到屬性。當傳遞整個物件時,會讓函式和這個物件的介面耦合,但卻可以輕鬆的讀取該物件中的其他屬性,當未來邏輯改變時,不需要修改這個函式的任何呼叫方,並可以增加函式的封裝性。
Rename Variable(更改變數名稱)
如果要修改「常數」名稱,和修改函式名稱一樣,一個好用的技巧是先同時新舊兩個變數名稱,逐步替換完畢後,再把舊的變數刪除。
假設我們希望把 cpyNm
改成 companyName
:
// 這是原本的變數名稱
const cpyNm = 'Acme Gooseberries';
我們先建立新的變數,並將舊的變數參照到新的變數:
// 這是希望修改後的變數名稱
const companyName = 'Acme Gooseberries';
const cpyNm = companyName;