1. 程式人生 > >為什麼要重構&如何實施程式碼重構?

為什麼要重構&如何實施程式碼重構?

程式碼重構簡介:(英語:Code refactoring)重構就是在不改變軟體系統外部行為的前提下,改善它的內部結構。
為什麼要重構(Refactoring)???
為什麼要這麼做?投入精力僅僅改變了軟體的實現方式,這是否是在浪費客戶的投資呢?
對軟體的生命造成威脅的因素:需求的變更。一個軟體總是為解決某種特定的需求而產生,時代在發展,客戶的業務也在發生變化。有的需求相對穩定一些,有的需求變化的比較劇烈,還有的需求已經消失了,或者轉化成了別的需求。在這種情況下,軟體必須作出相應的改變。考慮到成本和時間等因素,當然不是所有的需求變化都要在軟體系統中實現。但是總的說來,軟體要適應需求的變化,以保持自己的生命力。
這就產生了一種糟糕的現象:軟體產品最初製造出來,是經過精心的設計,具有良好架構的。但是隨著時間的發展、需求的變化,必須不斷的修改原有的功能、追加新的功能,還免不了有一些缺陷需要修改。為了實現變更,不可避免的要違反最初的設計構架。經過一段時間以後,軟體的架構就千瘡百孔了。bug越來越多,越來越難維護,新的需求越來越難實現,軟體的構架對新的需求漸漸的失去支援能力,而是成為一種制約。最後新需求的開發成本會超過開發一個新的軟體的成本。最終,該軟體的生命到了盡頭。
怎樣避免這樣的現象?


系統發展到一定階段後,使用重構的方式,不改變系統的外部功能,只對內部的結構進行重新的整理。通過重構,不斷的調整系統的結構,使系統對於需求的變更始終具有較強的適應能力。
有些程式設計師總是能夠快速編寫出可執行的程式碼,但程式碼中晦澀的命名使人暈眩得需要緊握坐椅扶手,試想一個新兵到來接手這樣的程式碼他會不會想當逃兵呢?
軟體的生命週期往往需要多批程式設計師來維護,我們往往忽略了這些後來人。為了使程式碼容易被他人理解,需要在實現軟體功能時做許多額外的事件,如清晰的排版佈局,簡明扼要的註釋,其中命名也是一個重要的方面。
對於那些讓人充滿迷茫感甚至誤導性的命名,需要果決地、大刀闊斧地整容,永遠不要手下留情!

孔子說過:溫故而知新。重構程式碼時逼迫你加深理解原先所寫的程式碼。
從長遠來看,有助於提高程式設計效率

為什麼要重構:延續軟體生命、適應需求變更、加深理解程式碼、提高自我程式設計能力

如何實施重構:
何時著手重構(Refactoring)

新官上任三把火,開始一個全新??、腳不停蹄、加班加點,一支聲勢浩大的千軍萬”碼”夾裹著程式設計師激情和扣擊鍵盤的鳴金奮力前行,勢如破竹,攻城掠地,直指”黃龍府”。開發經理是這支浩浩湯湯程式碼隊伍的統帥,他負責這支隊伍的命運,當齊桓公站在山頂上看到管仲訓練的隊伍整齊劃一地前進時,他感嘆說”我有這樣一支軍隊哪裡還怕沒有勝利呢?”。但很遺憾,你手中的這支隊伍原本只是散兵遊勇,在前進中招兵買馬,不斷壯大,所以隊伍變形在所難免。當開發經理髮覺隊伍變形時,也許就是剋制住攻克前方山頭的誘惑,停下腳步整頓隊伍的時候了。(什麼變形??當專案經理看到下面這些情況就已經變形了:程式碼中存在重複的程式碼、過大的類和過長的方法、牽一毛而需要動全身的修改、類之間需要過多的通訊、過度耦合的資訊鏈、各立山頭幹革命、不完美的設計、缺少必要的註釋

,重複程式碼,過長方法就不解釋了。牽一髮而動全身,當你發現修改一個小功能,或者增加一個小功能,卻影響了這裡那裡。過多的通訊,A類需要呼叫C類的過多的方法來訪問C類的內部資料,這兩個類的關係就可以不用分家了。過度耦合,當在程式碼中看到需要取得一個資訊,要呼叫A類的一個方法呼叫另外一個B類的方法呼叫另外一個C類的方法再呼叫D類的方法…我已經暈bi了,銜接層數太多了,就需要考慮移除一些中間層,或者更直接的呼叫方法。各立山頭,我曾經寫了一個處理字串的一個類,但是沒有及時通告團隊其他成員,後來發現,專案中有3個處理字串的類。不完美的設計,不合理,不可擴充套件性,一次性用品。缺少註釋就不用說了,還是說說吧,許多書籍常常提醒防止過多的註釋,但是我發現這個擔心好像沒什麼必要,我看到的程式碼基本上沒有註釋。往往程式設計師關注的是功能而非程式碼註釋,畢竟前者更能帶來成就感,當過了一段時間再回頭補註釋,很容易‘提筆忘字,欲言又止’。)

重構(Refactoring)的難題
學習一種可以大幅提高生產力的新技術時,你總是難以察覺其不適用的場合。通常你在一個特定場景中學習它,這個場景往往是個專案。這種情況下你很難看出什麼會造成這種新技術成效不彰或甚至形成危害。十年前,物件技術(object tech.)就是如此。
現在,重構的處境也是如此。我們知道重構的好處,我們知道重構可以給我們的工作帶來垂手可得的改變。但是我們還沒有獲得足夠的經驗,我們還看不到它的侷限性。
難題:

  1. 資料庫(database):結構緊密耦合在一起、資料遷移。
  2. 介面(interface):修改錯了就gg了。該如何面對那些必須修改「已釋出介面」的重構手法?已經發布的介面,就同時維護新舊兩個介面,更甚至很多版本的介面。讓新舊介面都能繼續工作。如果需要修改某個函式名稱,留下舊的函式,讓舊函式來呼叫新的函式,不要拷貝函式的實現程式碼,可能會讓你陷入重複程式碼的泥沼。可以對舊的方法標記“反對”的關鍵字,比如Java中的deprecated。這樣,呼叫者就會注意到了。
    「保留舊介面」的辦法通常可行,但很煩人。起碼在一段時間裡你必須建造(build)並維護一些額外的函式。它們會使介面變得複雜,使介面難以使用。還好我們有另一個選擇:不要釋出(publish)介面(不要把所有的介面都公開出去),不要過早的釋出。
  3. 難以通過重構完成的設計改動:將某個設計重構為另一個設計的難度有多大?如果看上去很簡單,我就不必太擔心選擇是否得當,於是我就會選最簡單的設計,哪怕它不能覆蓋所有潛在需求也沒關係。但如果預先看不到簡單的重構辦法,我就會在設計上投入更多力氣。

何時不該重構?

  • 重新編寫所有程式碼的時候。程式碼實在太混亂,重構它還不如從新寫一個來得簡單。but作出這種決定很困難。
  • 現有程式碼根本不能正常運作。重構之前,程式碼必須起碼能夠在大部分情況下正常運作。
  • 如果專案已近最後期限。因為已經沒有時間了。不過多個專案經驗顯示:重構的確能夠提高生產力。如果最後你沒有足夠時間,通常就表示你其實早該進行重構。
    關於如何實施程式碼重構
    常說事不過三,但也有再三強調。
    1.新增功能時重構
    2.修補錯誤時重構
    3.複審程式碼時重構
    關於如何實施重構,這個不能泛泛而談。必須自己理解總結。
    另外,如果需要在重構方面有所見長的話,可以看看這本書,《重構》
    看到簡書上有人讀了這本書之後寫了一篇,地址:http://www.jianshu.com/p/dac7979f5a29?ref=myread 個人覺得還是寫得很好的,在這裡推薦一下。