最近重读了Martin Fowler的经典著作《重构:改善既有代码的设计》,这本书,可以说是,每个程序员,都应该读的,经典书籍,之一。第一次读,的时候,我,还是,一个,刚入行的,新人,很多内容,都,看不太懂,也,没有,太深的,体会。这次重读,结合,这几年的,工作经验,和,踩过的坑,我,对重构,有了,完全不同的,理解,也,终于明白了,这本书,为什么,能成为经典,为什么,能影响,一代又一代的,程序员。

今天这篇文章,就来整理一下,《重构》的读书笔记,聊聊什么是重构,为什么要重构,以及这本书对我的影响和启发。

一、先说说这本书和作者

先简单说说,这本书,和,作者。

Martin Fowler,是,世界,著名的,软件,工程师,和,作家,也是,敏捷开发,的,创始人,之一,他,在,软件,设计,和,架构,方面,有,很深的,造诣,写了,很多,经典的,书籍,比如,《重构》《分析模式》《企业应用架构模式》《领域特定语言》等等,每一本,都是,经典,都,影响了,很多,程序员。

《重构:改善既有代码的设计》,这本书,第一版,出版于,1999年,到现在,已经,20年了,但是,里面的,内容,依然,不过时,依然,很,有,价值,2018年,Martin Fowler,又,出版了,第二版,更新了,一些,内容,把,例子,从Java,改成了,JavaScript,也,增加了,一些,新的,重构,手法,但是,核心的,思想,和,原则,没有,变。

这本书,的,核心,内容,就是,教,我们,如何,系统地,改善,既有代码,的,设计,在,不,改变,代码,外部,行为,的,前提下,调整,代码,的,结构,让,代码,更,容易,理解,更,容易,修改,更,有,质量。

这本书,分为,几个,部分,首先,介绍了,什么,是,重构,为什么,要,重构,重构,的,原则,和,流程,然后,介绍了,代码,的,坏味道,也就是,哪些,代码,需要,重构,最后,详细,介绍了,几十种,重构,的,手法,每种,手法,都,有,详细的,步骤,和,例子,很,实用,也,很,系统。

我,第一次读,这本书,的时候,是,刚,入行,不久,那时候,写代码,只,追求,能,跑,起来,就行,根本,不,关心,代码,的,质量,也,不,懂,什么,设计,什么,重构,所以,看,这本书,的,时候,很多,内容,都,看不太懂,也,觉得,没,什么,用,觉得,代码,能,跑,就行,搞,那么,多,花里胡哨的,干什么。

但是,工作,了,几年,之后,写了,很多,代码,也,维护,了,很多,别人,写的,烂代码,踩了,很多,坑,才,慢慢,明白,代码,质量,的,重要性,也,明白,了,重构,的,重要性,这,时候,再,重读,这本书,才,发现,这本书,真的,是,太,经典,了,里面,说的,很多,东西,都是,我,踩过的,坑,都是,我,在,工作,中,遇到的,问题,而,这本书,早就,给了,我们,系统的,解决方案。

所以,我,强烈,建议,每个,程序员,都,应该,读,这本书,而且,最好,是,工作,了,几年,有,一定,经验,之后,再,读,这样,体会,会,更,深,收获,会,更,大。

二、什么是重构?

先说说,什么,是,重构。

很多人,一听,重构,就,觉得,是,把,代码,全部,重写,一遍,或者,是,大规模地,修改,代码,其实,不是,这样的。

Martin Fowler,在,书,里,给,重构,的,定义,是:

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

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

简单来说,重构,就是,在,不,改变,代码,功能,的,前提下,调整,代码,的,结构,让,代码,更,容易,理解,更,容易,修改,质量,更高。

重构,的,核心,有,两个,关键点:

  1. 不改变外部行为:重构,之后,代码,的,功能,和,之前,一样,用户,感知,不到,任何,变化,输入,一样,输出,也,一样,只是,内部,的,代码,结构,变了。
  2. 改善内部结构:重构,的,目的,是,改善,代码,的,内部,结构,让,代码,更,清晰,更,简洁,更,容易,理解,更,容易,修改,降低,维护,成本。

所以,重构,不是,重写,重写,是,把,代码,全部,推倒,重来,而,重构,是,在,现有,代码,的,基础,上,逐步,调整,改善,结构,不,改变,功能。

而且,重构,是,小步,的,增量的,不是,一步到位,的,每次,只,做,一个,小的,调整,测试,通过,之后,再,做,下,一个,调整,这样,就算,出了,问题,也,很,容易,回退,不会,影响,太大。

很多人,对,重构,有,误解,觉得,重构,就是,瞎折腾,就是,为了,技术,而,技术,其实,不是,重构,是,为了,让,代码,更,容易,维护,降低,维护,成本,提高,开发,效率,是,很,有,价值,的,事情。

三、为什么要重构?

再说说,为什么,要,重构。

很多人,会,问,代码,能,跑,就行,为什么,要,花,时间,去,重构,呢?重构,又,不,能,带来,新的,功能,用户,也,感知,不到,有,什么,用,呢?

Martin Fowler,在,书,里,说了,重构,的,几个,重要,原因:

1. 重构,能,改进,软件,的,设计

如果,不,重构,代码,的,设计,会,越来越,腐化,因为,我们,在,添加,新功能,的,时候,往往,是,在,现有,代码,的,基础,上,打补丁,而,不是,从,整体,设计,的,角度,去,考虑,时间,长,了,代码,的,设计,就,会,越来越,乱,越来越,难,理解,越来越,难,修改。

而,重构,能,帮,我们,整理,代码,的,结构,改善,代码,的,设计,让,代码,的,结构,更,清晰,更,合理,更,容易,理解,和,修改。

2. 重构,能,让,软件,更,容易,理解

代码,是,写给,人,看的,不是,只,写给,机器,看的,我们,写,的,代码,不仅,要,能,跑,起来,还要,能,让,其他,程序员,容易,理解,这样,别人,才能,容易,维护,和,修改。

但是,很多,代码,写,得,很,乱,很,难,理解,别人,看,半天,都,看,不,懂,这样,的,代码,维护,成本,很,高,也,很,容易,出,bug。

重构,能,帮,我们,把,难,理解,的,代码,改成,容易,理解,的,代码,比如,把,很长的,函数,拆,成,几个,小,函数,把,难懂的,变量,名,改成,有,意义,的,名字,把,复杂的,条件,判断,简化,等等,这样,代码,就,更,容易,理解,了。

3. 重构,能,帮助,找到bug

重构,的,过程,中,我们,需要,仔细,阅读,和,理解,代码,这,时候,往往,能,发现,一些,隐藏,的,bug,因为,很多,bug,都,藏在,复杂的,难,理解,的,代码,里,当,我们,把,代码,重构,得,更,清晰,的,时候,这些,bug,就,会,暴露,出来。

而且,重构,之后,代码,更,清晰,更,容易,理解,我们,也,更,容易,发现,潜在的,问题,和,bug。

4. 重构,能,提高,编程,速度

很多人,觉得,重构,会,耽误,时间,影响,开发,速度,其实,不是,这样的,短期,来看,重构,确实,会,花,一些,时间,但是,长期,来看,重构,能,大大,提高,开发,速度。

因为,如果,代码,质量,差,设计,乱,难,理解,难,修改,那么,每次,添加,新功能,的,时候,都,要,花,很多,时间,去,理解,现有,代码,去,和,烂代码,作斗争,而且,很,容易,引入,新的,bug,又,要,花,时间,去,修bug,这样,开发,速度,就,会,越来越,慢。

而,如果,代码,质量,好,设计,清晰,容易,理解,容易,修改,那么,添加,新功能,的,时候,就,很,快,很,顺利,也,不,容易,出,bug,这样,长期,来看,开发,速度,反而,更,快。

所以,重构,不是,耽误,时间,而是,为了,以后,更,快,是,很,有,价值,的,投资。

四、什么时候重构?

再说说,什么时候,重构。

很多人,觉得,重构,是,一个,专门,的,阶段,要,专门,留出,一段时间,来,做,重构,其实,不是,这样的,Martin Fowler,说,重构,应该,随时随地,做,而,不是,专门,留出,时间,做。

他,提出了,几个,重构,的,时机:

1. 三次法则,事不过三,三则重构

这,是,重构,的,一个,重要,原则,意思,是,第一次,做,一件事,直接,做,就,行,第二次,做,类似,的,事,虽然,反感,但是,还是,可以,重复,做,第三次,做,类似,的,事,就,应该,重构,了,不要,再,重复,了。

因为,重复,的,代码,是,代码,坏味道,的,一种,重复,越多,维护,成本,越高,修改,的,时候,要,改,好,几个,地方,很,容易,漏,所以,当,你,第三次,写,类似,的,代码,的,时候,就,应该,重构,把,重复,的,代码,抽,出来,复用。

2. 添加功能,的,时候,重构

当,你,要,添加,新功能,的,时候,如果,发现,现有,代码,的,结构,不,太,好,不,容易,添加,新功能,那么,就,先,重构,一下,现有,代码,让,它,更,容易,添加,新功能,然后,再,添加,新功能。

这样,虽然,短期,看,花,了,一些,时间,重构,但是,添加,新功能,的,时候,会,更,顺利,更,快,而且,代码,质量,也,更,好。

3. 修bug,的,时候,重构

当,你,要,修,一个,bug,的,时候,如果,发现,代码,很,乱,很,难,理解,导致,bug,很难,找,那么,就,先,重构,一下,代码,让,代码,更,清晰,更,容易,理解,然后,bug,就,会,更容易,发现,也,更容易,修复。

而且,重构,之后,代码,更,清晰,以后,再,出,bug,也,更容易,修复。

4. 代码评审,的,时候,重构

代码评审,的,时候,往往,能,发现,很多,代码,的,问题,和,坏味道,这,时候,就,可以,提出,重构,的,建议,让,代码,的,作者,去,重构,或者,一起,重构。

代码评审,是,发现,代码,问题,的,好,时机,也是,推动,重构,的,好,时机。

总之,重构,应该,随时随地,做,融入,到,日常,的,开发,工作,中,而,不是,专门,留出,一个,阶段,做,专门,的,重构,阶段,往往,效果,不,好,因为,重构,的,需求,是,在,日常,开发,中,不断,出现的,随时随地,重构,才,是,最,有效,的。

五、代码的坏味道

Martin Fowler,在,书,里,列举了,很多,代码,的,坏味道,也就是,哪些,代码,需要,重构,下面,说说,几个,常见,的,坏味道。

1. 神秘命名

变量,函数,类,的,名字,起,得,很,神秘,让人,看,不,懂,比如,用,a,b,c,这样,的,变量,名,或者,用,很,奇怪,的,缩写,别人,看,半天,都,看,不,懂,这,就是,神秘命名,的,坏味道。

好的,名字,应该,能,清楚,地,表达,它,的,含义,让人,一看,就,懂,不用,猜,所以,当,你,发现,代码,里,有,神秘,的,名字,就,应该,重构,改成,有,意义,的,名字。

2. 重复代码

重复,代码,是,最,常见,的,坏味道,也是,最,应该,重构,的,坏味道,相同,或者,类似,的,代码,出现在,多个,地方,这,就是,重复代码。

重复代码,的,危害,很大,修改,的,时候,要,改,好,几个,地方,很,容易,漏,而且,维护,成本,很高,所以,当,发现,重复代码,的,时候,就,应该,重构,把,重复,的,代码,抽,出来,做成,函数,或者,类,复用。

3. 过长函数

函数,太长,比如,一个,函数,有,几百行,甚至,上千行,这,就是,过长函数,的,坏味道,过长,的,函数,很,难,理解,也,很,难,修改,很,容易,出,bug。

好的,函数,应该,短小,精悍,一个,函数,只,做,一件,事,而且,做好,所以,当,发现,过长,的,函数,就,应该,重构,把,它,拆,成,几个,小,函数,每个,小,函数,做,一件,事,这样,代码,更,容易,理解,也,更,容易,复用。

4. 过大的类

类,太大,负责,的,事情,太多,属性,和,方法,太多,这,就是,过大的类,的,坏味道,过大,的,类,往往,违反,了,单一职责,原则,一个,类,做,了,太多,的,事情,很,难,理解,也,很,难,维护。

好的,类,应该,职责,单一,一个,类,只,负责,一个,功能,所以,当,发现,过大,的,类,就,应该,重构,把,它,拆,成,几个,小,类,每个,类,负责,一个,功能,这样,代码,更,清晰,也,更,容易,维护。

5. 过长参数列表

函数,的,参数,太多,比如,一个,函数,有,七八个,甚至,十几个,参数,这,就是,过长参数列表,的,坏味道,参数,太多,的,函数,很,难,调用,也,很,难,理解,很,容易,传,错,参数。

如果,参数,之间,有,关联,可以,把,这些,参数,封装,成,一个,对象,用,对象,作为,参数,这样,参数,就,简化,了,也,更,容易,理解,和,维护。

6. 发散式变化

一个,类,因为,不同,的,原因,在,不同,的,方向,上,发生,变化,比如,一个,类,既有,数据库,操作,又,有,业务,逻辑,又,有,界面,显示,这样,不同,的,变化,都会,影响,这个,类,这,就是,发散式变化,的,坏味道。

这样,的,类,职责,不,单一,很,难,维护,应该,把,不同,职责,的,代码,拆,到,不同,的,类,里,每个,类,只,因为,一个,原因,而,变化。

7. 霰弹式修改

如果,每,遇到,一个,变化,都,要,在,多个,不同,的,类,里,做,很多,小,修改,这,就是,霰弹式修改,的,坏味道,就,像,霰弹枪,一样,打,一片,到处,都,要,改。

这样,的,代码,修改,起来,很,麻烦,很,容易,漏,应该,把,相关,的,代码,搬,到,同一个,类,里,这样,修改,的,时候,只,要,改,一个,类,就,行,了。

8. 依恋情结

一个,函数,对,某个,类,的,兴趣,高过,对,自己,所在,类,的,兴趣,比如,一个,函数,大部分,时间,都,在,调用,另一个,类,的,方法,访问,另一个,类,的,数据,这,就是,依恋情结,的,坏味道。

这样,的,函数,应该,搬,到,它,依恋,的,那个,类,里,这样,更,合理,也,更,容易,理解,和,维护。

9. 数据泥团

很多,数据,总是,成群结队,地,出现,在,多个,地方,比如,用户,的,姓名,电话,地址,总是,一起,出现,在,多个,函数,的,参数,里,这,就是,数据泥团,的,坏味道。

这样,的,数据,应该,封装,成,一个,对象,比如,用户,信息,对象,这样,代码,更,清晰,也,更,容易,维护。

10. 基本类型偏执

总是,用,基本,类型,来,表示,简单,的,概念,比如,用,字符串,表示,电话号码,用,整数,表示,金额,这,就是,基本类型偏执,的,坏味道。

简单,的,概念,应该,封装,成,类,比如,电话号码,类,金额,类,这样,能,提供,更多,的,操作,也,更,安全,更,容易,维护。

这些,都是,常见,的,代码,坏味道,当,你,在,代码,里,发现,这些,坏味道,的,时候,就,应该,考虑,重构,了,把,这些,坏味道,去掉,代码,质量,就,会,提高,很多。

六、重构的原则

再说说,重构,的,原则,这,是,重构,的,指导,思想,很,重要。

1. 重构,不,改变,外部,行为

这,是,重构,最,核心,的,原则,重构,的,过程,中,代码,的,外部,行为,不能,改变,输入,一样,输出,也,一样,用户,感知,不到,任何,变化。

如果,重构,的,过程,中,改变,了,外部,行为,那,就,不是,重构,了,而是,重写,或者,修改,功能,了,所以,重构,的,时候,一定要,注意,不要,改变,代码,的,功能。

2. 小步,重构,随时,测试

重构,要,小步,进行,每次,只,做,一个,小的,调整,然后,运行,测试,确保,测试,通过,代码,功能,没有,变化,然后,再,做,下,一个,调整。

不要,一下子,做,很大,的,重构,这样,很,容易,出,问题,而且,出,了,问题,也,很,难,找,原因,很,难,回退,小步,重构,随时,测试,就算,出,了,问题,也,很,容易,发现,很,容易,回退,风险,很小。

3. 重构,之前,确保,有,测试

重构,之前,一定要,确保,有,可靠,的,测试,这样,重构,的,过程,中,才能,随时,运行,测试,确保,代码,功能,没有,变化。

如果,没有,测试,重构,就,很,危险,因为,你,不,知道,自己,的,修改,有没有,改变,代码,的,功能,有没有,引入,新的,bug,所以,重构,之前,最好,先,写,测试,确保,代码,的,功能,被,测试,覆盖,了,然后,再,重构。

4. 重构,是,为了,让,代码,更,好,不是,为了,重构,而,重构

重构,的,目的,是,让,代码,更,容易,理解,更,容易,修改,质量,更高,不是,为了,用,什么,高大上,的,技术,或者,设计模式,而,重构。

很多人,学,了,一些,设计模式,或者,重构,手法,就,到处,用,不管,有没有,必要,这样,反而,会,让,代码,更,复杂,更,难,理解,这,就,违背,了,重构,的,初衷。

所以,重构,要,根据,实际,情况,来,只有,当,代码,有,坏味道,需要,改善,的,时候,才,重构,不要,为了,重构,而,重构。

七、这本书对我的影响

最后,说说,这本书,对,我,的,影响。

1. 让我,重视,代码,质量

之前,我,写代码,只,追求,能,跑,起来,就行,不,太,关心,代码,质量,读,了,这本书,之后,我,才,明白,代码,质量,的,重要性,代码,不仅,要,能,跑,还要,容易,理解,容易,修改,质量,高,这样,才能,降低,维护,成本,提高,开发,效率。

现在,我,写代码,的,时候,会,很,注意,代码,质量,变量,名,函数,名,要,有,意义,函数,要,短小,精悍,类,要,职责,单一,尽量,避免,代码,坏味道,写,出来,的,代码,比,以前,质量,高,了,很多。

2. 让我,学会,了,系统地,重构

之前,我,也,会,重构,代码,但是,都是,凭,感觉,瞎,改,没有,系统,的,方法,也,没有,什么,原则,经常,改,着,改,着,就,出,问题,了,或者,越,改,越,乱。

读,了,这本书,之后,我,才,明白,重构,是,有,系统,的,方法,和,原则,的,要,小步,进行,随时,测试,要,按照,一定,的,手法,来,重构,这样,才能,安全,地,改善,代码,结构,不,会,出,问题。

现在,我,重构,代码,的,时候,会,按照,书,里,的,方法,小步,进行,随时,测试,用,书,里,的,重构,手法,来,改善,代码,重构,的,效率,和,安全性,都,提高,了,很多。

3. 让我,学会,了,识别,代码,坏味道

之前,我,看,代码,的,时候,只能,看,出来,代码,很,乱,但是,说,不,出来,具体,哪里,乱,怎么,改,读,了,这本书,之后,我,学会,了,识别,代码,的,坏味道,比如,重复代码,过长函数,过大的类,神秘命名,等等,能,准确,地,指出,代码,的,问题,也,知道,怎么,去,改。

现在,我,看,代码,的,时候,会,下意识,地,找,代码,坏味道,然后,想,办法,重构,去掉,这些,坏味道,代码,审查,的,时候,也,能,提出,更,有,价值,的,建议,帮助,团队,提高,代码,质量。

4. 让我,明白,了,技术债,的,重要性

之前,我,对,技术债,没有,太,深的,理解,觉得,代码,能,跑,就行,技术债,什么的,无所谓,读,了,这本书,之后,我,才,明白,技术债,的,危害,代码,质量,差,就,像,欠,了,债,一样,现在,省,了,时间,以后,要,花,更多,的,时间,来,还,而且,还有,利息,越,拖,越,难,还。

所以,现在,我,会,很,注意,避免,制造,技术债,写代码,的,时候,尽量,写,高质量,的,代码,发现,技术债,的,时候,也,会,及时,重构,偿还,技术债,不让,技术债,越,积,越多。

八、写在最后

《重构:改善既有代码的设计》,是,一本,非常,经典,的,软件工程,书籍,它,教,我们,如何,系统地,改善,既有代码,的,设计,让,代码,更,容易,理解,更,容易,修改,质量,更高。

这本书,我,第一次读,的时候,没有,太,深的,体会,这次,重读,结合,工作,经验,才,真正,明白,了,它,的,价值,它,不仅,教,了,我,重构,的,手法,更,重要,的,是,改变,了,我,对,代码,质量,的,态度,让,我,更,重视,代码,质量,更,注重,写,高质量,的,代码。

我,强烈,建议,每个,程序员,都,应该,读,这本书,而且,最好,是,工作,了,几年,有,一定,经验,之后,再,读,这样,体会,会,更,深,收获,会,更,大。

当然,读书,只是,第一步,更,重要,的,是,实践,把,书,里,的,方法,和,原则,用到,实际,的,工作,中,不断,练习,不断,总结,这样,才能,真正,掌握,重构,的,精髓,写出,高质量,的,代码。

最后,希望,大家,都,能,写出,高质量,的,代码,都,能,成为,优秀,的,程序员。

愿,我们,都,能,在,代码,的,世界,里,追求,卓越,写出,优雅,的,代码。