iT邦幫忙

2025 iThome 鐵人賽

DAY 9
0
自我挑戰組

30天 Git 版本控制實戰筆記系列 第 23

Day 23:Code Review 最佳實務 - 提升程式碼品質

  • 分享至 

  • xImage
  •  

今日目標
• 理解 Code Review 的重要性
• 學習如何給予建設性的 Review
• 掌握接受 Review 的心態
• 建立高效的 Review 流程
什麼是 Code Review?
簡單定義:
Code Review = 程式碼的「健康檢查」

就像:
📝 作文被老師批改
🏠 房子被建築師檢查
🍳 料理被主廚品嚐

目的:
→ 發現問題
→ 分享知識
→ 提升品質
→ 團隊成長
為什麼需要 Code Review?
❌ 沒有 Review 的風險:

  • Bug 直接上線
  • 程式碼品質參差不齊
  • 沒人知道別人在做什麼
  • 技術債累積
  • 安全漏洞被忽略

✅ 有 Review 的好處:

  • 提早發現問題(便宜 10 倍)
  • 知識在團隊中傳播
  • 統一程式碼風格
  • 提升開發技能
  • 建立團隊默契

Code Review 的類型

  1. Pull Request Review(最常見)
    流程:
    開發者 → 建立 PR → 同事 Review → 修改 → 合併

優點:
✅ 正式且有記錄
✅ 可以多人參與
✅ 整合 CI/CD
✅ 適合遠端團隊
2. Pair Programming(結對編程)
流程:
兩人共用一台電腦 → 一人寫一人看 → 即時討論

優點:
✅ 即時回饋
✅ 知識快速傳遞
✅ 適合複雜任務
3. Over-the-Shoulder Review(肩並肩)
流程:
寫完後找同事看 → 面對面討論 → 立即修改

優點:
✅ 快速簡單
✅ 適合小修改
✅ 即時溝通


如何進行好的 Code Review
作為 Reviewer(審查者):
基本原則:
✅ 友善和建設性
✅ 具體且清楚
✅ 解釋原因
✅ 提供建議
✅ 讚美好的部分

❌ 避免:
❌ 人身攻擊
❌ 模糊的批評
❌ 只說不好不說為什麼
❌ 過度挑剔小事
❌ 延遲 Review
Review 檢查清單:

  1. 功能性
    □ 程式碼是否符合需求?
    □ 邏輯是否正確?
    □ 邊界條件是否處理?
    □ 錯誤處理是否完善?
    □ 是否有遺漏的功能?
  2. 程式碼品質
    □ 命名是否清楚易懂?
    □ 函數是否太長?(建議 < 50 行)
    □ 是否有重複程式碼?
    □ 是否遵循 DRY 原則?
    □ 註解是否必要且清楚?
  3. 效能
    □ 是否有效能瓶頸?
    □ 資料庫查詢是否優化?
    □ 是否有不必要的迴圈?
    □ 記憶體使用是否合理?
  4. 安全性
    □ 是否有 SQL 注入風險?
    □ 是否有 XSS 漏洞?
    □ 敏感資料是否加密?
    □ 輸入驗證是否完整?
  5. 測試
    □ 是否有足夠的測試?
    □ 測試是否涵蓋邊界條件?
    □ 測試是否可讀易懂?
  6. 可維護性
    □ 程式碼是否容易理解?
    □ 是否容易修改?
    □ 文件是否更新?
    □ API 是否向後相容?

Review 評論範例
❌ 不好的評論:
這裡寫得不好。

這個函數太複雜了。

為什麼要這樣寫?

這樣不行。
問題:
• 沒有具體說明
• 沒有建議
• 語氣不友善
• 沒有解釋原因
✅ 好的評論:
建議:這個函數目前有 80 行,建議拆分成更小的函數。

例如:

  • validateInput() - 驗證輸入
  • processData() - 處理資料
  • saveToDatabase() - 儲存到資料庫

這樣可以:

  1. 提高可讀性
  2. 更容易測試
  3. 更容易重用

參考:Clean Code 第 3 章
優點:
• 具體指出問題
• 提供解決方案
• 說明好處
• 給予參考資料


不同情況的評論技巧

  1. 發現 Bug:
    🐛 潛在問題:

在第 45 行,當 usernull 時會造成錯誤。

建議加入檢查:

if (!user) {
  return { error: 'User not found' };
}
這樣可以避免程式崩潰。

### **2. 效能問題:**

```markdown
⚡ 效能建議:

這裡在迴圈內執行資料庫查詢,當資料量大時會很慢。

建議改用批次查詢:
```javascript
// 改前:O(n) 次查詢
users.forEach(user => {
  db.query('SELECT * FROM posts WHERE userId = ?', user.id);
});

// 改後:1 次查詢
const userIds = users.map(u => u.id);
db.query('SELECT * FROM posts WHERE userId IN (?)', userIds);
預期可以提升 10-100 倍效能。

### **3. 程式碼風格:**

```markdown
💡 風格建議:

為了保持一致性,建議使用專案的命名規範:

- 函數名稱:camelCase
- 常數:UPPER_SNAKE_CASE
- 類別:PascalCase

例如:
```javascript
// 建議改為
function getUserProfile() { ... }
const MAX_RETRY_COUNT = 3;
class UserManager { ... }
這樣整個專案會更統一。
註:這不影響功能,可以之後再調整。

### **4. 讚美好的程式碼:**

```markdown
👍 寫得很好!

這個錯誤處理很完善:
1. 涵蓋了所有可能的錯誤情況
2. 錯誤訊息清楚易懂
3. 有適當的日誌記錄

這種寫法值得其他地方參考!
________________________________________
作為 PR 作者(被 Review 者):
提交前的自我檢查:
□ 跑過所有測試
□ 自己先 Review 一遍
□ 移除 console.log 和 debug 程式碼
□ 更新相關文件
□ commit 訊息清楚
□ PR 描述完整
PR 描述模板:
## 📋 變更說明
簡述這個 PR 做了什麼

## 🎯 相關 Issue
Closes #123

## ✨ 變更內容
- [x] 新增使用者登入功能
- [x] 加入表單驗證
- [x] 實作錯誤處理

## 🧪 測試方式
1. 前往 `/login` 頁面
2. 輸入帳號密碼
3. 確認可以成功登入

## 📸 截圖(如適用)
(貼上截圖)

## 📝 備註
這是第一版實作,密碼加密將在下個 PR 完成。

## ✅ 檢查清單
- [x] 測試通過
- [x] 文件已更新
- [x] 無 console.log
- [x] 程式碼自我 Review
接受 Review 的心態:
✅ 正確心態:
- Review 是幫助你成長
- 批評程式碼,不是批評你
- 問題被發現是好事
- 學習的機會
- 感謝 Reviewer 的時間

❌ 錯誤心態:
- 覺得被針對
- 防衛性回應
- 堅持己見不願改
- 覺得浪費時間
回應 Review 的技巧:
1. 同意並感謝:
✅ 好的建議,已修改!感謝指出這個問題。

已改為使用批次查詢,測試後效能提升了 50 倍。

Commit: abc1234
2. 不同意但願意討論:
🤔 我理解你的考量,不過我這樣寫是因為...

這個場景下資料量不會超過 10 筆,所以效能影響不大。
而且這樣寫可讀性更好。

不過如果你覺得還是有問題,我可以改。你覺得呢?
3. 需要更多資訊:
❓ 可以請你詳細說明嗎?

我不太確定你指的「太複雜」是指哪個部分?
是邏輯太多層?還是函數太長?

或者你可以給個範例嗎?
________________________________________
Review 時間管理
優先級:
🔴 高優先(24 小時內):
- Hotfix PR
- 阻擋其他人的 PR
- 簡單的 bug 修復

🟡 中優先(2-3 天內):
- 一般功能開發
- 重構
- 文件更新

🟢 低優先(一週內):
- 非緊急的優化
- 實驗性功能
Review 大小建議:
理想大小:
- 200-400 行程式碼
- 30-60 分鐘可以 Review 完

太大的 PR:
- 超過 1000 行 → 建議拆分
- 超過 2 小時 Review 時間 → 品質下降

如何拆分:
1. 按功能拆
2. 按檔案拆
3. 先重構後功能
________________________________________
團隊 Review 規範範例
# Code Review 指南

## 基本原則
1. 所有程式碼必須經過至少一人 Review
2. Reviewer 必須在 48 小時內回應
3. 作者必須在 24 小時內回應 Review 意見
4. 使用建設性語言
5. 讚美好的程式碼

## Review 重點
- 功能正確性
- 程式碼品質
- 測試覆蓋率
- 安全性
- 效能

## 批准條件
- 至少一個 Approve
- 所有 CI 檢查通過
- 沒有未解決的 Request Changes
- 符合程式碼規範

## 評論標籤
- 🐛 Bug
- ⚡ 效能
- 💡 建議
- ❓ 問題
- 👍 讚美
- 🔒 安全性

## 回應時效
- Hotfix: 4 小時內
- 一般 PR: 48 小時內
- 大型 PR: 分批 Review
________________________________________
常見陷阱與解決
陷阱1:過度挑剔
問題:
糾結在縮排、命名等小事上

解決:
- 用 Linter 自動檢查風格
- 專注在邏輯和架構
- 風格問題可以之後統一調整
陷阱2:Rubber Stamp(橡皮圖章)
問題:
不認真看,直接 Approve

解決:
- 設定最少 Review 時間
- 要求至少一條有意義的評論
- 輪流擔任主要 Reviewer
陷阱3:Review 積壓
問題:
PR 堆積如山,沒人 Review

解決:
- 設定 Review 輪值
- 限制同時開啟的 PR 數量
- 小而頻繁的 PR
- 設定 SLA(回應時間)
________________________________________
實戰練習
練習:Review 這段程式碼
function getUsers() {
  let users = [];
  for(let i=0;i<100;i++) {
    let user = db.query('SELECT * FROM users WHERE id = ' + i);
    if(user) {
      users.push(user);
    }
  }
  return users;
}
你的 Review 會怎麼寫?
<details> <summary>參考答案</summary> 
發現幾個問題需要改進:

🐛 **安全性問題**
- 第 4 行有 SQL 注入風險
- 建議使用 prepared statement

⚡ **效能問題**  
- 在迴圈中執行 100 次資料庫查詢
- 建議改用一次批次查詢

💡 **程式碼品質**
- 魔術數字 100 應該定義為常數
- 建議加入錯誤處理

**建議修改:**
```javascript
async function getUsers() {
  const MAX_USERS = 100;
  try {
    // 一次查詢所有使用者
    const users = await db.query(
      'SELECT * FROM users WHERE id <= ? LIMIT ?',
      [MAX_USERS, MAX_USERS]
    );
    return users;
  } catch (error) {
    console.error('Failed to fetch users:', error);
    throw error;
  }
}
這樣可以:
1.	避免 SQL 注入
2.	效能提升 100 倍
3.	加入錯誤處理
4.	程式碼更清楚
</details>

---

## **今日重點回顧**
- ✅ 理解 Code Review 的價值
- ✅ 學會給予建設性的評論
- ✅ 掌握接受 Review 的正確心態
- ✅ 建立高效的 Review 流程

## **核心原則總結**
作為 Reviewer:
•	友善和建設性
•	具體且清楚
•	解釋原因
•	提供建議
•	讚美好的部分
作為作者:
•	自我檢查
•	詳細描述
•	開放心態
•	及時回應
•	感謝 Reviewer

上一篇
Day 22:Git Flow 工作流程 - 企業級分支管理策略
下一篇
Day 24:多人協作進階技巧 - 避免協作陷阱
系列文
30天 Git 版本控制實戰筆記30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言