一個函式最好的狀態,是像一個精密的工具:功能單一、目的明確、高效可靠。
如果你的函式名字需要用 and
來描述,那它就太長了。
一個函式只做一件事,而且要把它做得漂亮。
那種長達 200 行,處理驗證、計算、資料庫更新和發送郵件的巨無霸函式,就是超級臭扣。
把它們拆開!拆成一個個只做一件事的小函式。
小函式容易命名、容易理解、容易測試,也容易被替換。
以常見的「使用者註冊」流程為例。
🔴 巨無霸函式(身兼數職)
這個函式什麼都做:驗證、檢查重複、加密、建立物件、儲存、發郵件、記日誌... 它像一個什麼都管的經理,最終什麼都管不好。
// 這個函式什麼都做,除了幫你泡咖啡
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) { /* 只記錄日誌 */ }
現在,每一個小函式都有明確的單一職責,變成了一個清晰的流程說明,它們易於理解、易於單獨測試。
每個步驟的具體實作都被封裝在它自己的小函式裡。
如果你的函式名稱需要用 and 或 then 來描述(例如 validateAndSaveUser),那它就違反了這個原則。
一個函式只該有一項職責,一個改變它的理由。
當函式職責單一時,命名就變得異常簡單。
calculateOrderTotal、validateUserInput、sendConfirmationEmail,這些名稱本身就是最好的文件。
相反,如果你不知道怎麼給一個函式命名,很可能是它做了太多的事情。
這個函式只做一件事嗎?它有幾個「職責」?
函式名稱是否清晰、準確地描述了它的功能?
如果需要修改某個功能(例如,從發 Email 改成發 SMS),我是否只需要修改這一個小函式?
這個函式是否容易被單獨測試?
每個函式只做一件事,並把它做好。
將巨無霸函式拆解成一系列微小、專注的原子函式。
主流程函式應該作為「指揮官」,協調其他小函式完成工作。
單一職責是寫出可維護、可測試、可複用程式碼的基礎。
好的函式就像樂高積木。
職責單一、接口標準。你可以用它們自由組合,搭建出穩固且複雜的應用系統。
動手拆解你的巨無霸函式吧!將它原子化。
這是消除程式碼臭味,邁向清爽、健壯架構的一大步。