重构的原则

105 阅读5分钟

重构的原则

🏃重构的定义

​ 🦖重构(名词):对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。这个定义适用于我在前面的例子中提到的那些有名字的重构,例如提炼函数和以多态取代条件表达式。

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

​ 可观测行为是什么?它的意思是,整体而言,经过重构之后的代码所做的事应该与重构之前大致一样。重构之后的代码不一定与重构前行为完全一致。比如说,提炼函数会改变函数调用栈,因此程序的性能就会有所改变;改变函数声明和搬移函数等重构经常会改变模块的接口。**不过就用户应该关心的行为而言,不应该有任何改变。**这句话需要解释。编程的书中经常出现用户一词,其实我认为用户是使用这个函数,接口,类的人。一般还是我们或者是团队的其他人。这句话就是说改了之后使用的地方应该产生和之前一样的效果或结果。

❓为何重构

​ 为什么重构?或者说重构有什么好处?它可以帮你始终良好地控制自己的代码。重构可以让代码可读性更好和更容易修改。当你的代码可读性很好的时候,你会更容易发现设计上的问题,可以用设计模式更进一步重构代码。当你的代码更容易修改时,面对新的需求时,你也更好实现。

🎩两顶帽子

​ 🌻Kent Beck 提出了“两顶帽子”的比喻。使用重构技术开发软件时,我把自己的时间分配给两种截然不同的行为:添加新功能重构。添加新功能时,我不应该修改既有代码,只管添加新功能。通过添加测试并让测试正常运行,我可以衡量自己的工作进度。

重构时我就不能再添加功能,只管调整代码的结构。

软件开发过程中,我可能会发现自己经常变换帽子。首先我会尝试添加新功能,然后会意识到:如果把程序结构改一下,功能的添加会容易得多。于是我换一顶帽子,做一会儿重构工作。程序结构调整好后,我又换上原先的帽子,继续添加新功能。新功能正常工作后,我又发现自己的编码造成程序难以理解,于是又换上重构帽子……整个过程或许只花 10 分钟,但无论何时我都清楚自己戴的是哪一顶帽子,并且明白不同的帽子对编程状态提出的不同要求。

⏲何时重构

​ 🤚什么时候应该重构呢?Don Roberts 给了我一条准则:第一次做某件事时只管去做;第二次做类似的事会产生反感,但无论如何还是可以去做;第三次再做类似的事,你就应该重构。三次法则,事不过三,三则重构。

两顶帽子的择决:我已经理解代码在做什么,但发现它做得不好,例如逻辑不必要地迂回复杂,或者两个函数几乎完全相同,可以用一个参数化的函数取而代之。这里有一个取舍:我不想从眼下正要完成的任务上跑题太多,但我也不想把垃圾留在原地,给将来的修改增加麻烦。如果我发现的垃圾很容易重构,我会马上重构它;如果重构需要花一些精力,我可能会拿一张便笺纸把它记下来,完成当下的任务再回来重构它。

重构是编程的一部分不是专门要一个人做这样的一件事。它是一个工具,帮助你更好的适应软件的演进。

🏄🏻重构的挑战

​ 🐰尽管重构的目的是加快开发速度,但是,仍旧很多人认为,花在重构的时间是在拖慢新功能的开发进度。“重构会拖慢进度”这种看法仍然很普遍,这可能是导致人们没有充分重构的最大阻力所在。

有一种情况确实需要权衡取舍。我有时会看到一个(大规模的)重构很有必要进行,而马上要添加的功能非常小,这时我会更愿意先把新功能加上,然后再做这次大规模重构。

有些人试图用“整洁的代码”“良好的工程实践”之类道德理由来论证重构的必要性,我认为这是个陷阱。重构的意义不在于把代码库打磨得闪闪发光,而是纯粹经济角度出发的考量。我们之所以重构,因为它能让我们更快——添加功能更快,修复 bug 更快。一定要随时记住这一点,与别人交流时也要不断强调这一点。重构应该总是由经济利益驱动。

增量式重构 = 自动化测试+持续集成+TDD驱动设计