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等领域都有卓越贡献。著有《重构》《分析模式》《领域特定语言》等经典著做。