simon

simon

github

Code Review Guide-代碼審核規範

代碼審核指南 - 代碼審核規範#

創建日期:2021 年 6 月 22 日 下午 5:47

基於 Google Code Review Practice 和 Zaihui 實踐

#術語 Term

為簡化描述,先統一術語縮寫

  • TLDR - Too long, Don't Read 太長不讀的版本
  • Author - 本 PR 的作者 代碼作者
  • CR - Code Review 代碼審查,也簡稱為 Review
  • PR - Pull Request, 代碼合併請求,包含 Change List 代碼變更
  • Reviewer - 審查代碼的人
  • WIP - Working In Progress 開發中,不可以被合併
  • Comment
    • 本文有兩種 comment
    • 代碼中的 comment,是為注釋
    • CR 過程中留下的 comment,是為改進意見
  • Code Base - 代碼庫
  • Deadline - 截止日期
  • Judgement Call - 依據你工程師的良心進行的個人選擇
  • LGTM - Look good to me 看起來不錯
  • NIT
    • NitPick
    • 雞蛋裡挑骨頭,指可以被忽略的改進建議
  • SG - Style Guide, 代碼風格規範
  • UT - Unit Test, 單元測試
  • Emergency - 緊急情況,可以放棄部分 CR 標準
    • Hotfix
    • 出現不合理的 deadline 時,但 deadline 過後,也應當補上缺失部分

目的 Purpose#

  • 進行高質量快速的 Code Review,用以持續提高 Code Base 的代碼質量
  • 通過閱讀代碼或留下 comment,傳授或學習新的語言、框架、設計模式等知識

原則 Standard#

  • 保證 Code Base 的整體代碼健康
  • 滿足原則 1 的情況下,儘可能的 approve PR,即便它不完美
  • 持續優化比完美更重要
  • 儘可能留下多的改進意見 comment,如果改進不是必須的,用 'nit:' 開頭以表示不是必須改進。
  • Review comment 應當儘量提供一定的改進方案,但也應當鼓勵 author 發現更好的方案。
  • 除非是緊急 PR,否則 PR 不應該損害 Code Base 的整體質量,何為緊急後續有描述

關注要點 What to look for#

總結 Summary-TLDR#

  • 代碼需要很好的設計
  • 功能性應當對代碼的使用者友好
  • 任何的 UI 變動都必須合理且良好
  • 任何並行編程都要保證其安全性
  • 代碼應該儘可能的簡單
  • 開發者不應該提前編寫現在還不要的功能
  • 代碼應該有合適的 UT
  • UT 需要有良好的設計
  • 開發者應該給所有東西一個簡潔清晰的命名
  • 代碼注釋應該簡潔和有用,並且解釋原因,而不是解釋是什麼
  • 代碼應該被合適的文檔化
  • 代碼要符合代碼風格規範

設計 Design#

  • 與其他代碼的交互設計合理與否?
  • 與整合系統的整合性如何?

功能性 Functionality#

  • PR 的作者目的是什么?
  • 這個目的對系統是好的還是不好的?
  • 並發編程的是否必要,以及是否會觸發死鎖(deadlock)或者競態(race condition)。儘量避免使用會造成死鎖或競態的並發模型。

複雜度 Complexity#

  • PR 是否比起應當的過度複雜?
  • 定義
    • 如果當前的設計,導致使用或者修改這些代碼變得更容易引入 bug,則說明其設計過於複雜
    • 過度設計 over-engineering
      • 開發者將代碼設計的比其需要的更通用
      • 或者加入了系統當前並不需要的功能
      • 未來的功能儘量留在未來解決,因為當這個需求真的需要時,其相關的客觀環境和場景可能已經發生變化,導致提前寫的代碼並不適用。
      • PS: 提前開發沒有必要,但為未來的需求在設計上留有餘地是有需要的
  • 分析角度
    • 獨立的代碼行
    • 函數

測試 Testing#

  • 通常情況下,測試必須和增加的功能代碼在同一個 PR 中,除非是緊急情況
  • 測試設計
    • 準則
      • 正確
      • 合理
      • 有用
      • 有效
    • 需要思考的問題
      • 數據準備是否和真實情況完全一致?不要只構造部分數據
      • 所有成功的路徑是否都覆蓋到?
      • 所有 400 的可能性是否都有針對的測試?返回的錯誤信息是否有校驗與預期一致?
      • 成功的請求,除了返回數據一致以外,數據庫內的數據是否也是準確?
      • 代碼被破壞時,測試是否會正常的失敗?
      • 如果代碼發生變化,是否會出現虛假的正確(false positives)?
        • 例如為了讓 UT 通過,設置一些特殊的數據,表面 UT 通過,實際有 bug
      • 每個測試是否都有簡單有效的校驗?
      • 測試是否合理的切分成不同的測試方法?
      • 測試也是代碼,因此不要因為他們不是主要分支,就允許他們進行不必要的複雜(complexity)

命名 Naming#

  • 開發者是否每個命名都是好的?
  • 好的命名需要
    • 包含足夠的信息描述它是什麼或做什麼
    • 但又不至於過長導致難以閱讀

代碼注釋 Comment#

  • 原則
    • 簡潔
    • 可理解
    • 必須
  • 內容
    • 是代碼所無法表達的內容
    • 應該出現的內容
      • 決定背後的原因
      • 為何這些代碼會存在
      • todo 未來需要做的事,以 todo 開頭進行 comment
    • 不應該出現的內容
      • 不應該解釋代碼在做什麼
        • 代碼功能解釋應該由代碼自己來表達
        • 如果代碼不夠簡潔,需要文字描述來說明其功能,那麼代碼需要被簡化
        • 例外:正則表達式或者複雜算法依賴詳細的 comment 解釋
      • 不應該解釋代碼應該怎麼用,有什麼表現
        • 這是文檔該做的事情

風格 Style#

  • 公司內部,每一種使用的主要語言都要有對應的強制統一的合理風格規範(style guide,SG)
  • SG 是絕對的權威。PR 應該符合 SG,SG 不應該適應 PR。
  • 如果你想提出 SG 中不存在的代碼風格改進,需要加上 “nit”,表明其不是必須的。不應該因為個人的代碼風格偏好,拖慢 PR 通過的速度。
  • 必須的 style 應該加入到 SG 中
  • 如果進行大量的代碼風格修改,必須單獨提出 PR,不可以與其他功能代碼混合。

一致性 Consistency#

  • PR 是否與 SG 一致?
  • 如果 SG 的內容只是推薦,而不是強制要求,那是否修改就依賴 Judgement call
    • 但還是優先偏向符合 SG,除非改動後會使代碼可讀性下降

文檔 Document#

  • 何時需要文檔?
    • 當 PR 改變了代碼的使用、測試、交互或發布流程
    • PR 刪除或棄用(deprecated)代碼,考慮刪除相關文檔
    • 如果發現文檔缺失,請要求原作者添加文檔
  • 需要修改的文檔
    • README
    • 任何相關的文檔

每一行 Every Line#

  • 請閱讀每一行你被分配到要 review 的代碼
  • 你可以掃讀的內容
    • 數據文件
    • 生成的代碼
    • 大型數據結構
  • 不可掃讀的內容
    • 人為書寫的 類、方法、代碼塊
  • 部分代碼值得獲得更多的關注
    • 這依賴 reviewer 的 judgement call
    • 對於不想給太多關注的代碼,你也必須至少確定理解這些代碼在做什麼
  • 如果你發現代碼過長或過於複雜,妨礙了你的 review 速度和理解速度
    • 你應當立即告知 PR 作者
    • 等待 PR 作者簡化或者聲明清楚代碼作用後,再繼續進行 code review
  • 如果你理解這些代碼,但感到自己的能力不夠評審其中部分的代碼
    • 請確保邀請一個你認為能力足夠的 reviewer,加入到 code review 中

上下文 Context#

  • 添加的代碼塊往往只是部分邏輯,需要結合上下文的代碼來閱讀
  • 如果上下文不多,可以在代碼評審工具中展開查看
  • 如果上下文過於複雜,則需要將代碼下載到本地,使用 IDE 或其他工具查看

好實踐 Good Things#

  • 通常,review 留下的 comment 是提出批評改進意見的
  • 但,當你發現代碼中有很棒的東西時,請不要吝嗇用 comment 發出你的讚美,表達你對 PR author 的感激,鼓勵大家使用更好的實踐。
    • 比如:“牛逼啊”
    • 比如:“這段代碼寫的很精妙,學習了”
    • 除了讚美詞,要是有些言之有物的讚美就更加棒啦,可以和作者產生共鳴

如何看一個 PR#

總結 - TLDR#

  • 符合我們的 PR 規範
  • 這個 PR 變動是否合理,PR 不合理需要立即打回
  • 檢查 PR 的主要部分的設計,出現設計問題,需要立即反饋
  • 以代碼邏輯鏈的順序看完餘下部分

Step zero: 是否符合必要的規範#

  • 是否關聯的 Jira ticket
  • commit message 是否符合規範
    • Jira-ticket(tag): description
    • tag:
      • feat 功能
      • fix 修復
      • ut 單元測試
      • mi 表改動
      • refactor 重構
      • inf 基建
  • 是否 rebase 了目標分支

Step one: 對變動進行一個大致的了解#

  • 查看 PR 描述,了解其大致在做什麼
  • 改動本身是否 make sense
  • 如果感到不合理,需要立即反饋
    • 反饋時,先肯定對方的工作,再給出不接受的理由,並提出下一步該怎麼做
  • 出現持續的不合理 PR 時,需要反思一下開發流程(團隊內部和延伸團隊)
    • 使這些不合理的 PR,在開發前就被叫停

Step two: 檢查 PR 的主要部分#

  • 找到主要代碼邏輯文件
  • 如果找不到,就詢問作者,或者要求作者進行 PR 拆分
  • 先檢查主要的設計問題,如果出現問題,必須立即反饋,並停止當前的 CR
    • 一般開發者提出 PR 後,會繼續開發,如果基於這個 PR 開發,需要儘快叫停,及時止損
    • 設計問題需要大量的時間來修復,大部分功能都有一個 deadline,提早提出修改,有利於趕上 deadline

Step three: 以合理的順序查看餘下的 PR#

  • 找出 PR 的邏輯鏈
  • 按照邏輯鏈 Review
  • 可以先讀 UT,有利於了解設計理念

快速的 CR#

總結 - TLRD#

  • 即使很忙碌也要即時反饋
  • 最長反饋時間在一個工作日內
  • 如果你正在專注工作,請不要中斷手上的工作
  • 大型的 PR 應當被拆分成小的 PR,如無法拆分,也必須完成 step one 的 review
  • 代碼的複雜度導致 CR 速度下降時,需要立即反饋作者進行簡化或給出說明

原因#

  • 過慢的 CR 會降低團隊效率,阻塞其他人的開發
  • 過慢的 CR 可能導致開發者抵觸 CR 流程
  • Code base 的代碼質量會受到影響
    • 一方面提升代碼不能有效的合併
    • 另一方面,過慢的 CR 會降低開發者的開發質量

應當多快?#

  • 除非你在專注的進行一項任務,否則接到 CR 請求時應當立即開始 review
  • 最長反饋時間不可以超過 1 個工作日

速度 VS 打斷#

  • 保證不被打斷比 CR 的速度重要
  • 因為從打斷恢復為專注狀態需要大量的時間
  • 應當選擇一個專注中斷的點,開始 CR

快速響應#

  • 即使你很忙,也應當有個及時的響應
  • 如果真的非常忙,可以先提供一些大致的意見,也就是上文的 step one

跨時區 CR#

  • 保證在對方下班前完成 CR,不然 CR 流程就會因為時差大大的延長

LGTM with comments#

  • LGTM 意味著可以合併
  • 需要注意的是,LGTM 的本意是,這段代碼符合 “我們” 的標準,而 不是 “我”
  • 有的時候 LGTM 也有 comment,但不影響給 approve
    • reviewer 對開發者有信心,知道其後續會解決這個問題
    • 餘下的 comment 不關鍵,不是必須要解決

大型 PRs#

  • 要求 author 將 PR 拆分成小的 PR
  • 如果無法拆分,那麼儘量過一下整體設計,即 step one
  • 保證降低代碼質量的前提下,不阻塞開發的下一步流程

Author 在 CR 中應當做什麼#

關聯一個 Jira ticket#

  • PR 的內容要與 Jira ticket 一致
  • 出現不同 task,需要新建 ticket 關聯,單獨提 PR

以 feature branch 提出#

  • 不應當用自己遠端中與主要分支同名的分支提出 CR
  • 也不應用 alpha-only, free-only 這種非穩定分支提測
  • 應當在自己的遠端,基於目標分支為 code base,創建的 feature branch 進行開發和 CR

以 Code Review 的角度審視一遍自己的 PR#

  • 詳情參照 第四節

完成冒煙用例自測#

  • 提出 CR 請求前,需要完成自測。
  • 測試大佬會提供冒煙用例 checklist,需要全部完成。

遵守 commit message 規範#

  • 一個 PR,一個 ticket,一個 commit
  • 關聯 Jira ticket
  • 記得移除 WIP 的前綴
  • 格式:見 第五節 的 step zero

保證 pipeline 通過#

  • code style
  • test
  • build

指定必須要 review 的 assigner#

  • 對於新的功能邏輯,除了 author,還需要一位 backup 人員作為主要的 reviewer,這樣同樣的邏輯就不止一個人知曉
  • 對於舊邏輯的改動,需要 assign 給原始代碼的作者進行 review,因為對方更加了解這部分的業務邏輯和歷史問題。原作者的信息可以通過 git blame 獲知

跟進 CR 的進度,提供必要的幫助和反饋#

  • 一旦 CR 提出,author 就有義務和責任推動 PR 快速被合併 code base
  • 如果代碼邏輯鏈路比較長,可以通過 PR 描述 或 直接給 reviewer 解釋的方式,幫助 reviewer 快速理解主要邏輯鏈。但要注意,儘量減少對 reviewer 的打斷,只有當 reviewer 表示開始 CR 才進行口頭描述。
  • 對於 Reviewer 提出的 comment,都需要以 comment 的形式回覆,給出是否修改的回覆。如果不準備修改,需要提供合理的理由。如果 reviewer 還是不予同意,則需要線下討論或引入第二個 reviewer 進行仲裁。
  • 如果 PR 在 CR 提出後一個工作日內還沒有被 review,第二日晨會的時候需要提出。

PR 合併後,應儘快提測#

  • PR 合併表示這段代碼可以進入測試流程
  • 如果是前後端聯合開發,一般由前端提測。純後端開發功能由後端提測。
  • 但本著分步提測的原則,後端 PR 合併後也可單獨提測,這點需要和測試提前溝通確認

Review 的開始#

原則:

  • reviewer 的精神狀態要完備
  • reviewer 不處於心流的工作狀態
  • reviewer 和 author 可以高效地互動

結論:

  • CR 需要有個固定的時間
  • 推薦在晚飯後的一個小時
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。