---
# System prepended metadata

title: JS 程式碼改造計畫：從揪出異味到實現 Clean Code - Sunny Wu
tags: [JSDC2025]

---

# JS 程式碼改造計畫：從揪出異味到實現 Cl# JS 程式碼改造計畫：從揪出異味到實現 Clean Code - Sunny Wu

{%hackmd @JSDC-tw/B1loEcwJZl %}
###### tags: `JSDC2025`

Slido：https://app.sli.do/event/r8dpNR9ocUMEmmcoN1UaaN

> 開始做筆記

- 不管是什麼語言 clean code 的原則都是相通的
- 今天分享以前在專案中踩的坑跟解決方式

## 程式碼異味一：波動拳

### 心法一：儘早返回

- 定義好你的資料流、扁平化
- 可以讓程式碼的 flow 呈現一直線（線性流程）

```js
function checkValue(a, b, c, d, e) {
  if (a > 0) {
    if (b > 0) {
      if (c > 0) {
        if (d > 0) {
          if (e > 0) {
            return "All positive";
          } else {
            return "e is not positive";
          }
        } else {
          return "d is not positive";
        }
      } else {
        return "c is not positive";
      }
    } else {
      return "b is not positive";
    }
  } else {
    return "a is not positive";
  }
}
```

```js
function checkValue(a, b, c, d, e) {
  if (a <= 0) return "a is not positive";
  if (b <= 0) return "b is not positive";
  if (c <= 0) return "c is not positive";
  if (d <= 0) return "d is not positive";
  if (e <= 0) return "e is not positive";
  return "All positive";
}
```

## 程式碼異味二：千層麵

- 上帝物件（god object）
- 一薪多用

### 心法二：單一職責原則 SRP

- 一個函式只做一件事
- 拆分純函式與組合函式

範例：一個函式同時做三個驗證＋登入
拆成 三個純函式＋一個組合函式


```js
// 純函式
function vaildateInput (username, password) {
    // 驗證格式
}
function verifyPassWord(username, password){
    // 檢查密碼
}
function logLogin(username){
    // 記錄登入
}

// 組合函式
function handleUserLogin (username, password) {
    if (!vaildateInput(username, password) return false;
    if (!verifyPassword(username, password) return false;
    
    logLogin(username);
    return true;
}
```

## 程式碼異味三：義大利麵

例如：
- UI 邏輯、資料處理、 API 呼叫、驗證規則、全部寫在一起
- 一個 .vue 寫了一兩千行

### 心法三：分層架構＋關注點分離 SoC

- UI 層：只負責顯示
- 組合層：負責組合功能
- 資料層＋邏輯層
    - 資料層：只取 API
    - 邏輯層：只負責驗證、格式化


```
UI 層        -> 組合層      -> { 邏輯層 + 資料層 }
TodoList.vue -> useTodos() -> validateTodo()
                           -> formatTodo()
                           -> fetchTodos()
```

## 改造前的起手式



測試就是你的安全網

有各種測試類型：
單元測試
整合測試
端對端測試
元件測試
UX 測試
視覺回歸測試
資料庫測試
...etc

### 特徵測試

1. 給定一組輸入 -> 紀錄實際輸出
2. 把這個輸入輸出關係寫成測試
3. 重構時，只要輸出還是一樣的，就代表行為沒變

輸出變了就知道改壞了
邊改程式就可以邊測（去看結果有沒有變）

範例：

```js
function calculatePrice(price, vip) {
    return vip ? price * 0.8 : price;
}

// 一樣的 input 和 output
test('VIP客戶有 8 折', () => {
    expect(calculatePrice(100, true)).toBe(80);
})

test('一般客戶原價', () => {
    expect(calculatePrice(100, false)).toBe(100);
})
```

## 我們的下一步

修改頻率低或比較不重要的功能，就沒有必要重構
把精力放在高價值、有風險的程式區塊

### 三個問題
- 新人看得懂嗎？
- 能單獨測試嗎？
- 修改安全嗎？

好的程式碼在五分鐘內就可以抓到重點
看函式的命名如果不能看出來用途，可能就要拆分
一個函式要呼叫另一個函式才能運作 -> 耦合太緊

### 可讀性 > 炫技

避免用縮寫：
Ｘ usr
O user

## 結語

降低我們的壓力
節省我們的時間

讓程式碼告訴我們意圖，而不是去猜
> 聊天區

---

{%hackmd @JSDC-tw/jsdc2025_sponsor %}