文档章节

重构20年,呼唤匠艺

o
 osc_fmg49rzg
发布于 2019/03/20 13:23
字数 4653
阅读 14
收藏 0

精选30+云产品,助力企业轻松上云!>>>

1999年,世界软件开发大师,ThoughtWorks首席科学家马丁·福勒(Martin Fowler)出版《重构:改善既有代码的设计》,读者反馈甚佳,重构(Refactoring)的理念被广泛接纳,成为编程的词汇表中不可或缺的部分。2019年,恰逢《重构》一书推出20周年,马丁重新梳理他对重构理念的最新思考,不朽经典重磅升级。

今天,马丁·福勒(Martin Fowler)在“技术雷达十周年峰会”现场与大家分享过去十年来技术领域的趋势变化,聆听Martin的大师观点。《重构 》第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先生近廿载对这本书、对重构手法的精心打磨,给了我们一个榜样:一个对匠艺上心的专业人士,日积月累对过程与方式的重视,是能有所成就的。

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

 

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。
提升代码内外部质量的22条经验

本文主要关注代码的内部和外部质量,编程的价值观,代码质量的评估标准,整洁代码的匠艺以及如何维护已有的代码。 外部质量:用户所能感受到的部分,正确性,易用性,效率,可靠性。 内部质量...

葡萄城控件技术团队
2014/06/11
27
0
提升代码内外部质量的22条经验

本文主要关注代码的内部和外部质量,编程的价值观,代码质量的评估标准,整洁代码的匠艺以及如何维护已有的代码。 外部质量:用户所能感受到的部分,正确性,易用性,效率,可靠性。 内部质量...

幕三少
2013/09/26
0
0
提升代码内外部质量的22条经验

本文主要关注代码的内部和外部质量,编程的价值观,代码质量的评估标准,整洁代码的匠艺以及如何维护已有的代码。 外部质量:用户所能感受到的部分,正确性,易用性,效率,可靠性。 内部质量...

Yamazaki
2013/09/18
6
0
提升代码内外部质量的22条经验

原创作品,允许转载,转载时请务必以超链接形式标明文章原始出处 、作者信息和本声明。否则将追究法律责任。http://powertoolsteam.blog.51cto.com/2369428/1298688 本文主要关注代码的内部和...

crystaltiger
2013/09/29
24
0
小书匠更新说明

小书匠编辑器更新手册 小书匠 编辑器 更新手册 1.1.01 1.1.01 新功能 客户端实现文件关联打开。window系统自动关联.md,.markdown两种扩展名。其他系统用户自己可进行修改文件关联,命令行执...

booksmith
2015/02/08
23
0

没有更多内容

加载失败,请刷新页面

加载更多

setShadowLayer阴影与SetMaskFilter发光效果

一、setShadowLayer构造函数 public void setShadowLayer(float radius, float dx, float dy, int color) radius:模糊半径,radius越大越模糊,越小越清晰,但是如果radius设置为0,则阴...

IamOkay
3分钟前
0
0
做儿媳的,千万不要把婆婆当亲妈看

我和老公结婚有三四个年头了,还生育了两个调皮可爱的孩子。在别人眼里,我就像掉进了福窝里一样。然而我有时候在老公面前耍小性子,撒娇卖萌什么样的,婆婆却指责我不守妇道。 结婚起初婆家...

创业hzcya
13分钟前
0
0
多线程之线程部分

① 进程与线程 程序、进程、线程、协程的概念 程序: 用某种语言编写的一组指令的集合,即指一段静态的代码; 进程:简单地说就是一个正在执行的程序或应用,是资源分配的最小单位; 线程:线...

Arno_pei
25分钟前
0
0
08VulKan——描述符布局、缓冲、描述符池和描述符集

整体思想: 对于一些所有顶点都共享的属性,比如顶点的变换矩阵,将它们作为顶点属性为每个顶点都传递一份显然是非常浪费的 。VulKan提出使用资源描述符解决这种全局变量, 描述符是用来在着...

黑白双键
36分钟前
7
0
将分段视频合并

环境 操作系统:Ubuntu Kylin 优麒麟 20.04 LTS 适用架构:AMD64、ARM64(鲲鹏、飞腾) 方法 将下载的视频分片段放入同一个文件夹。按片段排序的文件名汇入list.txt。 ls qq_video*.mp4 | s...

chipo
39分钟前
13
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部