iT邦幫忙

2025 iThome 鐵人賽

DAY 1
1
Software Development

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

Day 1- 好命名:必須精準傳達意圖

  • 分享至 

  • xImage
  •  

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

消除你程式碼的臭味 Day 1- 好命名:必須精準傳達意圖

你的命名必須準確傳達意圖,不能讓人猜
程式碼是寫給人看的,不是給機器看的。
如果需要花時間去猜一個變數或函式在做什麼,那這個程式碼已經發臭了。

好的程式碼不應該有任何「猜測」的空間。

你寫的程式碼,最後會由人來維護,這個人可能是未來的你,也可能是你的同事,或是其他陌生人。
如果他們看不懂,每一次的維護都會變成一場災難。

怎麼樣讓程式碼有可讀性?
也就是從 好命名 開始,有好命名,命就好。


命名:你最好的註解

命名不只是換個變數名,它關乎你對資料結構的理解,你不需要再維護程式碼旁邊的註解,只要專注好你的功能本身就好。

如何讓程式碼表達?

  1. 資料結構優先:寫程式前,先釐清你處理的資料結構是什麼。
    一個儲存訂單項目的陣列,命名為 orderItems,會比 odlist 更具體。

  2. 用動詞或動詞片語命名函式:函式代表行為,它的名稱必須明確指出它的作用。

    • getUserById(userId)

    • validateUserInput(userData)

  3. 布林變數使用 is/has/can/should:這讓變數的布林性質一看就懂。

    • isUserLoggedIn

    • hasValidEmail

  4. 避免縮寫和簡寫:不要為了省幾個字而讓未來的自己和同事陷入「通靈遊戲」。使用 currentUser 而非 usruserPassword 而非 pwd

  5. 使用領域語言:命名應與你解決的業務問題緊扣。

    • class OrderProcessor 優於 class DataProcessor

    • processOrder(order) 優於 processData(input)


重構的訣竅:從命名開始

看看下面這段程式碼:

// 🔴 飄散臭味
function p(d) {
  let r = [];
  for (let i = 0; i < d.length; i++) {
    let item = d[i];
    if (item.s > 0) {
      let t = item.p * item.q;
      r.push({
        id: item.id,
        name: item.n,
        total: t
      });
    }
  }
  return r;
}

這個函式有三個問題:

  • 神奇的單字元變數p, d, r, s, t… 誰知道這些是什麼?

  • 魔術數字item.s > 0,這個 0 代表什麼意思?

  • 不必要的縮排和複雜性:這個函式可以寫得更簡單。

在我們動手改變數名之前,首先思考一個問題:d 是什麼?p 函式在做什麼?

首先搞懂了資料結構(dorderItems)和函式的意圖(pcalculateEffectiveOrderTotals

p 函式看起來像是在處理一個「訂單項目清單」(d),items 應該是某種狀態,p 是價格,q 是數量。

再來計算每個有效(item.s > 0)項目的總價,最後回傳一個新的清單。

重構命名後的程式碼長這樣:

// 更清楚地表達了意圖:計算可用訂單項目的總價
const ITEM_STATUS_AVAILABLE = 1;

function calculateAvailableItemsTotals(orderItems) {
  const processedItems = [];
  for (let i = 0; i < orderItems.length; i++) {
    const item = orderItems[i];
    if (item.status === ITEM_STATUS_AVAILABLE) {
      const itemTotal = item.price * item.quantity;
      processedItems.push({
        id: item.id,
        name: item.name,
        total: itemTotal,
      });
    }
  }
  return processedItems;
}

命名的影響:猜測 vs 理解
https://ithelp.ithome.com.tw/upload/images/20250904/20124462vTJfsoVHiP.png

好命名可以讓你用最簡單、最直接的方式,設計出合格60分的程式碼,但這樣子還不夠。
如果程式碼需要超過三層縮排,代表還是有優化空間。

終極優化版本:

// 🟢 更簡單、更可讀性
function calculateAvailableItemsTotals(orderItems) {
  return orderItems
    .filter(item => item.status === ITEM_STATUS_AVAILABLE)
    .map(item => ({
      id: item.id,
      name: item.name,
      total: item.price * item.quantity,
    }));
}

程式設計的思路應該是操作資料流,而不是手動去遍歷然後判斷。

先過濾,再轉換。 消除那個 if

它清楚地告訴下一個人:
我們先篩選出可用的項目,然後把它們轉換成我們想要的格式,一行解決更清晰。
這才是「乾淨的程式碼」。

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

命名檢查清單

在命名時,問自己:

  1. 這個命名清楚敘述了它的功能嗎?
  2. 這個命名是否過於通用或過於冗贅?
  3. 是否使用了領域語言?
  4. 是否避免了縮寫和簡寫?

預告重點

我們之後的系列文章將以 JavaScript 為主,帶你持續精進,架構如下:

第一週:主要原則與思維模式 (好命名、好品味)

第二週:消滅複雜性 (消除邊界情況)

第三週:優雅的設計與重構 (簡化資料結構)

第四週:強韌程式碼與持續精進 (向後相容性)

https://ithelp.ithome.com.tw/upload/images/20250903/20124462cMg0FjpcmS.png
下一次,我們來談談如何消除特殊情況


下一篇
Day 2- 好品味:優秀工程師的直覺
系列文
消除你程式碼的臭味3
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言