如果無暇重構,我們是否應該為遺留代碼編寫測試方案?
譯文編者按:本文主要圍繞著“是否應該為遺留代碼編寫測試方案”進行討論,一位同事主張“一次性大規模重構”要比多次小規模測試更好的觀點,引來多位網友不同的看法。以下是幾位網友的回答以及得到不同票數的肯定。歡迎朋友們一起討論!
網友is4發問:
在工作中遇到問題時,我一般傾向于采取《高效處理遺留代碼》這本書給出的建議。我會消除代碼依賴性,將一部分代碼轉移到VisibleForTesting公共靜態方法及新類當中、從而使這些代碼(或者至少是其中的一部分)具備可測試條件。另外,我還會編寫測試來確保自己的修改方案或者新功能添加操作不會影響遺留代碼的固有效果。
但一位同事對我的作法提出了不同意見。他的觀點是:
• 首先,原始代碼在新環境下的工作效果可能并不盡如人意。而為其編寫測試也許會讓日后的修復與修改工作變得更為困難,因為開發人員必須在著手之前先看懂這些測試本身并對其加以修改。
• 如果遺留的GUI代碼中包含某種邏輯(例如,~23 lines,2-3 if/else blocks),那么為此編寫測試實在無甚價值——畢竟這部分代碼的功能根本無足輕重。
• 類似的糟糕狀況在代碼庫的其它部分也可能存在(我是個新人,因此還沒見過此類情況);因此通過一次性大規模重構將它們徹底掃清的作法更輕松些。將邏輯提取出來能夠消除這部分代碼在未來引發麻煩的可能性。
如果我們沒有足夠的時間對遺留代碼進行全面重構,那我是否應該放棄提取可測試部分并為之編寫測試的作法?這樣做有哪些我沒有注意到的弊端?請大家提出自己的意見。
感興趣的朋友可以點擊此處查看關于這個問題的原版表述。
這是種錯覺
網友Killian Foth的回答(獲得79票支持):
我來說說自己對于這個問題的一點不成熟見解:不編寫測試的理由看起來似乎廣泛適用,但這其實只是種錯覺。
首先,沒錯,現有代碼的確有可能存在錯誤——但同時它也有可能正確無誤。由于相關應用程序整體對于我們來說存在價值(否則我們大可以直接將其拋棄),因此在不具備詳細信息的前提下,我們不妨假定其是正確的。“編寫測試會讓事情更麻煩的原因在于,這樣將給整體方案引入更多代碼”,這種態度既簡單粗暴又站不住腳。
其次,請通過各種手段擴大現有重構、測試以及改進成果的適用范圍,從而在實現***價值的同時盡可能縮減需要投入的精力。利用值進行格式設定的GUI方案不該被優先考慮。不過僅僅因為某些內容“非常簡單”就放棄對其進行測試也是不科學的。幾乎所有嚴重錯誤的產生都是因為人們自以為了解真實信息,但實際情況卻恰恰相反。
第三點,“我們將在未來一次性進行大規模重構”,這個點子相當不錯。通常來講,就算暫時按兵不動、將來也總有機會對遺留代碼進行這樣一輪大規模清洗的。但我個人更信奉“穩扎穩打才能贏”的理念。
建立堅實的基礎
網友guillaume31的回答(獲得34票支持):
我來談談自己的幾點思考:
當我們對遺留代碼進行重構時,自己編寫的測試是否會偶爾與理想規范產生沖突其實并不重要。真正重要的是,它們能夠切實對程序的當前運行狀態作出評估。重構的意義在于通過一系列細微且獨立的功能性步驟讓代碼變得更加簡潔;大家肯定不希望在進行重構的同時還要操心漏洞修復工作。而且如果我們在過程中發現了嚴重漏洞,它也不會隨著時間推移而自行消失。我們可以為其編寫一套回歸測試并暫時將其禁用,或者在自己的待辦事宜列表中加中這項漏洞修復任務以待日后處理。一次做一件事,這才叫有條不紊。
我也同意,純粹的GUI代碼很難進行測試,可能也不太符合《高效處理遺留代碼》一書中的重構指導方針。但這并不意味著我們應該把與GUI層無關的其它代碼同樣拋在一邊,而不對其進行任何測試。另外需要強調一點,“12 lines, 2-3 if/else block”絕對不能算是無足輕重。任何哪怕涉及一丁點狀態邏輯的代碼都應該被加以測試。
根據我的個人經驗,大規模重構工作難度很高而且效果一般都不好。如果大家不能為自己設定精確而且細化的執行目標,那么整個重構過程很可能陷入無休無止的惡性循環,甚至最終變成像拉住頭發把自己提離地面這種根本沒有希望的任務。修改的程度越高,破壞原有內容的風險就越大、導致我們陷入失敗境地的可能性也將愈發高企。
利用臨時性的小規模重構逐步取得進展并不意味著要“破壞未來大規模重構的可能性”,這其實是一種促進手段——即鞏固應用程序所依賴的主干與根基。總之,我們應當采取這種步步為營的應對策略。
得不償失
網友Robbie Dee的回答(獲得9票支持):
某些企業的固有文化主張允許開發人員在任何時間對代碼進行強化,而非為其提供更為直接的附加價值——也就是新功能。
也許隨意發表個人意見有點多此一舉,但在我看來這種作法真的有點得不償失。純粹、簡潔的代碼當然能為開發人員帶來回報,不過這樣的回報實在不夠明顯。
我個人贊同所謂“童子軍原則”(即加入童子軍的小朋友需要在‘離開營地前進行清掃活動’),但其他人(正如大家所見)對此往往不以為然。
也就是說,不可知性與技術工作壓力會對軟件帶來不利影響。也許前任開發者時間太過緊張(或者可能是太懶甚至缺乏經驗),因此他們也許已經在有限的時間內拿出了雖然存在漏洞但已經是***的設計方案。雖然對這些開發成果進行重構似乎能夠收到很好的效果,但同時也可能給原本正常運作的代碼帶來新的漏洞、甚至進而給用戶造成影響。
比較之下,某些改動的風險可能比其它變更更低一些。舉例來說,我所面對的方案當中存在大量重復代碼,完全可以被安全地從對業務影響很小的子程序中轉移出來。
總結來講,我們必須要在這樣的兩難選擇中作出判斷:既要考慮自己未來何時真正著手進行重構,又要確定從零開始編寫自動化測試到底能為業務帶來哪些切實存在的價值。
譯者:核子可樂
英文:Shoud I Write Tests for Legacy Code if There’s No Time for Refactoring

























