Principles in Refactoring

重構的原則 (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) 來管理綱目變更,並支援多版本並行以利平滑升級

關於品質與速度:

  • 小步驟是關鍵: 透過極小的步驟進行重構,能讓你快速寫出好程式,且因為每次變動極小,幾乎不需要花時間除錯
  • 優秀的程式碼更需要重構: 許多人認為只有醜陋的程式碼才需要重構,事實上,為了保持優秀的設計與適應性,優秀的程式碼也需要經歷大量的重構