
一個 junior 開了人生第一個 PR,收到 47 條 comment,每條都是「這裡不對」「改成這樣」,沒有一條解釋為什麼。他改了三天,信心全碎,從此看到 Code Review 就 PTSD。
這不是 Code Review,這是公開處刑。
先講結論
Code Review 的本質是三件事:知識傳遞(senior 傳 junior,junior 也能教 senior)、品質把關(多一雙眼睛少一個 production bug)、團隊文化(「我們一起把 code 變好」不是「你寫的爛我來挑」)。
這篇講 Author 和 Reviewer 各自的責任。團隊導入 Code Review 的實戰建議見 Code Review 團隊導入指南。
Author 的責任:讓 PR 好 Review
你一定收到過那種 PR:title 寫 fix bug,打開一看改了 87 個檔案、2000 行 diff。你內心 OS:「我看了什麼?」然後默默按 Approve。
這是 reviewer 擺爛嗎?真正的問題在 author——你沒有讓 PR 好 review。
控制 PR 大小
- < 400 行:理想,reviewer 能仔細看,30 分鐘搞定
- 400-800 行:勉強可以,但開始漏細節
- > 800 行:大家會直接 Approve,你知道的
Google 的研究數據:PR 超過 400 行,reviewer 發現 bug 的能力急遽下降。
怎麼控制?拆 feature 成多個 PR、先 refactor 再加功能分兩個 PR、修 bug 不要順手改 coding style。
PR Description 是 Reviewer 的地圖
## What
修正購物車多幣別切換時的匯率計算錯誤
## Why
用戶反映切換幣別後總金額錯誤(Jira: CART-1234)
根因:匯率快取沒在幣別切換時清除
## How
- CurrencyContext 切換時清除匯率快取
- useEffect cleanup 確保切換時重新 fetch
- 加了 3 個 unit test
## Screenshot
(修復前後截圖)對比壞的 PR Description:fix cart bug。就這樣。什麼都不知道。
開 PR 前先 Self-Review
自己都不想 review 自己的 code,你怎麼期待別人認真看?
檢查:diff 裡有沒有 console.log(忘記刪很丟臉)、有沒有 .env 進 commit、變數命名有沒有一下 userId 一下 user_id。
Reviewer 的責任:三層 Review 法
不要從第一行看到最後一行。從大到小:
第一層:架構(最重要)——方向對嗎?有更好的設計嗎?
看到 N+1 Query 問題別只 comment「變數名可以改一下」:
// PR 裡的 code — 每個 order 發一次 query,典型 N+1
for (const order of orders) {
order.items = await db.orderItems.findMany({
where: { orderId: order.id }
});
}正確的 comment:
[must]N+1 query 問題。100 筆訂單 = 101 次 query。建議用include一次撈完。
第二層:邏輯——邊界條件?錯誤處理?race condition?
第三層:風格(最不重要)——命名、格式、註解。這些應該交給 ESLint。 能自動化的就自動化,人類只 review 機器做不到的事。
Comment 怎麼寫:四種前綴
沒有分類的 comment 讓雙方都痛苦。
[must]:必須改,不改不能 merge[nit]:小建議,可改可不改[question]:我看不懂,回覆解釋就好[nice]:寫得好,給個讚
黃金原則:指出問題 + 解釋原因 + 給出建議。三個缺一不可。
光指出問題沒原因,author 覺得你找碴。光有建議沒原因,author 不知道為什麼要改。「這裡不對」「改成 xxx」——這些都不是 review,是命令。
被 Review 的心態:Code 不是你
收到 [must] comment 覺得「他是不是覺得我很爛」?然後開始防禦:「這本來就可以動啊」「你不懂需求」。
Code 是 code,你是你。Reviewer 在 review 程式碼,不是你這個人。
- 不要急著回覆,先理解 reviewer 想表達什麼
- 假設善意——除非有明確證據
- 可以不同意,但用技術論點,不用情緒
- 有人花時間認真看你的 code,說聲謝謝
一個好的回覆:
Reviewer:
[question]為什麼用 WeakMap?Author: 好問題!這個 cache 的 key 是 DOM element,用 Map 的話 element 被移除後 reference 還在會 memory leak。WeakMap 的 key 是 weak reference,GC 時 cache entry 自動清除。我加個註解。
不防禦、不攻擊、正面回答、主動改善。這就是 senior 的表現。
接下來:Code Review 團隊導入指南——從零開始讓團隊願意做 Code Review,而不是把它當成懲罰。