精進程式碼檢閱
2021 年 1 月 28 日
當人們想到程式碼檢閱時,他們通常會想到開發團隊工作流程中的一個明確步驟。現今,在 整合前檢閱 中執行的 Pull Request 是程式碼檢閱最常見的機制,以至於許多人愚蠢地認為不使用 Pull Request 會消除所有進行程式碼檢閱的機會。如此狹隘的程式碼檢閱觀點不僅忽視了許多明確的檢閱機制,更重要的是忽視了可能是最強大的程式碼檢閱技術——由整個團隊進行的持續精進。
軟體中最普遍的觀點之一是,它是我們建立並完成的東西——因此有了建築施工和架構的無盡隱喻。然而,軟體的主要特性在於它是柔軟的,在釋出後可以像最初在程式設計師編輯器中撰寫時一樣容易修改。這就是為什麼 Erik Dörnenburg 明智地認為架構是一個糟糕的隱喻,並且會更好 用都市計畫取代。有價值的軟體通常處於持續變化的狀態,因為我們從對其價值的更深入了解中新增功能。但機會不僅在於新增新功能,還在於精進該軟體——納入團隊持續學習到的教訓,了解如何讓該軟體最能支援這些變更。
在適當的環境下,我可以檢視六個月前寫的程式碼,找出一些撰寫上的問題,並快速修正它們。這可能是因為這段程式碼在撰寫時就有缺陷,或是因為程式碼庫自那之後的變更導致程式碼不再完全正確。無論原因為何,重要的是在問題開始阻礙我們時盡快修正它們。一旦我對程式碼有了不從閱讀中立即可見的理解,我就有責任(正如 Ward Cunningham 如此精彩地說)將這種理解從我的腦中取出,並放入程式碼中。這樣,下一個讀者就不必費這麼大的力氣了。
這種精煉過程與程式碼審查中發生的過程完全相同,但它是在每次檢視程式碼時觸發,而不是在將程式碼新增到程式碼庫時觸發。對我來說,這是一個至關重要的見解。畢竟,程式碼審查試圖解決的許多問題都是只有在未來閱讀程式碼時才會成為問題的問題。有強烈的論點認為,在那之前不必擔心它們。畢竟,就像新增一棟大型公寓大樓會改變交通模式一樣,我們可能會在六個月後改變程式碼的背景,從而改變程式碼所需的修正類型。它還涉及更多的人,在此架構中,每個閱讀程式碼的開發人員都是審查者,而且能夠根據他們實際使用程式碼而不是根據一些一般的、但通常是含糊不清的準則來審查。
思考一種做法的有效性的方法是思考如果它是一種壟斷會發生什麼。如果我們擁有的唯一程式碼審查機制是後續程式設計師的迭代,那會怎樣?一個後果是,審查注意力集中在更常被閱讀的程式碼區域 - 這主要是應該受到關注的區域。一個擔憂是從未被閱讀的程式碼永遠不會被審查 - 但大多數情況下這沒問題。擁有良好測試實務的團隊可以確信程式碼可以正常運作,效能測試可以找出效能問題。有鑑於此,如果程式碼永遠不需要再被檢視,我們就不需要花力氣讓它易於理解。我預期這種情況極為罕見,但這是一個具有啟發性的思想實驗。
但大多數 ≠ 全部。這裡一個明顯的例外是安全性問題。程式碼可以在多年內正常運作,直到攻擊者找到一個漏洞,在那時我們會哀嘆它缺乏審查。這是高影響但罕見的安全問題的一個例子,值得特別審查。然而,這並不意味著我們不應該有意識地使用精煉作為程式碼審查機制。相反,這意味著我們應該意識到罕見的高影響問題,並調整我們的流程,以在我們的情況下需要時注意這種特定類型的問題。威脅分析應該提醒我們需要額外關注的模組以及它們面臨的風險類型。針對安全性問題可能會安排有針對性的程式碼審查,這些審查可以更有效地執行,因為它們專注於特定類型的問題。
為了進行這種永久的程式碼精煉,我們需要其他實務。如果我要變更程式碼,我需要確信它不會破壞現有的功能,所以我需要類似於 自測程式碼 的東西。我需要知道它不會對其他人造成重大的合併衝突,所以我需要 持續整合。我們所有人都必須擅長 重構,這樣我們才能有效地變更程式碼。由於這依賴於預期許多開發人員修改程式碼庫的任何部分,因此我們最好採用 集體(或至少是弱的)程式碼所有權。但是,如果一個團隊具備這些技能,他們就可以依賴使用他們的定期精煉作為程式碼審查策略的重要部分。
如果沒有其他,我想重要的是我們要更深入思考精煉在程式碼檢閱中的角色。只專注於整合前檢閱的其中一個危險是,它可能導致團隊忽略變更在程式碼庫中的運作方式。如果我有一個原始主線,並確保合併到該主線的每個提交都是原始的 - 我能確定在六個月後程式碼庫仍然是原始的嗎?我會主張我不能,因為這些變更表示六個月前關於某些程式碼的良好決策現在不再是一個良好的決策。精煉程式碼允許我們根據這個變更用法評估舊程式碼,讓我們維持其正常運作。