寫出乾淨函式的黃金法則:新手程式設計師必備指南

更新日期: 2025 年 2 月 3 日

想像你正在組裝樂高城堡,卻把所有零件混在一起亂拼,最後變成無法維護的畸形結構——這就是不良函式設計的後果。

許多新手開發者在寫程式時,容易陷入「能跑就好」的思維,導致程式碼變得難以閱讀、維護和擴充。

《Clean Code》第三章揭示的函式撰寫原則,就像一份「程式設計樂高說明書」,幫助我們打造簡潔、易讀、可維護的程式碼。

本文將透過程式碼示範 + 生活化比喻,帶你掌握寫出乾淨函式的九大黃金法則,讓你的程式碼告別「義大利麵式寫法」,邁向專業工程師之路!


函式結構設計原則

短小精悍法則:函式不是長篇小說

優秀函式的長度標準

理想長度:20 行以內
最佳可讀性:螢幕不滾動即可完整查看

不良示範:功能混雜的長函式

function processUserData(user) {
  // 驗證資料 (15 行)
  if (!user.name) throw new Error(...);
  if (user.age < 18) throw new Error(...);
  
  // 轉換格式 (10 行)
  const formattedUser = { ... };

  // 存入資料庫 (20 行)
  db.connect();
  db.insert(...);

  // 發送通知 (15 行)
  emailService.send(...);
}

最佳做法:拆分單一職責函式

function validateUser(user) { /* 驗證邏輯 */ }
function formatUserData(user) { /* 格式轉換 */ }
function saveToDatabase(user) { /* 資料庫操作 */ }
function sendNotification(user) { /* 發送通知 */ }

單一抽象層級:別把食譜寫成化學公式

函式應該維持統一的抽象層級,不能同時包含高層次步驟與細節執行邏輯。

不良示範:抽象層級混亂

def bake_cake():
    prepare_ingredients()  # 高層次步驟
    oven.set_temperature(180)  # 低層次實作
    while oven.current_temp < 180:
        wait(60)
    mix_ingredients()  # 回到高層次
    put_in_oven()

最佳做法:封裝底層細節

def preheat_oven(temp):
    oven.set_temperature(temp)
    while oven.current_temp < temp:
        wait(60)

def bake_cake():
    prepare_ingredients()
    preheat_oven(180)  # 抽象化細節
    mix_ingredients()
    put_in_oven()

二、函式介面設計藝術

命名比你想像的更重要

好的函式命名應該具備清晰的動作與受詞,讓讀者無需進入函式內部,也能理解其功能。

壞命名好命名改善點
handleData()calculateUserAge()明確指出計算邏輯
doStuff()validateEmailFormat()描述具體驗證行為
process()exportReportToPDF()指出輸出格式與目標

最佳命名準則
動詞 + 受詞組合(例:convertCurrency
長但具描述性,勝過短而模糊

參數數量控制:越少越好

參數數量 vs. 可讀性關係

  • 0~2 個參數:最佳範圍
  • 3 個參數:可接受,但要小心
  • 4 個以上參數:應考慮重構

不良示範:過多參數

public void createUser(String name, int age, String email, String address, boolean isVIP) { ... }

最佳做法:使用物件封裝參數

public class UserParams {
    String name;
    int age;
    String email;
    String address;
    boolean isVIP;
}

public void createUser(UserParams params) { ... }

三、函式行為規範

3.1 純函式原則:避免隱藏地雷

壞味道:副作用函式

let logCount = 0;
function saveOrder(order) {
    db.insert(order);  // 修改外部狀態
    logCount++;        // 改變全域變數
    sendEmail();       // 觸發其他行為
}

最佳做法:純函式(Pure Function)

function validateOrder(order) {
    return order.items.length > 0 && order.total > 0;
}

純函式不會改變外部變數,更易測試、更可預測

指令查詢分離:別讓函式精神分裂

不良示範:修改資料 + 查詢狀態混合

def update_and_check_user(user):
    db.update(user)
    return db.get_status()  # 混合指令與查詢

最佳做法:分開指令與查詢

def update_user(user):
    db.update(user)

def check_user_status(user_id):
    return db.get_status(user_id)

錯誤處理與維護性

異常處理 vs. 錯誤碼

情境錯誤碼異常處理
檔案不存在return -1throw new FileNotFoundException()
網路連線失敗return 404throw new NetworkException()
資料驗證失敗return falsethrow new ValidationError()

異常處理的好處
✔ 分離正常邏輯與錯誤處理
✔ 強制呼叫方處理異常狀況

DRY 原則:消滅重複程式碼

不良示範:重複邏輯

function calculateTotal(price, quantity) {
    return price * quantity * 1.08;  // 稅率 8%
}

function calculateSubtotal(price, quantity) {
    return price * quantity;
}

最佳做法:提煉重複邏輯

function applyTax(amount, taxRate) {
    return amount * (1 + taxRate);
}

function calculateTotal(price, quantity) {
    return applyTax(price * quantity, 0.08);
}

結語:乾淨函式帶來的複利效應

遵循這些原則初期可能需要更多思考時間,但會帶來長期收益:

  • 除錯時間減少 50%:清晰函式讓問題定位更快
  • 新人上手速度提升 3 倍:自解釋的程式碼減少溝通成本
  • 功能擴充容易度倍增:模組化設計讓修改影響範圍可控

記住大師 Robert C. Martin 的建議:「寫程式碼的藝術,在於把複雜問題分解成簡單函式的組合」。

從今天起,讓你寫的每個函式都像樂高積木——獨立、完整、可任意組合!

Similar Posts