這本經典書 20 年後重磅升級,更新內容超 30%,更新了眾多專案案例。
1999 年,世界軟體開發大師,ThoughtWorks 首席科學家馬丁·福勒(Martin Fowler)出版《重構:改善既有程式碼的設計》,讀者反饋甚佳,重構(Refactoring)的理念被廣泛接納,成為程式設計的詞彙表中不可或缺的部分。2019 年,恰逢《重構》一書推出 20 週年,馬丁重新梳理他對重構理念的最新思考,不朽經典重磅升級。
今天,馬丁·福勒(Martin Fowler)在“技術雷達十週年峰會”現場與大家分享過去十年來技術領域的趨勢變化,聆聽馬丁的大師觀點。《重構 》第 2 版,20 年後重磅升級,也將在此次會議上新書首發。
現在,我們節選了本書的譯者熊節先生的序言,重讀《重構》,呼喚匠藝,與你共勉。(原文較長,本文有刪節)
2009 年,在為《重構》第 1 版的中譯本再版整理譯稿時,我已經隱約察覺行業中對“重構”這個概念的矛盾張力。一方面,在這個“VUCA”(易變、不確定、複雜、模糊)橫行的年代,有能力調整系統的內部結構,使其更具長期生命力,這是一個令人神往的期許。另一方面,重構的扎實功夫要學起來、做起來,頗不是件輕鬆的事,且不說詳盡到近乎瑣碎的重構手法,光是單元測試一事,怕是已有九成同行無法企及。結果,“重構”漸漸成了一塊漂亮的招牌,大家都願意掛上這個名號,可實際上乾的卻多是“刀劈斧砍”的勾當。
如今又是 10 年過去,只從國內的情況而論,“重構”概念的表裡分離,大有愈演愈烈之勢。隨著當年的一線技術人員紛紛走上領導崗位,他們樂於將“重構”這塊漂亮招牌用在更寬泛的環境下,例如系統架構乃至組織結構,都可以“重構”一下。然而基本功的欠缺,卻也一路如影隨形。當年在物件中的刀劈斧砍,如今被照搬到了架構、組織的調整。於是“重構”的痛苦回憶又一遍遍重演,甚而程度更深、影響更廣、為害更烈。
此時轉頭看 Martin Fowler 時隔將近廿載後終於付梓的《重構》第 2 版,我不禁感嘆於他對“微末功夫”的執著。在此書尚未成型之前,我和當時 ThoughtWorks 的同事曾有很多猜測,猜 Fowler 先生是否會在第 2 版中拔高層次,多談談設計乃至架構級別的重構手法,甚或跟隨“敏捷組織”“精益企業”的風潮談談組織重構,也未為不可。孰料成書令我們跌破眼鏡,Fowler 先生不僅沒有拔高,反而把工夫做得更扎實了。
對比前後兩版的重構串列,可以發現:第 2 版收錄的重構手法在用途上更加內聚,在操作上更加連貫,更重視重構手法之間的組合運用。第 1 版中佔了整章篇幅的“大型重構”,在第 2 版中全數刪去。一些較為複雜的重構手法,例如複製“被監視資料”、塑造模板函式等,第 2 版也不再收錄。而第 2 版中新增的重構手法,則多是提煉變數、移動陳述句、拆分迴圈、拆分變數這樣更加細緻而微的操作。這些新增的手法看似簡單,但直指大規模遺留程式碼中最常見的重構難點,正好補上了第 1 版中闕漏的細節。這一變化,正反映出 Fowler 先生對於重構一事一貫的態度:千里之行積於跬步,越是面對複雜多變的外部環境,越是要做好基本功、邁出扎實步。
識別壞味道、測試先行、行為保持的變更動作,是重構的基本功。在《重構》第 2 版裡,重構手法的細節被再度打磨,重構過程比之第 1 版愈發流暢。細細品味重構手法中的前後步驟,琢磨作者是如何做到行為保持的,這是能啟發讀者舉一反三的讀書法。以保持物件完整重構手法為例,第 1 版中的做法是在原本函式上新添引數,而第 2 版的做法則是先新建一個空函式,在其中做完想要的調整之後,再整體替換原本函式。兩相對比,無疑是新的做法更加可控、出錯時測試失敗的範圍更小。
無獨有偶,我在 ThoughtWorks 時的同事王健在開展大型的架構重構時,總結了重構的“十六字心法”,恰與保持物件完整重構手法在第 2 版中這個新的做法暗合。這十六字心法如是說:
舊的不變,
新的建立,
一步切換,
舊的再見。
從這個視角品味一個個重構巨細靡遺的做法,讀者大概能感受到重構與“刀劈斧砍”之間最根本的分歧。在很多重構(例如最常用的改變函式宣告)的做法中,Fowler先生會引入“很快就會再次修改甚至刪除”的臨時元素。假如只看起止狀態,這些變更過程中的臨時元素似乎是浪費:為何不直接一步到位改變到完善的結果狀態呢?然而這些臨時元素所代表的,是對變更過程(而非只是結果)的設計。缺乏對過程的精心設計與必要投入,只抱著對結果的美好憧憬提刀上陣,遇到困難就靠“奮鬥精神”和加班解決,這種“刀劈斧砍”不止發生在缺乏審慎的“重構”現場,又何嘗不是我們這個行業的縮影?
是以,重構這門技藝,以及 Fowler 先生撰寫《重構》的態度,代表的是軟體開發的匠藝——對“正確的做事方式”的重視。在一個浮躁之風日盛的行業中,很多人會強調“只看結果”,輕視做事的過程與方式。然而對於軟體開發的專業人士而言,如果忽視了過程與方式,也就等於放棄了我們自己的立身之本。 Fowler 先生近廿載對這本書、對重構手法的精心打磨,給了我們一個榜樣:一個對匠藝上心的專業人士,日積月累對過程與方式的重視,是能有所成就的。
所謂重構(refactoring)是這樣一個過程:在不改變程式碼外在行為的前提下,對程式碼做出修改,以改行程式的內部結構。重構是一種經千錘百煉形成的有條不紊的程式整理方法,可以最大限度地減小整理過程中引入錯誤的機率。本質上說,重構就是在程式碼寫好之後改進它的設計。
“在程式碼寫好之後改進它的設計”這種說法有點兒奇怪。在軟體開發的大部分歷史時期,大部分人相信應該先設計而後編碼:首先得有一個良好的設計,然後才能開始編碼。但是,隨著時間流逝,人們不斷修改程式碼,於是根據原先設計所得的系統,整體結構逐漸衰弱。程式碼質量慢慢沉淪,編碼工作從嚴謹的工程墮落為胡砍亂劈的隨性行為。
“重構”正好與此相反。哪怕手上有一個糟糕的設計,甚至是一堆混亂的程式碼,我們也可以藉由重構將它加工成設計良好的程式碼。重構的每個步驟都很簡單,甚至顯得有些過於簡單:只需要把某個欄位從一個類移到另一個類,把某些程式碼從一個函式拉出來構成另一個函式,或是在繼承體系中把某些程式碼推上推下就行了。但是,聚沙成塔,這些小小的修改累積起來就可以根本改善設計質量。這和一般常見的“軟體會慢慢腐爛”的觀點恰恰相反。
有了重構以後,工作的平衡點開始發生變化。作者發現設計不是在一開始完成的,而是在整個開發過程中逐漸浮現出來。在系統構築過程中,作者學會瞭如何不斷改進設計。這個“構築-設計”的反覆互動,可以讓一個程式在開發過程中持續保有良好的設計。
本書是一本為專業程式員編寫的重構指南。作者的目的是告訴你如何以一種可控且高效的方式進行重構。你將學會如何有條不紊地改行程式結構,而且不會引入錯誤,這就是正確的重構方式。
第 1 章展示了一個小程式,其中有些常見的設計缺陷,我把它重構得更容易理解和修改。其間你可以看到重構的過程,以及幾個很有用的重構手法。如果你想知道重構到底是怎麼回事,這一章不可不讀。
第 2 章討論重構的一般性原則、定義,以及進行重構的原因,作者也大致介紹了重構面臨的一些挑戰。第 3 章由 Kent Beck 介紹如何嗅出程式碼中的“壞味道”,以及如何運用重構清除這些“壞味道”。測試在重構中扮演著非常重要的角色,第4章介紹如何在程式碼中構築測試。
從第 5 章往後的篇幅就是本書的核心部分——重構名錄。儘管不能說是一份巨細靡遺的串列,卻足以改寫大多數開發者可能用到的關鍵重構手法。這份重構名錄的源頭是 20 世紀 90 年代後期作者開始學習重構時的筆記,直到今天仍然不時查閱這些筆記,作為對不甚可靠的記憶力的補充。每當作者想做點什麼——例如拆分階段(154)——的時候,這份串列就會提醒他如何一步一步安全前進。希望這是值得你日後一再回顧的部分。
作者選擇了用 JavaScript 來展現本書中的重構手法,因為感到大多數讀者都能看懂這種語言。不過,即便你眼下正在使用的是別的程式語言,採用這些重構手法也應該不困難。作者儘量不使用 JavaScript 任何複雜的特性,這樣即便你對這門程式語言只有粗淺的瞭解,應該也能跟上重構的過程。另外,使用 JavaScript 展示重構手法,並不代表作者推薦這門程式語言。
使用 JavaScript 展示程式碼範例,也不意味著本書介紹的技巧只適用於 JavaScript。本書的第 1 版採用了Java,但很多從未寫過任何 Java 程式碼的程式員也同樣認為這些技巧很有用。作者曾經嘗試過用十多種不同的程式語言來呈現這些範例,以此展示重構手法的通用性,不過這對普通讀者而言只會帶來困惑。本書是為所有程式語言背景的程式員所作,除了閱讀“範例”小節時需要一些基本的 JavaScript 知識,本書的其餘部分都不特定於任何具體的程式語言。希望讀者能汲取本書的內容,並將其應用於自己日常使用的程式語言。具體而言,希望讀者能先理解本書中的 JavaScript 範例程式碼,然後再將其適配到自己習慣的程式語言。
因此,除了在特殊情況下,當談到“類”“模組”“函式”等詞彙時,都按照它們在程式設計領域的一般含義來使用這些詞,而不是以其在 JavaScript 語言模型中的特殊含義來使用。
本書的首要標的讀者群是想要學習重構的軟體開發者,同時對於已經理解重構的人也有價值——本書可以作為一本教學輔助書。在本書中,作者用了大量篇幅詳細解釋各個重構手法的過程和原理,因此有經驗的開發人員可以用本書來指導同事。
下麵我要告訴你,如何能夠在不通讀全書的情況下充分用好它。
-
如果你想知道重構是什麼,請閱讀第 1 章,其中的示例會讓你弄清楚重構的過程。
-
如果你想知道為什麼應該重構,請閱讀前兩章,它們會告訴你重構是什麼以及為什麼應該重構。
-
如果你想知道該在什麼地方重構,請閱讀第 3 章,它會告訴你一些程式碼特徵,這些特徵指出“這裡需要重構”。
-
如果你想著手進行重構,請完整閱讀前四章,然後選擇性地閱讀重構名錄。一開始只需概略瀏覽串列,看看其中有些什麼,不必理解所有細節。一旦真正需要實施某個重構手法,再詳細閱讀它,從中獲取幫助。串列部分是供查閱的參考性內容,你不必一次就把它全部讀完。
給形形色色的重構手法命名是編寫本書的重要部分。合適的詞彙能幫助我們彼此溝通。當一名開發者向另一名開發者提出建議,將一段程式碼提取成為一個函式,或者將計算邏輯拆分成幾個階段,雙方都能理解提煉函式(106)和拆分階段(154)是什麼意思。這份詞彙表也能幫助開發者選擇自動化的重構手法。
《重構:改善既有程式碼的設計(第2版)》
作者:馬丁·福勒(Martin Fowler)
作者:馬丁·福勒(Martin Fowler)
世界軟體開發大師,ThoughtWorks的首席科學家。他是一位作家、演說者、諮詢師和泛軟體開發領域的意見領袖。他致力於改善企業級的軟體設計,對優秀的設計以及支撐優秀設計的工程實踐孜孜以求。他在重構、面向物件分析設計、樣式、XP和UML等領域都有卓越貢獻。著有《重構》《分析樣式》《領域特定語言》等經典著作。