《重構(gòu)》一書寫的非常好,讓我大大開闊了思路,認(rèn)識到對代碼的修改是一個可量化、可重復(fù)的過程,軟件業(yè)中最缺乏的好像就是可量化和可重復(fù)的過程。
但是和大多數(shù)介紹方法論的書相似,這本書并未對重構(gòu)的適用范圍進(jìn)行探討,更沒有對現(xiàn)實中軟件編碼工作中重構(gòu)的作用和地位做出評價。當(dāng)然也許這兩個問題太過廣泛,不容易下一個定論。這篇文章希望能對重構(gòu)適用的范圍和重構(gòu)在軟件開發(fā)過程中的位置進(jìn)行一番探討,權(quán)作拋磚引玉。
以下是對重構(gòu)的受限范圍作的一個思考:
1. 對局部代碼的重構(gòu)與對設(shè)計的重構(gòu)是兩個完全不同的領(lǐng)域。雖然大規(guī)模的對代碼進(jìn)行重構(gòu),也會影響到設(shè)計,但是這都是間接的影響。直接針對設(shè)計的重構(gòu)包括重構(gòu)API契約、領(lǐng)域模型、數(shù)據(jù)庫Schema等“不破不立”的系統(tǒng)關(guān)鍵部分。關(guān)于如何對設(shè)計進(jìn)行重構(gòu),目前還沒有較好的解決方案。
推論1:不能把針對局部代碼的重構(gòu)與針對設(shè)計的重構(gòu)混為一談,尤其注意不能同時進(jìn)行這兩件工作,否則軟件開發(fā)可能會迅速地失控。
2. 程序正式發(fā)布之前的重構(gòu)環(huán)境與程序發(fā)布之后的重構(gòu)環(huán)境完全不同,發(fā)布之前,基本上所有東西都可以重構(gòu),宏觀的包括總體結(jié)構(gòu)、界面、服務(wù)層API、數(shù)據(jù)庫Schema,微觀的包括一些局部代碼的改良等等。但是程序作為產(chǎn)品正式提供給用戶后,界面與數(shù)據(jù)庫重構(gòu)的難度立刻上升。很多時候出于一些非技術(shù)原因,這兩種重構(gòu)根本不可能進(jìn)行。例如用戶不希望界面有任何的變動,除非界面本身已經(jīng)不能滿足他的需求。數(shù)據(jù)庫重構(gòu)會造成歷史數(shù)據(jù)與新數(shù)據(jù)庫Schema的不一致,而遷移數(shù)據(jù)的風(fēng)險,通常用戶都不愿意接受。
推論2:產(chǎn)品發(fā)布之后,對界面和數(shù)據(jù)庫Schema(包括實體)的重構(gòu)非常困難。
3. 根據(jù)經(jīng)驗,如果試圖用重構(gòu)代替事先設(shè)計,會導(dǎo)致重構(gòu)的代價與時間成比例(甚至是指數(shù))上升,而且通常這時進(jìn)行重構(gòu)的代價,比簡單修改Bug的代價更大。對于重構(gòu)與設(shè)計的關(guān)系,一種更優(yōu)的想法如下:在編寫代碼之前,合理的嘗試做出一個好的設(shè)計,然后在編碼過程中使用重構(gòu)來解決余下的設(shè)計錯誤。這里的關(guān)鍵是分配設(shè)計與重構(gòu)的時間比例,以達(dá)到最大的投入/產(chǎn)出平衡。
推論3:重構(gòu)對預(yù)先設(shè)計是一個補(bǔ)充,而不是替代。
4. 何時停止重構(gòu)并沒有一個量化的標(biāo)準(zhǔn),根據(jù)邊際價值遞減規(guī)律,無休止的重構(gòu)會使成本上升。
推論4:當(dāng)“編程帽子”可以很容易地戴在頭上時,就沒有必要繼續(xù)重構(gòu)了。如果你仍然看不到如何帶上編程這頂帽子,那么就繼續(xù)重構(gòu)。
以下是對適于重構(gòu)的情況做的一個簡單總結(jié):
1. 改善API內(nèi)部的設(shè)計。
API發(fā)布后,通常很難對其簽名進(jìn)行重構(gòu),此時可以使用重構(gòu)來改善其內(nèi)部設(shè)計。
2. 代碼復(fù)核時,改善局部代碼的質(zhì)量。
找到局部代碼的壞味道后,可以使用重構(gòu)對其進(jìn)行局部的修正。
3. 添加新功能之前,整理舊的代碼。
添加新的功能,如果需要復(fù)用以前的一些函數(shù)或代碼,可以先使用重構(gòu)使原來的函數(shù)或代碼更適于復(fù)用,然后再編寫新的代碼。
4. 設(shè)計遇到困難時,可以考慮使用重型重構(gòu)來改良以往的設(shè)計,然后再添加新的設(shè)計。重型重構(gòu)包括界面重構(gòu)、API重構(gòu)、領(lǐng)域模型重構(gòu)、數(shù)據(jù)庫Schema重構(gòu),重型重構(gòu)是有破壞性的,尤其破壞了系統(tǒng)內(nèi)部和外部的延續(xù)性,這與普通的局部重構(gòu)截然不同,因此使用的時候要格外小心。