文章目录
1.前言
- 文档编写:记录学习《重构 改善既有代码的设计》。时间久了发现程序员这个行业的魅力就是神秘。
- “我不是个伟大的程序员,我只是个有这一些优秀习惯的好程序员。”重构能够帮助我更有效地写出强健的代码。
- 如果你要跟诶程序添加一个特性,但发现代码因缺乏良好的结构而不易于进行修改,那就先重构那个程序,使其比较容易添加该,然后再添加该特性。
- 重构前,先检查自己是否有一套可靠的测试集。这些测试必须有自我检验能力。
- 重构技术就是以微小的步伐修改程序。如果你犯下错误,很容易便可发现它。
- 傻瓜都能写出计算机可以理解的代码。唯有能写出人类容易理解的代码,才是优秀的程序员。
- 编程时,需要遵循营地法则:保证你离开时的代码库一定比来时更健康。
- 重构时,重构的度是不好衡量的,设计的尽善尽美,还是针对于问题解决是要根据需求进行剖析的。
2.重构定义
- 名词形式:对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。
- 动词形式:使用一系列重构手法,在不改变软件可观察行为的前提下,调整其结构。
- 重构是为了让代码“更容易理解,更易于修改”。可能使程序运行更快,也可能是程序运行得更慢。
- “重构就是在整理代码吗?”从某种角度上,是的。但是重构不止于此,因为它提供了一种更高效且受控的代码整理技术。
- 重构的目的是使软件更容易被理解和修改。你可以在软件内部做很多修改,但必须对软件可观察的外部行为制造成很小变化,或设置不造成变化。
- “两顶帽子”:使用重构技术开发软件时,我把自己的时间分配给两种截然不同的行为:添加新功能和重构。
- 添加新功能时,我不应该修改既有代码,只管添加新功能。通过添加测试并让测试正常运行,我可以衡量自己的工作进度。
- 重构时我就不能再添加功能,只管调整代码的结构。此时我不应该添加任何测试(除非发现有先前遗漏的东西),只在绝对必要(用以处理接口变化)时才修改测试。
3.为何重构
3.1.重构改进软件设计
- 如果没有重构,程序的内部设计(或者叫架构)会逐渐腐败变质。
- 改进设计的一个重要方向消除重复代码。
3.2.重构使软件更容易理解
- 我所做的就是填补“我想要它做什么”和“我告诉它做什么”之间的缝隙。
- 编程的核心就在于“准确说出我想要的”。
3.3.重构帮助找到bug
3.4.重构提高编程速度
4.何时重构
- 三次法则:第一次做某件事时只管去做,第二次做类似的时会产生方案,但无论如何还是可以去做;第三次再做类似的事情,你就应该重构。
- 事不过三,三则重构。
4.1.预备性重构:让添加新功能更容易
- 重构的最佳时机就在添加新功能之前。
- 新功能与以往代码相似需要做微调的时候。
4.2.帮助理解的重构:使代码更易懂
- 一旦我需要思考“这段代码到底在做什么”,我就会自问:“能不能重构这段代码,令其一目了然?”
- 修改晦涩难懂的变量名字,将长函数拆成几个小函数。
4.3.捡垃圾式重构
4.4.有计划的重构和见机行事的重构
- 预备性重构、帮助理解的重构、捡垃圾式重构都是见机行事的。
- 肮脏的代码必须重构,但漂亮的代码也需要很多重构。
- 每次要修改时,首先修改很容易(警告这件事有时会很难),然后进行这次容易的修改。满足于设计模式中对于扩展是开放的,对修改是关闭的原则。
- 建议:将重构与新功能在版本控制的提交中分开。这样做的一大好处是可以独自独立地审阅和批准这些提交。但新功能会触发重构,又密不可分。
4.5.长期重构
- 大多数重构可以在几分钟----最多几个小时----内完成。但有一些大型的重构可能要花上几个星期,那么可以让整个团队达成共识,在未来几周时间里逐步解决这个问题,这经常是一个有效的策略。每当有人靠近“重构区”的代码,就把它朝想要改进的方向推动一点。通过引进新的一层抽象。
4.6.复审代码时重构
5.代码的坏味道
5.1. 神秘命名
5.2. 重复代码
5.3.过长函数
5.4.过长参数列表
5.5.全局数据
- 防御手段是封装变量。
5.6.可变数据
5.7.发散式变化
- 如果某个模块经常因为不同的原因在不同的方向上发生变化,发散式变化就出现了。
5.8.霰弹式修改
- 霰弹式修改类似于发散式变化,但又恰恰相反。
- 如果每遇到某种变化,你都必须在许多不同的类内做出许多小修改,你所面临的坏味道就是霰弹式修改。
- 如果需要修改的代码散步四处,你不但很难找到它们,也很容易错过某个重要的修改。
- 搬移函数和搬移字段把所有需要修改的代码放进同一个模块里。如果有很多函数都在操作相似的数据,可以使用函数组合类。
6.重构的重点
- 《重构改善既有代码的设计》中我觉得比较重要的东西就是Kent Beck的说法摘写,真的很厉害说的很清楚。
- 对于“为什么重构有用?”。程序编写不是牺牲明天为了完成今天的任务的编写。
- “是什么让程序如此难以了解?”
a.难以于都的程序,难以修改;
b.逻辑重复的冲虚,难以修改;
c.添加新行为时需要修改已有代码的程序,难以修改;
d.带负载条件逻辑的程序,难以修改。 - 我们希望程序:(1) 容易阅读;(2)所有逻辑都只在唯一地方指定;(3)新的改动不会危及现有行为;(4)尽可能简单表明田间逻辑;
- 对于“间接层和重构”。计算机科学是这样一门科学:它相信所有问题都可以通过增加一个间接层来解决。间接层的某些价值:
a.允许逻辑共享。比如一个子函数在两个不同的地方被调用,或超类中的某个函数被所有子类共享。
b.分开解释意图和实现。你可以选择每个类和函数的名称,这给了你一个解释自己意图的机会。类和函数内部则解释实现这个意图的做法。如果类和函数内部又以更小单元的意图来编写,你所写的代码就可以描述其结构中的大部分重要信息。
c.隔离变化。很可能我在两个不同地方使用同一对象,其中一个地点我想改变对象行为,但如果修改了它,我就要冒同时影响两处的风险,为此我做出一个子类,并在需要修改处引用这个子类,现在,我可以修改这个子类而不必承担无意中影响另一处的风险。
d.封装条件逻辑。对象有一种奇妙的机制:多态消息,可以灵活而清晰地表达条件逻辑,将条件逻辑转化为消息形式,往往能降低代码的重复、增加清晰度并提高弹性。