《重构》读后感(第四章)

第四章:构筑测试体系。

PS:本章内容主要是通过一个JavaScript示例来讲解如何构筑测试体系。以下内容只总结一些心得和要点,具体如何构筑自己所用开发语言的测试体系,请自行了解。

要正确的进行重构,前提是得有一套稳固的测试集合,以帮我们发现难以避免的疏漏。

一、自测试代码的价值:
我们编写代码的时间仅占所有时间中很少的一部分。有些时间用来决定下一步干什么,有些时间花在设计上,但是花在测试上的时间是最多的。修复一个bug通常是比较快的,但是找出bug通常都比较难,越到后期,修改一个bug的时候越容易引起另一个bug,而我们又很难注意到它。一套测试就是一个强大的bug侦测器,能够大大缩减查找bug的时间。

二、 撰写测试代码的最好时间:
是在开始动手编码之前,因为编写测试代码其实就是问自己:我需要实现什么?

三、一些要点:
1、要频繁的运行测试,对于你正在处理的代码,与其对应的测试至少每隔几分钟就要运行一次,每天至少运行一遍所有的测试。
2、测试应该是一种风险驱动的行为,我测试的目的是希望找出现在或未来可能出现的bug。而测试的重点应该是那些我最担心的出错的部分,这样就能从测试工作中得到最大利益。
3、多考虑可能出错的边界条件,把测试火力集中在那里。
4、不要因为测试无法捕捉所有的bug就不写测试,因为测试的确可以捕捉到大多数bug。
5、编写未臻完善的测试并经常运行,好过对完美测试的无尽等待。除非很简单,不然我们很难一次就把测试写对,需要不断的完善它。
6、测试同样过犹不及,测试写的太多的一个征兆是:相比要改的代码,我在改动测试上花费更多时间。
7、如今一个框架的好坏,很大程度要取决于它的可测试性,这是一个好的行业趋势。

《重构》读后感(第三章)

第三章:在何处重构。

决定何时重构以及何时停止重构与知道重构机制如何运转一样重要。

1、神秘代码:整洁代码最重要的一环就是好的名字。命名是编程中最难的两件事之一(扩展阅读:另一件是缓存失效)。
2、重复代码:注意是否有细微差异,以及其调用者等,这决定了我们要怎么去处理它。
3、过长函数:函数越长,越难理解。让小函数易于理解的关键还是在于良好的命名,这样我们只看函数名而不用看整段代码就知道这个函数在做什么,随意起的名字只会让我们浪费更多时间。作者说:每当感觉需要以注释来说明点什么的时候,我们就可以把要说明的东西写进一个独立的函数中,然后以其用途来命名(不要在意其函数名长度)。不过我们自己也应该看情况决定是否需要这么做(最后一条有说明)。
4、过长参数列表:使用类/传入完整对象/合并为一个对象都可以有效的缩短参数列表,需要我们自己看情况决定。
5、全局数据:因为从代码库的任何角落都可以修改它,类变量和单例也有这种问题。对全局变量最好封装起来,限制它的作用域。
6、可变数据:对数据的修改经常导致出乎意料的结果和难以发现的bug。可变数据的作用域越大,风险也越大,同全局数据。
7、发散式变化:指某个模块经常因为不同的原因在不同的方向上发生变化。
8、霰(xiàn)弹式修改:指如果每遇到某种变化,你都必须在许多不同的类内作出许多小修改。
9、依恋情节:在模块化时一个函数跟另一个模块中的函数或者数据交流的格外频繁,远胜于在自己所处模块内部的交流。最好的办法当然是,将他们合并到一起。
10、数据泥团:指那些你常常在很多地方可以见到的相同的三四项数据,例如:两个类中相同的字段、许多函数签名中相同的参数等。最好的办法就是新建一个类,这样可以消除大量的重复。
11、基本类型偏执:指大量的使用基本类型,而很少创建对自己的问题域有用的基本类型。例如:把钱当做普通数字来计算、计算物理量时无视单位等。
12、重复的switch:指在不同的地方反复使用同样的switch逻辑(也可能是连续的if/else语句)。最佳的解决办法就是多态。
13、循环语句:使用管道操作来替代。至于什么是管道操作,看了后边的示例,主要指代filter和map,iOS没有这东西,JavaScript和Java的同学应该了解。
14、冗赘的元素:指那些简单的不需要搞的复杂的代码。例如:某个函数的名字和它的实现代码看起来一模一样,或者某个类根本就是一个简单的函数。
15、夸夸其谈通用性:主要指那些你以为将来会用到的代码。
16、临时字段:指仅为某种特定情况而设的字段。
17、过长的消息链:最好的办法是,先观察消息链最终得到的对象是用来干什么的,然后选择性的重构。
18、中间人:指过度运用委托。
19、内幕交易:指为了减少耦合而建起高墙。在实际情况中,一定的数据交换不可避免,我们必须尽量减少内幕交易这种情况,把这种交换都放到明面上。
20、过大的类:观察一个大类的使用者。经常能找到如何拆分类的线索。
21、异曲同工的类:使用类的好处之一就是可以替换,今天用这个类,未来可以换成另外一个。
22、纯数据类:指它们拥有一些字段,以及用于访问这些字段的函数,除此之外一无长物。纯数据类常常意味着行为被放到了错误的地方。也就是说,只要把处理数据的行为放到纯数据类中,就能是情况大为改观。不过一个非常常见的特殊情况就是,这个纯数据记录对象被用于函数调用的返回结果,此时无需操作。
23、被拒绝的遗赠:指子类继承了超类的所有函数和数据,但是它可能不想或者不需要继承,或者只需要其中的几样。此处建议:如果子类继承了超类的实现,却不愿意支持超类的接口,那就是不能被接受的。拒绝继承超类的实现可以被接受。
24、注释:注释可以帮我们找到重构的点,看到注释应该先想是否可以尝试重构。有用的注释一般指用来记录将来的打算,或者你暂时没有把握的内容,或者你为什么这么做。其他的注释就试试重构吧。