題目與適用情境
給你 30 分鐘審查一份陌生的 Pull Request。請說明你會如何理解改動意圖、安排檢查順序、區分阻擋問題與非阻擋建議、寫出作者能執行的意見,並決定核准、僅留言或要求修改。
這是一道通用軟體工程面試題,適合後端、前端、行動端、基礎設施與技術管理職位。題目可能只要求口述,也可能提供一段 diff 讓候選人現場留下意見。兩種形式都在考察同一件事:能否在有限時間內找到對使用者與系統最重要的問題,而不是盡量挑出更多格式細節。
以下假設可以看到 PR 說明、關聯需求、改動檔案與測試結果,但不熟悉程式碼庫,也不能隨時詢問作者。若面試官提供不同條件,應先調整風險判斷與審查範圍。
面試官考察重點
第一個訊號是能否先重建「改動應該做什麼」。沒有需求、介面契約或失敗邊界,意見只能表達個人偏好。強回答會先讀 PR 說明與相鄰程式碼,確認行為變化,再開始逐行檢查。
第二個訊號是優先順序。正確性、資料損壞、安全、權限、並行與相容性問題,通常比命名或排版更值得先看。面試官會觀察候選人是否能說清楚潛在後果,並把時間放在風險最高的路徑。
第三個訊號是證據。指出「這裡可能有問題」只是起點。高品質意見會給出觸發條件、可觀察後果與驗證方法;如果缺少脈絡,就寫成精確問題,不把猜測偽裝成阻擋結論。
最後看審查決定與溝通。候選人要區分必須修正、可選建議、釐清問題與純粹的 nit,並在摘要中說明審查了哪些範圍、哪些風險仍未驗證,以及為何核准或要求修改。意見針對程式碼與影響,不評價作者能力。
回答前需要釐清的問題
- 這是口述流程,還是要現場審查真實 diff? 前者應提供可重複使用的框架;後者先用幾十秒說明框架,再套用到具體程式碼,不能只背清單。
- 能看到哪些脈絡? 有需求、介面契約與相鄰程式碼時,可以驗證行為;只有孤立函式時,應明確寫出假設,把無法確認的契約改成問題。
- 改動是否涉及高風險領域? 支付、授權、隱私、資料移轉或公開 API 會提高證據門檻,也可能需要領域專家;內部低風險工具可以更偏向快速改進。
- 面試官期待什麼輸出? 逐行意見、整體摘要、是否核准與測試建議是不同交付物。先確認,才能合理分配 30 分鐘。
- 這是一般改動還是緊急修正? 緊急情況可以接受更窄的修正與後續任務,但不能用「緊急」跳過已知的資料損壞或安全風險。
- 你是否具備所需領域知識? 不熟悉密碼學、隱私或資料庫移轉時,應審查自己能確認的部分,並明確請合格審查者加入,而不是憑信心核准。
30 秒回答架構
「我先確認 PR 的目標、行為變化與失敗影響,再做兩階段審查。第一階段看改動邊界、資料流與高風險路徑,優先找正確性、安全、資料、並行與相容性問題;第二階段檢查邊界條件、錯誤處理、測試、可觀測性、效能與可維護性。每則意見都寫明嚴重程度、觸發條件、後果與期望結果。有可重現的阻擋問題就要求修改;只有建議和 nit 時可以核准並註明。最後摘要已審範圍、未驗證風險與決定依據。」
分步深入解答
先建立基準。閱讀 PR 標題、說明、關聯需求、介面或資料模型變化,以及既有測試。用一句話重述:「這項改動讓誰在什麼條件下獲得什麼新行為,同時必須維持哪些舊契約。」如果寫不出這句話,應先補脈絡,逐行留言還沒有判斷標準。
接著標出改動邊界。查看入口、狀態變化、外部副作用與回傳路徑,不只看被標示的行。新增參數會影響哪些呼叫端?資料庫寫入與訊息傳送是否在同一失敗邊界?公開回應、事件格式或設定預設值是否改變?這一遍的目標是畫出「輸入從哪裡來、經過什麼信任邊界、改變什麼、如何失敗」。
在 30 分鐘的範例時間盒中,可以用 3 分鐘理解意圖、7 分鐘查看邊界與高風險路徑、12 分鐘逐段檢查、5 分鐘核對測試與執行保障、3 分鐘整理意見與決定。這是練習用配置,需依 diff 大小與風險調整;它的用途是避免前 20 分鐘都花在命名上。
第一階段採用風險優先順序:
- 行為與正確性: 主要路徑是否符合契約?空輸入、重複請求、部分失敗與重試會怎樣?
- 安全與資料: 權限檢查是否位於信任邊界之前?敏感資料是否外洩?失敗是否會造成遺失、重複或不可逆狀態?
- 並行與相容性: 兩個請求同時執行是否破壞不變量?舊用戶端、舊資料與滾動部署期間的混合版本是否仍能運作?
- 架構邊界: 改動是否把職責放在正確元件,還是繞過既有約束並複製狀態?
第二階段再看更細的實作:控制流程與錯誤傳播、資源釋放、查詢或迴圈規模、日誌與指標、測試是否會在程式出錯時真正失敗、命名與註解是否幫助未來讀者。格式與可自動修正的樣式放在最後,避免自動化工具能發現的 nit 擠掉人工判斷時間。
發現問題後,先驗證它是否由本次改動引入。若新程式碼讓允許為空的 items 直接存取 items[0],這是具體回歸;若同一檔案原本就有一段無關的複雜邏輯,應在摘要中標為既有技術債或另開任務,除非它與本次改動組合後造成安全或正確性風險。審查範圍不能無限擴張。
意見使用四種意圖:
- Blocker: 已有證據顯示會違反契約,造成錯誤結果、安全問題、資料損壞或不可接受的相容性風險;合併前必須處理。
- Question: 缺少一項會改變結論的脈絡。作者回答後,它可能消失,也可能升級成 Blocker。
- Suggestion: 能改善設計、可維護性或執行保障,但目前實作仍達到合併標準。
- Nit: 非阻擋的細小可讀性或一致性問題,最好交由格式化與靜態檢查處理。
一則可執行意見包含「級別 + 條件 + 後果 + 期望結果」,必要時再提供一種修正方向。例如:
Blocker: 當請求允許items=[]時,這裡讀取items[0].id會拋出錯誤,批次介面回傳 500。請在進入迴圈前處理空陣列並補一個回歸測試;回傳空結果或 400 應依介面契約決定。
如果不知道空陣列是否合法,應改寫成問題:「介面契約是否允許空陣列?目前路徑會回傳 500;若允許,需要明確處理並測試。」這樣既指出證據,也沒有捏造需求。
最後作出審查決定。有未解決 Blocker 時選擇「要求修改」;需要脈絡但還無法判斷時提交「留言」,不要用核准掩蓋未知風險;只有非阻擋建議時可以核准,同時明確說明建議不是合併條件。摘要至少包含:審查範圍、關鍵發現、執行或測試證據、未覆蓋領域與最終狀態。
綠色 CI 不是審查完成的證明。測試可能漏掉關鍵分支,靜態工具也不知道業務契約;反過來,人工審查也不該取代可執行測試。強回答會把兩者連接起來:意見指出可失敗的條件,並要求能在修正前失敗、修正後通過的驗證。
高品質示範回答
「我不會一開始就逐行找問題。我會先讀 PR 說明、關聯需求與介面變化,用一句話重述目標及必須維持的舊行為。拿不到脈絡時,我會列出假設,不會把猜測寫成 blocker。
在 30 分鐘裡,我會做兩階段審查。第一階段沿入口、狀態變化、外部副作用與回傳路徑走一遍,先看正確性、安全、資料損壞、並行與相容性。第二階段再檢查邊界條件、錯誤處理、效能、日誌、測試與可維護性。樣式放最後,而且只指出工具沒有覆蓋、確實影響理解的部分。
每個發現都要能回答三個問題:什麼條件會觸發、後果是什麼、如何驗證。我會把必須修正的問題標成 Blocker;資訊不足但會改變結論的寫成 Question;非阻擋改進寫成 Suggestion;純細節寫成 Nit。例如,空陣列路徑會存取第一項,而介面允許空輸入,我會說明它會導致 500,要求明確處理並加入回歸測試,而不只寫『這裡有空指標風險』。
送出審查前,我會再檢查意見是否由本次 diff 引入、是否把個人偏好當成標準,以及是否遺漏領域專家。若有可重現的安全、資料或正確性問題,我選擇要求修改;只有建議時可以核准。摘要會寫清楚已審檔案、測試證據、尚未驗證的部分與決定理由,讓作者知道下一步,也讓後續審查者知道我實際覆蓋了什麼。」
常見錯誤
- 打開 diff 就逐行挑錯 → 沒有目標與契約,容易把合法取捨誤判為問題 → 先重述意圖、行為變化與失敗邊界。
- 依發現順序留言 → 命名細節可能淹沒資料損壞或權限風險 → 先做風險巡查,再處理實作細節。
- 只寫「這裡可能有 bug」 → 作者不知道觸發條件,也無法驗證修正 → 寫明條件、後果、證據與期望結果。
- 所有意見都要求修改 → 作者無法區分合併條件與個人偏好 → 使用 Blocker、Question、Suggestion 與 Nit 表明意圖。
- 為了顯得全面而列長清單 → 清單沒有套用到資料流,也不能證明判斷力 → 沿一條關鍵路徑展示實際推導,再說明剩餘覆蓋。
- 要求順手修正所有舊問題 → PR 範圍不斷擴大,風險與驗證成本失控 → 區分本次回歸與既有技術債,安全或正確性耦合問題除外。
- 把綠色 CI 當成核准依據 → 測試可能沒有覆蓋錯誤契約 → 檢查測試是否會在實作錯誤時失敗,並補上最關鍵反例。
- 評論作者而不是程式碼 → 產生防禦情緒,也沒有提供技術依據 → 描述程式碼、條件與影響,假設對方善意。
- 不懂領域仍直接核准 → 審查狀態會製造虛假的安全感 → 標明自己覆蓋的部分並請領域審查者加入。
追問與應對
追問一:作者不同意你的 Blocker,怎麼辦?
回到可驗證的契約與後果。確認雙方是否對輸入、風險或發布條件有不同理解;能執行最小重現就用證據解決。仍無法達成共識時,請程式碼擁有者或領域負責人裁決,並把口頭結論記錄回 PR,不能讓分歧無限懸置。
追問二:PR 太大,30 分鐘看不完怎麼辦?
不要假裝完成完整審查。先依風險選擇關鍵入口、資料變化與公開契約,明確說明哪些檔案已逐行檢查、哪些只掃描、哪些未覆蓋,並要求拆分或增加領域審查者。核准狀態必須符合實際覆蓋。
追問三:發現一個嚴重的既有問題,但它不在 diff 中呢?
先判斷本次改動是否放大或觸發它。若會造成目前發布的安全、資料或正確性風險,應阻擋並說明關聯;若完全獨立,記錄證據、建立高優先後續任務並通知負責人,不把無邊界重構塞進目前 PR。
追問四:緊急修正沒有完整測試,可以核准嗎?
先確認不修正的立即損失、改動是否足夠小、是否有回復方式或開關,以及至少能執行哪項針對性驗證。可以在明確的緊急流程下接受後續補測,但已知安全、資料損壞或不可回復風險仍需要更高層級核准,不會因時間壓力自動放行。
追問五:你不熟悉改動涉及的領域,如何審查?
繼續檢查通用的控制流程、錯誤處理、測試與介面變化,同時標記自己沒有資格判斷的部分。對密碼學、隱私、資料庫移轉或複雜並行,請相應負責人加入。部分審查仍有價值,前提是沒有把它描述成完整核准。
追問六:測試很多,還需要逐行看程式碼嗎?
需要,但關注點不同。測試提供已編碼情境的執行證據,審查還要檢查需求是否正確、是否遺漏風險、設計是否增加不必要複雜度、日誌與相容性是否合理。反過來,審查發現的關鍵反例應轉成測試,避免只靠未來審查者記住它。