重构之十六字心法

文/ThoughtWorks 王健

这篇文章是我写过的所有文章里最难产的一篇,前前后后斟酌酝酿了好几个月。因为重构对于我来讲真的太重要也太深刻了,包含的内容和想说的也太多了。如果说这几年自己觉得在哪些方面的收获最大的话,非重构莫属了。

重构的威力

软件开发的难点在于不确定性,前几天邱大师刚写了一篇《软件开发为什么很难》就提到

软件的复杂性来自于大量的不确定性,而这个不确定事实上是无法避免的。

需求在变,语言在变,框架在变,工具在变,框架在变,架构在变,趋势在变,甚至连组织结构都在不断的变化。

随着变化的不断产生,软件变得越来越复杂。就像《架构腐化之谜》中提到的一样,我们的软件也会像一个生命体,经历从新生到衰老腐化的过程。而重构就像是一次手术,通过优化内部结构,减慢腐化衰老,让软件“青春永驻”,可见重构的威力。

重构教会了我如何通过高效安全地改善内部设计以使之适应外部的不确定性和频繁变化。

重构威力无边,就像是武侠小说中的一件插在石头上的上古神器,但同样也不是一般人可以轻松驾驭的。如果运用不当,造成的损害也会同样巨大。

如何将重构这件神器运用自如,发挥其最大的威力,也是我一直在探寻的,即重构的手法和心法。

合格的重构

在谈手法和心法之前,可能很多人会有疑惑,觉得重构并不像你说的那么难啊,我们每天都在做,就是改改代码改改设计,哪有你说的那么邪乎。那我就先来讲讲我认为怎么样才算是一次合格的重构。

对于什么是重构,《重构》书中已经有明确的定义,分名词和动词两种形式。

重构(名词):对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。
重构(动词):使用一系列重构手法,在不改变软件可观察行为的前提下,调整其结构。

就像“看板”不是“我们看到的那个白板”一样,“重构”也不是“重新修改代码”那么简单。

我就看到过太多打着重构的幌子,把系统改的面目全非,最后出了问题直接甩锅到重构身上的场景了。那怎样才算是一次合格的重构呢?我觉得至少需要做到以下几点:

  • 消除味道:一个重构应该是从识别一个坏味道(Bad Smell)开始,以消除一个坏味道结束,任何不以消除坏味道为目标的重构都是耍流氓。
  • 始终工作:即重构定义中的“在不改变软件可观察行为的前提下”,说白了就是重构过程不能破坏甚至改变软件外在功能。
  • 持续集成:不需要为重构单建分支,重构过程可以做到Feature开发在同一分支上持续集成持续交付。
  • 随时中止:例如一个方法重命名,需要修改100个调用点,当改到50个的时候有个紧急的Feature,我可以随时暂停重构,立即切换到Feature开发上,且不需要回滚已做的重构。
  • 断点续传:还是上边的例子,假如我已经完成了紧急Feature的开发,可以随时继续之前的重构,完成剩下50个调用点的重命名。
  • 过程可逆:对于重构,经常有人会问:你怎么保证重构就会更好而不是更坏呢?重构的伟大就在于他跳出了对错之争,将关注点放到如何快速平滑安全的变化上,当然也包括反向重构。所以我的回答是:无法保证,但是我可以一分钟就重构回来。如果仔细看,《重构》书里的所有重构手法都是双向的,比如“Extract Method”和“Inline Method”。

可以反思一下,我们平时自认为的那些重构,是否都符合了以上的这些要求?

  • 多少次我们打着重构的旗号,七零八碎,无法复原。
  • 多少次我们打着重构的旗号,分支开发,集成困难。
  • 多少次我们打着重构的旗号,半途而废,迷途难返
  • 多少次我们打着重构的旗号,孤注一掷,进退两难。

在我的眼里,这些都不是合格的重构,甚至都不能称之为重构,好的重构应该像一边开车一边换轮胎一样,保证系统随时可工作的前提下,还可以对其结构做出安全高效的调整。

可见重构并不简单,那要怎样才能达到上述的那些要求呢?

重构的心法

在过去的几年,我一直在学习和思考重构的各种手法。从刚开始的乱改一气,到学习基于IDE和插件的各种快捷键流的重构手法,以及研究如何通过组合各种基础重构手法形成“连招”,从而快速实现更复杂的重构过程。

随着对于基于IDE的快捷键重构手法越来越娴熟,在IDE和插件的帮助下,我的重构手法越来越华丽而迅捷,在沾沾自喜的同时心里也慢慢萌生了一些质疑:难道这就是重构么?如果没有IDE没有了插件,我还会做重构么?如何用编辑器(Vim,Emacs)做重构?重构只是代码级别的么?数据库如何重构呢?系统架构如何重构呢?工具框架如何重构呢?微服务架构下的服务重构呢?公司组织重构呢?

这种感觉就像是武侠小说中的某个柔弱书生,无意中掉到了一个悬崖下,找到了一本武林秘籍,照着上边的招式练了练就自以为已绝学在身,结果出去虽然能招架一时,但禁不住更大的挑战。被打的体无完肤后,重新掏出那本秘籍,收起浮躁,怀着诚敬之心努力去参悟那些招式背后更深的哲理,也就是所谓的心法。此时对于我来说,而那本武林秘籍就叫做《重构》

在带着这些疑问重读《重构》的过程中,我欣喜地发现书中那些细致入微但看似笨拙拖沓的重构手法(例如Rename,使用现代IDE一个快捷键就可以搞定,但是老马用了很多步骤才完成),其实都蕴含着重构最重要最基本的原则和思路,只要按着这些原则去做,无论什么层次的重构:代码重构、架构重构、服务重构甚至是组织重构,都可以做到上面提到的一个合格重构的基本要求,即平滑安全可停可续。

把其中的原则思路抽取出十六个字,即所谓的:重构十六字心法

解释起来也很简单,往往我们做”重构“的时候就是在旧的结构(这里的结构可以是一个方法、一个对象、一个服务、一个数据库、一个服务甚至是一个组织结构)上直接修改,导致系统长时间处于一个中间不可用状态,这个状态持续的时间越长,”重构“失败的可能性和负面影响就会越大。

而《重构》告诉我们,做内部结构调整时,先不要直接修改旧的结构,保持旧的结构不变,先按照新的设计思路创建一个新的结构,因为这个过程中对于旧的内部结构没有任何影响,所以是安全的,可持续集成的。当新的结构构件完成时,我们再把对于旧结构的依赖一个个的切换到新的结构上,即所谓的”一步切换“。最后当确认所有对于旧的结构都切换到新的结构上,而且没有问题后,再将已经没有任何引用的旧结构删除掉,完成整个重构过程。

这里的“一步切换”并不是说整个重构的切换过程必须是一步完成的,例如前面重命名的例子,100个调用点的切换可能是分多次完成的,在这个例子里一步切换指的是每一个调用点的切换过程。这个切换过程是最容易暴露出问题的,所以越简单越快速越好,一旦出现了问题,就快速的切换回旧的结构后再慢慢排查问题,从而实时保证系统的可用性。

大道至简,一旦领悟并掌握了这个心法,就发现自己一下从之前狭义的代码重构中跳脱出来,任何广义上的重构都立刻变得有章可循。

在架构重构中常用的抽象分支(BranchByAbstraction),以及在微服务架构下服务重构常用到的绞杀者模式,其实都是这种原则的一种体现。

总结

重构可以使软件更容易地被修改和被理解。通过不断地改进软件设计以达到简单设计的目标,减少由于设计与业务的不匹配带来的架构与设计腐化。

掌握了重构的手法和心法,会让重构变得更加简单安全高效可控,从而真正的发挥出其巨大的威力,让我们的软件永葆青春。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容

  • 这篇文章是我写过的所有文章里最难产的一篇,前前后后斟酌酝酿了好几个月。因为重构对于我来讲真的太重要也太深刻了,包含...
    王健_TW阅读 4,748评论 7 39
  • 重构的威力 软件的复杂性来自于大量的不确定性,而这个不确定事实上是无法避免的。 需求在变,语言在变,软件的复杂性来...
    蜡笔晓晓新阅读 468评论 0 0
  • 重构的定义: 所谓重构是这样一个过程:在不改变代码外在行为的前提下,对代码做出修改,以改进程序的内部结构。 重构是...
    天色将变阅读 1,412评论 0 1
  • 为什么要重构 你可能正在面对一个遗留系统,增加一个需求要改动好几个文件,定位 Bug 经常要花掉一整天时间,修复一...
    SeabornLee阅读 5,571评论 7 30
  • 引言 Martin Fowler的《重构:改善既有代码的设计》一书从问世至今已有十几年时间了,按照计算机领域日新月...
    MagicBowen阅读 4,593评论 3 9