今日目標
• 理解 Code Review 的重要性
• 學習如何給予建設性的 Review
• 掌握接受 Review 的心態
• 建立高效的 Review 流程
什麼是 Code Review?
簡單定義:
Code Review = 程式碼的「健康檢查」
就像:
📝 作文被老師批改
🏠 房子被建築師檢查
🍳 料理被主廚品嚐
目的:
→ 發現問題
→ 分享知識
→ 提升品質
→ 團隊成長
為什麼需要 Code Review?
❌ 沒有 Review 的風險:
✅ 有 Review 的好處:
Code Review 的類型
優點:
✅ 正式且有記錄
✅ 可以多人參與
✅ 整合 CI/CD
✅ 適合遠端團隊
2. Pair Programming(結對編程)
流程:
兩人共用一台電腦 → 一人寫一人看 → 即時討論
優點:
✅ 即時回饋
✅ 知識快速傳遞
✅ 適合複雜任務
3. Over-the-Shoulder Review(肩並肩)
流程:
寫完後找同事看 → 面對面討論 → 立即修改
優點:
✅ 快速簡單
✅ 適合小修改
✅ 即時溝通
如何進行好的 Code Review
作為 Reviewer(審查者):
基本原則:
✅ 友善和建設性
✅ 具體且清楚
✅ 解釋原因
✅ 提供建議
✅ 讚美好的部分
❌ 避免:
❌ 人身攻擊
❌ 模糊的批評
❌ 只說不好不說為什麼
❌ 過度挑剔小事
❌ 延遲 Review
Review 檢查清單:
Review 評論範例
❌ 不好的評論:
這裡寫得不好。
這個函數太複雜了。
為什麼要這樣寫?
這樣不行。
問題:
• 沒有具體說明
• 沒有建議
• 語氣不友善
• 沒有解釋原因
✅ 好的評論:
建議:這個函數目前有 80 行,建議拆分成更小的函數。
例如:
validateInput()
- 驗證輸入processData()
- 處理資料saveToDatabase()
- 儲存到資料庫這樣可以:
參考:Clean Code 第 3 章
優點:
• 具體指出問題
• 提供解決方案
• 說明好處
• 給予參考資料
不同情況的評論技巧
在第 45 行,當 user
為 null
時會造成錯誤。
建議加入檢查:
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