提取函式 (Extract Function)

★★★★★Reviewed

FromRefactoringClean Code

📚 From the Books

提取函式 (Extract Function)Refactoring Moves

把一段程式碼抽成獨立函式,用一個好名字描述它「做什麼」。這是最常用、也最基礎的重構——多數其他手法都從它長出來。

🧠 Why It's a Problem

抽取的判準不是「程式碼夠長」,而是 意圖與實作的距離:當你得讀完一整段才搞懂它在幹嘛,就把那段封進一個名字。

TIP

Fowler 的立場:只要命名能讓意圖更清楚,即使函式只有一行也值得抽。 函式的價值在「以名代義」,不在省行數。

⚖️ Refactoring

機械步驟:① 建新函式、用「意圖」命名 → ② 把選取片段複製過去 → ③ 處理區域變數(成為參數或回傳值)→ ④ 原處改成呼叫 → ⑤ 測試。

前 — 意圖埋在細節裡
function priceOrder(product, quantity) {
  const basePrice = product.basePrice * quantity;
  const discount =
    Math.max(quantity - product.discountThreshold, 0) *
    product.basePrice * product.discountRate;
  const shipping = Math.min(basePrice * 0.1, 100);
  return basePrice - discount + shipping;
}

讀者得逐行算才知道「價格 = 底價 − 折扣 + 運費」。

後 — 每個概念有名字
function priceOrder(product, quantity) {
  const basePrice = product.basePrice * quantity;
  const discount = discountFor(product, quantity);
  const shipping = shippingFor(basePrice);
  return basePrice - discount + shipping;
}

function discountFor(product, quantity) {
  return Math.max(quantity - product.discountThreshold, 0) *
    product.basePrice * product.discountRate;
}

function shippingFor(basePrice) {
  return Math.min(basePrice * 0.1, 100);
}

主函式現在直接讀作公式本身;折扣和運費規則各自獨立,將來改規則只動一處。

WARNING

反向手法是 Inline Function:當函式本體已和名字一樣清楚、或一層間接反而礙事時,把它合回去。抽取不是越多越好——目標是清晰,不是數量。

🔑 Takeaways

✍️ My Notes

No notes yet — jot your takeaways or Q&A here.

📖 Further Reading