如何在遺留代碼基礎上開發
對于大多數開發者來說,在遺留代碼基礎上開發是日常工作的一部分,畢竟從頭開始創建全新系統的機會不是很多。架構師、《漫談設計模式》作者劉濟華結合自身的實際經歷分享了如何在遺留代碼基礎上開發的經驗。
劉濟華首先指出,大多數系統是構建在之前的遺留系統之上的,在開始,很難把遺留系統直接丟棄,特別是一些業務邏輯非常復雜的金融電信系統。 這些代碼往往有如下特點:
- 舊的編程語言開發低效。
- 代碼冗繁,質量差。
- 添加新的功能和修改錯誤(Bugs)的周期時間長而痛苦。
- 這些代碼沒有單元測試,甚至沒有功能測試、冒煙測試、回歸測試。
- 無法交接這些代碼,因為寫代碼的這些人很多已經離職。
- 維護這些代碼代價高,大家心驚肉跳,特別是系統遇見特殊情況(節假日,高峰訪問期等),無法安寧。 </ul>
- 具有性能瓶頸的遺留系統——曾經遇到過一個應用服務,是C語言寫的,周圍其他系統都是采用 Java 開發,與此系統的交互都是采用非標準的協議完成,而且此系統處于比較核心的位置,但是維護非常復雜,不穩定,訪問壓力大是經常宕機,無法水平擴展,只能提高硬件設備水平等方式考慮。
在原有協議基礎上開發,使其具有水平擴展能力,代價和開發一套標準協議的實現沒有任何區別,往往會帶了協議不夠完善所產生的問題。于是,我們為其開發新的標準協議,WS,MQ 等等,然后在標準協議上負載均衡實施水平擴展,非常方便。
隨著后來的發展,此遺留代碼也慢慢被新開發系統取代,期間經歷了新系統和舊系統同時存在,此時新系統未完全具有舊系統的全部功能,這部分功能還是使用舊系統完成,只不過在原有均衡負載層多了層查找和分配的,后來到舊系統完全取代。此過渡還算平順。
</li> - 功能性改造型系統——大多數就是這種系統,保留的話,代碼極其復雜,維護麻煩,丟棄的話,無法一夜之間寫出新的系統。曾經接手了一個開發失敗的項目,包括代碼和文檔都未完善,如果重新來過,終究不劃算,后來在此系統上進行改造,特別是花了大量時間寫單元測試,保證代碼測試覆蓋率極高,這樣一邊熟悉代碼,一邊重構代碼,系統的健壯性發生根本改變,前提是有時間。這只是特例。很多時候遇見的系統,同樣測試代碼很少,在添加新的功能和修復錯誤(Bugs)時,為這些能夠接觸到的代碼完善測試,新代碼必須測試覆蓋率必須很高,經過 4 個月,,此系統代碼覆蓋率已經達到 50% 以上。以后的迭代開發越來越快。 </ul>
- 修改一處代碼即可,這個時候非常簡單,修改代碼處即為切入點,找到這處修改即可,為此處代碼寫完善的單元測試代碼,特別是對于輸入條件和測試條件盡量能夠完整測試。
- 修改多處代碼,位置分散,并且修改代碼如果有多種方案,我們找出最少修改代碼的地方,而不是最佳的修改方式,很多時候,此時最佳的代碼修改會修改很多代碼,導致測試代碼無法一下子完善,另外,此時認為的最佳方案隨著時間的推移,或許又是糟糕的代碼,所以沒有必要花費更多的精力在上面,當然也可以選擇比較中庸的方式。 </ul>
- 找測試方便、改動較小的方式來修改遺留代碼。
- 重構在一個類中那些重復的方法,并且保證其健壯性。
- 為依賴的具體類提取新的接口,并使用注入依賴技術,使得測試更加容易,不管是使用 Mock tool 還是自己編寫 Mock 對象,都會非常容易測試。
- 盡量使測試的范圍縮小在受修改影響的類中,對類中的改動進行全面測試。保證每處修改完全測試,保證測試類減少。
- 類之間交互的代碼重構,如果這些交互僅在修改的代碼之中,只要保證修改的代碼完全測試即可。而對于那些可能影響此時其他不需要進行修改代碼的類,可以先放下,為其創建新的方法,在此次修改和以后修改中,使用和重構新的方法。對于老的方法,等到以后代碼覆蓋率提高,能夠覆蓋所有此類交互方法的代碼時,重構此方法,這是你會發現,修改很簡單,并且如果修改錯誤,或者不能處理極端的邏輯,也會和容易找出問題所在。
- 努力汲取業務邏輯知識。
- 《修改代碼的藝術》(Michael Feathers 著)建議找到切入點(Inflection Point),往往我們找的點很多,每一次修改都可能不一樣,為此花很多代價找尋,還不如直接進入修改,找出最佳的修改方式避免代碼過度重構和修改,減少影響,這才是有有實踐價值和有意義的。 </ul>
但是這些代碼能夠完成當時的功能,直接拋棄這些代碼,重新開發將會耗費很大的資源,且不一定成功,如果新的需求不斷變化,往往沒有時間來重新開發這些代碼。而這些遺留代碼的功能沒有完善的文檔說明,甚至沒有。 在此現狀下,如何改善這些代碼,將是考驗程序員和一個團隊的智慧。
接著,劉濟華分析了對于遺留代碼取舍的親身經歷。
那么如何在在遺留代碼上編程呢?劉濟華覺得首先要找到代碼修改點:
遺留系統代碼往往測試少,或者沒有,導致軟件開發者對軟件發布沒有信心。但是為所有的遺留代碼寫單元測試,初始代價非常高,在添加一個很小的功能時,并沒有時間大動干戈。
</blockquote>如何找切入點呢?劉濟華總結了幾種情況:
在修改時需要一些技巧,其中包括:
如何保證質量呢?劉濟華建議: