讓代碼審查快 10 倍的思維模型

本文深入探討了高效代碼審查的思維模型,通過聚焦風險,提升審查效率,并且有助于高效緩解項目風險。原文:The Mental Model That Made Code Reviews 10x Faster

不要追求完美,而是關注風險

以前代碼審查總讓我筋疲力盡。一個 PR 要花 30 分鐘,留下 15 條評論,卻還是覺得漏掉了什么重要問題。提交者越來越抵觸審查,我也累得不行,完全沒效率可言。

后來一位技術主管教了我另一種審查思路,用一個問題改變了一切。

我不再問「這段代碼有什么問題?」,而是問「這個 PR 里風險最高的地方是什么?」

突然間,代碼審查從 30 分鐘縮短到了 10 分鐘。評論少了,但每條都切中要害。奇怪的是,提交者開始感謝我的審查,不再跟我爭論。

完美審查的問題

我以前總想找出所有問題:每個風格問題、每個潛在改進、每個微小優(yōu)化。審查清單通常是這樣的:

  • 「這個變量應該用 const,不該用 let」
  • 「考慮把這塊提取成輔助函數(shù)」
  • 「小問題:這里多了空格」
  • 「這段可以寫成更函數(shù)式的風格」
  • 「你有沒有考慮用 Map 代替對象?」
  • 還有 12 條評論……

你猜結果怎么著?提交者要么忽略大部分反饋,要么花幾個小時處理雞毛蒜皮,反而把我埋在第 8 條評論里的真正 bug 給漏掉了。

問題不在于我挑錯了,而在于我審查時把所有問題都看得同等重要。

事實上它們根本不一樣。

基于風險的框架

這個思維模型是:每個代碼變更都有風險等級。你的工作是識別并解決風險,而非追求完美。

致命風險 —— 很可能導致生產(chǎn)環(huán)境問題:

  • 安全漏洞
  • 可能造成數(shù)據(jù)損壞
  • 競態(tài)條件
  • 關鍵路徑缺少錯誤處理
  • 破壞公共 API 的變更

高風險 —— 可能導致生產(chǎn)環(huán)境問題:

  • 大規(guī)模場景下的性能問題
  • 缺少數(shù)據(jù)庫遷移
  • 業(yè)務邏輯錯誤
  • 破壞現(xiàn)有功能

中風險 —— 可能導致問題或技術債務:

  • 錯誤信息不清晰
  • 缺少調試日志
  • 代碼難以維護
  • 過度耦合會影響未來變更

低風險 —— 代碼風格和微小改進:

  • 變量命名
  • 代碼組織
  • 微小性能優(yōu)化
  • 遵循模式保持一致性

我以前的審查全都是低風險評論,純粹是吹毛求疵。

轉變:我從致命風險和高風險開始看。如果找到了這些問題,在解決之前,其他一切都不重要。

3 分鐘掃描法

現(xiàn)在我首先會做一個快速的 3 分鐘掃描,專門尋找暗示高風險的特定模式:

沒有遷移的數(shù)據(jù)庫變更:

// 紅旗:模式更改,但沒有遷移
class User {
  email: string;
  emailVerified: boolean;  // 新字段,遷移在哪里?
}

沒有錯誤處理的外部 API 調用:

// 紅旗:沒有重試,沒有超時,沒有錯誤處理
async function syncUser(id) {
  const data = await externalAPI.getUser(id)
  return db.users.update(id, data)
}

認證/授權變更:

// 紅旗:認證邏輯修改
if (user.role === 'admin' || user.isOwner) {  // 這里以前是'與'嗎?
  allowAccess();
}

可能處理大量數(shù)據(jù)的數(shù)組操作:

// R紅旗:沒有分頁,可能有數(shù)百萬條記錄
const users = await db.users.findAll();
return users.map(formatUser);

如果發(fā)現(xiàn)任何上述問題,審查就只關注這個,其他問題都先放一放。

兩評論規(guī)則

我只允許自己留兩種評論:

1. 阻塞評論 —— 合并前必須解決:「如果兩個用戶同時編輯,這會導致數(shù)據(jù)丟失。我們需要樂觀鎖?!?/p>

2. 僅供參考 —— 需要知道,但不阻塞合并:「FYI: 我們在 utils.js 里有一個類似的函數(shù),對空值的處理方式不同,可以考慮對齊一下?!?/p>

沒有「考慮一下」這種評論,沒有「也許」評論,沒有「你怎么看?」這種評論。

要么重要到需要阻塞合并,要么就只是提供信息。

這迫使我必須有明確立場。如果我都不愿意為此阻塞 PR,這事兒真有那么重要嗎?

那個被漏掉的 bug 的故事

這個方法曾經(jīng)救過我們一次。我當時在審查一個支付處理的 PR,改動了 200 多行代碼。作者做了很多重構:重命名變量、提取函數(shù)。有很多地方可以評論。

放在以前,我會留下 20 條關于代碼風格和組織的評論。

但現(xiàn)在,我做了 3 分鐘掃描,發(fā)現(xiàn)了這個:

async function processRefund(orderId, amount) {
  const order = await getOrder(orderId)
  await stripe.refund(order.chargeId, amount)
  await db.orders.update(orderId, { status: 'refunded', refundedAmount: amount })
  return { success: true }
}

看起來沒問題,對不對?但風險在這里:如果 Stripe 調用成功,但數(shù)據(jù)庫更新失敗怎么辦?

我們已經(jīng)退了款,但數(shù)據(jù)庫不知道。客戶拿到了錢,我們卻沒有記錄。這就是致命風險。

我的整個審查就一條評論:「如果 Stripe 退款成功后數(shù)據(jù)庫更新失敗,我們會虧錢。需要用事務處理或者添加對賬機制?!?/p>

提交者用分布式事務包裝修復了這個問題,添加了冪等性,還加了對賬任務。

一條評論,就可能避免了數(shù)千美元的退款損失。

那個 PR 的其他一切 —— 變量命名、函數(shù)提取、代碼組織 —— 根本不重要。

我現(xiàn)在不再評論的內(nèi)容

我不再評論這些:

linter 能抓到的代碼風格問題。 如果團隊用了 Prettier 或 ESLint,相信它們,不要做人類 linter。

主觀改進。「這段可以更函數(shù)式」這種話毫無幫助。要么有具體問題,要么就沒有問題。

沒有數(shù)據(jù)支撐的性能優(yōu)化。 除非你能證明這是瓶頸,否則優(yōu)化都是過早的。

過度的抽象爭論。 如果代碼能用且清晰,抽象層級就沒問題。

個人偏好。 我更喜歡 Map 而不是對象。挺好。但如果別人用對象,也完全沒問題。

放下這些,我的審查時間減半,而且審查結果有用多了。

「LGTM」的驚人力量

當 PR 沒有重大風險時,我開始只用「LGTM」批準。

一開始,我覺得這樣不對。我總得找點什么評論來體現(xiàn)我的價值吧?

但結果是:PR 合并速度變快了。作者能更快得到反饋。而且當我真的留下評論時,他們開始相信這些評論確實重要。

上個月我給出的最棒的審查就是一句話:

「LGTM —— 實現(xiàn)干凈,測試覆蓋率好,沒有明顯風險?!?/p>

這個 PR 一小時后就合并了。沒有來回拉扯,沒有無謂爭論,直接上線。

相比之下,一周前我在一個類似 PR 上留了 12 條小評論,結果我們爭論變量名稱就花了三天才合并。

讓一切聚焦的問題

寫任何評論之前,我都會問:「如果保持原樣上線,最糟會發(fā)生什么?」

如果答案是:

  • 「生產(chǎn)環(huán)境崩潰」 → 阻塞 PR
  • 「我們會在凌晨 2 點被叫醒」 → 阻塞 PR
  • 「靜默數(shù)據(jù)損壞」 → 阻塞 PR
  • 「用戶會看到錯誤」 → 阻塞 PR
  • 「代碼稍微沒那么干凈」 → 批準合并

這就過濾掉了我以前會評論的 80% 內(nèi)容。

什么時候需要徹底審查

有些時候還是需要慢下來,一絲不茍:

對安全敏感的代碼。 認證、支付、個人身份信息處理 —— 這些需要深度審查。我會追蹤每一條路徑,檢查每一處驗證,確認每一個權限檢查。

核心基礎設施變更。 數(shù)據(jù)庫 schema 變更、API 契約變更、部署配置 —— 這些影響方方面面,值得仔細審查。

新團隊成員寫的代碼。 不是因為他們技術不行,而是因為他們還不了解我們的坑。這是教學時間。

看不懂的變更。 如果你理不清邏輯,這就是一個信號。要么請求澄清,要么讓他們簡化。

但普通功能開發(fā)?認證中間件重構?修復管理后臺的 bug?快速掃描風險,批準,繼續(xù)下一個。

引以為傲的一次審查

有人提交了一個 PR,要用 WebSocket 添加實時更新。500 多行新代碼。放在以前,我會花一個小時逐行檢查。

這一次,我用 3 分鐘掃描聚焦于:

  1. 連接斷開了怎么處理?
  2. 服務器重啟會發(fā)生什么?
  3. 消息保序嗎?
  4. 我們會持久化任何內(nèi)容嗎?
  5. 故障模式是什么?

找到了兩個致命問題:

「如果服務器重啟,客戶端不會重連。它們就會一直停在那里顯示過期數(shù)據(jù)。我們需要帶指數(shù)退避的自動重連?!?/p>

「消息沒有持久化到任何地方。如果客戶端消息到達時不在線,他們就永遠看不到了。我們需要消息隊列或事件日志?!?/p>

這些都是阻塞問題。其他一切 —— 代碼結構、命名、模式 —— 都沒問題。

審查花了 15 分鐘,避免了兩起生產(chǎn)事故。

模式識別游戲

做了幾百次審查后,你會開始立刻識別風險模式:

「碰了數(shù)據(jù)庫,碰了外部 API」 → 檢查事務邊界和故障處理。

「新增環(huán)境變量」 → 檢查是否有文檔,是否有合理的默認值。

「修改錯誤處理」 → 檢查錯誤是否仍然被日志記錄/監(jiān)控。

「并發(fā)原語(鎖、原子操作、通道)」 → 檢查死鎖和競態(tài)條件。

「日期/時間處理」 → 檢查時區(qū)處理。

「刪除代碼」 → 檢查是否真的沒人用,會不會破壞功能。

「配置變更」 → 檢查向后兼容性。

這種模式匹配讓審查變得飛快。我不需要逐行閱讀,只需要掃描我知道有風險的模式。

好審查的標準

我最近做過的最好的代碼審查都有這些共同點:

  • 一到兩條聚焦的評論,而不是一長串清單
  • 清晰解釋風險,而不只是說「這錯了」
  • 盡可能給出具體建議
  • 快速反饋 —— 當天完成審查,通常幾小時內(nèi)
  • 信任作者 —— 假設對方能力足夠,不故意找茬

說實話,最好的審查往往就是一句:「看起來不錯,上線吧。」

實踐中的思維模型

我現(xiàn)在實際的審查流程是這樣的:

1. 閱讀描述(1 分鐘) 這是要做什么?為什么要做?這個區(qū)域的風險等級是什么?

2. 掃描關鍵模式(2 分鐘) 數(shù)據(jù)庫變更?API 調用?認證?并發(fā)?外部依賴?

3. 必要時深入(5-10 分鐘) 如果發(fā)現(xiàn)風險,徹底理解它。追蹤代碼路徑,想清楚各種故障模式。

4. 評論或批準(1 分鐘) 要么清晰說明理由阻塞合并,要么批準繼續(xù)下一個。

總計:根據(jù)復雜度和風險,每次審查 5-15 分鐘。

對比以前的我:每次 30-45 分鐘,留下 15 條評論,大部分都不重要。

思維轉變

思維轉變就是:不要再追求代碼完美,而是努力防止事故。

你的工作不是抓到所有問題,而是抓到重要問題。

代碼審查不是為了代碼質量,而是為了緩解風險。

當我明白這一點后,審查變得輕松多了,也有效多了。

現(xiàn)在我打開 PR,只會問一個問題:「這里風險最高的是什么?」

其他一切都是噪音。

本文由mdnice多平臺發(fā)布

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容