iT邦幫忙

2025 iThome 鐵人賽

DAY 6
1
Software Development

消除你程式碼的臭味系列 第 6

Day 6- 函式原子化:每個函式只做一件事,而且做得漂亮

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20250903/20124462P1N8QjGguI.png

消除你程式碼的臭味 Day 6- 函式原子化:每個函式只做一件事,而且做得漂亮

一個函式最好的狀態,是像一個精密的工具:功能單一、目的明確、高效可靠。

如果你的函式名字需要用 and 來描述,那它就太長了。

一個函式只做一件事,而且要把它做得漂亮。

那種長達 200 行,處理驗證、計算、資料庫更新和發送郵件的巨無霸函式,就是超級臭扣。

把它們拆開!拆成一個個只做一件事的小函式。
小函式容易命名、容易理解、容易測試,也容易被替換。

經典案例:巨無霸函式 vs. 原子化函式

以常見的「使用者註冊」流程為例。

🔴 巨無霸函式(身兼數職)

這個函式什麼都做:驗證、檢查重複、加密、建立物件、儲存、發郵件、記日誌... 它像一個什麼都管的經理,最終什麼都管不好。

// 這個函式什麼都做,除了幫你泡咖啡
function processUserRegistration(userData) {
    // 職責 1: 驗證資料
    if (!userData.name || !userData.email || !userData.password) { /*...*/ }
    
    // 職責 2: 檢查使用者是否存在
    const existingUser = users.find(u => u.email === userData.email);
    if (existingUser) { /*...*/ }
    
    // 職責 3: 加密密碼
    const salt = crypto.randomBytes(16).toString('hex');
    const hash = crypto.pbkdf2Sync(userData.password, salt, /*...*/).toString('hex');
    
    // 職責 4: 建立使用者物件
    const user = { /*...*/ };
    
    // 職責 5: 儲存到資料庫
    users.push(user);
    
    // 職責 6: 發送歡迎郵件
    sendEmail(user.email, 'Welcome!', /*...*/);
    
    // 職責 7: 記錄日誌
    console.log(`New user registered: ${user.email}`);
    
    return user;
}

這個函式難以測試(你如何單獨測試郵件功能?)、難以複用(你無法在其他地方只使用它的驗證邏輯)、也難以修改(修改加密方式可能會影響到日誌記錄)。


🟢 原子化函式(各司其職)

重構後,processUserRegistration 函式本身變成了一個清晰的「指揮官」,它不親自做任何事,只負責協調調度其他「專門小函式」來完成任務。

function processUserRegistration(userData) {
    const validatedData = validateUserData(userData);
    checkUserExists(validatedData.email);
    const user = createUser(validatedData);
    saveUser(user);
    sendWelcomeEmail(user);
    logUserRegistration(user);
    
    return user;
}

// --- 以下是各司其職的「專門函式」 ---

function validateUserData(userData) { /* 只做驗證 */ }
function checkUserExists(email) { /* 只檢查重複 */ }
function createUser(validatedData) { /* 只建立使用者物件與加密 */ }
function saveUser(user) { /* 只儲存使用者 */ }
function sendWelcomeEmail(user) { /* 只發送郵件 */ }
function logUserRegistration(user) { /* 只記錄日誌 */ }

現在,每一個小函式都有明確的單一職責,變成了一個清晰的流程說明,它們易於理解、易於單獨測試。
每個步驟的具體實作都被封裝在它自己的小函式裡。

函式原子化的差異對比圖

https://ithelp.ithome.com.tw/upload/images/20250908/201244624FhCOVLRJn.png

原子化的兩大原則

1. 單一職責原則 (Single Responsibility Principle)

如果你的函式名稱需要用 and 或 then 來描述(例如 validateAndSaveUser),那它就違反了這個原則。
一個函式只該有一項職責,一個改變它的理由。

2. 清晰的命名

當函式職責單一時,命名就變得異常簡單。
calculateOrderTotal、validateUserInput、sendConfirmationEmail,這些名稱本身就是最好的文件。
相反,如果你不知道怎麼給一個函式命名,很可能是它做了太多的事情。

職責檢查清單

  1. 這個函式只做一件事嗎?它有幾個「職責」?

  2. 函式名稱是否清晰、準確地描述了它的功能?

  3. 如果需要修改某個功能(例如,從發 Email 改成發 SMS),我是否只需要修改這一個小函式?

  4. 這個函式是否容易被單獨測試?

今日重點

  • 每個函式只做一件事,並把它做好。

  • 將巨無霸函式拆解成一系列微小、專注的原子函式。

  • 主流程函式應該作為「指揮官」,協調其他小函式完成工作。

  • 單一職責是寫出可維護、可測試、可複用程式碼的基礎。

好的函式就像樂高積木。
職責單一、接口標準。你可以用它們自由組合,搭建出穩固且複雜的應用系統。

https://ithelp.ithome.com.tw/upload/images/20250908/20124462cO1fea2jie.png
動手拆解你的巨無霸函式吧!將它原子化。
這是消除程式碼臭味,邁向清爽、健壯架構的一大步。


上一篇
Day 5- 簡潔性:程式碼是斯巴達式的
下一篇
Day 7- 資料結構至上:好程式碼的關鍵思考
系列文
消除你程式碼的臭味12
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言