2月5-7日QCon全球软件开发大会携手100+位大咖讲师落定北京,点击查看完整日程>> 了解详情
写点什么

重构之十六字心法(二)

  • 2020-01-16
  • 本文字数:2436 字

    阅读完需:约 8 分钟

重构之十六字心法(二)

合格的重构

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


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


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

重构(动词):使用一系列重构手法,在不改变软件可观察行为的前提下,调整其结构。

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


我就看到过太多打着重构的幌子,把系统改的面目全非,最后出了问题直接甩锅到重构身上的场景了。


那怎样才算是一次合格的重构呢?我觉得至少需要做到以下几点:


  • 消除味道:一个重构应该是从识别一个坏味道(Bad Smell)开始,以消除一个坏味道结束,任何不以消除坏味道为目标的重构都是耍流氓。

  • 始终工作:即重构定义中的“在不改变软件可观察行为的前提下”,说白了就是重构过程不能破坏甚至改变软件外在功能。

  • 持续集成:不需要为重构单建分支,重构过程可以做到 Feature 开发在同一分支上持续集成持续交付。

  • 随时中止:例如一个方法重命名,需要修改 100 个调用点,当改到 50 个的时候有个紧急的 Feature,我可以随时暂停重构,立即切换到 Feature 开发上,且不需要回滚已做的重构。

  • 断点续传:还是上边的例子,假如我已经完成了紧急 Feature 的开发,可以随时继续之前的重构,完成剩下 50 个调用点的重命名。

  • 过程可逆:对于重构,经常有人会问:你怎么保证重构就会更好而不是更坏呢?重构的伟大就在于他跳出了对错之争,将关注点放到如何快速平滑安全的变化上,当然也包括反向重构。所以我的回答是:无法保证,但是我可以一分钟就重构回来。如果仔细看,《重构》书里的所有重构手法都是双向的,比如「Extract Method」和「Inline Method」。


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


  • 多少次我们打着重构的旗号,七零八碎,无法复原。

  • 多少次我们打着重构的旗号,分支开发,集成困难。

  • 多少次我们打着重构的旗号,半途而废,迷途难返。

  • 多少次我们打着重构的旗号,孤注一掷,进退两难。


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



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


重构的心法

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


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


这种感觉就像是武侠小说中的某个柔弱书生,无意中掉到了一个悬崖下,找到了一本武林秘籍,照着上边的招式练了练就自以为已绝学在身,结果出去虽然能招架一时,但禁不住更大的挑战。


被打的体无完肤后,重新掏出那本秘籍,收起浮躁,怀着诚敬之心努力去参悟那些招式背后更深的哲理,也就是所谓的心法。


此时对于我来说,而那本武林秘籍就叫做《重构》。



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


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



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


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


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


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


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


总结

重构可以使软件更容易地被修改和被理解。


通过不断地改进软件设计以达到简单设计的目标,减少由于设计与业务的不匹配带来的架构与设计腐化。


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


本文转载自健荐公众号。


原文链接:https://mp.weixin.qq.com/s/SyKu1m7FVXzB5fInmj44wQ


2020-01-16 17:53475

评论

发布
暂无评论
发现更多内容

Linux安装JDK并配置环境变量 - 详细步骤,被腾讯辞退的高级Java工程师现在怎么了

Java 程序员 后端

Matlab数值微分与数值积分,linux环境高级编程

Java 程序员 后端

Maven虐我千百遍,我待Maven如初恋!,mongodb教程

Java 程序员 后端

MyBatis07:使用注解开发,java教程视频我赢职场

Java 程序员 后端

Kafka-探险---生产者源码分析---核心组件,2021年Java社招面试题精选

Java 程序员 后端

为什么一定要学习设计模式

Tom弹架构

Java 架构 设计模式

Kurento实战之五:媒体播放,mysql高级教程ppt

Java 程序员 后端

Mybatis学习笔记--延迟加载与缓存,深入分析解读MySQL锁,解决幻读问题

Java 程序员 后端

MyBatis初级实战之二:增删改查,java项目开发实战入门光盘

Java 程序员 后端

JVM知识点总览,实战java虚拟机第二版

Java 程序员 后端

Kafka消费组核心API与核心参数运行机制剖析,java银行面试题目及答案

Java 程序员 后端

MyBatis初级实战之三:springboot集成druid,java实用教程第五版

Java 程序员 后端

Linux怎么学?一张思维导图带你深入Linux核心原理,mybatis基础面试题

Java 程序员 后端

Mybatis入门篇之结果映射,你射准了吗?,java框架ssh和ssm百度

Java 程序员 后端

Mybatis学习笔记--自定义Mybatis,java数据结构面试题及答案

Java 程序员 后端

Mybatis学习笔记--多表查询,java入门基础代码

Java 程序员 后端

MyBatis官方文档-入门,java开发工程师技术栈

Java 程序员 后端

K8S的StorageClass实战(NFS),java程序设计任务驱动式教程

Java 程序员 后端

Kafka的生产者原理及重要参数说明,大厂程序员35岁后的职业出路在哪

Java 程序员 后端

Kubernetes官方java客户端之四:内部应用,孙鑫java视频教程百度网盘

Java 程序员 后端

mybatis学习一之入门示例,阿里+头条+腾讯等大厂Java面试题分享

Java 程序员 后端

Mybatis学习笔记--Mybatis的概念与入门案例,java中高级面试题最新

Java 程序员 后端

Kafka-Java客户端数据生产流程解析,从发送类型实现代码到序列化器实现代码!

Java 程序员 后端

Kubernetes实战(一)-Kubernetes集群搭建,java注解扫描原理

Java 程序员 后端

Maven虐我千百遍,我待Maven如初恋!(1),springcloud实战演练

Java 程序员 后端

linux中route命令超详细用法(十五万字),nginx实战基于luapdf

Java 程序员 后端

JVM探究:全面解析OOM异常,都在这了,windows内核编程全套视频教程

Java 程序员 后端

K8S的Kafka监控(Prometheus+Grafana),java语法规则视频

Java 程序员 后端

Kubernetes官方java客户端之八:fluent style,java语言视频教学

Java 程序员 后端

Kotlin(1)-lambda表达式和高阶函数操作符,java面试资料推荐

Java 程序员 后端

Lua+OpenResty+nginx,java菜鸟教程集合

Java 程序员 后端

重构之十六字心法(二)_文化 & 方法_王健_InfoQ精选文章