名詞定義:對軟體內部結構的一種調整,目的是在不改變「軟體可察行為」前提下,提高其可理解性,降低其修改成本。
動詞定義:使用一系列重構準則(手法),在不改變「軟體可察行為」前提下,調整其結構。
簡單的講,就是整理程式碼。
將設計由「較不適合」改成「更為適合」的實務技術。
添加新功能、修改bug與重構的關係
為了添加新功能,先重構,讓功能更好添加。
流程範例:重構 → 通過現有的測試 → 寫新功能的測試 → 添加新功能 → 通過所有的測試
為了修改bug,先重構,讓bug更清楚的被定位出來。
流程範例:重構 → 通過現有的測試 → 為bug寫新的測試 → 測試不通過,定位到bug → 修改程式 → 通過所有的測試
改進軟體設計:消除重覆的程式碼,每個小功能被歸責到適當的物件中,物件間的相依關係與數量更合理,讓物件自己說話
使軟體更容易被理解:想想過一段時間後的第二個讀者,而且這個人通常是你自己。
協助你找到bug:有責任清楚的物件群還會不容易除debug嗎。
助你提高編程速度:有責任清楚,關係合理的物件群,要添加新功能會更容易。
重構不是一件特別撥出時間做的事,當你覺得程式碼需要重構了,那就先重構再去做該做的事。
幾個時機點:
三次法則:同樣的事做三次,表示這事要被重構到唯一且適當的物件了。
添加功能時一併重構:如果現有設計對添加功能有防礙,先完成重構再添加功能。
修補錯誤時一併重構:如果現有設計對於定位bug有防礙,先完成重構再debug。
複審程式碼時一併重構:別人如果看不懂,那就不是適當的設計;清楚的程式碼讓人看到更高層次的設計想法。
重構是專業程式設計師提高生產力的工具,不用特別跟經理說。
透過重構手法,為軟體加入適當的間接層或消除不必要的間接層。
間接層的價值:
允許共享邏輯(To enable sharing of logic):一個method可在不同地方被呼叫
分開解釋意圖與實作(To explain intention and implementation separately):用class與method的名字做說明
將變化加以隔離(To isolate change):適當使用subclass將變動的衝擊抵消
將條件邏輯加以編碼(To encode conditional logic):以多型特性取代判斷邏輯
與許多技術一樣,重構也有它難以發揮的地方。
data schema的修改難以用重構調整,書本在討論這邊時,建議可在物件模型與資料庫模型之間加入分隔層,將來升級某一邊時,只需跟著升級分隔層就好。這部份需要再討論。
發佈的介面如果被修改了,也很難用重構調整,作者建議非到必要,不要發佈介面,也介紹了幾個應對介面修改的技巧。
決定設計架構時,應想好如果將來要由A設計重構成B設計,是否很困難,若不困難則可選擇適合目前且較簡單的設計。但有些情況仍很難透過重構達到,例如將無安全需求的系統重構成安全性良好的系統是幾乎不可能的。
專案後期,上線前。若這時才想到要大量重構,表示之前都沒做重構的動作,或設計太過草率。
重構與設計彼此互補:設計的越差(靈活性不足或過多),將來重構的成本就越高。
有了設計,我可以思考更快,但其中充滿小漏洞。依靠重構微調設計以補足漏洞。
有了重構,一樣會進行預設計,但不再至力於找出最佳的解決方案(可能保有一些設計靈活性,但不會到處留靈活性),而是選擇一個當前合理、適當的方案,面對將來無法應付的需求改變,再以重構手法調整設計。重構手法降低了我們調整設計的難度。
量測系統,不要臆測。
雖然重構會使軟體變慢,但它也使軟體的效率最佳化更易進行。
編寫快速軟體的秘訣就是寫出「可調軟體」,調整它以求獲得足夠速度。
被分解良好(well-factored)的軟體,更容易定位出效率瓶頸,就更好調整,要達到分解良好就需要好的設計,好的設計需要適當的重構手法來達成。