关于refactoring思考(二)

2008-04-09 04:08:15来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折

为什么要 Refactoring

为什么要去改变已经可以正确运行的软件?这样的改变是否影响到我们的设计,从而进一步改变我们对于面向对象系统进行设计的方法和思路?本部分试图回答这些问题。
Refactoring虽然需要更多的"额外工作",但是它给我们带来的各种好处显然值得我们做出这样的努力:
简化测试
一个好的Refactoring实现能够减少对新设计的测试量.因为Refactoring的每一步都保持可观察的行为,也就是保持系统的所有单元测试都能顺利通过。所以只有发生改变的代码需要测试.这种增量测试使得所有的后续测试都建立在坚实的基础之上,整个系统测试的复杂性大大降低。
更简单的设计
Refactoring降低初始设计的复杂程度.Gamma指出复杂设计模式的一个陷阱是过度狂热:"模式有其成本(间接性、复杂化),因此设计应该达到需求所要求的灵活性,而不是越灵活越好"。如果设计试图介入太多以后可能需要的灵活性,就会产生不必要的复杂和错误。Refactoring能够以多种方式扩展设计。他鼓励为手头的任务建立刚刚合适的解决方案,当新的需求来到时,可以通过Refactoring扩展设计。
Refactoring增进软件可理解性
程序的最终目的是为了指引计算机完成人们需要完成的事情。但是,要完成这个目标并非想象的那么容易。
程序编写是人的活动,人首先要理解才能行动。所以,源代码的另一个作用就是用于交流的工具。其他人可能会在几个月之后修改你的代码,如果连理解你的代码都做不到,他又如何完成所需的修改呢?我们通常会忘掉源代码的这种用处,尽管它可能是源代码更重要的用处。不然,我们为什么发展高级语言、面向对象语言,为什么我们不直接使用汇编语言甚至是机器语言来编写程序?难道我们真的在意计算机多花了几个CPU周期去完成一件事?
如果一个人能够理解我们的代码,他可能只需要一天的时间完成一个增加功能的任务,而如果他不理解我们的代码,可能需要花上一个礼拜或更长的时间。这里的问题是,我们在编写代码的时候不但需要考虑计算机CPU的想法,更要把以后的开发者放在心上。除非,你写代码的唯一目的就是把它丢掉。你不想让任何别的开发人员用到这段代码,包括你自己。因为你不可能记得所有你写过的代码,如果你经常回过头去看一下自己的代码,你就会体会到代码的可理解是如何重要。
Refactoring可以使得你的代码更理解,Refactoring支持更小的类、更短的方法、更少的局部变量、更小的系统耦合,Refactoring要求你更加小心自己的命名机制,让名字反映出你的意图。如果哪一块代码太复杂以至于哪一理解,你都需要对他进行Refactor。
你可能认为,反映代码的意图应当是注释和文档的责任。假设你写好了一段程序,给他加上注释,来说明你这段代码完成了什么。每次代码发生改变,你都需要修改注释。而其实代码本身应当足以说明这个问题。如果代码不能反映自己的意图,即使是再多的注释也不足以让你理解代码的所有机制,除非你把代码的每一句话都加上注释。甚之,这种重复的责任使得一旦注释和代码发生不一致,它反而会阻碍你对代码的理解。而任何一个程序员都不愿意写太多的注释和文档。所以Martin fowler说:
When you feel the need to write a comment,first try to refactor the code so that any comment becomes superfluous。
Martin Fowler同时指出,Refactoring不但能够增加别人对你代码的理解,而且是一种非常好的理解别人代码,学习别人代码的方法。通常,当你拿到一大堆代码时,你可能会觉得一片茫然,不知道从何处开始。学习别人代码最好的方法就是对代码进行进行Refactor。如果你发现自己不能理解一段代码,那么试图使用对自己说,哦,这段代码可能是在做什么事情。给他一个有意义的名字,refactor它。Refactor使得你对代码的理解不是仅仅停留在脑袋中,而是看到代码确实按照你的理解再发生变化。如果你的refactor改变了系统的行为,那么说明你的理解还有问题。你必须返回重来。
Refactoring 改进软件的设计
许多人把编程看作是一种低级活动。他们认为代码仅仅是设计的附属物。然而正是代码,而不是你脑袋里或纸上的设计,真正驱动计算机完成你想做的事情。而绝大多数的bug也产生于编码阶段。
很多方法学认为通过分析和设计的严格化就能产生更高质量的软件,这实际上是不可能的。正如Brain Foote和Joseph Yoder在《Big Ball of MUD》一文中指出,虽然许多作者提出了很多理想上非常完美的体系结构,如Layer、PIPELINE等等。但在实践中,几乎从来都不能看到这么结构清晰的系统。
这一方面是由于分析和设计一个领域的应用程序需要对该领域丰富的知识,而这种知识不是在一开始都能获得的。我们通常需要在实践反馈的过程中才能一步步加深自己对该领域的理解。因而,我们一开始的设计可能并不能正确反映系统的内在本质,所以也不可能在代码中得到很好的反映。
另一方面,即使一开始的设计是完好的,随着用户对系统使用的深入,新的需求可能会被加入,旧的需求会被修改、删除。一个最先的设计不可能完全预料到这些变化。
一旦实现开始偏离最初的设计,那么它的代码将不受控制,从而不可避免地开始腐蚀。代码加入越多,腐蚀的速度越快。如果没有办法让设计尽可能地与实现保持一致,那么这种腐蚀的最后结果就是代码不得不被抛弃。
但是让代码实现和设计始终保持一致并非那么简单,在传统的软件方法中,一旦开发到了实现阶段,就很难对设计做出变化。所以最近发展的面向对象方法学把增量迭代(iterative)作为一个基本原则。
也许是题外话,在目前最为时行的一些"重型"软件方法学中,我们很难找到对迭代(包括设计的迭代)明确的支持、定义和操作过程,以及如何提高程序员适应这种动态开发能力的方法。在我看来,重型的软件方法学即使能够对软件开发起到一定的作用,他也不可能包罗万象,解决软件开发中的所有问题。开发方法学重视生命周期管理和控制,但软件的开发并不只有过程和生命周期,更重要的是,同时往往被"正规"的软件方法所忽略的是,软件开发是人的活动。不管你的过程控制是多么的严格,不管你的生命周期模型是多么的完美,如果不能提高人的生产力,提高产品的质量,那么一切都是毫无意义的。

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:商业软件功能需求的量化分析方法

下一篇:关于refactoring思考(四)