「程式碼壞味道(Code Smells)」並非指程式碼有 Bug,
而是指程式碼結構中可能存在深層設計問題的跡象。

識別這些味道,是進行重構的第一步。本章列出常見的壞味道及其對應重構策略。

mindmap
  root((Code Smells))
    命名與基本邏輯
      Mysterious Name
      Duplicated Code
      Comments
    函式與參數
      Long Function
      Long Parameter List
    資料與變數
      Global Data
      Mutable Data
      Data Clumps
      Primitive Obsession
    變更擴散
      Divergent Change
      Shotgun Surgery
    OO 濫用
      Repeated Switches
      Large Class
      Refused Bequest
      Temporary Field
    模組耦合
      Feature Envy
      Message Chains
      Middle Man
      Insider Trading
    其他
      Loops
      Lazy Element
      Speculative Generality
      Data Class

命名與基本邏輯 (Naming & Basics)#

程式碼的可讀性始於命名與去重。

Code Smell症狀Refactoring
Mysterious Name難以命名,代表功能理解不足Rename
Duplicated Code相同邏輯散落各處Extract Function
Comments用註釋解釋複雜程式碼抽為函式或用斷言說明

註釋往往像「除臭劑」,用來掩飾程式碼的低劣品質。
如果你需要寫註釋來解釋程式碼,不如先試著重構它。

函式與參數 (Functions & Parameters)#

函式應專注於「做什麼(What)」而非展示冗長的「如何做(How)」。

Code Smell症狀Refactoring
Long Function函式過長拆分成小函式並命名
Long Parameter List參數過多組合成 Parameter Object

資料與變數管理 (Data Handling)#

資料的範圍與型態管理不當,是導致系統脆弱的主因。

Code Smell症狀Refactoring
Global Data資料可在任何地方被修改用存取函式封裝
Mutable Data變數頻繁變動,作用域大封裝變數,查詢與修改分離
Data Clumps資料總是成群出現提取為獨立類別
Primitive Obsession過度使用基本型態代表業務概念改為 Value Object

變更的擴散與隔離 (Change Prevention)#

當需求變更時,好的設計應能將修改範圍限縮在單一模組內。

Code Smell症狀Refactoring
Divergent Change一個類別因不同原因被不同方式修改拆分成不同類別,建立領域邊界
Shotgun Surgery一個修改需更動多個類別搬移函式,將相關邏輯集中
  • 發散式修改是「一個類別受多種變化影響」
  • 散彈式修改是「一種變化影響多個類別」
flowchart LR
    subgraph divergent ["發散式修改 (Divergent Change)"]
        direction TB
        D1[變化 A] --> C1[類別 X]
        D2[變化 B] --> C1
        D3[變化 C] --> C1
    end
    subgraph shotgun ["散彈式修改 (Shotgun Surgery)"]
        direction TB
        S1[變化 X] --> T1[類別 A]
        S1 --> T2[類別 B]
        S1 --> T3[類別 C]
    end

類別與物件導向濫用 (Object-Orientation Abusers)#

這些味道顯示程式碼未能有效利用物件導向的特性。

Code Smell症狀Refactoring
Repeated Switches相同 Switch 邏輯散落各處使用多型取代條件判斷
Large Class類別有太多欄位或職責拆解為子類別或元件
Alternative Classes類似功能但介面不同提取共同父類別
Refused Bequest子類別只用父類別一小部分功能改用委託 (Delegation)
Temporary Field欄位只在特定情況有值提取為新類別

模組間的耦合 (Coupling)#

模組間應低耦合,避免過度親密或不必要的傳話。

Code Smell症狀Refactoring
Feature Envy函式對別的類別資料更感興趣將函式移到資料所在類別
Message Chains層層呼叫如 a.getB().getC()隱藏委託或抽取成函式
Middle Man過半函式只是委託給另一類別移除中間人,直接溝通
Insider Trading模組間過度隱晦交換資料搬移函式或用中介模組

其他可疑之處 (Others)#

Code Smell症狀Refactoring
Loops用傳統迴圈處理集合使用 Pipeline(filter、map)
Lazy Element目前沒作用的函式或類別Inline 消除
Speculative Generality為未來設計的複雜機制移除(遵循 YAGNI)
Data Class只有欄位和 Getter/Setter將相關行為搬入類別
如何看待壞味道

識別壞味道不是為了追求完美,而是為了風險管理
當你聞到味道時,不代表必須立即修改,但它是個強烈訊號,
告訴你這裡未來可能會出問題,或這裡是難以維護的熱點。