重構20年,呼喚匠藝

1999年,世界軟件開發大師,ThoughtWorks首席科學家馬丁·福勒(Martin Fowler)出版《重構:改善既有代碼的設計》,讀者反饋甚佳,重構(Refactoring)的理念被普遍接納,成爲編程的詞彙表中不可或缺的部分。2019年,恰逢《重構》一書推出20週年,馬丁從新梳理他對重構理念的最新思考,不朽經典重磅升級。程序員

今天,馬丁·福勒(Martin Fowler)在「技術雷達十週年峯會」現場與你們分享過去十年來技術領域的趨勢變化,聆聽Martin的大師觀點。《重構 》第2版,20年後重磅升級,也將在這次會議上新書首發。編程

如今,咱們拿出來了本書的譯者熊節先生的序言,重讀《重構》,呼喚匠藝,與你共勉。小程序


2009年,在爲《重構》第1版的中譯本再版整理譯稿時,我已經隱約察覺行業中對「重構」這個概念的矛盾張力。一方面,在這個「VUCA」(易變、不肯定、複雜、模糊)橫行的年代,有能力調整系統的內部結構,使其更具長期生命力,這是一個使人神往的期許。另外一方面,重構的紮實功夫要學起來、作起來,頗不是件輕鬆的事,且不說詳盡到近乎瑣碎的重構手法,光是單元測試一事,怕是已有九成同行沒法企及。結果,「重構」漸漸成了一塊漂亮的招牌,你們都願意掛上這個名號,可實際上乾的卻可能是「刀劈斧砍」的勾當。promise

現在又是10年過去,只從國內的狀況而論,「重構」概念的表裏分離,大有愈演愈烈之勢。隨着當年的一線技術人員紛紛走上領導崗位,他們樂於將「重構」這塊漂亮招牌用在更寬泛的環境下,例如系統架構乃至組織結構,均可以「重構」一下。然而基本功的欠缺,卻也一路如影隨形。當年在對象中的刀劈斧砍,現在被照搬到了架構、組織的調整。因而「重構」的痛苦回憶又一遍遍重演,甚而程度更深、影響更廣、爲害更烈。安全

此時轉頭看Martin Fowler時隔將近廿載後終於付梓的《重構》第2版,我不由感嘆於他對「微末功夫」的執着。在此書還沒有成型以前,我和當時ThoughtWorks的同事曾有不少猜想,猜Fowler先生是否會在第2版中拔高層次,多談談設計乃至架構級別的重構手法,甚或跟隨「敏捷組織」「精益企業」的風潮談談組織重構,也未爲不可。孰料成書令咱們跌破眼鏡,Fowler先生不只沒有拔高,反而把工夫作得更紮實了。架構

對比先後兩版的重構列表,能夠發現:第2版收錄的重構手法在用途上更加內聚,在操做上更加連貫,更重視重構手法之間的組合運用。第1版中佔了整章篇幅的「大型重構」,在第2版中全數刪去。一些較爲複雜的重構手法,例如複製「被監視數據」、塑造模板函數等,第2版也再也不收錄。而第2版中新增的重構手法,則可能是提煉變量、移動語句、拆分循環、拆分變量這樣更加細緻而微的操做。這些新增的手法看似簡單,但直指大規模遺留代碼中最多見的重構難點,正好補上了第1版中闕漏的細節。這一變化,正反映出Fowler先生對於重構一事一向的態度:千里之行積於跬步,越是面對複雜多變的外部環境,越是要作好基本功、邁出紮實步。框架

識別壞味道、測試先行、行爲保持的變動動做,是重構的基本功。在《重構》第2版裏,重構手法的細節被再度打磨,重構過程比之第1版愈發流暢。細細品味重構手法中的先後步驟,琢磨做者是如何作到行爲保持的,這是能啓發讀者觸類旁通的讀書法。以保持對象完整重構手法爲例,第1版中的作法是在本來函數上新添參數,而第2版的作法則是先新建一個空函數,在其中作完想要的調整以後,再總體替換本來函數。兩相對比,無疑是新的作法更加可控、出錯時測試失敗的範圍更小。async

無獨有偶,我在ThoughtWorks時的同事王健在開展大型的架構重構時,總結了重構的「十六字心法」,恰與保持對象完整重構手法在第2版中這個新的作法暗合。這十六字心法如是說:編程語言

舊的不變,函數

新的建立,

一步切換,

舊的再見。

從這個視角品味一個個重構鉅細靡遺的作法,讀者大概能感覺到重構與「刀劈斧砍」之間最根本的分歧。在不少重構(例如最經常使用的改變函數聲明)的作法中,Fowler先生會引入「很快就會再次修改甚至刪除」的臨時元素。假如只看起止狀態,這些變動過程當中的臨時元素彷佛是浪費:爲什麼不直接一步到位改變到完善的結果狀態呢?然而這些臨時元素所表明的,是對變動過程(而非只是結果)的設計。缺少對過程的精心設計與必要投入,只抱着對結果的美好憧憬提刀上陣,遇到困難就靠「奮鬥精神」和加班解決,這種「刀劈斧砍」不止發生在缺少審慎的「重構」現場,又未嘗不是咱們這個行業的縮影?

是以,重構這門技藝,以及Fowler先生撰寫《重構》的態度,表明的是軟件開發的匠藝——對「正確的作事方式」的重視。在一個浮躁之風日盛的行業中,不少人會強調「只看結果」,輕視作事的過程與方式。然而對於軟件開發的專業人士而言,若是忽視了過程與方式,也就等於放棄了咱們本身的立身之本。Fowler先生近廿載對這本書、對重構手法的精心打磨,給了咱們一個榜樣:一個對匠藝上心的專業人士,日積月累對過程與方式的重視,是能有所成就的。

17年前,我以菜鳥之身讀到《重構》,深受其中蘊涵的工匠精神感召,在Fowler先生與侯捷老師的幫助下,完成了本書第1版的翻譯工做。現在再譯本書第2版,來自ThoughtWorks的青年才俊林從羽君主動請纓與我搭檔合譯,我亦將此視爲匠藝傳承的一樁美事。新一代程序員中,關注新工具、新框架、新商業模式者夥矣,關注面向對象、TDD、重構之類基本功者寥寥。林君年紀雖輕,卻能平心靜氣磨礪技藝,對基本功學而時習,很有老派工匠之風。當年藉由翻譯《重構》一書,我從Fowler先生、侯捷老師身上學到他們的工匠精神,十餘年來時時踐行自勉。現在新一代軟件工匠的表明人物林君接手此書,必會令工匠精神傳承光大。

聽說古時高僧有偈雲:「時時勤拂拭,勿使惹塵埃。」代碼當如是,專業人士的技藝亦當如是。與《重構》的諸位讀者共勉。

01什麼是重構

 

 

所謂重構(refactoring)是這樣一個過程:在不改變代碼外在行爲的前提下,對代碼作出修改,以改進程序的內部結構。重構是一種經千錘百煉造成的有條不紊的程序整理方法,能夠最大限度地減少整理過程當中引入錯誤的機率。本質上說,重構就是在代碼寫好以後改進它的設計。

「在代碼寫好以後改進它的設計」這種說法有點兒奇怪。在軟件開發的大部分歷史時期,大部分人相信應該先設計然後編碼:首先得有一個良好的設計,而後才能開始編碼。可是,隨着時間流逝,人們不斷修改代碼,因而根據原先設計所得的系統,總體結構逐漸衰弱。代碼質量慢慢沉淪,編碼工做從嚴謹的工程墮落爲胡砍亂劈的隨性行爲。

「重構」正好與此相反。哪怕手上有一個糟糕的設計,甚至是一堆混亂的代碼,咱們也能夠藉由重構將它加工成設計良好的代碼。重構的每一個步驟都很簡單,甚至顯得有些過於簡單:只須要把某個字段從一個類移到另外一個類,把某些代碼從一個函數拉出來構成另外一個函數,或是在繼承體系中把某些代碼推上推下就好了。可是,積少成多,這些小小的修改累積起來就能夠根本改善設計質量。這和通常常見的「軟件會慢慢腐爛」的觀點偏偏相反。

有了重構之後,工做的平衡點開始發生變化。做者發現設計不是在一開始完成的,而是在整個開發過程當中逐漸浮現出來。在系統構築過程當中,做者學會了如何不斷改進設計。這個「構築-設計」的反覆互動,可讓一個程序在開發過程當中持續保有良好的設計。

 

02本書有什麼

 

 

本書是一本爲專業程序員編寫的重構指南。做者的目的是告訴你如何以一種可控且高效的方式進行重構。你將學會如何有條不紊地改進程序結構,並且不會引入錯誤,這就是正確的重構方式。

按照傳統,圖書應該以概念介紹開頭。儘管做者也贊成這個原則,可是他發現以歸納性的討論或定義來介紹重構,實在不是一件容易的事。因此他決定用一個實例做爲開路先鋒。

第1章展現了一個小程序,其中有些常見的設計缺陷,我把它重構得更容易理解和修改。其間你能夠看到重構的過程,以及幾個頗有用的重構手法。若是你想知道重構究竟是怎麼回事,這一章不可不讀。

第2章討論重構的通常性原則、定義,以及進行重構的緣由,做者也大體介紹了重構面臨的一些挑戰。第3章由Kent Beck介紹如何嗅出代碼中的「壞味道」,以及如何運用重構清除這些「壞味道」。測試在重構中扮演着很是重要的角色,第4章介紹如何在代碼中構築測試。

從第5章日後的篇幅就是本書的核心部分——重構名錄。儘管不能說是一份鉅細靡遺的列表,卻足以覆蓋大多數開發者可能用到的關鍵重構手法。這份重構名錄的源頭是20世紀90年代後期做者開始學習重構時的筆記,直到今天仍然不時查閱這些筆記,做爲對不甚可靠的記憶力的補充。每看成者想作點什麼——例如拆分階段(154)——的時候,這份列表就會提醒他如何一步一步安全前進。但願這是值得你往後一再回顧的部分。

03JavaScript代碼範例

 

 

與軟件開發中的大多數技術性領域同樣,代碼範例對於概念的闡釋相當重要。不過,即便在不一樣的編程語言中,重構手法看上去也是大同小異的。雖然會有一些值得留心的語言特性,但重構手法的核心要素都是同樣的。

做者選擇了用JavaScript來展示本書中的重構手法,由於感到大多數讀者都能看懂這種語言。不過,即使你眼下正在使用的是別的編程語言,採用這些重構手法也應該不困難。做者儘可能不使用JavaScript任何複雜的特性,這樣即使你對這門編程語言只有粗淺的瞭解,應該也能跟上重構的過程。另外,使用JavaScript展現重構手法,並不表明做者推薦這門編程語言。

使用JavaScript展現代碼範例,也不意味着本書介紹的技巧只適用於JavaScript。本書的第1版採用了Java,但不少從未寫過任何Java代碼的程序員也一樣認爲這些技巧頗有用。做者曾經嘗試過用十多種不一樣的編程語言來呈現這些範例,以此展現重構手法的通用性,不過這對普通讀者而言只會帶來困惑。本書是爲全部編程語言背景的程序員所做,除了閱讀「範例」小節時須要一些基本的JavaScript知識,本書的其他部分都不特定於任何具體的編程語言。但願讀者能汲取本書的內容,並將其應用於本身平常使用的編程語言。具體而言,但願讀者能先理解本書中的JavaScript範例代碼,而後再將其適配到本身習慣的編程語言。

所以,除了在特殊狀況下,當談到「類」「模塊」「函數」等詞彙時,都按照它們在程序設計領域的通常含義來使用這些詞,而不是以其在JavaScript語言模型中的特殊含義來使用。

做者只把JavaScript用做一種示例語言,所以也會盡可能避免使用其餘程序員可能不太熟悉的編程風格。這不是一本「用JavaScript進行重構」的書,而是一本關於重構的通用書籍,只是採用了JavaScript做爲示例。有不少JavaScript特有的重構手法頗有意思(如將回調重構成promise或async/await),但這些不是本書要討論的內容。

 

04你該如何讀?

 

本書的首要目標讀者羣是想要學習重構的軟件開發者,同時對於已經理解重構的人也有價值——本書能夠做爲一本教學輔助書。在本書中,做者用了大量篇幅詳細解釋各個重構手法的過程和原理,所以有經驗的開發人員能夠用本書來指導同事。

儘管本書的關注對象是代碼,但重構對於系統設計也有巨大影響。資深設計師和架構師也頗有必要了解重構原理,並在本身的項目中運用重構技術。最好是由有威望的、經驗豐富的開發人員來引入重構技術,由於這樣的人最可以透徹理解重構背後的原理,並根據狀況加以調整,使之適用於特定工做領域。若是你使用的不是JavaScript而是其餘編程語言,這一點尤爲重要,由於你必須將給出的範例用其餘編程語言改寫。

下面我要告訴你,如何可以在不通讀全書的狀況下充分用好它。

  • 若是你想知道重構是什麼,請閱讀第1章,其中的示例會讓你弄清楚重構的過程。

  • 若是你想知道爲何應該重構,請閱讀前兩章,它們會告訴你重構是什麼以及爲何應該重構。

  • 若是你想知道該在什麼地方重構,請閱讀第3章,它會告訴你一些代碼特徵,這些特徵指出「這裏須要重構」。

  • 若是你想着手進行重構,請完整閱讀前四章,而後選擇性地閱讀重構名錄。一開始只需概略瀏覽列表,看看其中有些什麼,沒必要理解全部細節。一旦真正須要實施某個重構手法,再詳細閱讀它,從中獲取幫助。列表部分是供查閱的參考性內容,你沒必要一次就把它所有讀完。

給形形色色的重構手法命名是編寫本書的重要部分。合適的詞彙能幫助咱們彼此溝通。當一名開發者向另外一名開發者提出建議,將一段代碼提取成爲一個函數,或者將計算邏輯拆分紅幾個階段,雙方都能理解提煉函數(106)和拆分階段(154)是什麼意思。這份詞彙表也能幫助開發者選擇自動化的重構手法。

 

《重構:改善既有代碼的設計(第2版)》

做者:馬丁·福勒(Martin Fowler)

 

本書是經典著做《重構》出版20年後的更新版。書中清晰揭示了重構的過程,解釋了重構的原理和最佳實踐方式,並給出了什麼時候以及何地應該開始挖掘代碼以求改善。書中給出了60多個可行的重構,每一個重構都介紹了種通過驗證的代碼變換手法的動機和技術。本書提出的重構準則將幫助開發人員小步地修改代碼,從而減小了開發過程當中的風險。

本書適合軟件開發人員、項目管理人員等閱讀,也可做爲高等院校計算機及相關專業師生的參考讀物。

做者:馬丁·福勒(Martin Fowler)

世界軟件開發大師,ThoughtWorks的首席科學家。他是一位做家、演說者、諮詢師和泛軟件開發領域的意見領袖。他致力於改善企業級的軟件設計,對優秀的設計以及支撐優秀設計的工程實踐孜孜以求。他在重構、面向對象分析設計、模式、XP和UML等領域都有卓越貢獻。著有《重構》《分析模式》《領域特定語言》等經典著做。

相關文章
相關標籤/搜索