設(shè)施:開(kāi)放式Code Review機(jī)制設(shè)計(jì)與落地)
1. 先聊聊為什么很多團(tuán)隊(duì)的Code Review形同虛設(shè)我參與過(guò)大大小小不下十個(gè)項(xiàng)目的評(píng)審流程改造見(jiàn)過(guò)最典型的一個(gè)場(chǎng)景是團(tuán)隊(duì)嘴上喊著我們要做Code ReviewGitHub倉(cāng)庫(kù)的PR也確實(shí)掛了一堆但點(diǎn)進(jìn)去一看評(píng)論全是LGTMLooks Good To Me或者一個(gè)表情代碼照樣帶著明顯的問(wèn)題合并進(jìn)了主干。等到線(xiàn)上出了故障回滾、加補(bǔ)丁、復(fù)盤(pán)一套流程走下來(lái)所有人精疲力盡最后結(jié)論往往是下次評(píng)審要更認(rèn)真一點(diǎn)——然后下個(gè)迭代又重復(fù)一遍。這不是某個(gè)團(tuán)隊(duì)的個(gè)例而是一個(gè)普遍現(xiàn)象。問(wèn)題出在哪我后來(lái)想明白一件事大多數(shù)團(tuán)隊(duì)把Code Review當(dāng)成了一道行政關(guān)卡而不是一個(gè)技術(shù)協(xié)作過(guò)程。一旦它變成關(guān)卡人的心態(tài)就會(huì)自動(dòng)切換到怎么盡快通過(guò)模式質(zhì)量和效率自然顧不上了。1.1 評(píng)審流于形式的三類(lèi)典型表現(xiàn)第一類(lèi)是點(diǎn)贊式評(píng)審。評(píng)審人打開(kāi)PR掃一眼標(biāo)題和描述看到CI是綠的隨手點(diǎn)個(gè)通過(guò)。這種情況在新人多的團(tuán)隊(duì)特別常見(jiàn)——不是大家不想認(rèn)真看而是根本不知道要看什么沒(méi)有一張明確的檢查清單只能憑感覺(jué)掃一眼。第二類(lèi)是馬拉松式評(píng)審。一個(gè)PR掛了兩周沒(méi)人理提PR的人每天在群里催最后在周五晚上十點(diǎn)一個(gè)剛加完班的同事用半小時(shí)刷刷刷看完全部改動(dòng)甩出幾條不痛不癢的評(píng)論然后通過(guò)。這種評(píng)審不僅沒(méi)有質(zhì)量還在持續(xù)消耗團(tuán)隊(duì)的信任感——每個(gè)人心里都清楚這流程是走過(guò)場(chǎng)。第三類(lèi)是站隊(duì)式評(píng)審。資深工程師覺(jué)得新手寫(xiě)的代碼太蠢評(píng)論寫(xiě)得像法庭陳詞新手心里不服又不敢反駁改了兩次之后干脆什么都不說(shuō)反正你說(shuō)怎么改我就怎么改。這種評(píng)審最終會(huì)消滅所有人的主動(dòng)性代碼質(zhì)量和團(tuán)隊(duì)氛圍雙雙滑坡。1.2 問(wèn)題不在人在機(jī)制我見(jiàn)過(guò)太多團(tuán)隊(duì)把評(píng)審流于形式的鍋甩給大家態(tài)度不端正或者工程師太忙了但實(shí)際拆解下來(lái)問(wèn)題幾乎都出在機(jī)制設(shè)計(jì)上。沒(méi)有明確的評(píng)審標(biāo)準(zhǔn)沒(méi)有合理的PR粒度約定沒(méi)有時(shí)限約束沒(méi)有爭(zhēng)議升級(jí)機(jī)制評(píng)審人全憑自覺(jué)發(fā)揮——結(jié)果當(dāng)然取決于每個(gè)人的當(dāng)天心情和空閑程度。真正有效的Code Review需要被當(dāng)成一套有明確輸入輸出、有流程節(jié)點(diǎn)、有質(zhì)量反饋閉環(huán)的協(xié)作系統(tǒng)來(lái)搭建。這就是我在這篇文章里想聊的核心怎么圍繞開(kāi)放代碼評(píng)審這個(gè)思路從機(jī)制、流程、工具和團(tuán)隊(duì)文化四個(gè)層面把評(píng)審從形式主義變成真正能攔截缺陷、傳遞經(jīng)驗(yàn)、提升代碼質(zhì)量的基礎(chǔ)設(shè)施。下文所有內(nèi)容都基于我過(guò)去幾年的實(shí)際落地經(jīng)驗(yàn)?zāi)憧梢灾苯诱罩钜部梢愿鶕?jù)團(tuán)隊(duì)規(guī)模做裁剪——但核心的機(jī)制設(shè)計(jì)邏輯建議不要省。2. 開(kāi)放式評(píng)審機(jī)制怎么設(shè)計(jì)四個(gè)躲不開(kāi)的核心要素很多團(tuán)隊(duì)搭建Code Review流程時(shí)第一件事是去選工具第二件事是寫(xiě)一份團(tuán)隊(duì)規(guī)范文檔。這個(gè)順序其實(shí)是錯(cuò)的。工具和規(guī)范之前必須先想清楚機(jī)制——也就是每個(gè)人的角色、每個(gè)環(huán)節(jié)的規(guī)則、每個(gè)產(chǎn)物的標(biāo)準(zhǔn)是什么。工具只是這些規(guī)則的載體。2.1 把評(píng)審從審批變成協(xié)作我在好幾個(gè)團(tuán)隊(duì)里做的第一個(gè)機(jī)制調(diào)整是把評(píng)審必須由指定負(fù)責(zé)人審批通過(guò)這個(gè)規(guī)則改成任何人可以評(píng)論作者必須逐條響應(yīng)。這兩句話(huà)看起來(lái)差不多實(shí)際效果差別巨大。審批制意味著評(píng)審人是裁判作者是考生雙方天然站在對(duì)立面。而開(kāi)放式評(píng)審的規(guī)則是評(píng)審人提供意見(jiàn)作者決定是否采納——但前提是每一條意見(jiàn)都必須有一個(gè)明確的處置結(jié)果采納、不采納但說(shuō)明理由、還是調(diào)整方案后再討論。這樣一來(lái)評(píng)審就從你審我變成了我們一起把這個(gè)改動(dòng)打磨好。落地時(shí)我會(huì)在團(tuán)隊(duì)規(guī)范里寫(xiě)死幾條規(guī)則任何人對(duì)任何PR都有評(píng)論權(quán)不限角色和職級(jí)。作者必須在24小時(shí)內(nèi)對(duì)每條評(píng)論給出響應(yīng)即使是這個(gè)建議我考慮一下明天回復(fù)也行。評(píng)論討論超過(guò)三天且沒(méi)有結(jié)論的自動(dòng)升級(jí)到技術(shù)負(fù)責(zé)人參與仲裁。這幾條規(guī)則看起來(lái)簡(jiǎn)單但它保證了每一條意見(jiàn)都會(huì)進(jìn)入閉環(huán)不會(huì)出現(xiàn)評(píng)論躺了三天作者直接點(diǎn)了合并的情況。2.2 變更粒度控制在多少合適評(píng)審失效的另一個(gè)重要原因是PR太大。我見(jiàn)過(guò)一個(gè)新人把一個(gè)功能從零寫(xiě)到上線(xiàn)整個(gè)PR包含了40個(gè)文件、2000多行改動(dòng)、前端后端數(shù)據(jù)庫(kù)全都有——這種規(guī)模沒(méi)有任何人有能力在合理時(shí)間內(nèi)完成有效評(píng)審。評(píng)論者只能看看核心邏輯邊緣代碼全靠運(yùn)氣。我建議的約定是一個(gè)PR的改動(dòng)量控制在200到400行之間涉及文件不超過(guò)10個(gè)耗時(shí)超過(guò)三天的開(kāi)發(fā)任務(wù)必須拆成多個(gè)階段性PR每一步合并后都保持主干可用。為什么定這個(gè)數(shù)200行大概是30到40分鐘能認(rèn)真讀完的量再往上走評(píng)審人的注意力會(huì)肉眼可見(jiàn)地下降10個(gè)文件意味著改動(dòng)邊界清晰跨模塊的隱含影響在可控范圍內(nèi)。這條規(guī)則的落地阻力很大尤其是習(xí)慣了開(kāi)一個(gè)分支悶頭開(kāi)發(fā)兩周的團(tuán)隊(duì)。我的處理辦法是先定規(guī)則再提供拆分模板每個(gè)功能先出一個(gè)接口定義PR再出實(shí)現(xiàn)PR再出測(cè)試補(bǔ)充PR最后出聯(lián)調(diào)修改PR。模板給到位執(zhí)行就順很多。2.3 評(píng)審時(shí)限與響應(yīng)機(jī)制評(píng)審卡在沒(méi)人看是團(tuán)隊(duì)最常見(jiàn)的問(wèn)題。我的觀點(diǎn)是不要把評(píng)審時(shí)限寄托在自覺(jué)上要把它設(shè)計(jì)成剛性的SLA服務(wù)等級(jí)協(xié)議。實(shí)際落地時(shí)我們團(tuán)隊(duì)約定的是工作時(shí)間之內(nèi)首次響應(yīng)不超過(guò)4小時(shí)整體評(píng)審不超過(guò)24小時(shí)。首次響應(yīng)不強(qiáng)制要求審?fù)甑仨氂幸粭l評(píng)論——可以是收到下午細(xì)看也可以是看完了主要問(wèn)題如下。同時(shí)設(shè)置一個(gè)自動(dòng)化的提醒機(jī)器人超過(guò)2小時(shí)沒(méi)有響應(yīng)就在群里提醒一次超過(guò)4小時(shí)直接提醒對(duì)應(yīng)小組的技術(shù)負(fù)責(zé)人。這里有個(gè)容易被忽視的細(xì)節(jié)SLA要雙向生效。不僅評(píng)審人要在時(shí)限內(nèi)響應(yīng)作者也要在評(píng)審人發(fā)出評(píng)論后的24小時(shí)內(nèi)回復(fù)。單向SLA會(huì)讓評(píng)審人覺(jué)得我積極響應(yīng)了結(jié)果對(duì)方晾了我兩天——這種不公平感會(huì)迅速殺死評(píng)審積極性。雙向SLA才能形成良性循環(huán)。2.4 定義清晰的完成標(biāo)準(zhǔn)什么叫一個(gè)PR可以合入這個(gè)問(wèn)題很多團(tuán)隊(duì)答不上來(lái)。沒(méi)有清晰標(biāo)準(zhǔn)評(píng)審就只能靠各人直覺(jué)。我整理過(guò)一份能直接抄作業(yè)的完成標(biāo)準(zhǔn)清單CI全部通過(guò)包括單元測(cè)試、靜態(tài)檢查、覆蓋率達(dá)標(biāo)線(xiàn)。所有評(píng)審評(píng)論都有明確的處置結(jié)果沒(méi)有遺留的待討論標(biāo)簽。涉及外部接口或數(shù)據(jù)結(jié)構(gòu)的變更必須同步更新相應(yīng)文檔。新增或修改的邏輯至少有對(duì)應(yīng)的單元測(cè)試覆蓋關(guān)鍵分支不允許裸奔。變更描述里寫(xiě)清楚改了什么、為什么改、怎么驗(yàn)證三件事。你可能注意到了這些標(biāo)準(zhǔn)里沒(méi)有代碼風(fēng)格這一項(xiàng)——因?yàn)轱L(fēng)格問(wèn)題應(yīng)該交給格式化工具自動(dòng)處理人類(lèi)評(píng)審員不應(yīng)該把精力浪費(fèi)在這里該不該加個(gè)空格這種噪音上。3. 工具鏈落地GitHub/GitLab與Gerrit的選型邏輯機(jī)制定清楚了下一步才是選工具。我常說(shuō)一句話(huà)工具決定不了評(píng)審質(zhì)量但工具可以放大機(jī)制的效力也可以把機(jī)制毀掉。選型的關(guān)鍵不是看誰(shuí)的功能多而是看它和你們團(tuán)隊(duì)的協(xié)作方式是否匹配。3.1 GitHub/GitLab的PR/MR評(píng)審流程如果你的團(tuán)隊(duì)規(guī)模在50人以?xún)?nèi)、追求輕量高效的協(xié)作節(jié)奏GitHub的Pull Request和GitLab的Merge Request是最自然的選擇。這類(lèi)工具的核心邏輯是**分支 請(qǐng)求合并**評(píng)審記錄天然和代碼變更綁定在一起每一條評(píng)論都能精確定位到具體的代碼行。我在GitHub上落地評(píng)審流程時(shí)最常用的組合是Branch protection規(guī)則 CODEOWNERS文件 自動(dòng)化機(jī)器人。Branch protection保證master分支不能直接推送任何改動(dòng)必須經(jīng)過(guò)PRCODEOWNERS把不同目錄的負(fù)責(zé)人指定好比如src/api/目錄歸后端組負(fù)責(zé)前端組件目錄歸前端組負(fù)責(zé)改動(dòng)涉及哪個(gè)目錄對(duì)應(yīng)的CODEOWNERS會(huì)自動(dòng)被拉進(jìn)評(píng)審機(jī)器人則負(fù)責(zé)檢查PR描述是否填寫(xiě)完整、是否有對(duì)應(yīng)的issue編號(hào)、覆蓋率是否達(dá)標(biāo)等機(jī)械性檢查項(xiàng)。GitLab相比GitHub的一個(gè)優(yōu)勢(shì)是內(nèi)置了Merge Request Approvals功能可以配置一個(gè)MR必須經(jīng)過(guò)幾個(gè)指定角色的批準(zhǔn)才能合并并且可以針對(duì)不同分支設(shè)置不同的批準(zhǔn)規(guī)則。對(duì)于需要滿(mǎn)足審計(jì)要求的團(tuán)隊(duì)這個(gè)功能比GitHub的默認(rèn)分支保護(hù)更精細(xì)。3.2 Gerrit的嚴(yán)格合入門(mén)禁如果你的團(tuán)隊(duì)做的是基礎(chǔ)組件、底層中間件或者所在公司有較強(qiáng)的合規(guī)審計(jì)壓力Gerrit依然是一個(gè)值得認(rèn)真考慮的選擇。Gerrit的設(shè)計(jì)哲學(xué)和GitHub完全不同它不采用合并整個(gè)分支的PR模型而是每個(gè)commit單獨(dú)評(píng)審評(píng)審?fù)ㄟ^(guò)后才合入主干并且高度依賴(lài)的Hook機(jī)制可以把非常多質(zhì)量卡點(diǎn)前置到push階段之前。我在用Gerrit做開(kāi)源基礎(chǔ)庫(kù)的評(píng)審時(shí)最認(rèn)可它的點(diǎn)是補(bǔ)丁集Patch Set機(jī)制。每個(gè)版本迭代都會(huì)生成一個(gè)新的Patch Set評(píng)審人可以直觀地對(duì)不同版本做diff對(duì)比——這次修改到底改了什么一目了然。這個(gè)能力在GitHub上需要通過(guò)第三方插件才能勉強(qiáng)實(shí)現(xiàn)體驗(yàn)要差不少。但必須坦率地說(shuō)Gerrit的上手門(mén)檻較高。它內(nèi)置了獨(dú)立的三方合流邏輯權(quán)限模型也復(fù)雜團(tuán)隊(duì)里得有一個(gè)愿意研究它的人才行。如果只是為了評(píng)審?fù)ㄟ^(guò)才能合代碼GitLab的Approvals其實(shí)已經(jīng)夠用了不必非上Gerrit。我的建議是維度GitHub PRGitLab MRGerrit學(xué)習(xí)成本低低高評(píng)審粒度變更整體變更整體單個(gè)Commit版本對(duì)比體驗(yàn)一般需插件一般原生強(qiáng)項(xiàng)權(quán)限與審批控制中等較強(qiáng)最嚴(yán)格適合場(chǎng)景中小團(tuán)隊(duì)、開(kāi)源項(xiàng)目中大型團(tuán)隊(duì)、合規(guī)要求基礎(chǔ)組件、審計(jì)嚴(yán)格、多人高頻協(xié)作3.3 機(jī)器人助手與自動(dòng)化檢查配置不管選哪個(gè)平臺(tái)我都建議配置一套自動(dòng)化輔助——能交給機(jī)器判斷的絕不占用評(píng)審人的時(shí)間和精力。我常用的組合是CI跑測(cè)試和覆蓋率靜態(tài)分析工具跑代碼規(guī)范和安全掃描再加上一個(gè)自定義機(jī)器人檢查PR元信息。以GitHub為例我會(huì)用.github/workflows里的actions做三層檢查。第一層是基礎(chǔ)檢查PR標(biāo)題是否符合約定格式、是否關(guān)聯(lián)了issue、分支是否基于最新的master。第二層是質(zhì)量檢查跑完整單測(cè)、增量代碼覆蓋率、ESLint或golangci-lint之類(lèi)的靜態(tài)檢查。第三層是部署預(yù)檢如果有預(yù)覽環(huán)境自動(dòng)生成一個(gè)預(yù)覽鏈接讓產(chǎn)品和設(shè)計(jì)可以直接點(diǎn)開(kāi)看效果。這三層檢查的意義不只是攔住問(wèn)題代碼更重要的是把有效評(píng)審的上下文給評(píng)審人送過(guò)去——評(píng)審人打開(kāi)PR時(shí)已經(jīng)知道測(cè)試過(guò)了、風(fēng)格沒(méi)問(wèn)題、預(yù)覽地址有了就可以集中精力看邏輯和設(shè)計(jì)而不是從零開(kāi)始檢查基礎(chǔ)項(xiàng)。4. 評(píng)審意見(jiàn)怎么寫(xiě)才有效率經(jīng)驗(yàn)與話(huà)術(shù)有了流程、工具、自動(dòng)化評(píng)審的一個(gè)核心環(huán)節(jié)——人怎么提意見(jiàn)——才真正浮出水面。這是最依賴(lài)個(gè)人經(jīng)驗(yàn)的部分也是決定評(píng)審體驗(yàn)與效果的一環(huán)。同樣的一個(gè)Bug不同表達(dá)方式帶來(lái)的是完全不同的后續(xù)反應(yīng)。4.1 區(qū)分必要修改和建議優(yōu)化我在評(píng)審時(shí)會(huì)把評(píng)論分成三個(gè)明確的優(yōu)先級(jí)必須修改Blocking、建議優(yōu)化Non-blocking、純探討Nit。這個(gè)分類(lèi)不是隨口說(shuō)說(shuō)的它對(duì)應(yīng)著不同的處置規(guī)則。必須修改表示這個(gè)問(wèn)題不解決這個(gè)改動(dòng)不能合入比如明顯的邏輯錯(cuò)誤、安全隱患、會(huì)導(dǎo)致線(xiàn)上故障的邊界條件。建議優(yōu)化表示不改也能合但改了會(huì)更好比如可讀性提升、性能優(yōu)化點(diǎn)、設(shè)計(jì)模式選得不夠優(yōu)雅。純探討則是我個(gè)人對(duì)某個(gè)實(shí)現(xiàn)的興趣討論作者可以不處理回復(fù)一句這個(gè)想法有意思即可。這個(gè)分類(lèi)最大的好處是降低溝通成本。我見(jiàn)過(guò)太多評(píng)審人把意見(jiàn)寫(xiě)成模糊的句子這個(gè)函數(shù)感覺(jué)不太對(duì)你再看一下?!髡吣玫竭@種評(píng)論只能一臉問(wèn)號(hào)。而如果明確標(biāo)注是必須修改這個(gè)循環(huán)在n為0時(shí)會(huì)死循環(huán)討論就能直接進(jìn)入解決方案而不是在到底有沒(méi)有問(wèn)題上扯皮。4.2 用提問(wèn)代替命令保留對(duì)方的主人翁感這是我從過(guò)去帶團(tuán)隊(duì)踩過(guò)最多次坑換來(lái)的經(jīng)驗(yàn)。直接命令式的評(píng)審意見(jiàn)把這里改成XXX會(huì)立刻把討論變成防守和攻擊而提問(wèn)式的意見(jiàn)如果用XXX方式實(shí)現(xiàn)會(huì)不會(huì)更簡(jiǎn)潔則會(huì)把討論變成技術(shù)探索。舉個(gè)例子。一個(gè)同事用了一個(gè)復(fù)雜的嵌套循環(huán)處理數(shù)據(jù)映射與其說(shuō)這個(gè)邏輯太繞了重寫(xiě)不如說(shuō)我注意到這里有三層嵌套循環(huán)在數(shù)據(jù)量大的情況下性能會(huì)有問(wèn)題嗎我印象中可以用哈希表預(yù)索引一下直接把查找從O(n)降到O(1)——你評(píng)估一下有沒(méi)有必要效果對(duì)比很明顯。第一種表達(dá)方式對(duì)方大概率會(huì)不服氣地改完然后背后吐槽第二種表達(dá)方式對(duì)方會(huì)認(rèn)真審視自己的實(shí)現(xiàn)即使最后決定不優(yōu)化也會(huì)在回復(fù)里說(shuō)明原因——這個(gè)過(guò)程本身就很有價(jià)值。4.3 應(yīng)對(duì)搶著合代碼的沖突場(chǎng)景最后一個(gè)關(guān)于人的問(wèn)題是當(dāng)作者急著合代碼、評(píng)審人還有疑問(wèn)時(shí)雙方很容易起沖突。我現(xiàn)在的處理原則是如果還有清楚指出的必須修改級(jí)別問(wèn)題沒(méi)有解決該合并的審核就不能通過(guò)如果只是建議優(yōu)化級(jí)別我不會(huì)阻塞合并但會(huì)明確標(biāo)注這條意見(jiàn)記錄在案建議在后續(xù)迭代處理。在這個(gè)基礎(chǔ)上還有一個(gè)團(tuán)隊(duì)級(jí)的約定值得做PR沒(méi)有完成評(píng)審閉環(huán)之前任何人不允許合并。哪怕是作者自己就是技術(shù)負(fù)責(zé)人也不例外。這條規(guī)則的執(zhí)行需要一把最后的閘門(mén)——通常由CI或平臺(tái)本身的保護(hù)機(jī)制來(lái)實(shí)現(xiàn)而不靠人盯人規(guī)則才能穩(wěn)定執(zhí)行。5. 把評(píng)審數(shù)據(jù)變成團(tuán)隊(duì)改進(jìn)的依據(jù)評(píng)審流程跑順了之后團(tuán)隊(duì)會(huì)積累大量的數(shù)據(jù)每個(gè)PR的評(píng)審時(shí)長(zhǎng)、評(píng)論數(shù)、Bug發(fā)現(xiàn)數(shù)、一輪評(píng)審?fù)ㄟ^(guò)的占比等等。這些數(shù)據(jù)不只是給管理者看的報(bào)表更是一個(gè)團(tuán)隊(duì)識(shí)別自身協(xié)作瓶頸的最重要依據(jù)。5.1 評(píng)審數(shù)據(jù)看板上應(yīng)該放什么我見(jiàn)過(guò)有團(tuán)隊(duì)把評(píng)審數(shù)據(jù)做成一個(gè)巨大的Dashboard上面幾十個(gè)指標(biāo)結(jié)果沒(méi)人看——因?yàn)榇蠹也恢揽词裁匆膊恢滥男┲笜?biāo)值得關(guān)注。我的建議是只保留四個(gè)核心指標(biāo)平均首次響應(yīng)時(shí)長(zhǎng)衡量評(píng)審響應(yīng)速度的核心指標(biāo)超過(guò)4小時(shí)說(shuō)明資源分配有問(wèn)題。平均評(píng)審周期從PR創(chuàng)建到合并的總時(shí)長(zhǎng)超過(guò)3天說(shuō)明PR粒度偏大或者流程卡住。每PR平均評(píng)論數(shù)評(píng)論過(guò)少低于3條通常說(shuō)明評(píng)審流于形式評(píng)論過(guò)多高于15條可能說(shuō)明設(shè)計(jì)文檔階段溝通不足。一次通過(guò)率沒(méi)有必須修改意見(jiàn)就直接合并的PR占比低于50%說(shuō)明設(shè)計(jì)階段問(wèn)題較大高于90%可能說(shuō)明評(píng)審過(guò)于寬松。這四個(gè)指標(biāo)組合在一起能快速定位流程的瓶頸環(huán)節(jié)。比如首次響應(yīng)很快但評(píng)審周期很長(zhǎng)問(wèn)題往往出在意見(jiàn)來(lái)回討論的回合數(shù)太多如果評(píng)論數(shù)很大但一次通過(guò)率很高說(shuō)明評(píng)審人都在提小事沒(méi)抓到核心問(wèn)題。5.2 定期評(píng)審復(fù)盤(pán)怎么開(kāi)我建議團(tuán)隊(duì)每?jī)芍芑?0到45分鐘做一次評(píng)審復(fù)盤(pán)但復(fù)盤(pán)的重點(diǎn)不是追責(zé)而是找機(jī)制漏洞。流程很簡(jiǎn)單從最近合并的PR中挑2到3個(gè)討論質(zhì)量最高或問(wèn)題最多的逐條回顧評(píng)審意見(jiàn)看哪些意見(jiàn)是真正值得提的、哪些是在放空炮、哪些重要的問(wèn)題當(dāng)時(shí)沒(méi)被提出來(lái)。復(fù)盤(pán)會(huì)上最常暴露出的問(wèn)題是評(píng)審人之間對(duì)什么算嚴(yán)重問(wèn)題的標(biāo)準(zhǔn)不一致——一個(gè)人覺(jué)得必須改的性能問(wèn)題另一個(gè)人覺(jué)得完全可以盲合。這種不一致會(huì)讓作者非常困惑。每次復(fù)盤(pán)會(huì)上我會(huì)把這類(lèi)爭(zhēng)議拉出來(lái)公開(kāi)討論讓團(tuán)隊(duì)逐步收斂出一份常見(jiàn)評(píng)審問(wèn)題清單后面的人照著清單看評(píng)審質(zhì)量會(huì)穩(wěn)定很多。5.3 讓新人通過(guò)評(píng)審快速成長(zhǎng)開(kāi)放式評(píng)審的隱藏價(jià)值是師徒傳承。我在帶新人時(shí)會(huì)刻意安排核心模塊的PR帶上學(xué)徒評(píng)審人——不是讓他獨(dú)立審核而是跟著有經(jīng)驗(yàn)的工程師一起看先自己寫(xiě)評(píng)論再和師傅的評(píng)論對(duì)比看漏了什么、抓偏了什么。這個(gè)做法效果很驚人。新人通常在3到6個(gè)月內(nèi)就能形成對(duì)代碼質(zhì)量的判斷力而且因?yàn)樵u(píng)審判定標(biāo)準(zhǔn)是公開(kāi)討論出來(lái)的新人也會(huì)更快理解團(tuán)隊(duì)的技術(shù)價(jià)值取向。相比之下那些讓新人獨(dú)立寫(xiě)代碼、獨(dú)立修Bug、只在評(píng)審時(shí)被動(dòng)接受意見(jiàn)的團(tuán)隊(duì)新人成長(zhǎng)速度明顯慢一大截。6. 落地過(guò)程中的坑與對(duì)策我踩過(guò)的和見(jiàn)過(guò)別人踩的最后一部分聊聊實(shí)操中最容易踩的坑。我不會(huì)給你一份完美指南——那種東西現(xiàn)實(shí)中不存在。這里是我和身邊團(tuán)隊(duì)真正遇到過(guò)的問(wèn)題以及最后摸索出的解決方案。6.1 反對(duì)聲最大時(shí)的過(guò)渡策略改評(píng)審機(jī)制一定會(huì)有阻力尤其是從沒(méi)人管直接切到嚴(yán)格門(mén)禁的團(tuán)隊(duì)。我記得有一個(gè)團(tuán)隊(duì)在推行強(qiáng)制CODEOWNERS時(shí)項(xiàng)目負(fù)責(zé)人當(dāng)場(chǎng)提出激烈反對(duì)理由是這樣會(huì)拖慢交付速度。我的應(yīng)對(duì)方法是分階段走第1到2周只把新規(guī)則用于非核心業(yè)務(wù)的新PR老分支不納入管理讓團(tuán)隊(duì)先體驗(yàn)有評(píng)審和沒(méi)評(píng)審的差異第3到4周擴(kuò)大到核心業(yè)務(wù)第5周之后全量鋪開(kāi)。同時(shí)用數(shù)據(jù)說(shuō)話(huà)——對(duì)比機(jī)制變化前后的Bug率、返工時(shí)間讓對(duì)機(jī)制不滿(mǎn)的人也看到實(shí)際的投入產(chǎn)出比。6.2 評(píng)審文化執(zhí)行中的意外情況處理我遇到過(guò)的意外情況包括評(píng)審人離職了PR掛在那一拖就是兩周作者把評(píng)審意見(jiàn)原封不動(dòng)循環(huán)回復(fù)了好幾個(gè)來(lái)回新來(lái)的外包同事完全不按分支規(guī)范直接往主干推代碼。這類(lèi)事情任何規(guī)則文檔都覆蓋不到。我的經(jīng)驗(yàn)是不要試圖把所有意外都預(yù)料到而是要有一個(gè)兜底機(jī)制——在這類(lèi)例外情況下有一個(gè)負(fù)責(zé)人可以拍板決定PR的處置通常建議由技術(shù)負(fù)責(zé)人或架構(gòu)師擔(dān)任。這個(gè)兜底人不參與日常評(píng)審只在流程無(wú)法收斂或出現(xiàn)平臺(tái)級(jí)沖突時(shí)介入。6.3 評(píng)審疲勞與參與感的維持最后聊一個(gè)容易被忽視的隱患評(píng)審疲勞。當(dāng)團(tuán)隊(duì)規(guī)模大、PR數(shù)量多時(shí)資深工程師每天可能要花兩三個(gè)小時(shí)在評(píng)審上很容易產(chǎn)生抵觸情緒。對(duì)此我的做法是輪值評(píng)審每個(gè)模塊設(shè)置一輪值期按周輪換避免同一批人長(zhǎng)期承擔(dān)全部評(píng)審壓力。同時(shí)明確要求輪值期間可以把自己的開(kāi)發(fā)任務(wù)排輕一點(diǎn)給評(píng)審留出充足精力。我還發(fā)現(xiàn)一個(gè)很有效的做法評(píng)審也可以被評(píng)審。每季度讓團(tuán)隊(duì)匿名給評(píng)審人的評(píng)審質(zhì)量打分——有沒(méi)有認(rèn)真看代碼有沒(méi)有無(wú)理取鬧的意見(jiàn)表達(dá)是幫助成長(zhǎng)還是打擊士氣這個(gè)反饋機(jī)制會(huì)讓評(píng)審人意識(shí)到他們的意見(jiàn)也是工作成果的一部分值得好好對(duì)待——而不是隨便敷衍了事。