金戈
(廣州賽寶認證中心,廣州 510610)
代碼重構的作用和時機
金戈
(廣州賽寶認證中心,廣州 510610)
軟件的修改會不斷地產生技術債務,而重構是償還技術債務的有效方法。對代碼重構的作用進行歸納,體現在改進軟件設計,幫助理解代碼、發現缺陷和提升效率等方面;并分析在添加新功能、修改錯誤和代碼評審這三個重構的時機。
代碼重構;軟件;技術債務
在面對不斷變化的需求時,由于倉促實現某些功能特性而對代碼庫及其架構產生的破壞,就會產生一種技術債務,如果現在不解決,這些債務遺留下來就會阻礙未來開發。而且,技術債務有一個致命的特點,那就是會利滾利。如果開發者在一個類中欠下了技術債務,之后的程序又對這個類進行了擴展和修改,再后的程序對擴展后的程序又做出了更大的擴展,或者說后來的程序在一些功能的寫法上參照了欠下債務的類,那么這個債務就會產生非常大的利息,甚至于超過了債務本身。用不了太多時間就會發現,這份技術債務已經無力償還了。因此,在開發過程中首先盡量不要欠下技術債務,其次一旦迫不得已欠下了債務,就應該以最快的速度償還,時間拖得越久,償還債務的負擔也就會越重。
而如何償還技術債務的答案就是重構。重構就是對軟件內部結構的一種調整,目的是在不改變軟件可觀察行為的前提下,提高其可理解性,降低其修改成本。
設計人員都會面臨這樣的難題,要設計一個可以應對各種變化、擴展靈活的產品是非常困難的。大部分設計人員,尤其是交付型項目的設計人員,往往沒有足夠的時間去詳細設計產品的每個細節,在后續開發中進行設計的調整在所難免。隨著代碼的不斷修改,系統的整體結構會變得混亂,代碼質量慢慢沉淪,從而欠下越來越多的技術債務,阻礙整個系統后期的改變和發展。
重構則是一個相反的過程,它的每一個步驟都很簡單,開發者只需要把某個函數中的一段代碼拉出來形成一個新的函數,或者把一些方法在繼承體系內進行移動,甚至修改一些變量名稱和注釋就可以了。這樣,每一次微小的修改積累起來就可以從本質上改善設計和代碼的質量。
當項目為了完成快速交付時,往往沒有很多精力關注在設計和代碼的結構上,隨著代碼的增多,代碼逐漸失去了自身的結構。這種結構的流失累積到一定程度的時候,對代碼的理解就會變得越來越困難。
再加上項目的需求總是不斷地變化,項目組需要不斷地對現有的系統進行修改和完善。為了盡快實現這些變更,不可避免地要違反最初的設計。因此軟件的結構就會出現混亂,容易導致項目bug越來越多,軟件的維護越來越困難。
重構能夠最大限度地避免以上這些現象的出現。當項目開發到一定程度后,對系統使用重構的方式,在不改變系統外部功能的情況下,對內部的結構進行重新的整理。不斷完善系統的結構,使系統對需求的變更始終具有較強的適應能力。
通過重構,可以帶來以下幾方面的好處:
(1)可以改進軟件的設計
人們在修改和維護代碼時往往只考慮短期內的目的,或者沒有完全理解軟件的整體設計,這樣程序就會逐漸失去原有的結構,也越來越難以通過閱讀源代碼來理解軟件原來的設計。并且代碼結構的流失是積累性的,越難看出代碼所表示的設計意圖,也就越難保護其中的設計。而重構就像是對代碼的整理,讓代碼的各個部分處于合理的位置上,通過經常性的重構來幫助代碼維持自己應該有的形態。
設計不良的程序常常會在不同的地方使用完全相同的語句來做同樣的事,從而需要更多的代碼來完成特定的功能。因此消除這些重復的代碼成為了軟件設計改進的一個重要方向。雖然簡化代碼并不會讓系統運行得更高效,但卻使未來可能的對程序的修改變得容易的多。
(2)使軟件代碼更容易理解
Martin Flower在《重構》中有一句經典的話:“任何一個傻瓜都能寫出計算機可以理解的程序,只有寫出人類容易理解的程序才是優秀的程序員?!?/p>
目前,大部分軟件已經不再是通過一個人就可以完成的了,軟件需要大量的人員來進行開發和維護。為了使代碼容易被他人理解,開發團隊需要遵照統一的編碼規范,需要讓代碼寫得更加簡練和可讀性更強。通過代碼的重構,可以使代碼更加簡潔,使團隊成員更容易理解軟件的設計思路,也就更容易讀懂代碼。
(3)幫助發現隱含在代碼中的缺陷
開發人員在進行重構的時候,需要對代碼進行理解,搞清楚程序的結構。這時,就容易發現之前編寫的代碼中沒有關注到的一些問題。通過重構,可以將這些問題找出來,加以糾正,使代碼更加健壯、質量更高。
(4)重構有助于提高編碼效率
重構沒有改變功能,為什么會提高效率?正如之前所言,重構可以幫助改善設計,而良好的設計是快速交付的根本。如果設計出現問題,開發團隊會發現需要花大量的時間在設計不足帶來的修改,以及理解系統等方面的問題上。
重構可以幫助建立良好的設計,及時找出程序中的問題,使我們的軟件向良性方向發展,從而減少我們花在理解和返工上的時間,幫助提升編碼的效率。
在重構的這些作用里,和設計的關系應當顯得尤為重要,它們之間是一種互補的關系。在傳統觀念里,設計是軟件開發的關鍵環節,而編碼只是機械式的低級勞動,設計就像畫工程圖紙而編碼就像施工。但是,軟件和機械、建筑有著很大差異,軟件的可塑性更強,而且完全是思想的體現。因此就產生了另外的一種觀點,認為重構可以取代預先的設計。這代表我們根本不必做任何設計,只需按最初的想法進行編碼,讓代碼有效運作,然后再將它重構成型。事實上這種方法是可行的,在極限編程中也會倡導這種方法。
盡管只運用重構也能得到效果,但這并不是最有效的途徑,極限編程的愛好者們也會預先使用諸如CRC卡等方法來檢驗各種不同的想法并得到可接受的解決方案,然后才開始編碼并進行重構。這關鍵在于重構改變了預先設計的角色。如果沒有重構,就必須保證設計完全正確無誤,并且如果將來要對原始設計做任何修改,代價都會非常高昂。而如果選擇了重構并且仍然預先進行設計,那么在設計時只需要得到一個足夠合理的解決方案即可。在實現這個初始的解決方案的時候,開發者對問題的理解也會逐漸加深,從而可以通過重構不斷地完善設計。如此一來,軟件設計變得更加簡化。原先在設計時會力求靈活的解決方案,考慮軟件未來可能變化的方向,并讓這個解決方案能夠適應未來的變化,但是靈活的設計會帶來更高的復雜性和設計成本,并且有些靈活性的設計也未必能派上用場,而項目團隊也無法預測哪些靈活性未來不會用到。有了重構,雖然仍需要思考潛在的變化,但卻不必預先實現所有的設計,而是只考慮建造當前可運行的最簡方案,以及將這個最簡方案重構成一個靈活的方案。
對于何時進行重構,只要團隊覺得有必要,任何時候都可以開始。如果資源有限,至少可以在以下三個方面開展重構:
(1)增加新功能重構
在添加新功能時,為了幫助更好地理解需要修改的代碼,開發團隊可以對已有的代碼進行重構。不論之前的代碼是別人寫的,還是自己寫的,只要需要理解代碼時就可以考慮重構,這樣可以隨著程序更新的進展而不斷理清代碼結構,也可以從中理解更多的東西。當然,除了幫助理解代碼外,還有一個原因就是代碼的設計無法幫助開發人員輕松添加新的特性。在理解了原有的設計后,可以考慮用某種新的方式來設計,從而使添加新的特性變得簡單,如此就能用重構來彌補之前設計上的不足。重構是一個快速流暢的過程,一旦完成重構,新特性的添加就會更加快速和流暢。
(2)修改錯誤重構
在軟件調試過程中,對代碼進行重構,可以讓代碼更具可讀性。在閱讀代碼并試圖理解它的時候,可以通過重構來作為幫助,并且在理解和重構的過程中可以找出代碼中的bug,因而當團隊收到缺陷報告的時候,就是需要開始重構的信號,這說明代碼還沒有清晰到可以一眼看出缺陷。
(3)代碼評審重構
很多公司都會做代碼評審,因為這種活動可以改善開發情況,它有助于在開發團隊中傳播知識,也有助于讓較有經驗的開發人員把知識傳遞給比較欠缺經驗的人,并幫助更多的人理解系統軟件中的內容。
重構可以幫助評審別人的代碼。開始重構前可以先閱讀別人的代碼,得到一定程度的理解,并提出一些建議。一旦想到一些好的解決方法,就可以通過重構來實現它們。開發團隊可以通過自己動手來實現它們,也可以通過提醒別人來實現它們。重構還可以使代碼評審工作得到更具體的結果。不僅獲得建議,而且其中很多建議能夠立刻實現。
(4)何時不該重構
當然,在以下情況出現時,開發團隊不應考慮對代碼進行重構:
現有代碼太混亂,重構不如重寫。當代碼中缺陷非常多,根本無法工作時,應考慮對代碼進行重寫而不是重構。重構的一個前提是代碼能夠在大部分情況下正常運行。
如果現有研發活動已經接近尾聲,需要盡快交付時,也應避免重構。因為這時項目可能已經沒有時間進行重構了。
通過代碼重構,可以幫助開發團隊理解之前的設計,幫助發現代碼中的缺陷,從而提高開發效率,償還技術上的債務。而由于資源和時間的限制,團隊需要確定是否需要重構,以及重構的最佳時機。重構的時機可以是軟件開發過程中覺得需要的任何時候,包括文中提及的三個方面等。
[1] Martin Fowler.重構:改善既有代碼的設計[M].熊節譯.北京:人民郵電出版社,2010,4
[2] Robert C.Martin,Micah Martin.敏捷軟件開發:原則、模式與實踐[M].鄧輝,孫鳴譯.北京:人民郵電出版社,2008,1
[3] 陳容華.軟件代碼重構的時機[J].科技資訊,2009(28)
Effect and Opportunity of Code Refactoring
JIN Ge
(CEPREI Certification Body,Guangzhou 510610)
Code refactoring is an effective method to repay technical debt,which caused by the modification to software.Sums up the effects of code refactoring,including improving software design,helping code understanding,defect discovery and increasing efficiency.Analyzes three opportunities for refactoring:while adding new functions,fixing defects,and code review.
Code Refactoring;Software;Technical Debt
1007-1423(2015)02-0051-04
10.3969/j.issn.1007-1423.2015.02.013
金戈(1986-),男,安徽合肥人,碩士,工程師,研究方向為質量過程改進、軟件工程
4-11-25
2014-12-16