淺談重構

前篇 Clean Code 簡單原則 中,談到寫出好的程式碼有兩個方法:一個是一開始就寫出乾淨的程式碼,但在對整個程式架構都不明瞭的情況下,就得寫出完美的程式碼非常困難;另一個則是靠重構程式碼,透過一次次等價交換小塊程式碼,讓其慢慢變得更乾淨。

重構是什麼?

重構就是一種在不改變程式外在表現的前提下,將其程式碼變得更容易閱讀,且更容易修改。

通常聽到重構,可能會聯想到大興土木的變革,其實不然。重構是一種寫程式的小習慣,是每次動手寫新程式前都會做的事情,有點像是打掃房間一樣,每次進房看到有髒亂的地方就順手整理一下,維持房間的乾淨整齊,而不是等到東西都堆滿地,想要放一張新的桌子都沒地方可以擺。

另外,重構可以幫助我們慢慢形塑整個系統,讓軟體一直貼近實際需求。以往瀑布式開發一開始精心規劃的架構,拆成一塊一塊後分批完成,最後統合起來形成整個系統。但需求一直在改變,從規劃到釋出軟體經過了一年以上,到時市場趨勢已經不是當初規劃的那個樣子,會造成極大的風險。

1399244627-1379743011

隨著敏捷開發的出現,人們開始縮短開發週期,加快取得使用者的回饋,以利調整方向,但這會造成程式碼必須頻繁的修改。

1486430757-1509367922_n

改動就會有風險,在開發的過程中需要利用兩頂帽子的設計方式:「重構」與「添加新功能」。重構確保所有功能不被更動的前提下,利用每次的等價交換,重新思考如何將程式碼分拆成小塊容易維護的樣子,並將區塊間的相依性降低,之後再來添加新功能。


講了這麼多,重構到底要怎麼進行呢?先有程式碼好壞的概念後,找到程式碼中不好的地方,用查表的方式替換成新的形式,代換完後測試一下程式,觀察結果是否與更改前一致,若一致就可以再尋找其他地方進行重構或添加新功能。

重構改善既有程式的設計 這本書提到一些程式碼的壞氣味:

  • Duplicated code 重複的程式碼
  • Long method 過長函式
  • Large class 過大類別
  • Long parameter list 過長參數列
  • Divergent change 發散式變化
  • Shotgun surgery 散彈式修改
  • Feature envy 依戀情結
  • Data clump 資料泥團
  • Primitive Obsession 基本型別偏執
  • Switch Statements 可怕的 Switch
  • Parallel inheritance hierarchies 平行繼承體系
  • Lazy class 冗員類別
  • Speculative generality 夸夸其談未來性
  • Temporary field 迷惑的佔時欄位
  • Message chains 過度耦合訊息鏈
  • Middle man 中間轉手人
  • Inappropriate intimacy 狎暱關係
  • Alternative class with different interfaces 異曲同工的類別
  • Incomplete library class 不完善的程式庫類別
  • Refused bequest 被拒絕的遺贈
  • Comments 過多的註釋

大話重構這本書中提供了一些較簡單的方向:

  1. 分解大函數
    大的函數是最常見的萬惡根源。
  2. 分拆大物件
    大的物件一次管了太多事情,需要將職責清楚劃分。
  3. 提高復用率
    發現重複的程式碼就抽取出來。
  4. 發現擴展點
    程式碼需要保留擴充性,但在擴充的過程中不能動到原來的程式碼。
  5. 降低依賴度
    將程式模組化,一個地方壞掉了,其餘的程式還是可以繼續運作。
  6. 分層
    區分程式與使用者和底層資料庫的距離,將業務分層以利管理。
  7. 領域驅動設計
    將專業領域的知識帶進程式模型中,讓程式更符合需求。

看了這麼多感覺有點嚇人,仔細看都是將大的切成小的、複雜的變成單純的、糾纏的變成獨立的,一開始記不了這麼多沒關係,多查工具書就行了。

重構一定要配合測試,驗證沒有破壞任何東西,不管是手動測試也好,自動測試也行,一定要把關重構的品質,才能降低未來出錯風險。也因為要頻繁的測試,就有人先寫測試再寫程式碼,衍生出測試驅動開發的模式。

總而言之,重構就是一個重新審視程式碼的過程,利用類似公式的代換,逐漸將結果轉變成較好理解的形式,降低修改成本與風險,才能因應未來的變化。

參考資料:
重構改善既有程式的設計
大話重構
Refactoring Guru


在〈“淺談重構”〉中有 1 則留言

發表迴響