
1. 一次評審翻車后我重新思考了代碼評審到底在看什么先說一個讓我印象很深的場景。前陣子我在某個訂單系統(tǒng)的權(quán)限模塊上提了一個合并請求自認為把所有邊界情況都想到了改動也就一百多行干凈利落。結(jié)果評審會上同組的A同學只問了一句如果下游服務(wù)三秒還沒返回你這邊的重試邏輯會把庫存扣兩次嗎我當場愣住——我的確加了重試但重試時沒有做冪等校驗。那次評審最終沒有通過卻讓我意識到一件事我們對代碼評審這四個字的理解很多時候是錯的。大家習慣把代碼評審當成一道質(zhì)量關(guān)卡覺得是找毛病、挑刺、攔住有問題的代碼。但實際上代碼評審更核心的價值是信息同步。寫代碼的人往往陷在自己的假設(shè)里評審者因為帶著局外人視角反而最容易發(fā)現(xiàn)這里跟需求文檔對不上這里跟調(diào)用方的約定不一致這里沒考慮并發(fā)下的重復請求這類問題。A同學能問出那句話不是因為我寫得不認真而是因為她看到了我看不到的上下文。這也是我把這套實踐命名為open-code-review的原因。它不是某個現(xiàn)成的開源工具而是一套我自己從多次評審中沉淀下來的開放評審方法對代碼保持開放對意見保持開放對流程本身也保持開放。你不需要成為專家才能用上它剛接觸評審的新手可以拿它當入門指南帶團隊的負責人可以拿它當流程改版的參考。它要解決的核心問題就一個讓評審真正攔住該攔的缺陷而不是變成走過場。順帶說一句很多人覺得代碼評審浪費時間。這個賬要算清楚缺陷發(fā)現(xiàn)得越晚修復成本越高。寫代碼時發(fā)現(xiàn)的是低固定成本到了線上出故障可能牽扯數(shù)據(jù)修復、客戶投訴、緊急回滾。一次十到二十分鐘的評審如果能攔下一個潛在的線上事故這筆投入就非常劃算。問題是大多數(shù)團隊的評審并沒有在攔事故而是在比誰的英語語法好、誰的命名風格更符合某個人的偏好。所以這篇內(nèi)容我把整個 open-code-review 實踐拆成六個方面評審對象、評審節(jié)奏、工具輔助、意見表達、常見陷阱以及我最終落地的檢查清單。內(nèi)容會比較多但每一條都是踩過坑之后整理出來的希望你不用再走一遍彎路。2. 評審對象與流程設(shè)計從看代碼到看設(shè)計意圖2.1 評審的粒度小型異步評審才是常態(tài)很多人一提到代碼評審腦子里浮現(xiàn)的是一屋子人圍在投影儀前。那是過去重型評審的典型畫面適合非常核心的模塊但對日常開發(fā)來說太笨重了。我們團隊現(xiàn)在的主流方式是小型異步評審開發(fā)者提交合并請求評審者在自己的電腦上看diff寫行內(nèi)評論最后給出結(jié)論。不占用會議室不用湊齊所有人隨時隨地可以開始。不過這里有個前提合并請求的粒度必須足夠小。我見過最夸張的一次有人把一個迭代兩周的功能、七八個文件、三千多行改動一次性塞進一個合并請求里美其名曰完整交付。結(jié)果就是評審人根本看不過來草草 approve上線第二天就出了事故?,F(xiàn)在我對粒度的要求很簡單一個合并請求只干一件事。重構(gòu)一個函數(shù)就只重構(gòu)這個函數(shù)修復一個bug就只修復這個bug新增一個接口就只新增這個接口。改動行數(shù)最好控制在三百行以內(nèi)超過這個數(shù)就要反思是不是沒拆干凈。為什么是三百行我記得有一次項目統(tǒng)計改動行數(shù)超過五百行的合并請求評審者平均只在三成區(qū)域留下了有效評論而小于兩百行的合并請求評審覆蓋率能到八成以上。人腦對連續(xù)信息的處理容量是有限的收益隨著代碼量增加迅速遞減。小粒度的合并請求還有一個隱藏好處回滾方便。萬一上線出問題一行g(shù)it revert就能干凈地撤銷整件事不用擔心帶上無關(guān)的改動。這對線上穩(wěn)定性的價值很多時候比評審本身還要大。2.2 評審清單怎么設(shè)計分層攔截而不是逐行讀代碼很多人評審的時候是悶頭讀代碼從第一個文件開始一個循環(huán)看一屏看到哪算哪。這種流式評審的效率非常低因為你沒有帶著靶子去看。我現(xiàn)在的做法是先列清單再按清單去掃描。清單不是流水賬而是分層設(shè)計。第一層是正確性與安全性這個問題最大直接決定上線后會不會炸。重點關(guān)注數(shù)據(jù)校驗是否完善、越權(quán)訪問有沒有攔截、并發(fā)場景下狀態(tài)會不會亂、異常分支是否處理、敏感信息有沒有打日志。第二層是可維護性這個問題不直接導致事故但決定了下個月的你或者同事會不會想罵人。函數(shù)是否過長、命名是否名不副實、是否存在重復代碼、模塊之間的依賴是否合理、有沒有留下讓人困惑的魔法數(shù)字。第三層才是代碼風格與性能。風格問題盡量交給自動化工具不值得人工花時間性能問題只在有明顯瓶頸的時候提不要在業(yè)務(wù)代碼里糾結(jié)一次遍歷是 O(n) 還是 O(2n)。這三層看起來簡單實際操作時有一個關(guān)鍵技巧先看測試再看實現(xiàn)最后看上下文引入點。大多數(shù)評審者習慣拿過代碼就開始讀實現(xiàn)讀到一半才去想這個函數(shù)應(yīng)該是干什么的。如果你先看測試用例測試的名稱和斷言會直接告訴你作者的真實意圖然后帶著這個意圖去看實現(xiàn)就能很快發(fā)現(xiàn)實現(xiàn)跟意圖之間的偏差最后再看這個改動被誰調(diào)用、影響哪些上游下游把全局上下文補上。這個順序我第一次用的時候只花了過去一半的時間就發(fā)現(xiàn)了兩個真正的邏輯漏洞。2.3 合并請求模板把該寫的信息前置流程設(shè)計里最容易忽略的是合并請求描述本身。我見過太多人只寫一句fix bug或者update評審人被迫從代碼里反推意圖。信息不對稱是評審低效的最大來源而模板是解決這個問題的最便宜的方案。一個實用的合并請求模板應(yīng)該包含三塊這次改動解決什么問題最好帶上復現(xiàn)步驟或現(xiàn)象截圖、改動涉及哪些模塊和文件讓評審人知道哪里是重點、測試情況如何單元測試、手動驗證、影響范圍。最后一塊特別重要很多人提交之前根本沒想自己測過什么寫著寫著就發(fā)現(xiàn)自己還有一堆沒驗證的地方。有了模板評審人可以在一兩分鐘內(nèi)建立起對改動的全局認知然后把注意力集中在真正有風險的地方。這個前置信息的小改動帶來的效率提升遠超你想象。3. 評審節(jié)奏與時間管理把評審控制在十五分鐘以內(nèi)3.1 為什么評審會拖成無效加班不知道你有沒有過這種經(jīng)歷一個合并請求掛在列表里好幾天催了兩次都沒人看最后催急了才有人熬夜幫你點了通過。評審周期拖得越長上下文丟失得越嚴重作者甚至都忘了自己當時為什么這么寫評審人還得花大量時間重新理解。更糟的是有些團隊會抱怨代碼評審拖慢了迭代其實拖慢迭代的不是評審本身而是沒有節(jié)奏的評審。我總結(jié)過幾個常見的節(jié)奏殺手評審請求發(fā)在群里沒人明確接單、評審人趕在下班前才開始看所以草草了事、一個改動同時等兩三個人評論導致結(jié)論打架、作者提交代碼后不主動跟進提醒。這些問題跟技術(shù)關(guān)系不大但跟評審能不能跑起來關(guān)系很大。3.2 設(shè)定明確的時間盒十五分鐘決策機制我現(xiàn)在的經(jīng)驗是每次評審最多給自己十五分鐘。聽起來很激進但配合小粒度的合并請求完全可行。前兩分鐘看描述和測試中間十分鐘過 diff 和關(guān)鍵分支最后三分鐘寫結(jié)論或者跟作者在線溝通。超過十五分鐘還沒看完說明這個改動已經(jīng)超出了它的安全評審范圍這時候就停下來讓作者拆下一次評審而不是硬撐著讀完。時間盒的好處是逼迫你區(qū)分必須看和可以跳過。很多人覺得每行都得看這是誤解。關(guān)鍵邏輯看三遍都不嫌多樣板代碼掃一眼就夠。有了時間壓力你的注意力反而更集中不會讀著讀著就跳到某個無關(guān)緊要的格式問題上。實際操作中我會配合一個簡單儀式評審完成后不管結(jié)果是通過還是打回都在評審記錄里寫一句已評審耗時X分鐘主要關(guān)注點是ABC。這句話幫作者快速定位風險區(qū)域也幫團隊統(tǒng)計評審效率。后來我們的合并請求平均合并速度從三天縮短到半天靠的其實都是這種小節(jié)奏的改進。3.3 評審會議出現(xiàn)在什么時候異步評審是主流但有一個場景我會特意安排同步討論跨模塊的接口變更。比如你的改動涉及調(diào)用方或者改了某個公共方法的入?yún)⑦@時候異步評論來回一輪可能要半天同步開個短會大家直接把路由打通把實現(xiàn)方的假設(shè)和調(diào)用方的需求放在同一張白板上效率反而更高。這類會議有個前提你必須帶著已經(jīng)完成的異步評審結(jié)論來而不是把會議當成評審起點。我參加過很多一起看代碼的會實際效果基本是幾個人盯著投影儀發(fā)呆誰都不好意思發(fā)言。正確姿勢是每個人先自己看一遍寫好問題清單會上只討論清單里的差異點十分鐘內(nèi)解決問題十五分鐘聊完收工。4. 工具鏈怎么輔助 open-code-reviewdiff、行內(nèi)評論與自動化檢查4.1 diff 閱讀順序與上下文切換代碼托管平臺的合并請求界面本質(zhì)上是把 diff 呈現(xiàn)給你看。但這個界面有個陷阱你看到的是變更后的代碼而評審真正需要對比的是變更前和變更后之間的語義差異。很多評審者看到一行刪除、幾行新增就急著評論其實根本不知道刪除的上下文在哪里。我建議按先新增、再刪除、后調(diào)整的順序讀 diff。新增代碼說明這個改動帶來了什么刪除代碼說明它移除了什么調(diào)整代碼說明它改了原來的什么假設(shè)。讀的時候注意平臺提供的展開上下文功能尤其是那些看似沒變的周邊代碼有時候 bug 就藏在那幾行沒變的調(diào)用里。行內(nèi)評論是異步評審的核心工具。它的優(yōu)勢是可以精確定位到某一行作者一打開就明白你在說什么完全可以替代那種整體寫得還不錯但邏輯有問題的模糊評語。我個人的習慣是每條評論盡量短只說一件事不搞長篇大論。如果確實需要解釋大背景我會先寫一行核心結(jié)論再用一個背景子段落展開方便作者快速決定要不要看細節(jié)。4.2 自動化檢查該攔什么、不該攔什么自動化工具是評審的好幫手但用不好也會制造噪音。我的原則其實很簡單能讓機器確定的事情就不要浪費人的時間機器不確定的事情也不要讓機器亂發(fā)言??梢越唤o自動化工具的有代碼格式、明顯的類型問題、未使用的變量、明顯的空指針風險、日志中是否打印了敏感信息、依賴license問題、重復代碼比例。這些檢查建議全部接入提交前和合并前的流水線攔截了就把這類型的評論從人工評審里剔出去。不該交給自動化工具的有業(yè)務(wù)邏輯是否正確、接口語義是否符合需求、并發(fā)處理是否合理、數(shù)據(jù)一致性是否保證。這些判斷需要完整的業(yè)務(wù)上下文機器現(xiàn)在遠做不到。很多團隊在流水線里塞了一堆建議級別的檢查規(guī)則結(jié)果開發(fā)者天天被逼著改無意義的告警反而沖淡了真正有價值的人工評審。自動化檢查應(yīng)該是守門員而不是評論員該守的門守住剩下的交給人去對話。4.3 評審結(jié)論的三種表達通過、評論、請求修改工具上通常有三個按鈕同意合并、評論、請求修改。這三個按鈕的語義一定要在團隊里對齊否則很快會出現(xiàn)一群人點了評論作者不知道到底能不能合并的混亂狀態(tài)。我把它們的邊界定義得很清楚。通過意味著我認為這個改動可以上線如果后續(xù)有問題我負責得起這是一個強承諾不是敷衍的點贊。評論意味著當前代碼沒問題但我有改進意見你可以擇機處理不阻塞合并。請求修改意味著當前代碼存在我無法接受的缺陷合并前必須解決。使用評論這一檔要尤其克制。我看到很多人明明發(fā)現(xiàn)了會影響線上正確性的 bug卻只寫了一句你可以考慮一下這里是否應(yīng)該加個判斷然后點了通過。這是典型的躲避沖突。正確的做法是如果有顧慮就明確說請求修改如果只是品味偏好就放在評論里別阻塞別人。這個邊界不清晰是評審失去效力的最大隱患之一。5. 評審意見的表達如何讓這段邏輯必須重寫不變成一場爭執(zhí)5.1 意見分三檔必須修、建議修、風格偏好評審者給出意見之前先自己心里分個檔。必須修是正確性問題比如數(shù)據(jù)會被覆蓋、權(quán)限會被繞過、異常會觸發(fā)嚴重 bug。建議修是可維護性問題比如命名不清、邏輯重復、缺少測試不修也不至于上線出事但留著會持續(xù)消耗后來的維護成本。風格偏好是純個人傾向比如變量名用哪個詞、花括號怎么換行、注釋中英文比例。這三個檔位在評論里要用明確的詞標出來比如[必須修] 這里缺少對空值的判斷[建議修] 這個函數(shù)可以拆成兩個小函數(shù)[風格] 我更喜歡用 start 而不是 begin。這樣作者接到意見時不需要自己去猜嚴重程度也避免了你居然為了一個變量名就打回我的代碼這種事。其實很多評審摩擦本質(zhì)就是檔位沒對齊。作者以為你在說風格結(jié)果你暗中是把他往必須修的檔位上算評審者以為自己在提建議結(jié)果用詞又像是在下命令。把檔位亮在明面上沖突能少掉一大半。5.2 用問題代替斷言評審者的蘇格拉底式提問我在評審中學到的最重要的一課是結(jié)論自己會讓人防御問題會讓人思考。你這塊代碼有并發(fā)風險和如果兩個請求同時在跑這段邏輯會不會出現(xiàn)重復扣款后者的接受度要高得多。原因很簡單代碼是作者花費時間和心思寫出來的直接下結(jié)論相當于否定了他的一部分勞動。但只要換成提問你們就從對立關(guān)系變成了一起探索問題的隊友。我自己做評審時有個硬性規(guī)定凡是必須修級的問題全部寫成問題形式措辭也盡量具體比如這個 null 是從哪里傳進來的調(diào)用方有沒有可能不傳而不是這里空指針了修一下。提問式評審的額外產(chǎn)出是它逼著你自己先想明白問題到底出在哪。比起脫口而出的斷言提問要經(jīng)過更嚴謹?shù)乃伎歼@對評審質(zhì)量本身也是一個正向加成。5.3 作者側(cè)的反向操作主動標記這里我看過沒把握評審意見的溝通壓力不只是評審者的問題作者也能做很多事。我的習慣是在提交信息或者合并請求描述里明確標出我自己懷疑過但拿不準的區(qū)域。這樣評審者就能把精力放在你最心虛的地方而不是均勻撒在全篇上。反過來作者越坦誠地暴露自己的不確定評審者越愿意給出真正有幫助的建議這是一條正向反饋。作者收到意見之后也要有個處理清單必須修的問題逐一確認修改建議修的問題能改就改不能改要給出理由風格偏好看情況跟自己的想法一致就采納不一致可以保留。最差的做法是看到評論就情緒上頭逐條反駁把評審變成辯論賽。代碼評審的目標是共同把代碼變得更好不是證明誰更聰明。6. 那些年踩過的評審坑形式化評審、無休止討論與漏網(wǎng)之魚6.1 全員通過卻照樣出事故評審為什么失效了最令人沮喪的情況莫過于評審流程走完了每個人都點了通過結(jié)果上線還是出了事故。這不是評審系統(tǒng)失效而是評審變成了形式化蓋章。我可以列出幾種常見病根。一種是因為權(quán)力關(guān)系不對等資深的人說沒問題其他人就不好意思再說話。一種是因為評審者對業(yè)務(wù)背景完全不了解看了代碼只覺得語法沒毛病就通過。還有一種是最普遍的改動太大、太雜評審者看了一部分就開始犯困最后大家都想著反正 CI 過了先合并再說。針對這些病根我做了兩手調(diào)整。其一評審意見和決定嚴格基于內(nèi)容和數(shù)據(jù)不基于等級資歷其二合并請求描述必須包含測試情況如果作者寫不出自己驗證過什么就不進入評審環(huán)節(jié)。這兩條規(guī)定一起執(zhí)行之后全員通過但事故照出的情況才真正開始變少。6.2 評審拖太久導致的上下文丟失評審周期過長不只是流程效率問題更會影響評審質(zhì)量本身。幾個真實體會改動提交第一天作者腦子里還有完整的上下文可以立刻響應(yīng)評論到第三天他自己都要重新看代碼才能想起當時的決策評論的回復質(zhì)量明顯下降到一周幾乎所有人都對這個改動失去新鮮感看到的只是一堆代碼而不是一個問題。所以我對評審超時的處理很干脆超過兩個工作日的評審自動提醒作者和評審者不解決就升級到同步會議。升級不是懲罰而是承認異步溝通在這個場景下已經(jīng)失效強制換一種模式。這時候開一個十五分鐘短會通常比繼續(xù)掛一天效率高得多。我還有一個親測有效的細節(jié)作者提交合并請求之后不要默默等待主動在團隊溝通頻道里發(fā)一條簡短說明包含描述鏈接和需要誰來評審。很多合并請求掛在列表里被遺忘不是大家不負責而是真的沒注意到。主動跟進這一下能把整個評審周期縮短一大截。6.3 低層次問題搶走了高層次注意力最后一個坑是評審者把精力花在了機器能解決的問題上。我看到過太多評審討論在吵命名這個變量叫 result 還是 outcome這個函數(shù)放 utils 還是 helper。吵到天荒地老卻沒有一個人關(guān)心核心業(yè)務(wù)邏輯有沒有缺陷。這不是說命名不重要而是說解決這個問題有更便宜的方式。代碼格式化工具、文檔規(guī)范、高質(zhì)量模板都能處理絕大多數(shù)低層次問題。人工評審是團隊成本最高、心智資源最稀缺的環(huán)節(jié)應(yīng)該把它留給只有人才能發(fā)現(xiàn)的問題。每當有人開始對著格式爭議我都會提醒一句先看邏輯格式上如果有潔癖請先去改自動化規(guī)則不要在這里消耗人。這個觀念的轉(zhuǎn)變也是 open-code-review 從找錯的流程進化成質(zhì)量共建系統(tǒng)的關(guān)鍵節(jié)點。評審不再是防御性的關(guān)卡而是大家一起討論設(shè)計意圖、發(fā)現(xiàn)盲區(qū)、對齊認知的協(xié)作場合。如果能做到這一點代碼庫的質(zhì)量會以肉眼可見的速度提升。7. 我現(xiàn)在的評審習慣與最終落地清單從那次訂單系統(tǒng)重試扣庫存翻車到現(xiàn)在我一直在迭代自己的評審方式最終形成了三個固定的習慣。第一個習慣是先問三個問題再看代碼這個改動要解決什么問題它影響哪些模塊和調(diào)用方作者驗證過什么三個問題在合并請求描述里找不到答案的話我會直接請作者補充而不是自己猜著往下讀。這讓我避開了大多數(shù)讀了一大半才發(fā)現(xiàn)方向不對的情況。第二個習慣是必須在一個小本子里留一句評審備注。評審完之后順手記一句這個改動哪個區(qū)域風險最高、哪條意見最值得后續(xù)跟進。本來只是給自己留痕跡沒想到后來做線上回查時幫了大忙能快速定位當初評審時擔心的地方。第三個習慣是評審別人之前先把自己的合并請求隨手處理掉。一個團隊里如果資深的人總把自己的評審壓到最后一刻新人很快就會覺得評審只是走個形式。先把別人交給我的代碼處理好再去推進自己的開發(fā)任務(wù)這個次序本身就在傳遞一種信號評審是值得被認真對待的事它不是可有可無的尾巴工程。如果你所在的團隊還在被無效評審困擾我的建議是不要指望一步到位。先從一件小事開始把合并請求拆分到三百行以內(nèi)給評審設(shè)定十五分鐘的時間盒把意見分檔標清楚。這三個動作不需要引入任何復雜平臺或工具只需要大家達成共識。我見過很多團隊做到這一步之后評審會議的爭吵少了上線故障也明顯少了因為大家終于把力氣花在了真正值得花的地方。open-code-review 說到底不是某種固定的形式。對別人寫的代碼保持開放對自己的盲區(qū)保持開放對流程的改進保持開放——能做到這三點代碼評審就再也不是每月吐槽清單里的負擔而會成為整個團隊質(zhì)量感覺最靈敏的一根神經(jīng)。