第二章 重构的原则
2.1 何谓重构“重构”这个词既可以用作名词也可以用作动词。名词情势的定义是:
重构(名词):对软件内部结构的一种调解,目标是在不改变软件可观察行为的条件下,提高其可理解性,降低其修改成本。这个定义适用于我在前面的例子中提到的那些著名字的重构,例如提炼函数(106)和以多态代替条件表达式(272)。
重构(动词):使用一系列重构伎俩,在不改变软件可观察行为的条件下,调解其结构。
以是,我可能会花一两个小时进行重构(动词),其间我会使用几十个差别的重构(名词)。
重构的关键在于运用大量微小且保持软件行为的步调,一步步达成大规模的修改。每个单独的重构要么很小,要么由多少小步调组合而成。因此,在重构的过程中,我的代码很少进入不可工作的状态,即便重构没有完成,我也可以在任何时刻停下来。
假如有人说他们的代码在重构过程中有一两天时间不可用,根本上可以确定,他们在做的事不是重构。
在上述定义中,我用了“可观察行为”的说法。它的意思是,团体而言,经过重构之后的代码所做的事应该与重构之前大致一样。这个说法并非完全严格,而且我是故意生存这点儿空间的:重构之后的代码不肯定与重构前行为完全一致。好比说,提炼函数(106)会改变函数调用栈,因此程序的性能就会有所改变;改变函数声明(124)和搬移函数(198)等重构经常会改变模块的接口。不外就用户应该关心的行为而言,不应该有任何改变。假如我在重构过程中发现了任何bug,重构完成后同样的bug应该仍然存在(不外,假如潜伏的bug还没有被任何人发现,也可以当即把它改掉)。
重构与性能优化有很多相似之处:两者都必要修改代码,而且两者都不会改变程序的团体功能。两者的差别在于其目标:重构是为了让代码“更容易理解,更易于修改”。这可能使程序运行得更快,也可能使程序运行得更慢。在性能优化时,我只关心让程序运行得更快,终极得到的代码有可能更难理解和维护,对此我有生理准备。
2.2 两顶帽子
Kent Beck提出了“两顶帽子”的比喻,即:添加新功能和重构。
添加新功能时,我不应该修改既有代码,只管添加新功能。通过添加测试并让测试正常运行,我可以权衡自己的工作进度。重构时我就不能再添加功能,只管调解代码的结构。
软件开辟过程中,我可能会发现自己经常变换帽子。起首我会尝试添加新功能,然后会意识到:假如把程序结构改一下,功能的添加会容易得多。于是我换一顶帽子,做一会儿重构工作。程序结构调解好后,我又换上原先的帽子,继续添加新功能。
2.3 为何重构
2.3.1 重构改进软件的计划
假如没有重构,程序的内部计划(大概叫架构)会逐渐腐败变质,于是代码逐渐失去了自己的结构。程序员越来越难通过阅读源码来理解原来的计划。代码结构的流失有累积效应。越难看出代码所代表的计划意图,就越难掩护其计划,于是计划就腐败得越快。经常性的重构有助于代码维持自己该有的形态。
重构的一个重要方向是消除重复代码,代码量减少将使未来可能的程序修改动作容易得多。
2.3.2 重构使软件更容易理解
重构可以帮我让代码更易读。
2.3.3 重构资助找到bug
对代码的理解,可以帮我找到bug。假如对代码进行重构,我就可以深入理解代码的所作所为,并立刻把新的理解反映在代码当中。搞清楚程序结构的同时,我也验证了自己所做的一些假设,于是想不把bug揪出来都难。
重构能够资助我更有用地写出结实的代码。
重构提高编程速度
重构帮我更快速地开辟程序。改善计划、提升可读性、减少bug,这些都能提高质量。但花在重构上的时间,难道不是在降低开辟速度吗?否则,一开始他们进展很快,但现在想要添加一个新功能必要的时间就要长得多,bug修改也越来越慢。
https://i-blog.csdnimg.cn/direct/be74bf4bb4564cd1a73c14a974b4741d.png
两种团队的区别就在于软件的内部质量。必要添加新功能时,内部质量精良的软件让我可以很容易找到在哪里修改、如何修改。精良的模块分别使我只必要理解代码库的一小部分,就可以做出修改。假如代码很清楚,我引入bug的可能性就会变小,纵然引入了bug,调试也会容易得多。
通过投入精神改善内部计划,我们增加了软件的长期性,从而可以更长时间地保持开辟的快速。
2.4 何时重构
Don Roberts给了我一条准则:第一次做某件事时只管去做;第二次做雷同的事会产生反感,但无论如何还是可以去做;第三次再做雷同的事,你就应该重构。
正如老话说的:事不外三,三则重构。
2.4.1 预备性重构:让添加新功能更容易
重构的最佳机遇就在添加新功能之前。在动手添加新功能之前。
假如对代码结构做一点微调,我的工作会容易得多。大概已经有个函数提供了我必要的大部分功能,但有几个字面量的值与我的必要略有冲突。假如不做重构,我可能会把整个函数复制过来,修改这几个值,但这就会导致重复代码——假如未来我必要做修改,就必须同时修改两处(更麻烦的是,我得先找到这两处)。假如把某些更新数据的逻辑与查询逻辑分开,会更容易避免造成错误的逻辑胶葛。
2.4.2 资助理解的重构:使代码更易懂
必要先理解代码在做什么,然后才能着手修改。在一些小细节上使用重构来资助理解,给一两个变量改名,让它们更清楚地表达意图,以方便理解,或是将一个长函数拆成几个小函数。
重构就像扫去窗上的灰尘,使我们得以看到窗外的风景。重构会引领我获得更高层面的理解,假如只是阅读代码很难有此意会。
2.4.3 捡垃圾式重构
我已经理解代码在做什么,但发现它做得欠好。例如,逻辑不必要地迂回复杂,大概两个函数险些完全雷同,可以用一个参数化的函数取而代之。
2.4.4 有计划的重构和见机行事的重构
预备性重构、资助理解的重构、捡垃圾式重构——都是见机行事的。
肮脏的代码必须重构,但美丽的代码也必要很多重构。重构就是人们补充已往的错误大概清理肮脏的代码。固然,假如遇上了肮脏的代码,你必须重构,但美丽的代码也必要很多重构。对于昨天的功能完全公道的权衡,在今天要添加新功能时可能就不再公道。
假如团队已往忽视了重构,那么常常会必要专门花一些时间来优化代码库,以便更容易添加新功能。偶然,即便团队做了日常的重构,还是会有问题在某个区域逐渐累积长大,终极必要专门花些时间来办理。但这种有计划的重构应该很少,大部分重构应该是不起眼的、见机行事的。
2.2.5 长期重构
有一些大型的重构可能要花上几个星期,即便在这样的环境下,我仍然不肯让一支团队专门
做重构。可以让整个团队达成共识,在未来几周时间里渐渐办理这个问题,这经常是一个有用的战略。每当有人靠近“重构区”的代码,就把它朝想要改进的方向推动一点。这个战略的长处在于,重构不会破坏代码——每次小改动之后,整个体系仍然照常工作。
Improvement task.
2.4.6 Code review是重构
代码复审有助于在开辟团队中流传知识,也有助于让较有经验的开辟者把知识传递给比力欠缺经验的人,并资助更多人理解大型软件体系中的更多部分。
代码复审也让更多人有时机提出有用的建议,究竟我在一个星期之内能够想出的好点子很有限。假如能得到别人的资助,我的生活会滋润得多,以是我总是期待更多复审。假如代码的原作者在旁边会好很多,因为作者能提供关于代码的上下文信息,而且充分认同复审者进行修改的意图。
Review meeting, requirement_id in MR
2.4.7 怎么跟经理说?
软件开辟者都是专业人士。我们的工作就是尽可能快速创造出高效软件。我的经验告诉我,对于快速创造软件,重构可带来巨大资助。------能够带来经济效益。
2.4.8 何时不应该重构
一块凌乱的代码,但并不必要修改它,那么我就不必要重构它。例如,貌寝的代码能被隐藏在一
个API之下,我就可以容忍它继续保持貌寝。只有当我必要理解其工作原理时,对其进行重构才有价值。
另一种环境是,假如重写比重构还容易,就别重构了。
2.5 重构的挑衅
2.5.1 延缓新功能开辟
重构的唯一目标就是让我们开辟更快,用更少的工作量创造更大的价值。
重构很有必要进行,而马上要添加的功能非常小,这时我会更乐意先把新功能加上,然后再做这次大规模重构。在我们这个行业里,重构不足的环境远多于重构过度的环境。
2.5.2 代码全部权
很多重构伎俩不仅会影响一个模块内部,还会影响该模块与体系其他部分的关系。
2.5.3 分支
每个团队成员各安闲代码库的一条分支上工作,进行相当大量的开辟之后,才把各自的修改合并回主线分支。
2.5.4 测试
不会改变程序可观察的行为,这是重构的一个重要特性。假如没有自测试的代码,这种担心就是完全公道的,这也是为什么我云云器重可靠的测试。
2.5.5 遗留代码
遗留代码往往很复杂,测试又不足,而且最关键的是,是别人写的(瑟瑟发抖)。重构可以很好地资助我们理解遗留体系。
2.6 重构、架构和YAGNI
在任何人开始写代码之前,必须先完成软件的计划和架构。一旦代码写出来,架构就固定了,只会因为程序员的马虎对待而逐渐腐败。
重构改变了这种观点。有了重构技能,即便是已经在生产环境中运行了多年的软件,我们也有能力大幅度修改其架构。
重构对架构最大的影响在于,通过重构,我们能得到一个计划精良的代码库,使其能够优雅地应对不断厘革的需求。
假如以后再重构有多困难。只有当未来重构会很困难时,我才思量现在就添加机动性机
制。我发现这是一个很有用的决议方法。这种计划方法有很多名字:简单计划、增量式计划
大概YAGNI——“你不会必要它”(you arenʼt going to need it)的缩写。
采用YAGNI并不表示完全不用预先思量架构。有一些时间,假如缺少预先的思考,重构会难以开展。但两者之间的平衡点已经发生了很大的改变:现在我更倾向于等一等,待到对问题理解更充分,再来着手办理。
2.7 重构与软件开辟过程
重构早先是作为极限编程(XP)的一部分被人们采用的。极限编程是最早的灵敏软件开辟方法之一。
假如一支团队想要重构,那么每个团队成员都必要掌握重构技能,能在必要时开展重构,而不会干扰其他人的工作。这也是我鼓励连续集成的缘故原由:有了CI,每个成员的重构都能快速分享给其他同事,不会发生这边在调用一个接口那边却已把这个接口删掉的环境;假如一次重构会影响别人的工作,我们很快就会知道。自测试的代码也是连续集成的关键环节,以是这三大实践——自测试代码、连续集成、重构。
2.8 重构与性能
为了让软件易于理解,我常会做出一些使程序运行变慢的修改。这是一个重要的问题。我并不赞成为了提高计划的纯洁性而忽视性能。固然重构可能使软件运行更慢[也可能是软件运行的更快],但它也使软件的性能优化更容易。
关于性能,一件很有趣的事情是:假如你对大多数程序进行分析,就会发现它把大半时间都泯灭在一小半代码身上。假如你等量齐观地优化全部代码,90%的优化工作都是白费劲的,因为被你优化的代码大多很少被执行。你花时间做优化是为了让程序运行更快,但假如因为缺乏对程序的清楚认识而花费时间,那些时间就都被浪费掉了。
在性能优化时,找出性能热点地点的一小段代码。然后我应该集中关注这些性能热点,并使用连续关注法中的优化手段来优化它们。由于把注意力都集中在热点上,较少的工作量便可显现较好的成果。
重构可以资助我写出更快的软件。短期看来,重构简直可能使软件变慢,但它使优化阶段的软件性能调优更容易,终极还是会得到好的效果。
性能优化找出瓶颈地点代码优化;
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]