接手舊專案時,發現該專案有一個現象,
就是單一Function內的Return非常多,
由於是檢測設備的軟體,例如要進行啟動好了,就會有非常多道程序,
只要其中一道程序失敗,便會直接被Return,後面程式碼就不繼續執行了,
但檢查是否Return的Code就一直被重複,
一個Function內使用非常多的Return也影響了結構化設計,
因為每次都可能從不同的Return結束該Function。
整理以上需求,有兩個需要改善的點:
1.封裝重複出現的Code
2.精簡Return數量
程式碼長得像這樣:
由於重複的程式碼太冗長,因此以註解( /* 進行某些出現錯誤時要做的設定 */ )替代。
簡單說明一下,接手到的Code習慣以回傳0或非0的結果,
0代表成功,非0代表錯誤。
而程式碼原始設計是希望只要有其中一個步驟錯誤了,
就必須直接使用Return跳出,後面的動作都不再進行。
很直覺的,會想把每一次判斷result的if區段包裝成function,
這樣就可以不用一直出現需要好幾行的if區段,
且每一段只需在function參數給予不同的Error Code。
(實務上這一串if區段可能約莫十行)
但問題來了,
由於if區段中包含了return,如果包裝成function,在function內發現需要return時,
回到了上一層,也沒辦法又馬上return呀。
心裡很想改善這種設計,看到一直重複出現的程式碼就非常的不舒服,
一時想不到該如何處理比較好,因為每個檢查點都包含了return敘述,
但檢查點的Code都是相同的,唯一的差異只有Error Code不同,
後來想到Clean Code第57頁,
" 保持單一進入點與單一離開點,Function會更有表達力。"
才想到使用這樣的觀念去整理code,讓code更簡短整潔。
來看看我做了那些修改:
第一點,
我在每一個獨立進行初始化的區塊外都使用 keepGoing 這個flag進行判斷(黃色箭頭處),
如果其中一個流程出現錯誤,那麼 keepGoing 變為false,後面所有的動作都將會略過,
直接到function最後一行的return。
=> 精簡Return數量: 改善架構,一個function只有一進一出。
第二點,
繁雜的if判斷區塊被我包裝成 CanIKeepGoing()。
同時把屬於這個動作流程的Error Code作為參數進行寫入,
閱讀時只需要閱讀一行就能理解該動作流程所屬的Error Code是哪一個,方便理解,
也可以發現在修改後的程式碼中,重複出現的程式碼都不見了(黃色箭頭處)。
=> 封裝重複出現的Code:大幅減少 Code 數量
實務上這樣子的重構有什麼好處?
第一點,
由於所有重複的if判斷區段都被封裝成function,
以上面例子來說,每個if判斷區段原本是十行,都被一行function給取代了。
在實務上我以這個方式只重構專案中的兩個function後,
就讓這兩個function各省下55%的程式碼數量,
兩個function皆是百行以上的內容,
原本需要滑鼠滾輪滾好幾次才看得完的程式碼,
現在只需要滾動一次就看完了,閱讀性提升非常多。
第二點,
如果需要debug,原先需要在每一個if區段內下中斷點(紅色箭頭),
現在只需要在 CanIKeepGoing() 內下中斷點(紅色箭頭),
就可以檢查每一個 initial function的結果了。
第三點,
假設我的 CanIKeepGoing() 內容需要做修正,我只需修改一個地方,
如果照原本的方式去修改,可能要改十幾個使用到if判斷區塊的地方,
非常可能造成沒修改到的漏洞。
第四點,
流程只有一個出口,較容易理解程式脈絡。
你說是不是非常有重構的價值?
沒有留言:
張貼留言