重構模式(二)---- 為什麼要 Refactoring
為什麼要去改變已經可以正確執行的軟體?這樣的改變是否影響到我們的設計,從而進一步改變我們對於物件導向系統進行設計的方法和思路?本部分試圖回答這些問題。
Refactoring雖然需要更多的"額外工作",但是它給我們帶來的各種好處顯然值得我們做出這樣的努力:
簡化測試
一個好的Refactoring實現能夠減少對新設計的測試量.因為Refactoring的每一步都保持可觀察的行為,也就是保持系統的所有單元測試都能順利通過。所以只有發生改變的程式碼需要測試.這種增量測試使得所有的後續測試都建立在堅實的基礎之上,整個系統測試的複雜性大大降低。
更簡單的設計
Refactoring降低初始設計的複雜程度.Gamma指出複雜設計模式的一個陷阱是過度狂熱:"模式有其成本(間接性、複雜化),因此設計應該達到需求所要求的靈活性,而不是越靈活越好"。如果設計試圖介入太多以後可能需要的靈活性,就會產生不必要的複雜和錯誤。Refactoring能夠以多種方式擴充套件設計。他鼓勵為手頭的任務建立剛剛合適的解決方案,當新的需求來到時,可以通過Refactoring擴充套件設計。
Refactoring增進軟體可理解性
程式的最終目的是為了指引計算機完成人們需要完成的事情。但是,要完成這個目標並非想象的那麼容易。
程式編寫是人的活動,人首先要理解才能行動。所以,原始碼的另一個作用就是用於交流的工具。其他人可能會在幾個月之後修改你的程式碼,如果連理解你的程式碼都做不到,他又如何完成所需的修改呢?我們通常會忘掉原始碼的這種用處,儘管它可能是原始碼更重要的用處。不然,我們為什麼發展高階語言、面嚮物件語言,為什麼我們不直接使用匯編語言甚至是機器語言來編寫程式?難道我們真的在意計算機多花了幾個CPU週期去完成一件事?
如果一個人能夠理解我們的程式碼,他可能只需要一天的時間完成一個增加功能的任務,而如果他不理解我們的程式碼,可能需要花上一個禮拜或更長的時間。這裡的問題是,我們在編寫程式碼的時候不但需要考慮計算機CPU的想法,更要把以後的開發者放在心上。除非,你寫程式碼的唯一目的就是把它丟掉。你不想讓任何別的開發人員用到這段程式碼,包括你自己。因為你不可能記得所有你寫過的程式碼,如果你經常回過頭去看一下自己的程式碼,你就會體會到程式碼的可理解是如何重要。
Refactoring可以使得你的程式碼更理解,Refactoring支援更小的類、更短的方法、更少的區域性變數、更小的系統耦合,Refactoring要求你更加小心自己的命名機制,讓名字反映出你的意圖。如果哪一塊程式碼太複雜以至於哪一理解,你都需要對他進行Refactor。
你可能認為,反映程式碼的意圖應當是註釋和文件的責任。假設你寫好了一段程式,給他加上註釋,來說明你這段程式碼完成了什麼。每次程式碼發生改變,你都需要修改註釋。而其實程式碼本身應當足以說明這個問題。如果程式碼不能反映自己的意圖,即使是再多的註釋也不足以讓你理解程式碼的所有機制,除非你把程式碼的每一句話都加上註釋。甚之,這種重複的責任使得一旦註釋和程式碼發生不一致,它反而會阻礙你對程式碼的理解。而任何一個程式設計師都不願意寫太多的註釋和文件。所以Martin fowler說:
When you feel the need to write a comment,first try to refactor the code so that any comment becomes superfluous。
Martin Fowler同時指出,Refactoring不但能夠增加別人對你程式碼的理解,而且是一種非常好的理解別人程式碼,學習別人程式碼的方法。通常,當你拿到一大堆程式碼時,你可能會覺得一片茫然,不知道從何處開始。學習別人程式碼最好的方法就是對程式碼進行進行Refactor。如果你發現自己不能理解一段程式碼,那麼試圖使用對自己說,哦,這段程式碼可能是在做什麼事情。給他一個有意義的名字,refactor它。Refactor使得你對程式碼的理解不是僅僅停留在腦袋中,而是看到程式碼確實按照你的理解再發生變化。如果你的refactor改變了系統的行為,那麼說明你的理解還有問題。你必須返回重來。
Refactoring 改進軟體的設計
許多人把程式設計看作是一種低階活動。他們認為程式碼僅僅是設計的附屬物。然而正是程式碼,而不是你腦袋裡或紙上的設計,真正驅動計算機完成你想做的事情。而絕大多數的bug也產生於編碼階段。
很多方法學認為通過分析和設計的嚴格化就能產生更高質量的軟體,這實際上是不可能的。正如Brain Foote和Joseph Yoder在《Big Ball of MUD》一文中指出,雖然許多作者提出了很多理想上非常完美的體系結構,如Layer、PIPELINE等等。但在實踐中,幾乎從來都不能看到這麼結構清晰的系統。
這一方面是由於分析和設計一個領域的應用程式需要對該領域豐富的知識,而這種知識不是在一開始都能獲得的。我們通常需要在實踐反饋的過程中才能一步步加深自己對該領域的理解。因而,我們一開始的設計可能並不能正確反映系統的內在本質,所以也不可能在程式碼中得到很好的反映。
另一方面,即使一開始的設計是完好的,隨著使用者對系統使用的深入,新的需求可能會被加入,舊的需求會被修改、刪除。一個最先的設計不可能完全預料到這些變化。
一旦實現開始偏離最初的設計,那麼它的程式碼將不受控制,從而不可避免地開始腐蝕。程式碼加入越多,腐蝕的速度越快。如果沒有辦法讓設計儘可能地與實現保持一致,那麼這種腐蝕的最後結果就是程式碼不得不被拋棄。
但是讓程式碼實現和設計始終保持一致並非那麼簡單,在傳統的軟體方法中,一旦開發到了實現階段,就很難對設計做出變化。所以最近發展的物件導向方法學把增量迭代(iterative)作為一個基本原則。
也許是題外話,在目前最為時行的一些"重型"軟體方法學中,我們很難找到對迭代(包括設計的迭代)明確的支援、定義和操作過程,以及如何提高程式設計師適應這種動態開發能力的方法。在我看來,重型的軟體方法學即使能夠對軟體開發起到一定的作用,他也不可能包羅永珍,解決軟體開發中的所有問題。開發方法學重視生命週期管理和控制,但軟體的開發並不只有過程和生命週期,更重要的是,同時往往被"正規"的軟體方法所忽略的是,軟體開發是人的活動。不管你的過程控制是多麼的嚴格,不管你的生命週期模型是多麼的完美,如果不能提高人的生產力,提高產品的質量,那麼一切都是毫無意義的。
在這裡,要實現這樣一種增量迭代的開發模型,你必須能夠讓分析人員、設計人員、程式人員、測試人員等等,所有參於開發活動的人有能力或者能夠有切實可行的方法來實現迭代,實現增量。如果不是這樣的話,你無法隨時保持實現和設計之間的一致性,無法把編碼實現中所發現的不合理設計反饋到初始設計,也無法在需求變化時對實現所產生的影響準確及時地得到反映。
如果沒有切實可行的基本方法來支援迭代中所需要的改變,那麼迭代將是非常困難的.我們可以設想,一旦新的需求到達,新的一輪迭代開始,而原先的系統設計被證明無法適應現在的變化,這個時候你如何能夠使得迭代順利地以增量的方式進行下去?
Refactoring提供了對incremental iterative development最好的支援。隨著系統的演變,程式碼的結構越來越差,通常這意味著要完成一件事情需要更多的程式碼。很多情況,通常緣於在幾個不同的地方都有類似的程式碼。因此Refactoring最重要的課題之一就是排除重複。我們通過排除重複力求能夠達到Once And Only Once的境界。而它正是好設計的一個基本標準。Once and Only Once雖然不能直接提高軟體的效率,但卻讓程式碼的修改和理解變得更為容易、系統的結構更加清晰。它是消除程式碼腐蝕的最佳途徑。
Refactoring 幫助你尋找 Bug
幫助理解程式碼同時也可以幫助你發現bug。很多程式碼處於系統中一些非常微妙的地方。如果你只是一遍又一遍地閱讀程式碼,恐怕你永遠也找不到bug。有的時候,你使用IDE提供的工具也難以跟蹤這樣的bug。因為如果你的程式碼沒有很好的結構,譬如一個類具有太多的責任,那麼它必然具有太多的狀態,在除錯程式的時候,你同樣需要注意太多的現象。
你可以用refactoring使得程式程式碼的結構更清晰,每一個時刻可以更集中關注專一的資料和行為,這會使你的工作量大大減少。同時,由於refactoring要求small steps,並且對每一步都進行嚴格的測試,這樣會使得bug很容易地浮現出來。
Refactoring 讓你程式設計更快
在瞭解refactoring後,你可能承認refactoring能夠改進軟體的質量、設計、結構、可讀性,減少bug,但是你會認為運用refactoring技術進行軟體開發有可能減慢你的開發速度。畢竟,你要編寫額外的單元測試,你要去refactor的程式碼本來就能夠工作的程式碼。
那麼,為什麼要如此麻煩?他不會拖我的進度嗎?
事實上,Refactoring確實能夠加快軟體的開發速度。一個好設計的基本前提就是允許更快的軟體開發。說得更絕對一點,好設計的全部就是它是否能夠更快、更靈活地支援軟體的變化。如果沒有一個好的設計,一開始你可能可以開發得很快,但是隨著功能的增加,你的程式碼逐漸腐蝕,結構漸漸失去。每次當你需要加入新功能時,你必須花大量的時間去理解原來的程式碼,修改原來程式碼的bug。改變一項功能需要花費越來越長的時間。
Refactoring支援好的結構、設計和理解性,它讓你更快地開發軟體。因為它可以防止軟體的侵蝕,他甚至用於改進設計。
相關文章
- 重構模式(四)---- 合理、勇敢地運用Refactoring模式
- 為什麼要重構?深入探討重構的原則、範圍和時機
- 重構模式(三)---- 應用 Refactoring 需要考慮的問題模式
- 為什麼要虛擬化,為什麼要容器,為什麼要Docker,為什麼要K8S?DockerK8S
- Java程式設計——重構-你為什麼要對引數賦值?Java程式設計賦值
- 為什麼要學資料結構?資料結構
- 為什麼 JavaScript 要設計原型模式JavaScript原型模式
- Web前端技術知識:為什麼要進行網站重構呢?Web前端網站
- java為什麼要重寫hashCode和equals方法Java
- Java重寫equals方法時為什麼要重寫hashcode方法Java
- 為什麼要removeREM
- 為什麼要敏捷?敏捷
- 重構(Refactoring)技巧讀書筆記 之三筆記
- 為什麼要code reviewView
- 為什麼要學習 RustRust
- 為什麼要學習 Julia
- 為什麼要指令重排序?排序
- 為什麼要學習 Vim?
- 為什麼要選擇SQL?SQL
- MySQL為什麼要set namesMySql
- 設計師為什麼要學程式設計,開發者為什麼要學設計?程式設計
- 為什麼 JavaScript 的 this 要這麼用?JavaScript
- 為什麼前端初學者必須要明白髮布訂閱模式前端模式
- 【Web】JavaWeb專案為什麼我們要放棄jsp?為什麼要前後端解耦?為什麼要前後端分離?2.0版,為分散式架構打基礎。 - CSDN部落格WebJavaJS後端解耦分散式架構
- 為什麼要學習資料結構和演算法?資料結構演算法
- 為什麼以及如何要進行架構設計權衡?架構
- Python是什麼?為什麼要掌握python?Python
- 關於程式碼重構的靈魂三問:是什麼?為什麼?怎麼做?
- 為什麼還要記密碼密碼
- 為什麼要閱讀原始碼原始碼
- 為什麼要學習Netty?Netty
- 為什麼要貢獻開源
- 前端為什麼要工程化?前端
- 為什麼要分庫分表?
- 為什麼要特徵標準化特徵
- 為什麼我要學習“機器學習”?機器學習
- 為什麼要網頁模組化?網頁
- 我為什麼要學技術