重构,系统改善之道

我常常喜欢把一个系统比喻成一辆车,你需要经常对它做维护和保养,才能保证它的良好运作。如果不这么做,虽然看着能开,但某一天一个严重的问题就会导致极其危险的后果。而持续重构就是我们给系统做的保养,这对于保证系统的稳定运行非常关键。

我曾主导过不少系统重构工作,从中也得出了一些我所认为的最佳实践,希望也能给其他程序员朋友们一些参考。

从构建工具开始

在接手去重构一个新的系统时,我常常会发现他们的构建脚本写得有多糟糕,有的系统甚至根本没有使用构建工具。更可气的是,负责系统的开发人员往往并不把它当回事,这就带来以下一些问题:

  • 自动化程度低下:很多本该由构建工具自动完成的工作,如:编译,测试,部署,都需要人工干预完成,或者由于构建脚本写得不好,本来可以增量编译和部署的,变为每次需要全量编译和部署,修改一行代码只用了一分钟,而等待构建却用了多达5分钟时间。
  • 缺少有效的包依赖与版本管控:构建工具可以帮助我们进行有效的依赖包与版本管理。缺少了它,则很可能造成因不同开发人员引入的第三方包版本不一致所导致的系统问题。
  • 缺少自动化测试覆盖:构建工具能够帮助我们在每次版本构建时,执行自动化测试,这对版本的交付是一个非常有效的质量保证。
  • 不利于团队构建:开发团队总是具有一定流动性的,我们经常需要新人加入团队参与系统的开发。缺乏良好的构建工具,往往迫使每个新人都需要耗费大量的时间去搭建开发环境,这对团队的构建也是非常不利的。

因此,对于我来说,系统重构的第一步便是引入构建工具或重写构建脚本:

  • 引入构建工具:对于后端Java程序来说,我最常使用的便是Groovy,目前也开始尝试使用Gradle。而对于前端来说Grunt或更新的Gulp都是不错的选择。
  • 第三方包依赖与版本管理:通过定义全局属性文件的方式,定义如系统的版本号,名称等信息,并在构建脚本中明确定义引入第三方包的依赖关系与使用的版本。使得整个开发团队都能使用统一且标准的开发环境。
  • 实现自动化:通过定义不同的target(注:Groovy中的一个任务称为target),来实现不同的目标。比如:增量编译与本地部署,自动化测试,打全量版本包等等。总之,将一切需要手工完成的任务,利用工具去帮你完成。
  • 写入开发手册:将构建工具的使用,不同target针对的不同应用场景写入开发手册,能够有效地减少新人的学习成本,并使整个团队开发效率得到提升。

让自动化测试成为重构的保障

我们重构的目的往往是去解决系统的某些痛点,这些痛点也往往是系统的核心功能,因此,在你直接动代码之前,需要详细分析修改可能造成的关联影响。下面是我在做关键功能重构时所采用的步骤:

  • 详细Review该功能的需求
  • 针对需求,完善自动化单元测试案例
  • 将这部分单元测试的执行引入到每次自动化构建中

在大部分我重构过的项目中,起初自动化单元测试都是缺失的。由于对核心功能的重构,往往涉及到大量代码的反复修改,因此,通过引入单元测试,可以非常有效地避免因重构造成的关联影响。而通过重构完善自动化测试,在我看来也是一个很好的重构实践,它将为我们未来的持续重构打下良好的基础。

代码级的持续重构

虽然我们一开始总是能够确保代码的质量,但不可否认,我们的代码会随着时间的推移变得越来越糟。这其中可能包括:

  • 重复的代码,它们可能存在于同一个类或不同类中
  • 不一致或没有标识性的对象、变量或方法命名
  • 过长的代码段
  • 让人费解的布尔表达式
  • 过于复杂的逻辑判断
  • 对象错误地暴露其内部状态
  • 遭废弃但没有删除的类或方法

对于上面这些代码中的坏味道,你应该一有机会就尝试去重构它。但记住,你不应该操之过急,想着一下在把所有问题都一起解决。你只需要先识别出这些问题,然后分步骤地逐步去解决,而每次重构你需要充分识别可能造成的关联影响。如果你已经为你的代码写了单元测试,那你的重构将会有很好的测试保证。如果没有,你也可以尽可能找人帮你review修改的代码,因为不同的人来看你所修改的代码总是能发现不同的东西。

另外,我们现在使用的IDE也能为我们提供很多帮助,比如找出要重构的方法在哪些地方被调用到,或者要重构的类的层级关系等等。它还能帮助我们自动地去重命名一个变量、方法甚至是类。

基于微服务的重构

最后,让我们从架构的角度来看看系统的重构。说到架构,时下最流行的一定是“微服务”架构了。在我看来,微服务并非是一个全新的架构方法论,而是对SOA——面向服务架构的一次升级。它的出现源于云计算、容器技术、DevOps等技术以及全新运维理念的不断成熟。

最近,我正在主导一个遗留系统基于微服务架构的升级工作。在技术层面,虽然业界已经出现了多个支持微服务的架构,我们选择的是Spring Boot,主要是因为它的背后是Spring团队强有力的技术支持与维护。我们的重构也很简单:

  • 服务识别
  • UI与服务的剥离
  • 构建服务

由于采用微服务架构,我们并不会在原有系统上进行重构,而是创建一个新的基于SpringBoot的项目,将原有系统的功能,逐步拆分成一个个服务,添加到新的项目中,然后利用一些开关设置,将原有功能切换到新的基于微服务的系统中,这是与之前系统重构一个很大的区别。

使用微服务框架,可以使开发变得更加简明,然而,它的难点恰恰在于服务的发现与定义。你系统中的哪些服务应该被独立出来,形成对外的服务,服务的粒度又应该是怎样的呢?我在做相关架构时,其实参考了领域驱动设计的思想,先识别出系统所包含的那些领域模型,然后按照领域的划分与不同的粒度来规划系统的服务。


重构虽然无法直接创造业务价值,但却能显著提高系统的可维护性,所以你在重构上所投入的每一分钟,都将转变为未来节省更多的维护时间,这也是为什么我们需要持续重构的原因。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容