機會主義重構
2011 年 11 月 1 日
從我開始談論和撰寫重構以來,人們就一直詢問我,重構應如何納入更廣泛的軟體開發流程中。軟體開發生命週期中是否應有重構階段?一個迭代中應將多少比例用於重構任務?我們應如何找出誰應負責重構工作?儘管有些預定的重構工作有其用武之地,但我更傾向於鼓勵將重構視為一種機會主義活動,由任何人、在任何需要清理程式碼的時間和地點進行。

這表示,任何人在任何時候看到某段程式碼不夠清楚時,都應把握機會立即修正它,或至少在幾分鐘內修正。這種機會主義重構通常稱為遵循露營地規則,也就是總是將程式碼留得比你發現時更好。如果團隊中的每個人都這麼做,他們每天都會對程式碼庫的健康狀況做出小而規律的貢獻。
這種機會可能出現在實作某項新功能或修正錯誤的過程中。一種是準備性重構,在開始實作某項功能之前,你會發現如果現有類別的 API 結構不同,這項任務會更容易。你會先將其重構成應有的樣子,然後再開始新增功能。
在新增功能時,你會發現新增的某段程式碼與現有程式碼重複,因此你需要重構現有程式碼以清理內容。持續關注程式碼很重要,但請記住,你只能在測試通過時重構。
你可能會讓某個功能運作,但發現如果變更與現有類別的互動方式會更好。在你認為自己完成了之前,請把握機會這麼做。
有時,你在進行其他事情時會看到一個機會。與其打斷你的思緒,不如記下它,等你準備好時再回來處理。不要拖太久,當天就回來處理,在你完成之前。
有些人反對這種重構,認為這會浪費時間,無法專注於有價值的功能。但重構的重點在於讓程式碼庫更容易處理,進而讓團隊能更快速地增加價值。如果你不花時間把握重構機會,程式碼庫就會逐漸劣化,你會面臨進度較慢的問題,以及與贊助者進行關於重構迭代的艱難對話。
在這裡,存在著陷入困境的真正危險,因為當你修正一件事時,你會發現另一件事,再發現另一件事,不久之後你就會深陷其中。熟練的機會重構需要良好的判斷力,你可以在其中決定何時結束。你希望讓程式碼比你找到的更好,但它也可以等待另一次拜訪,以你真正希望看到的方式進行。如果你總是讓事情變得更好一點,那麼重複的應用將對經常拜訪的區域產生重大的影響,而這些區域正是乾淨程式碼最有價值的地方。就像程式設計的大多數方面一樣,這個決定需要深思熟慮。
機會重構的一個特點是它可以擊中你正在處理的程式碼庫的任何部分。你可能在一個類別中完成大部分工作,但在程式碼中一個完全不同的區域中發現問題。這種缺乏局部性不應該阻止你現在進行更改。通常會有一種誘惑,將程式碼庫中另一部分的更改留到另一天,但另一天通常不會到來。
重構確實依賴於良好的回歸套件,如果你認為你即將觸及應用程式中比應有的測試更弱的部分,那麼保持警惕是明智的。在這種情況下,請記住,如果你可以在不偏離兔子洞太遠的情況下做到這一點,那麼投入一兩個額外的測試是相當合理的。我也發現,故意製造一個錯誤以查看測試是否能發現它,可以成為一種了解你的安全網有多好的方法。
我對任何會導致機會重構產生摩擦的開發實務感到擔憂,例如強烈的 程式碼所有權 或使用 功能分支。這實際上是我使用功能分支的主要顧慮。通常,當人們使用功能分支時,他們會被勸阻進行機會重構,因為它會讓合併變得更加困難 [1],特別是如果分支存活時間超過幾天。
我的感覺是,大多數團隊都沒有進行足夠的重構,因此關注任何會讓人們不願意這樣做的因素非常重要。為了幫助解決這個問題,請注意任何讓你感到不願意進行小規模重構的時間,你確信這只需要一兩分鐘。任何這樣的障礙都是一種氣味,應該促成一場對話。因此,請記下沮喪的情緒,並向團隊提出。至少應該在你的下一次回顧中討論它。
從一開始,我始終將重構視為一種持續進行的事情,就像輸入 if 語句一樣,是程式設計中不可分割且規律的一部分。然而,關於重構有一個常見的誤解,認為它是需要規劃的事情。當然,有地方需要規劃重構工作,甚至撥出一天或兩天來處理一段複雜的程式碼,這段程式碼幾個月來一直阻礙著每個人的進度。但是,善用重構的團隊幾乎不需要規劃重構,而是將重構視為一連串微小的調整,讓專案保持在 DesignStaminaHypothesis 的快樂曲線上
進一步閱讀
我在 重構工作流程 中的資訊卡,討論了將重構納入工作中的不同方式。
Ron Jeffries 想出一個 漂亮的視覺化,用來描述逐步重構雜亂的程式碼,以及為什麼不應該在待辦事項清單中加入重構任務。
技術負債 的比喻非常符合這些問題。
備註
1: 現代工具有所幫助,但仍然會被 語意衝突 絆倒。