好書妙評之《重構:改善既有程式碼的設計》

高翌翔發表於2012-05-06

作為程式設計師,對於《重構》一定並不陌生。儘管許多人把它奉為經典,例如有“改善程式碼的濟世良方”、“隱藏的寶藏”等等好評如潮,但也不乏對它言詞犀利的差評,有些甚至尖酸刻薄,例如“內容雖好但是寫得太爛”、“膚淺、冗長、且好高騖遠”等等。為何讀者的評論會出現如此巨大反差?真相到底是什麼?答案盡在“評論之評論”中為您揭曉 :D

作為程式設計師,對於《重構》一定並不陌生。儘管許多人把它奉為經典,例如有“改善程式碼的濟世良方”、“隱藏的寶藏”等等好評如潮,但也不乏對它言詞犀利的差評,有些甚至尖酸刻薄,例如“內容雖好但是寫得太爛”、“膚淺、冗長、且好高騖遠”等等。為何讀者的評論會出現如此巨大反差?真相到底是什麼?答案盡在“評論之評論”中為您揭曉 :D

順便說一句,俺把“好書評”改成了“好書評”的原因有二:一、好評、差評的譯文總共加起來有7000餘字,實在不短;二、原來的“短”字僅表示字數多寡,而改為“妙”字則能體現出內容之趣。

:本文書評均譯自原書Amazon書評,收錄日期為2012年04月28日。根據Amazon上評論的排名順序,分別選出名列前茅的好評、差評各5篇與大家分享於此!

好評

★★★★ 改善程式碼的濟世良方

評價日期:2000年05月05日
合計144人頂,6人踩。

正如“四人幫”(Gang of Four)那本里程碑式的著作《設計模式》(Design Patterns)一樣,Fowler和他的死黨已經建立了另一本編目式圖書,而這次的主題是重構(refactoring)。

重構(Refactoring)是指,拿來現有的工作軟體,並以改善其設計為目的進行改造,以便將來的修改和增強更容易新增進去。《重構》從根本上說是包含了大約70種不同種類改進方法的編目,那些改進方法都可用於開發物件導向軟體。

編目中的每個詞條均描述了實現問題、解決方案、應用解決方案的動機、重構的作法、以及範例。書中的範例都是用Java編寫的,不過C++程式設計師應該可以輕而易舉地研究這些重構方法。Fowler通常會用UML圖來說明各種重構方法,因此對一建模語言略知一二將會對你大有裨益。

儘管此編目很不錯,而且在大多數情況下各種重構方法顯而易見。甚至具有一定經驗的程式設計師無需按部就班地照著作法所述的那樣去做。然而,真正的好處在於,每種重構方法的作法有助於保證你可以在不引入新錯誤或副作用的情況下重構成功。比起大多數開發者自然採用地那些更粗糙的重構方法,他們鼓勵你採取若干較小的、可驗證步驟來完成重構。其實你這麼做可以節省時間。

你怎麼知道你的重構是安全的?Fowler等人給出的答案是單元測試(Unit testing)。Java開發者將會發現引入的JUnit測試框架是此書最有價值的部分,甚至超過了重構編目本身。

當然,書中除了編目和JUnit之外,還有更多內容。書中討論了重構的歷史、如何評估各種重構工具、以及如何說服管理部門,那些看似是開銷活動重構工作從長遠來看實際上是有用的。

很遺憾,這幾個章節都過於簡短。而且沒有討論如何將重構融入不同的軟體開發過程。例如,對於使用極限程式設計(Extreme Programming,XP)的程式設計師,當他們與單元測試一起配套使用Fowler的重構建議時,可能感覺就像在家一樣輕鬆自如。不過對於那些堅持如PSP(即Personal Software Process,個體軟體過程)等軟體工程協會過程的開發者而言,他們會把測試所用時間歸為故障時間,而即便與之相關的工作無法避免,那麼測試時間也要最小化。而淨室開發者所受的教導是,單元測試會干擾對質量的度量,並且對於單元測試的驗證又該如何去做。這些開發者是否要在每次重構之後重新驗證呢?對於這些問題書中並未給出答案。

第3章“程式碼的壞味道”是非同尋常的一章,這一章給出各種重構方法的所有動機。對於“Long Method(過長函式)”或“Lazy Class(冗贅類)”等諸如此類的模糊概念,恰恰是它們在談笑風生間為你著手重構提供了基礎。我之所以說“談笑風生”,主要是因為Beck和Fowler所用的那些稀奇古怪的類比(類之間變得過於親密,以至於探究起彼此的私密之處)常常讓人忍俊不禁(只用一章來討論程式碼的“壞味道”似乎感覺意猶未盡)。

總體而言,我很喜歡讀這本書,而且每當我把單元測試和各種重構方法付諸實踐時也會參閱此編目。Fowler的寫作風格如行雲流水,而且內容通俗易懂。此書不僅排版乾淨利落、圖表一清二楚,而且重構索引和“味道”索引都可謂功效不凡!


★★★★★ 重構:改善既有程式碼的設計

評價日期:2002年11月11日
合計101人頂,9人踩。

不久以前,有人向我提到了一個聞所未聞的詞,即重構。還告訴我,為了能更好地瞭解理解重構的含義,最好找本Martin Fowler的書讀一讀。我已讀過此書,朋友們,我想應該把此書算作“隱藏的寶藏”。

儘管沒有華而不實或是眾所周知的書名,但是我相信,與那些主流的、更受歡迎的技術圖書相比,其影響力一定會更為深遠。其傳授的基礎理論可受用多年,即便語言變更亦是如此。

關於此書,我覺得有僅幾件事值得推敲,詳述如下。

前言

前言開門見山,給出了重構一詞的定義。良好的開端是成功的一半,因為你已獲得了重構的確切定義。簡言之,重構是這樣一個過程:在不改變程式碼外在行為的前提下,對程式碼進行修改,從而改善其內部結構。

第1章 重構,第一個案例

在這一章中Fowler先生試圖從一個簡單的重構示例開始。而問題在於這章猶如滔滔江水連綿不絕,竟然寫了50多頁。儘管Fowler先生解釋了這樣做的原因,但是我仍然認為,簡單示本就該非常簡單。尤其是作為本書的首章更應如此。我絕無說此章不好之意。我只是覺得此章在書中出現得為時過早。換做是我,我會把它作為最後一章。

第2章 重構原則

這是很棒的一章。不僅討論了重構的定義,還談到了以下問題:為何重構?何時重構?怎麼對經理說?最後這個問題可能看上去很可笑,不過只要你讀了此章,自然就會明白其中的玄機。這章還討論了一些出現在重構期間的常見問題、以及重構與效能。

第3章 程式碼的壞味道

這一章討論了會使程式碼“散發味道”的一些東西。每當程式碼“散發味道”,那就是需要進行重構的跡象。一共討論了22種不同的“味道”。我最喜歡的是,Duplicated Code(重複程式碼) 、Large Class(過大的類)、還有Lazy Class(冗贅類)。這章中滿是令人拍案叫絕的隱喻。

第4章 構築測試體系

構築測試體系是重構的重要組成部分。重構是以小步推進,而且每一步完成後你都要測試。在這一章中討論了與重構時應用測試有關的過程和方法。

第5章 重構列表

這一章是對6至12章的快速介紹。Fowler先生解釋了每種重構的分類方法。他花了許多時間來命名並詳細解釋每種重構,這真是令人歎為觀止。

第6章 重新組織函式

我最愛的章節之一。Fowler先生開門見山地說道,“重構的很大一部分工作就是撰寫函式,以便妥善地把程式碼包裝起來。”這章一共解釋了9種重構方法。其中我最愛的是Inline Method(行內函數)和Extract Method(提煉函式)。

第7章 在物件之間搬移特性

有時你需要將某些東西從一個物件移動到另一個物件。這章討論了在物件之間搬移特性的技巧。一共討論、詳述了8中重構方法。這章中我最愛的是Extract Class(提煉類)。

第8章 重新組織資料

這是篇幅很大的一章,其中對16種重構方法進行了細緻入微的討論,這些方法會讓資料處理變得得心應手。這章中顯而易見的一點是,某些特定的重構方法可以彼此對調。例如Change Value to Reference(將值物件改為引用物件)和Change Reference to Value(將引用物件改為值物件)兩種方法就恰恰說明了這一點。因此對於一些重構方法不能高“一刀切”,而要因勢利導。

第9章 簡化條件表示式

由於在程式設計世界中條件邏輯已是司空見慣,因此這章十分有用。因為條件邏輯存在將問題複雜化的傾向,所以這章介紹的8種重構方法會有助於簡化它們。

第10章 簡化函式呼叫

這章中的15種重構方法有助於教會我們如何使方法呼叫變得易如反掌。這些方法從非常簡單的Rename Method(函式改名)到較為複雜的Replace Constructor with Factory Method(以工廠函式取代建構函式)。

第11章 處理概括關係

這裡介紹了12種重構方法,用於處理由於概括關係(generalization)而形成的狀況。其中還討論了繼承(Inheritance)、委託(Delegation)、以及介面(Interfaces)等主題。

第12章 大型重構

Kent Beck與Fowler先生二人合著此章。他們討論了4種大型重構:Tease Apart Inheritance(梳理並分解繼承體系)、Convert Procedural Design to Objects(將過程化設計轉化為物件設計)、Separate Domain from Presentation(將領域和表述/顯示分離)、以及Extract Hierarchy(提煉繼承體系)。相對於前面幾章中的小型的獨立重構方法而言,這些重構方法則屬於更加相容幷包的型別。二位高人竟然將通常要用長篇大論來解釋的內容一言以蔽之,堪稱功不可沒!

第13章 重構,複用與現實

這章是由William Opdyke編寫的。他不僅討論了他的重構經歷,還有比如為何開發者不願重構、以及如何減少重構開銷等其他主題。這章是“融會貫通”的絕妙一章,的確有助於高屋建瓴地審視書中觀點。

第14章 重構工具

Don Roberts與John Brant合著了這一章。正如這章標題所示,他們討論了重構工具。

第15章 總結

Kent Beck做了個4頁的快速總結。

我覺得值得推敲的另一件事情是,我希望示例語言不是用Java而是用其他語言。我對Java一竅不通。對我而言,如果能用VB.net來編寫示例,那麼我讀起來會更加駕輕就熟。幸好我深得其中要旨,當然這也是關鍵所在。

沒錯,如前所述,我把此書視為“隱藏的寶藏”。書中所探討的內容會在未來幾年幫助許多人寫出更好、更易懂的程式碼。要是10分制,我會給此書打9.5分。此書的確物有所值!


★★★★★ 讓老態龍鍾的程式碼煥發青春

評價日期:2000年05月17日
合計24人頂,0人踩。

此書的基本論點是,實際執行的程式由於多種原因被設計得千瘡百孔。那些程式出於各種各樣的原因變成了這樣。最初設計良好的軟體,可能由於程式擴充套件而導致衰退。始料未及的複雜度可能導致超大的方法。正如Fowler所述,重構的功能就是防止程式發生衰退轉變。由於這種轉變是可逆的,因此我們的目的就是以某種方式改善程式質量。

儘管Fowler覺得重構程式是為了使得新增新功能變得更簡單。然而重構程式同時也是為了使得人類讀者更易理解。

他還主張小步推進、保持功能,而且同時要頻繁使用詳盡的測試套件來進行單元測試。

此書一半是由重構方法編目組成的。他給每種重構方法都起了令人難以忘懷的名字,例如“Replace Type Code with Subclasses(以子類取代型別碼)”。他用兩幅UML類圖來對比說明設計轉換,而且還用一組標準段落來解釋:動機(Motivation)、作法(Mechanics)、以及範例(Example)。

動機(Motivation)是個平鋪直敘的段落,對重構方法進行描述和論證,並展示與其他重構方法之間的關係。

作法(Mechanics)是執行重構所需的一系列步驟,並以要點列表的形式展示出來。對於某些要點他會展開解釋。

範例(Example)是此書的價值所在。Fowler摘取了一些Java程式碼片段,並帶領我們一步一步地完成重構。儘管未必他展示的每一步都能讓我們心悅誠服,因而使得程式碼略顯不足,但是從實用的角度來看就足夠了。

對於非Java程式設計師而言,示例程式碼理解起來也是一目瞭然。他把程式碼解釋得一清二楚,對於那種書中程式碼含義不直觀的圖書,此書完全可以充當Java教程使用。在那些重構方法中有一或兩種方法是特定於Java物件模型的,而且不適用於其他語言。除了極少數語言特定的重構方法以外,其他語言皆可從類似的處理中獲益。

此書大有《設計模式》運動之遺風,書中頻繁引用了各種模式。重構方法的目的可能就是實現特定模式,或是利用特定模式。此書可作為《設計模式》教程使用。

我有幾句話不吐不快。Fowler主張在為了某次程式碼評審而研究程式碼時使用重構。此時程式設計師的職業敏感性應該非常靈敏,尤其當他或她是新手時更是如此。審閱者應該在閱讀程式碼的同時將重構銘記於心,並且可能還有一些重構建議,反而卻要程式設計師去完成那些更改,真是豈有此理!

通過閱讀此書,我已鼓起勇氣著手重構自己的程式碼。我的錯誤突顯出小步推進和頻繁測試的必要性。根據Fowler給出JUnit測試框架,我花了一天時間來構建有效的Delphi測試框架。不過對於高度耦合的解析程式碼(parsing code)而言,此類方法似乎並不適用。儘管我可以提煉出一些小的程式碼塊,但是它們彼此間仍然緊緊地耦合在一起,並且很難給出意味深長的名字。其中的答案可能是,沒有使用自底向上的重構方法,而是使用了自頂向下的遞迴下降法(approach of recursive descent)。或許遞迴下降可以指導重構。因為大部分重構都是區域性方法。有人幾乎說是針孔方法。有時全域性觀是必需的。

總之,我想說此書堪稱佳作,它不僅適合於那些對Java略知一二又滿腹疑團的Java菜鳥,而且還適合於我們這些略顯疲塌又需要新思想、新動力的老油條。


★★★★★ 不僅要讀,更要買!

評價日期:2000年07月18日
合計38人頂,3人踩。

我們可能讀到許多好書,要麼關於特定技術(COM、UML等),要麼關於特定程式語言,乃至關於不同的軟體開發方法(RUP、OPEN等),然而經典之作會時不時地出現。就像《設計模式》4年前橫空出世一樣,現在《重構》隨之而來。每位真正的物件導向開發者都應該擁有這兩本書。請捧起《重構》,只要讀一讀第3章(程式碼的壞味道)就好了,因為其中總結了所有可能在不知不覺間侵入程式碼的“壞味道”。一共列舉了21個關於程式設計的反面教材及其原因。此書的其餘部分介紹了大量用於改變既有程式碼的技術(各種重構方法),從而消除“壞味道”。大多數重構方法都附有一些UML圖示,從中足以領會重構之意圖,而且隨後還有Java程式碼示例。之所以成此書為傑作,是因為可以輕鬆地把它作為參考書來查詢,由於作者正是出於此目的對它進行了精心設計,通過查詢詳盡的索引和表格就可以匹配到各種壞味道及相應的重構方法。這些對於《程式碼大全》(CODE COMPLETE)的讀者是否有似曾相識之感,儘管《重構》的想法與之如出一轍,然而可謂更勝一籌。加之Fowler簡潔詼諧的寫作風格定會讓您盡享輕鬆、快樂的閱讀體驗。真心實意地推薦此書!


★★★★★ 別愣著,像我一樣該出手時就出手!

評價日期:2003年05月13日
合計19人頂,0人踩。

我得知此書已一年有餘。起初,我以為此書與重建遺留系統有關。常言道,事不關己高高掛起,由於我的工作與此不沾邊,因此也就沒有重視此書。然而在過去的一年裡,我總會無意中看到有人提到此書。似乎大家對此書交口稱讚,現在我終於明白其中緣由了。

在做物件導向設計的時候,很容易陷入“分析癱瘓”(analysis paralysis)的怪圈。常常會聽到這樣的抱怨,“我已經建立了27幅不同的類圖,還有42幅獨立的時序圖,但是我卻沒看見有任何書面程式碼產生……”極限程式設計(XP)的流行在一定程度上是因為,它讓你付諸行動——你立即著手編碼,而不是花上數週(或是數月)時間沒完沒了地建立類圖。極限程式設計的宗旨就是“不妨先動手!”。

但是,要使這種“先編碼,再提問”理念與至少需要做些設計工作的共識相一致,我們又該怎麼做呢?在《重構》中,Martin Fowler給出了答案。他的做法是,先建立一些可工作的程式碼,然後仔細研究程式碼,以便找出可改進之處——即重構它。

以Fowler觀點來看,在完成編碼以前,你無法真正瞭解問題所在,因此不要把未來3周的時間花在為下一個任務檢視找出完美模式上面,忘掉模式,而是動手編些程式碼。你至少要得到了一些可執行的程式碼以後,再考慮將某些模式重新融入到既有程式碼之中。

當然,這只是對此過程輕描淡寫的簡述,不過圍繞著“重構”過程散發出預備—射擊—瞄準(ready-fire-aim)過程的味道。而且看來切實可行——即使是那些對於極限程式設計其他核心實踐不買賬的人,他們的過程只要以重構為中心就可以了。

此書的重構方法編目為如何清理各種特定問題提供了一流的參考。不過就我而言,此書最有價值的部分是前50頁。

Fowler以一個簡單但糟糕的示例作為此書的開篇,然後他著手重構,逐步推進,並得到一些更為優雅的程式碼。如果你喜歡先學習各種原則,那麼在通讀此示例之前你會願意讀一下第2章(重構原則),不過我發現這是個非常有價值的練習。我建議用你所選擇的語言編寫此示例,然後與Fowler共同完成此示例的重構。

就像測試一樣,總有一種把重構歸為僅僅是另一種開發技術的傾向。不過正如測試一樣,重構的核心開發理念是:“我知道我不會在第一遍就把它做好,因此我只要盡我所能去做就好了。那樣做完以後,我會對如何改進它有更好的想法,而且我願意那樣做。不過會浪費一些時間,因此我要趕快行動。”

這種持續改進的理念使得開發者可以儘快開始行動,並降低由於延遲而導致失敗的風險。Fowler的書堪稱上上之作,它有助於開發者更快地建立更靈活的程式碼。我誠心誠意地向你推薦《重構》。

差評

★ 內容雖好但是寫得太爛

評價日期:2000年03月15日
合計72人頂,24人踩。

對於如何在無需徹底重寫程式碼的前提下改善既有程式碼的設計,書中給出了不少真知灼見,這完全不同於大多數UML型別圖書的套路,那些書都主張完全改變設計和構建軟體的方式。這並不是說設計和構建統一方法不好,只是說如果你不能掌控某個組織,那麼要改變其執行方式會比登天還難。Fowler先生提出了一種機制,以便既可以改善既有程式碼的設計,又可以向其中新增功能。不過一旦斷章取義,這些資訊就會變得十分有用。然而此書既不是“正規化轉換”,也不是《設計模式》伴侶——儘管Fowler在整本書中經常提到《設計模式》,但是《重構》肯定不是為那些《設計模式》的讀者寫的。因為在Fowler給出的那些將糟糕程式碼轉變為優質程式碼的示例中,從未用過一個出自《設計模式》的模式。此書適用於任何面嚮物件語言,儘管他在示例中使用的是Java,但是那些原則可以輕鬆對映到C++和SmallTalk。儘管幾乎書中提到的所有技術都是常識,不過他卻在書中用了很大篇幅以簡單的術語來解釋如何完成它們。對於每種“重構方法”,他都能用三言兩語概述其過程,並給出程式碼片段或是類圖來舉例說明。不過由於他要煞費苦心地解釋進行程式碼改進的過程,因此他的語氣會變得謙遜起來。例如,書中的首個技術是Extract Method(提煉函式),其簡明描述是:“[如果]你有一段可以組織到一起的程式碼片段……[那麼]將這段程式碼放進一個函式中,並用函式名來解釋其用途。”雖然相當簡單,但是要想完全理解他所講述的內容,這寥寥數語似乎還遠遠不夠。然而隨後,他用短小精幹的程式碼片段做到了畫龍點睛。至此需要大約半頁。但是他卻用了四頁半來進一步解釋如何完成這個簡單的剪下-貼上過程。在總共418頁的書中,竟然用270頁以此種不勝其煩的方式詳細解釋了72種重構方法。最有用的8頁用於說明程式碼中那些會導致“重構”的壞“味道”。又用了110頁來告訴你,如何向你的老闆證明此工作的合理性、無論你的老闆是否批准都鼓勵你進行重構、倡導極限程式設計所特有的“測試——小改動——測試”的結對程式設計技術。最後30頁由其他幾位作者所著。總而言之,我認為此書應該“重構”為100至150頁以內的軟皮手冊,這讓人不禁想起Scott Meyers所著的Effective C++系列圖書。如果你要找《設計模式:第2部》,那麼此書肯定不是!全文完。


★★ 膚淺、冗長、且好高騖遠

評價日期:2003年02月10日
合計28人頂,8人踩。

儘管此書試圖從格式和效果兩方面與《設計模式》匹配起來,然而很遺憾,它失敗了。作者用了大量篇幅來解釋一些微不足道的重構方法,例如Rename Method(函式改名)或是Replace Magic Number with Symbolic Constant(以字面常量取代魔法數)。任何具有一定經驗的軟體開發者現在就可以說出如何以及為何要執行那些任務,他們根本無需此書。此書並未涉及更為複雜或是稀奇古怪的重構方法,而那些方法對於經驗豐富的開發者更有價值,而且書中也沒有涉及重構可能對既有程式碼造成的影響、以及如何控制和最小化那些影響。

然而,書中對於使用重構來修正某些經典設計錯誤給出了一些真知灼見,這可能對於新手很有價值。那就給個2星吧!


★★ 也就50的書居然寫出來400多頁

評價日期:17, 2000年12月17日
合計20人頂,7人踩。

雖然主題一語中的,但是除此之外,此書應該有更多內容。有些頁僅有4行程式碼;我搞不明白為什麼要留那麼多空白。傳授的許多技術由來已久,而且本應就是開發和重構過程中的一部分。由於此書滿是顛來倒去之語,因此要是作者們能認真檢查彼此的手稿並“重構”,那就太好了。


★★★ 書名應為“適用於Java程式設計師的重構”

評價日期:1999年12月13日
合計11人頂,11人踩。

作為C++程式設計師,我發現許多示例與Java語言(對此我不太熟悉)的細節聯絡極為密切。我想要的是一本更有實質性的、通用的、物件導向程式設計圖書。其中許多示例都屬於物件導向程式設計的常識,所以此書看起來更適合作為學習Java程式設計的入門書,而不是為《設計模式》(堪稱傑作)讀者所寫的。


★★★ 一本入門書

評價日期:2002年04月07日
合計11人頂,15人踩。

首先,此書對於理解重構的含義及其技術大有裨益。如果你是名菜鳥程式設計師,那麼此書會對你十分幫助,它會告訴你如何重構、以及為何還有何時重構。

然而,問題就在於此書是本“書”。許多程式設計師對於書中的故事和技術都會有似曾相識之感。然而遺憾的是,書中的技術並不罕見。例如,書中竟然用了好幾頁來解釋瞭如何建立臨時變數以及如何消除它!對於程式設計師而言,此類內容不過是家常便飯。許多人根本不用學這個。

對於經驗豐富的程式設計師而言,重構的問題之一是,重構意味著不新增功能卻要“改變”既有程式碼。儘管給出了許多益處,但是重構也給出了一些問題。例如,在團隊協作過程中,即便是改變方法名都是非常困難的,因為改名經常會導致原始碼中出現衝突。然而,此書對於此類問題並沒有給出任何解決方案。

總之,我不會把此書推薦給經驗豐富的程式設計師。

評論之評論

首先,非常感謝您能讀到這裡 :D

閒話少敘,正如您所看到的:為何外國讀者的評論會出現如此巨大反差?真相到底是什麼?

對於第一個問題其實並不難回答,“眾口難調”四字足矣,當然用俗話說就是“蘿蔔白菜各有所愛”。除此之外,俺想多說一句,在差評中多位讀者提到此書過於淺顯,不適於經驗豐富的程式設計師,更適於剛入門的菜鳥。其實仔細想想就能明白,兩位主要作者Martin Fowler和Kent Beck都是敏捷社群的領軍人物,總不能算是菜鳥吧?他們勞神費力寫出的必定是自認為有價值的內容!二位牛人況且能一步一步地認真重構,可是為什麼所謂“經驗豐富的程式設計師”卻做不到呢?答案很簡單,他們驕傲了!(若您也有此苗頭,不妨待會兒讀讀《禪修程式設計師十誡》。)

人的問題講完了,回過頭來認真分析一下此書到底有沒有問題?

通過閱讀評論可知,此書雖然多次提及《設計模式》,但是與之聯絡並不密切,正如有位差評讀者所寫“此書不是為《設計模式》(堪稱傑作)讀者所寫的”。此書的重點在於苦練編碼基本功,消除程式碼中“壞味道”。而對於志在修煉更高階武功的讀者,不妨讀一讀《重構與模式》,該書開創性地深入揭示了重構與模式這兩種軟體開發關鍵技術之間的聯絡,說明了通過重構實現模式改善既有的設計,往往優於在新的設計早期使用模式……

接下來分析一下“囉嗦”的問題,在好評、差評中都有人抱怨書中“廢話太多”。當然每個人的時間都很寶貴,而Martin Fowler為何要費時又費力地寫一堆廢話呢?!莫非為了賺取稿酬?罪過罪過,還是不要“以小人之心,度君子之腹”了。話說《重構》最早是由中國電力出版社引進的,當時的譯者是侯捷、熊節,當時侯捷老師在譯序中也發表了同樣的看法:

初閱讀本書,屢屢感覺書中所列的許多重構目標過於平淡,重構步驟過於瑣屑。這些我們平常也都做、習慣大氣揮灑的動作,何必以近乎枯燥的過程小步前進?然後,漸漸我才體會,正是這樣的小步與緩步前進,不過激,不躁進,再加上完整的測試配套(是的,測試之於重構極其重要),才是「不帶來破壞,不引入臭蟲」的最佳保障。我個人其實不敢置信有誰能夠乖乖地按步遵循實現本書所列諸多被我(從人的角度)認為平淡而瑣屑的重構步驟。我個人認為,本書的最大價值,除了呼籲對軟體質量的追求態度,以及對重構「工程性」的認識,最終最重要的價值還在於:建立起吾人對於「目前和未來之自動化重構工具」的基本理論和實作技術上的認識與信賴。人類眼中平淡瑣屑的步驟,正是自動化重構工具的基礎。機器缺乏人類的「大局觀」智慧,機器需要的正是切割為一個一個極小步驟的指令。一板一眼,一次一點點,這正是機器所需要的,也正是機器的專長。

本書第14章提到,Smalltalk開發環境已含自動化重構工具。我並非Smalltalk guy,我沒有用過這些工具。基於技術的飛快滾動(或我個人的孤陋寡聞),或許如今你已經可以在Java, C++等物件導向程式設計環境中找到這一類自動化重構工具。

軟體技術圈內,重構(refactoring)常常被拿來與設計模式(design patterns)並論。書籍市場上,《Refactoring》也與《Design Patterns》齊名。GoF曾經說『設計模式為重構提供了目標』,但本書作者Martin亦言『本書並沒有提供助你完成所有知名模式的重構手法,甚至連 GoF 的23個知名模式都沒有能夠全部涵蓋。』我們可以從這些話中理解技術的方向,以及書籍所反映的侷限。我並不完全贊同Martin所言『哪怕你手上有一個糟糕的設計或甚至一團混亂,你也可以藉由重構將它加工成設計良好的程式程式碼。』但我十分同意Martin說『你會發現所謂設計不再是一切動作的前提,而是在整個開發過程中逐漸浮現出來。』我比較擔心,閱歷不足的程式設計師在讀過本書後可能發酵出「先動手再說,死活可重構」的心態,輕忽了事前優秀設計的重要性。任何技術上的說法都必須有基本假設;雖然重構(或更向上說XP,eXtreme Programming)的精神的確是「不妨先動手」,但若草率行事,代價還是很高的。重型開發和輕型開發各有所長,各有應用,世間並無萬應靈藥,任何東西都不能極端。過猶不及,皆不可取!

在侯捷老師譯序中不僅把“廢話太多”的原因解釋得清清楚楚了,而且順便解釋了《重構》與《設計模式》的關係,最後還告誡我們必須牢記“任何技術上的說法都必須有基本假設”(即應用的背景、上下文,Context)。
(只可惜再版的《重構》中沒有了這篇精彩譯序,有興趣的讀者不妨讀一讀繁體版原文。)

正如侯捷老師所說,世間並無萬應靈藥,《重構》無法解決所有問題。

  • 例如,評論中有人寫道“你怎麼知道你的重構是安全的?Fowler等人給出的答案是單元測試(Unit testing)。”,或許有人會聯想起“單元測試之爭”,沒錯,單元測試不是銀彈,它甚至無法保證在我們可預見的情況下是安全的,因此單元測試也有出錯的可能,所以才需要結對程式設計(一人編碼,一人旁觀,累了就互換角色)來輔助降低出錯的可能性。
  • 又如“如何將重構融入不同的軟體開發過程”的問題,正如在《軟體之道:軟體開發爭議問題剖析》一書作者所反思的那樣:“可複製性已被證明是一個很難捉摸的目標。”,可見那位讀者的問題已經超出了《重構》的範圍,而且很可能連Martin Fowler本人也給不出答案,因為《重構》產生的背景是極限程式設計和敏捷思想,至於如何將《重構》移植到其他軟體開發過程之中則是個全新的未知領域。
  • 再如有人提出重構不適用於“高度耦合的解析程式碼(parsing code)”,確實有些重構方法的改進目標是物件導向程式碼,不過也許多“微不足道”的重構程式碼是為了提高程式碼的可讀性,以便將來更易維護和擴充套件,從這個意義上說,《重構》不僅適用於物件導向程式設計,也適用於程式導向程式設計。《重構》是藏有72般武器的“寶箱”,程式設計師要在開發過程中自行挑選“稱手的兵刃”。
  • 如最後那位差評讀者寫道“儘管給出了許多益處,但是重構也給出了一些問題。”,即“在團隊協作過程中,即便是改變方法名都是非常困難的,因為改名經常會導致原始碼中出現衝突。”,然而此問題在今天看來已不算什麼問題了,因為先進的版本管理工具和協同開發工具會搞定這一切。

在我個人看來,《重構》不僅有助於改善既有程式碼質量,而且它還在潛移默化地“重構”著程式設計師的設計思想和行為習慣 :D

歡迎大家積極分享,各抒己見!

相關文章