最近在看一本書"The Pragmatic Programmer",裡有不少與重構相關的範例,值得參考,有與趣人可以買來看看。因此書,筆者心血來潮,分享一下自己的開發經驗。
在專案開發程式的過程,常會因時間壓力或市場考量,不得不加入很多非計畫中的程式碼。
開發時間越久,就漸漸難以維護,增加新功能更為秏時;當人力不足以達成出貨時程,便開始增加人力,最後日積月累,專案程式變成一個大怪物;直至某一日砍掉重練。
而筆者近年來,使用重構方法,使得自己不用一直為解專案bug而加班。
重構(Refactoring) 英文是一個現在進行式,表示這個動作需要一直不斷發生。
其中,"重構"的最重要的基石就是自動化測試程式,如每當重構程式碼中重覆的部分時,執行一下自動化測試程式,便可很快的確認程式修改後的正確性。
接下來我們來看一些筆者常用的小技巧,以下範例使用Python語言。
def show_animal_info0(animal): if animal == 'dog': print("The dog has four legs") elif animal == 'chick': print("The chick has two legs") else: print("There is an unknown animal") show_animal_info0("dog") show_animal_info0("chick") show_animal_info0("cat") |
重構if-else
通常if-else會越加越長,慢慢變得難以除錯。
animal_info_dict = { "dog": "four legs", "chick": "two legs" } def show_animal_info1(animal): try: info = animal_info_dict[animal] print("The %s has %s." % (animal, info)) except: print("There is unknown animal") |
用dict結構表格取代if-else, 也可用來取代switch |
重構重覆呼叫函式
這種函式大部分由copy and paste而來。
show_animal_info0("dog") show_animal_info0("chick") show_animal_info0("cat") |
def main(): animals = ["dog", "chick", "cat"] for name in animals: show_animal_info1(name) if __name__== "__main__": main() |
重構屬性
紅色legs部分也是重覆程式碼的狀況之一
animal_info_dict = { "dog": "four legs", "chick": "two legs" } def show_animal_info1(animal): try: info = animal_info_dict[animal] print("The %s has %s." % (animal, info)) except: print("There is unknown animal") |
animal_info_dict = { "dog": {"leg": "four"}, "chick": {"leg": "two"}, "cat": {"leg": "four"} } def show_animal_info1(animal): try: info = animal_info_dict[animal] legs = info['leg'] print("The %s has %s legs." % (animal, legs)) except: print("There is unknown animal.") |
自動化測試程式
要進行自動化測試,以本範例為例:
1. 將邏輯與資料顯示動作分離
def show_animal_info1(animal): try: info = animal_info_dict[animal] legs = info['leg'] print("The %s has %s legs." % (animal, legs)) except: print("There is unknown animal.") |
def get_animal_info1(animal): try: info = animal_info_dict[animal] legs = info['leg'] msg = "The %s has %s legs." % (animal, legs) except: msg = "There is unknown animal." return msg |
2. 比對預期函式回傳值結果
使用pyunit 來實作自動測試
import unittest from code_for_automation import * class DefaultTestCase(unittest.TestCase): def testTestDog(self): sample="The dog has four legs." msg = get_animal_info1('dog') assert msg == sample , 'test dog message' def testTestChick(self): sample="The chick has two legs." msg = get_animal_info1('chick') assert msg == sample , 'test chick message' def testTestCat(self): sample="The cat has four legs." msg = get_animal_info1('cat') assert msg == sample , 'test cat message' if __name__ == '__main__': myTestSuite = unittest.makeSuite(DefaultTestCase,'test') runner = unittest.TextTestRunner() runner.run(myTestSuite) |
3. 統計測試結果
$ python 05_automation.py ... ---------------------------------------------------------------------- Ran 3 tests in 0.000s OK |
結論
當有了自動化測試程式之後,可提高自行重構的信心,又不用花費手動一個個輸入測試的時間。
本文雖以python為例,但觀念是相通的,其他語言也有其自動測試函式庫可供使用,歡迎不吝指教。