🎯 什麼情境該想到我
當你「收到一個大到看兩遍還搞不懂影響範圍的變更,只好按下 LGTM」的時候。
⚙️ 怎麼用(步驟 / 公式)
意圖:用離工作最近的同事來找出錯誤,同時取得交叉訓練、同儕學習與技能提升的副效益。
適用範圍:這在開發領域叫 code review,但同樣適用於我們對應用或環境做的任何變更,包括伺服器、網路與資料庫。(書中也說明 code review 與 change review 兩詞交替使用。)
四條準則(書中的 Guidelines for code reviews):
- 每個人的變更在 commit 進 trunk 之前,都必須有人審(程式、環境等皆然)。
- 每個人都應該盯著團隊成員的 commit stream,好及早發現並審視潛在衝突。
- 定義哪些變更算高風險、需要指定的 subject matter expert 來審(例如資料庫變更、認證等安全敏感模組)。書中註腳提到:高風險程式與環境的清單,多半 change advisory board 早就整理好了。
- 如果有人送出的變更大到難以理解——具體判準是「讀過幾遍後你仍搞不懂它的影響,或你必須去問提交者才問得清楚」——就應該拆成多個能一眼看懂(understood at a glance)的小變更。
要求審查的地點:合乎邏輯的位置是在把程式 commit 進 trunk 之前,因為變更在那裡可能造成全隊或全域影響。最低限度是同事審過;高風險領域(資料庫變更、自動化測試覆蓋不足的業務關鍵元件)可以要求 SME 或多次審查(用「+2」而不只是「+1」)。
關鍵洞見:變更大小與風險是非線性關係
- Randy Shoup:「變更大小與整合該變更的潛在風險之間是非線性關係——從十行變成一百行,出錯的風險就超過十倍,以此類推。」所以開發者必須以小的、增量的步伐工作,而不是長命的 feature branch。
- 而且我們有意義地批評變更的能力會隨變更變大而下降。Giray Özil 的推文:「叫一個程式設計師審十行程式碼,他會找出十個問題;叫他審五百行,他會說看起來沒問題。」
- 小批量原則同樣適用於 code review:要審的變更越大,理解時間越久,審查者的負擔越重。
防橡皮圖章(rubber stamping):
- 檢視 code review 統計數據,看被核可 vs 未被核可的提案變更數各是多少。
- 抽樣並實際檢視具體的 code review。
四種審查形式:
- Pair programming:兩人成對工作(見 結對程式設計)。
- 「Over-the-shoulder」:一位開發者在作者肩後看著他走過程式碼。
- Email pass-around:原始碼管理系統在 check in 後自動把程式碼寄給審查者。
- Tool-assisted code review:作者與審查者使用專門的同儕審查工具(Gerrit、GitHub pull requests 等),或原始碼儲存庫提供的功能(GitHub、Mercurial、Subversion,以及 Gerrit、Atlassian Stash、Atlassian Crucible 等平台)。
配套一:GitHub Flow 五步驟(把審查與協調整合進日常工作)
- 要做新東西時,工程師從 master 開一個描述性命名的分支(例:「new-oauth2-scopes」)。
- 工程師在本地 commit 到該分支,並定期把工作推到伺服器上同名的分支。
- 當他需要回饋或協助、或認為分支可以合併時,開一個 pull request。
- 拿到想要的審查與必要核可後,才把它 merge 進 master。
- 程式碼變更 merge 並推上 master 後,工程師自己把它部署到生產環境。
- 成果:GitHub 在 2012 年做了 12,602 次部署;8 月 23 日(全公司高峰會後)是全年最忙的部署日,563 次 build、175 次成功部署到生產環境,全靠 pull request 流程達成。
配套二:怎麼評估 PR 的品質(Ryan Tomayko,GitHub 共同創辦人暨 CIO、pull request 流程發明人之一)
- 評估同儕審查是否有效的一個方法:看生產環境的 outage,回頭檢視相關變更的同儕審查過程。
- 壞 PR 的定義跟產出結果幾乎無關——壞 PR 是對讀者而言 context 不足、幾乎沒有記錄這個變更想達成什麼的那種。書中的實際反例:整個 PR 只寫「Fixing issue #3616 and #3841.」
- Tomayko 對這個反例的批評:沒有 @mention 任何特定工程師(至少該點名自己的 mentor 或所改領域的 SME,確保有適當的人來審),更糟的是完全沒有解釋變更到底是什麼、為什麼重要,也沒有揭露實作者的思路。
- 好 PR 的必要元素:必須有足夠的細節說明為什麼要做這個變更、變更是怎麼做的,以及任何已識別的風險與相應的對策。
- Tomayko 還會看是否有針對變更的良好討論(由充足 context 促成):指出額外風險、更好的實作方式、更好的風險緩解方式等。若部署時發生了不好或非預期的事,會被補進那個 pull request,並附上對應 issue 的連結;所有討論不指責任何人,而是坦率地談怎麼防止問題再發生。
- 評估方法:抽樣檢視 pull requests,可以從全體 PR 中抽,也可以只抽跟生產事故相關的那些。
規模參照(Google,2010/2013)
- 2013 年:超過一萬三千名開發者在單一原始碼樹上以 trunk-based 方式工作,每週超過 5,500 次 code commit,帶來每週數百次生產部署。
- 2010 年:每分鐘有 20 個以上的變更被 check in 到 trunk,使得每個月有 50% 的程式庫被改動。
- 這需要相當的紀律與強制的 code review,涵蓋:各語言的程式碼可讀性(強制風格指南)、子樹的 ownership 指派(維持一致性與正確性)、跨團隊的程式碼透明度與貢獻。
- Google 的資料顯示:送審的變更越大,取得必要簽核所需的前置時間越長。Randy Shoup 的親身教訓:他做了幾週的個人專案,最後找 SME 審查,將近三千行程式碼、讓審查者花了好幾天,對方說「拜託不要再這樣對我了」——他從此學會把 code review 變成日常工作的一部分。
原文:「There is a non-linear relationship between the size of the change and the」(L9609,接 L9610「potential risk of integrating that change—when you go from a ten line code」、L9611「change to a one hundred line code, the risk of something going wrong is more」)
原文:「words, you can’t understand its impact after reading through it a couple of」(L9633,接 L9634「times, or you need to ask the submitter for clarification—it should be split up」)
原文:「have enough context for the reader, having little or no documentation of what the」(L9851)
原文:「there must be sufficient detail on why the change is being made, how the change」(L9864,接 L9865「was made, as well as any identified risks and resulting countermeasures.」)
原文:「work off of trunk on a single source code tree, performing over」(L9672,接 L9673「5,500 code commits per week, resulting in hundreds of production」)
🧪 我實際套用的紀錄
- (待填)
⚠️ 注意 / 什麼時候不適用
- 審查會變成瓶頸:若只有少數資深工程師有核可權,審查會拖成數週(見 結對程式設計 的 Pivotal Labs 案例)。要監控的是審查前置時間,不只是有沒有做審查。
- 大變更等於沒有審查——不拆小的話,準則一到三做得再認真也只是形式。
- 「有審查」不等於「審查有效」:不做統計檢視與抽樣,橡皮圖章會悄悄發生。
- 好 PR 的判準是 context 充足,不是「有沒有出事」;用結果反推去責怪 PR 作者,會直接殺掉坦率討論。
🔗 相關工具
- 同儕審查取代變更審批(本條是它所說的「同儕審查」的具體準則)
- 結對程式設計(四種審查形式之一,也是審查瓶頸時的替代方案)
- 主幹開發(「commit 進 trunk 前必須有人審」的前提就是主幹開發)
- 保護部署管線(自動化控制與人工審查互補)
- 工具-部署管線與持續交付(GitHub Flow 第五步「自己部署」要靠它)
- 工具-心理安全感(不指責的 PR 討論才會有人願意寫下真實風險)
- DevOps手冊