重構帶來的好處為何?如何重構?

2023年3月3日

💎 加入 E+ 成長計畫 與超過 300+ 位軟體工程師一同在社群中成長,並且獲得更多的軟體工程學習資源

什麼是重構?

重構 (Refactoring)指的是「在不改變外部行為的情況下,重組程式碼的過程」,因此對於外部用戶而言,重構與否是沒有感覺的,但重構的好處在於:

  • 提高可讀性:通過重構,程式碼變得更加清晰、簡潔,並且具有更好的組織結構,從而提高可讀性和理解難度。
  • 提高可維護性:重構後的程式碼更加清晰,易於理解和修改,這有助於維護。
  • 減少冗餘:重構可以刪除無用的程式碼、合併重複的程式碼和重新組織程式碼,從而減少代碼冗餘。
  • 提高性能:重構可以幫助提高程式碼性能,例如通過減少循環次數和使用更高效的數據結構等。
  • 改善安全性:通過重構,可以刪除容易被攻擊的程式碼,提高程式碼的安全性。

何時該重構?

重構是一個持續發生的過程,而遇到以下的狀況時,都很適合開始著手重構:

  1. 程式碼重複:通過重構可以消除重複的程式碼,使程式碼庫更加簡潔。
  2. 技術債務:隨著時間的推移,程式碼庫可能變得混亂且難以維護,導致技術債務的累積。通過改善程式碼的結構和組織,重構可以減少這種債務。
  3. 添加新功能:在給現有程式碼添加新功能時,重構可以確保程式碼仍然易於維護和可擴展。
  4. 性能優化:如果程式碼運行過慢或需要太多資源,重構可以通過解決瓶頸和低效率來提高性能。
  5. 錯誤修復:重構可以使得更容易找到並修復程式碼中的錯誤,同時防止新的錯誤被引入。
  6. 團隊合作:如果多個開發人員正在對同一程式碼庫進行工作,重構可以通過使程式碼更容易理解和維護來提高合作。

如何重構?

好的重構建議是能夠切得夠小去做,並且不影響到外部行為,這裡介紹幾個常見的技術:

Red-Green-Refactor

Red-Green-Refactor 是一種軟體開發流程,通常用測試驅動開發 (TDD),此流程分成三個步驟:

  • Red(紅色):開發人員首先編寫一個失敗的測試,以驗證所需的功能不存在或不正確。
  • Green(綠色):開發人員接著編寫最少的程式碼來通過測試。
  • Refactor(重構):開發人員再次檢查程式碼,以確保其結構正確、可維護和易於理解。
Red-Green-Refactor
Red-Green-Refactor
圖片來源:https://www.altexsoft.com/blog/engineering/code-refactoring-best-practices-when-and-when-not-to-do-it/s

如上圖所示,通過這種方式,開發人員可以保證程式碼符合標準,同時避免因複雜的程式碼而導致的混亂。這種方法有助於確保程式碼質量,並通過經常測試來確保程序的正確性。

抽象化(Abstraction)

如果有很多地方需要做重構,可以用抽象化(Abstraction)的方式來做類繼承、層次結構和提取,目標是減少重複且不必要得程式碼。

Pull-Up and Push-Down
Pull-Up and Push-Down
圖片來源:https://www.altexsoft.com/blog/engineering/code-refactoring-best-practices-when-and-when-not-to-do-it/

上圖為 Pull-UpPush-Down 的方法,Pull-Up 是將方法從子類移動到父類,Push-Down 則是將方法從父類別移動到子類別。

合成方法(Composing Method)

  1. Extract Method:如果有一段程式碼能夠被獨立出來,則將它放到獨立的函數中,並讓函數名稱解釋該函數用途。下方有重構前後的範例。

原來的程式碼為:

void Process(MyDataSet mds) {
 int result = 0;
 if (mds.isReady) {
  int data1 = mds.param[0];
  int data2 = mds.param[1];
  result = data1 % data2;
 }
}

重構後的程式碼為:

void Process(MyDataSet mds){
 int result = 0;
 if (mds.isReady)
  result = CalculateMDS(mds.param[0], mds.param[1]);
}
int CalculateMDS(int data1, int data2) {
  return data1 % data2;
}

可以將不易理解的程式碼,放入新方法中,並且取一個有意義的命名,這樣可以提高可讀性和可維護性。

  1. Inline Method: 在函數調用的地方,直接插入函數本體,並且移除函數。下方有重構前後的範例。

原來的程式碼為:

class PizzaDelivery {
  // ...
  int getRating() {
    return moreThanFiveLateDeliveries() ? 2 : 1;
  }
  boolean moreThanFiveLateDeliveries() {
    return numberOfLateDeliveries > 5;
  }
}

重構後的程式碼為:

class PizzaDelivery {
  // ...
  int getRating() {
    return numberOfLateDeliveries > 5 ? 2 : 1;
  }
}

如果有些函數裡面的程式碼,和函數名其實同樣的清晰易懂,就可以直接去掉函數就好。

🧵 如果你想收到最即時的內容更新,可以在 FacebookInstagram 上追蹤我們