重構和代碼異味——通往更整潔的代碼
重構可以讓代碼更整潔,更易于理解和維護。“代碼異味(code smells)”的辨別需要實踐和經驗:設計不良的表征說明代碼存在更深層次的問題。工具可以幫助我們逐步重構,并防止破壞代碼。
在 SwanseaCon 2016 大會上,Codurance實習生Halima Koundi探討了重構和代碼異味。InfoQ正以Q&A、綜述和文章等形式對大會進行跟蹤報道。
Koundi引用了 Martin Fowler對代碼異味的定義 :
代碼異味是一種表象,它通常對應于系統中更深層次的問題。
如果重視不夠,沒有適當地維護或改進代碼,那么代碼質量就會下降。在演講中,Koundi總結了不同類型的代碼異味,并闡述了如何辨別它們。她提到的其中一類代碼異味是“面向對象濫用”;這類異味和面向對象設計的不完全或錯誤實現有關。辨別“面向對象濫用”異味有助于找出可能違反面向對象設計原則、可以導致錯誤的對象行為的代碼。
Koundi提到的另外一類代碼異味是“變更障礙”,即代碼的一處變更(例如,實現一個新特性或者調整一個現有特性)會影響許多類,需要對整個代碼進行大量的修改。“平行繼承層次”或“發散式變更”就是這類代碼異味的例子。
Koundi演示了如何使用Jetbrains的ReSharper安全地重構代碼。在演示過程中,她示范了當需要添加新的支付方法時如何調整代碼。她闡述了如何逐步重構代碼以及如何確保所做的變更不會破壞代碼。
演講結束后,InfoQ采訪了Koundi,內容涉及當前存在的不同類型的代碼異味、開發人員如何辨別代碼異味、消除代碼異味的原則、代碼重構實踐、開發人員如何確保所做的變更不會破壞代碼、什么時候應該重構及什么時候不應該重構、重構帶來的好處。
InfoQ:代碼異味有哪些不同的類型?
Halima Koundi:代碼異味有多種類型。部分代碼異味反復出現是因為開發人員不注意以及代碼庫的抽象不夠;這包括過長的方法、過長的參數列表等。其他的代碼異味是因為面向對象原則的不完全或糟糕實現,例如,“拒絕繼承(Refused Bequest)”就是這樣一種異味,該情況說明我們已經引入了錯誤的抽象。
向系統添加噪音的代碼是另外一類。例如,即使不刪出,你也應該減少代碼中的注釋,而為方法取一個更有意義的名字。無用的代碼應該刪除——即使你認為稍后可能需要。
InfoQ:開發人員如何辨別代碼異味?
Koundi:代碼異味可以通過代碼的可見特征、有形特征和無形特征來辨別。可見特征包括:過長的方法或函數體、過長的參數列表、變量多次成組出現且模式類似——這些是職責混亂抽象缺失的表征。對于有形特征,一個例子是變更需要查看并修改許多文件。無形特征是當你提出類似這樣的問題,“既然我需要的行為并不相同,我為什么還要繼承這個父類”。
代碼異味的辨別需要實踐和經驗。有許多方法和套路可以幫助你實踐。代碼異味是表征;它們通常說明你破壞了某些設計原則。了解這些原則有助于你理解代碼庫的問題。
InfoQ:消除代碼異味的一般原則是什么?
Koundi:重構是指改變代碼的設計,而不改變代碼的行為。重構是平臺無關的。代碼異味是糟糕設計的表征。我的建議是,讀下Martin Fowler的著作《重構:改善既有代碼的設計》。需要注意的是,重構為抽象概念并不總是正確的方式,因為那會增加系統的復雜度,而且本身可能會變成代碼異味。代碼有可能不是特別復雜,并不能從一定程度的抽象受益。
InfoQ:您談了重構代碼的實踐并進行了演示。您能舉幾個例子說明下如何重構代碼嗎?
Koundi:我發現,有兩種非常強大而又相當簡單的重構方法。
-
方法提取:假如你有一些函數,它們做了太多的事情,而你希望能夠讓代碼更簡單易讀,則可以按照算法的操作步驟把算法分解,并把每個操作都提取到自己的方法中,然后根據它們的行為命名這些方法。
-
方法重命名:表現力不夠的代碼難以使用。例如,你發現,在查看一個方法時,你花了10多分鐘才弄清楚它在做什么。如果你找到了一種更好的方法來描述代碼的行為,那么你應該重命名那個方法,前提是該方法沒有作為一個公共API暴露。
就像我所演示的那樣,工具和重構知識本身一樣重要。了解開發環境讓你可以更輕松、更迅速、更安全地執行重構。Matthew Butt整理了一系列的 重構截屏視頻 。他在視頻中演示了如何通過簡單的步驟重構代碼。
InfoQ:開發人員怎么做才能確保他們正在進行的重構不會破壞代碼?
Koundi:在開始重構之前,有幾個方面需要確認。
-
你可以核實系統的其他部分不受重構影響。這是通過測試完成的。
-
關于如何使用這段代碼,有一份清晰的文檔。那份文檔是由測試提供的。
-
你所重構的系統部分不會遭受衰退。你猜,那是誰的工作?測試!
在重構代碼之前,一定要確保自己已經有了各種測試。
InfoQ:什么時候應該重構?什么時候不應該?
Koundi:重構,像編寫測試一樣,應該成為同一個特性實現活動的一部分。它不是一個獨立的活動。當你希望修改代碼,而代碼本身尚未做好變更準備時,重構它。重構是測試驅動開發(TDD)的一個重要步驟。
代碼審查也是重構執行的上佳選擇。
另一方面,為了實現“完美的代碼”而在整個代碼庫上進行大量低價值的重構被稱為鍍金。這有損于代碼整潔,因為它削弱了重構的真實性需求,盲目地為了重構而重構。如果代碼正常,就不需要修改,不要碰他。
InfoQ:重構可以帶來什么好處?
Koundi:重構的目標是更整潔的代碼,就是說,重構旨在讓代碼更容易理解,降低變更成本。
來自:http://www.infoq.com/cn/news/2016/09/refactoring-code-smells