前言
极限编程(XP)的创始人之一 Ron Jeffries 说道:“在麻利中,让设计简单化,必须让设计从简略开始,而后变得成熟。要做到这一点,重构是惟一的前途。”什么是重构重构是指扭转代码的构造,而不是代码的行为。举个例子:假如一个程序中有两个办法,每个办法都蕴含几行雷同的代码,那么这几行雷同的代码能够从原来的两个办法中抽取进去,放到一个新的办法中,在原来搁置这几行代码的中央替换为调用这个新的办法。这个重构略微改善了程序的可读性和可维护性,因为当初一些代码显著被复用,并且反复的代码被移到了一个中央。代码构造产生了扭转,然而行为并没有变。
重构不仅对 TDD(测试驱动开发)的胜利至关重要,同时也有助于避免代码腐烂。代码腐烂是由反复的代码、有数的补丁、蹩脚的分类和其余编程差别造成的。团队的开发人员以他们本人的格调编写代码也会导致代码腐烂。产品公布后,代码腐烂是典型的综合症,如果容许代码腐烂,过不了几年,零碎就要全副重写。通过一直的重构,并且在一些小问题变成大问题之前一直地修复它们,咱们可能放弃咱们的应用程序不会腐烂。Robert C.Martin 称之为童子军规定。童子军里有一个规定:“来到的时候,总要让露营地比你来的时候更洁净。”利用于软件开发中就是:提交一个模块代码的时候,要让它比下载的时候更简洁一些,不管谁是这段代码的原作者。如果咱们都遵循这个简略的规定咱们的零碎最终会变得越来越好,是整个团队照料整个零碎,而非集体各自只关怀他们那一小部分,这样就合乎代码集体所有制准则,同时还能够造就团队成员的主人翁精力和责任感。
何时重构
Kent Beck 提出了“代码坏滋味”的说法,这种坏滋味,就是收回了重构的强烈信息,在《重构》一书中提到了 24 类,在这里咱们重点探讨以下几类:
1. 神秘命名
猜谜这件事如果产生在浏览代码的时候,就不是一个好的体验。代码整洁最重要的一项就是好的命名,尽量做到见名知意。每个团队都有本人对立的命名标准,常见命名办法有驼峰命名法如 userName,蛇形命名法如 user_name,脊柱命名法如 user-name 等,不管哪一种,就是不要呈现 theList,var1 这种写法。在代码编写过程中,咱们应该三思而行如何给函数、模块、变量和类命名,使他们可能清晰地表明本人的性能和用法。改名是最罕用的重构伎俩,包含批改函数申明、变量改名、字段改名等,好的名字可能节俭将来在猜谜上的大把工夫。如果想不出一个好的名字,阐明背地很可能潜在更深的设计问题,为一个名字所付出的纠结,经常能推动咱们对代码进行精简。
2. 反复代码
反复代码,顾名思义就是两段代码看上去简直雷同或者两段代码都是实现雷同的性能。当程序中存在大量反复的代码,会造成代码长度过长,不易浏览,遇到雷同或类似的代码段须要认真分辨,如果须要批改某一处的时候,为了防止脱漏须要查找出所有的雷同代码段进行批改,不易保护。如果是同一个类的两个函数含有雷同的代码,如文章结尾的例子,这时候能够用提炼函数来提炼出反复的代码,而后让这两个地点都调用被提炼出的那段代码。如果反复代码只是类似而不是雷同,能够先尝试用挪动语句重组代码程序,把类似的局部放在一起以便于提炼。
3. 过长参数列表
函数通常都须要接管参数,而后去实现某些解决,在《代码整洁之道》中提出,一个函数的参数应该尽可能短,最好只有一个,其次是两个,如果呈现三个以上的参数,就须要留神了。函数的参数过多不易于保护和批改,可读性也差,容易出错。如果一些参数来自同一个对象,那么就不要独自取出这些数作为函数参数传递,而是间接将这个对象传递过来。如果某些参数值能够通过调用已知的一个办法失去,那么就要把这个参数退换为在办法体内调用取值的那个已知办法。还有参数不来自同一个对象,如果有必要,咱们也要毫不犹豫的为这些参数新建一个不可变的类,强制将它们放在一起
4. 过长函数
在编程晚期,因为调用子函数须要产生额定的开销,所以大家都不喜爱小函数,一个函数动辄几百多行,鼠标的滚动条要滚好一会能力到办法开端,更不用说一行一行的去浏览,去了解,能够设想他人来批改这段代码的时候他有如许苦楚。古代的开发环境曾经齐全罢黜了过程内的函数调用开销。所以要保障本人的函数短小精悍。通常一个函数长度的底线是要在一个屏幕内齐全显示。当然有时候一个函数开始的时候并不是那么长,只是随着每次需要的变更,每次一点点的加代码而没有留神重构,幸运的认为一点点基本不算什么,千里之行; 始于足下最初终于不可收拾了。过长函数应该踊跃的进行函数合成,提炼函数,找到函数中适宜集中在一起的局部,把他们提炼进去造成一个新的函数。哪怕有时候是对一行代码进行这样的提取也是值得的口头,因为要害不在于函数的长度,而是在于函数做了什么。
5. 全局数据
在开始学习编程的时候,老师应该讲过防止应用全局变量,因为它太不可控了,在代码的任何一个角落都能够批改它,而且没有任何机制可能探测进去到底哪段代码做出了批改。全局变量一次次造成的那种诡异 bug,足够让你刻骨铭心。对于全局数据要防止应用,函数内的就放在函数体内,代码段内的就放在代码段中。无处可放,须要独自存在的全局数据就将其封装在函数中,这样就能够找到在哪个中央进行了批改,还要将这个函数放在某个类中,限定那些办法能够应用它,让数据的批改过程可控可追溯。
6. 正文
代码中如果呈现了大段的正文用来解释代码的含意,而起因是代码写的太蹩脚了,不得不依赖于正文,这就是一种坏滋味。
当你感觉须要写正文的时候,能够先试试重构,试着让所有正文都变得多余。如果须要正文来解释一段代码做了什么,能够试试提炼函数;如果函数曾经提炼进去,然而还是须要正文来解释做了什么,能够试试为函数申明改名;如果正文是阐明某些零碎的需要规格,试试引入断言。不是提倡不要写正文,而是要写适合的正文,对于正文,咱们应该遵循这样一条准则:“正文的应用不是为了阐明这段代码能做什么而是应该阐明为什么要这么做”。
7. 死代码
死代码泛指在程序运行过程中执行不到的代码,或者执行的到但没有任何作用的代码,也就是无用代码。当程序中的变量变成不依赖于内部传过来的数据, 被定义成常量时,便无奈适应外界其余的变动,就会产生死代码。这些代码通常是因为需要变更或者代码批改,变得用不到了,如果发现,就及时革除它们。
写在最初
重构越晚,须要批改的代码越多,就会造成技术债权。除了下面提到的几类重构的场景,还有很多其余的场景,重构尽管不是包治百病的灵丹妙药,然而重构是十分有价值的,能够帮忙你始终良好地管制本人的代码。尤其是作为麻利开发团队,重构是团队成员应该熟练掌握的,任何团队都应建设重构技能。同时,Scrum 培训师 Stefan Wolpers 示意,Scrum 团队应该思考将 15%~20% 的资源分配给每个 Sprint 周期的重构代码和修复谬误。由此可见,重构这件事件是循序渐进的作为一项改良流动继续进行。