重構-改善既有的程式設計feat.實戰經驗
這本書在我六年前剛轉職的時候有看過一遍,但那時的我因為經驗不足,其實看完沒有什麼感觸,現在累積了幾年的工作經驗再來二刷這本書,就蠻有共鳴了,開始可以體會何謂程式碼的「壞味道」,因此隨手將書中我覺得不錯的內容摘要下來,並且會結合我先前重構的經驗跟大家分享
重構的最終目的就是降低 bug 發生的機率,減少改 a 壞 b 的可能性,讓大家可以輕鬆地維護這包程式碼
當你發現你的函式做了太多事情的時候,超過六行的程式碼就會開始有壞味道,是該考慮將部份的功能抽離出來了,這樣一來也會比較好維護和除錯,
👉 我真的看過一個函式快要五百行,每次光是找對應的功能就找超久…
1 | //====重構前===== |
函式和變數的命名要明確,讓別人可以透過名稱就知道這個函式的目的是什麼,假設有在用 ai 輔助工具(ex. Copilot)寫程式的人,好的命名可以讓 ai 推論出更符合你要的需求的程式碼
👉 a、 b、 x、 y、 z 這類的命名真的是先不要,絕對會讓你的同事抓狂
避免使用全域變數,會很難知道有哪些程式碼接觸它
👉 早期還沒開始用前端框架開發時,真的就是用了一堆全域變數,要追查是哪些地方有修改到這個變數非常非常花時間
將函式參數化,如果兩個函式有非常相似的邏輯,使用不同的常數,可以將 它們改成一個函式,透過傳入不同的參數來做到差異化,增加函式的實用性
1 | //====重構前===== |
👉 早期寫程式的時候都不會發現自己寫了很多相似的函式 😂
移除旗標引數,因為它們會讓我難以理解函式有哪些呼叫方式
1 | //====重構前===== |
👉 透過參數(name)來識別 value 要賦值給哪一個變數,但這樣寫反而會增加一堆條件判斷式
將參數換成查詢程式,讓參數可以保持簡單,降低呼叫方的心智負擔
1 | //====重構前===== |
👉 假設傳入 function 的參數都是某個物件的屬性的話,就直接傳入物件即可
遇到難以閱讀的運算式就提取變數吧!
1 | //====重構前===== |
👉 為了提高程式碼可讀性,複雜的計算或是條件判斷都可以抽成變數
盡可能地使用 early return
1 | //====重構前===== |
👉 以前很容易就寫出巢狀的條件判斷式(波動拳等級),使用 early return 可以降低程式複雜度
重構最害怕的就是將原有的功能改壞,所以一定要有完整的自動化測試 support,才能無後顧之憂
👉 之前的重構給的工時非常短,因此測試什麼就放生了,完全沒寫單元測試,只靠 RD 簡單手動自測,果不其然重構之後衍生了不少的 bug,就變成上線之後讓客戶來幫你測試 😉
將重構的步驟拆解成很多小步驟,在除錯上會更容易
👉 重構就像拆彈作業一樣,小心謹慎一步一步來,確保程式碼可以正常運作
程式碼好壞的關鍵,在於它有多麼容易修改,如果有人想要修改,他們可以輕鬆地找到需要修改的地方
👉 我想大多數的人都會認同這句話,好的程式碼不需要花太多時間 trace code,就能夠找到要改的地方
不良的程式設計常用更多程式碼做同一件事,因此重構有一個很重要的面相是:消除重複的程式碼,才不會發生我明明修改了 A 處程式碼,卻沒有如我預期的運作,就是因為我沒有改到 B 處地方的程式碼
👉 之前曾經有過一個經驗,要調整某個功能的計算公式,但是我發現明明已經改了 A 地方的函式卻沒有套用新的公式,排查後才發現還有 B、C、D函式等漏網之魚,如果可以抽成共用函式的話,維護上會輕鬆很多
移除沒有用到的程式碼
👉 在重構的時候很常發現有些函式都沒有地方呼叫,隨著需求的變更,或許這個功能已經不需要了,那麼就毫不留念的拔掉它吧!
重構的挑戰
我個人認為重構向來是一項吃力不討好的工作,當你說要重構的時候,主管或是 pm 可能會問你,好端端的為什麼要重構?對他們而言,現有的架構都能夠正常運作,何必沒事找事做呢?這樣豈不是會影響新功能的開發時程嗎?有的人甚至認為重構根本沒有任何的產出,因此該如何說服對方,讓他們了解重構的好處與價值,是一項非常難的課題
結語
書中提到不少的重構手法,有趣的是有些重構手法是相互牴觸的,有點像矛盾大對決那種感覺,沒有所謂的某某作法一定是最好的,因此在重構的時候還是要看自身需求決定採取哪種手法,這本書還列舉非常多物件導向的優化例子,有機會的話強烈大家可以看看這本書!