重構的原則 (Principles in Refactoring) #
作者深入探討重構的四大面向:定義(What)、效益(Why)、時機(When)以及執行者與相關議題(Who)。
重構不僅是修改程式碼,更是種維持軟體生命力的核心紀律。
1. 什麼是重構 (Definition) #
作者將「重構」分為名詞與動詞兩層次來定義,強調其核心在於不改變外在行為。
- 名詞定義: 不改變軟體可觀察行為的前提下,對內部進行變動,以提高可理解性並降低修改成本
- 動詞定義: 使用一系列特定的重構手法來重新架構軟體
在重構過程中,不應同時加入新功能。重構與開發新功能應視為兩頂不同帽子,時刻區分清楚。
2. 為何需要重構 (Why) #
重構並非無謂的浪費時間,而是為了長遠的開發效率。
| 重構的目的與效益 | 核心說明與原理 | 不重構的後果 (代價) |
|---|---|---|
| 改善架構設計 | 抵抗架構的劣化 (Entropy)。透過不斷維護,保持系統的健康狀態。 | 架構會隨時間劣化,加速腐敗,導致日後修改困難。 |
| 讓軟體更容易理解 | 程式碼是寫給人看的。重構讓**「程式碼實際做的」與「開發者腦中期待它做的」保持一致**。 | 提高程式碼的理解成本與維護難度。 |
| 幫助找出 Bug | 重構要求開發者深入理解程式結構並釐清假設。 | 在釐清結構的過程中,往往能讓隱藏的 Bug 無所遁形。 |
| 提高開發速度 | 良好的模組化與清晰設計,讓開發者只需理解系統一小部分即可修改。 | 減少不必要的耦合與複雜度,從而加速整體開發節奏。 |
3. 何時該重構 (When) #
重構不應被視為專案結束後的「清理階段」,而應隨時隨地發生。
| 重構策略 | 說明與定義 | 觸發時機與核心原則 | 目的與重點 |
|---|---|---|---|
| 三次法則 (The Rule of Three) | 事不過三:當第三次做類似的事情時,就應該進行抽象化和重構 | 發現重複程式碼第三次出現 | 避免重複程式碼 (DRY),在問題萌芽時解決 |
| 預備性重構 (Preparatory Refactoring) | 在新增功能之前,先調整結構使程式碼更容易添加新功能 | 準備進行功能修改或新增 | 「讓修改變得容易,然後再進行容易的修改。」 (Make the change easy, then make the easy change) |
| 理解性重構 (Comprehension Refactoring) | 在修改程式碼前,為了理解其作用而進行的重構 | 遇到難以理解的舊程式碼 | 透過重構釐清邏輯,確保修改不會產生意外錯誤 |
| 撿垃圾式重構 (Litter-Pickup Refactoring) | 看到糟糕的結構就隨手清理 | 隨時隨地 | 類似**「童子軍軍規」**(離開營地時要比抵達時更乾淨) |
| 伺機性重構 (Opportunistic Refactoring) | 不必專門撥出時間,而是與當前的開發工作一同進行 | 專注於當前正在開發或接觸的區域。 | 將重構整合到日常開發流程中 |
| 長時程重構 (Long-Term Refactoring) | 對於大型架構的調整 | 涉及系統核心或多個模組的重大變動 | 不建議停下所有開發,而是在一段時間內,每當觸碰到相關區域時就進行一點改善 |
4. 重構的難題與應對 (Challenges) #
導入重構時,團隊往往會面臨技術與管理上的挑戰。
Code Review 是推廣重構的好時機。如果你先對程式碼進行重構,往往能給出更具體、優質的建議,而不僅是指出問題。
點擊展開:如何應對重構的五大難題
⚠️ 重構的常見挑戰與應對策略
| 挑戰/問題 | 核心問題或迷思 | 應對策略 (Countermeasure) |
|---|---|---|
| 減慢新功能開發速度 | 迷思: 認為重構會拖慢進度 | 真相: 現狀往往是人們**「過少」而非「過度」重構**。長期來看,重構能顯著提升速度 |
| 缺乏程式碼擁有權 (Code Ownership) | 當你需要修改的介面被其他團隊使用,但你無權修改他們的程式碼 | 保留舊介面但標註為「棄用 (Deprecated)」,讓呼叫端有時間遷移,之後再完整刪除 |
| 分支合併衝突 (Branch Merging Conflicts) | 重構改變大量程式碼結構,Feature Branch 在合併時會產生嚴重衝突 | 實施 持續整合 (CI),頻繁合併主幹,防止各分支版本差異過大 |
| 缺乏自我測試 (Self-Testing Code) | 不確定重構是否破壞了功能 | 建立自動化測試是重構的安全網,也是 持續交付 (CD) 的必要元素 |
| 處理老舊程式碼 (Legacy Code) | 遺留系統往往缺乏測試,重構風險極高 | 先尋找系統的「接縫 (Seams)」,插入測試,逐步建立信心圈,再進行重構 |
| 資料庫重構 (Databases) | 資料庫綱目 (Schema) 的變更帶來的挑戰 | 將資料庫變動視為版本控制的一部分。使用遷移腳本 (Migration Scripts) 來管理綱目變更,並支援多版本並行以利平滑升級 |
關於品質與速度:
- 小步驟是關鍵: 透過極小的步驟進行重構,能讓你快速寫出好程式,且因為每次變動極小,幾乎不需要花時間除錯
- 優秀的程式碼更需要重構: 許多人認為只有醜陋的程式碼才需要重構,事實上,為了保持優秀的設計與適應性,優秀的程式碼也需要經歷大量的重構