设计的臭味——腐化软件的气味

 

当软件出现下面任何一种气味时,就表明软件正在腐化。

Ø 僵化性(Rigidity):很难对系统进行改动,因为每个改动都会迫使许多对系统其他部分的其他改动。 

Ø 脆弱性(Fragility):对系统的改动会导致系统中和改动的地方在概念上无关的许多地方出现问题。 

Ø 牢固性(Immobility):很难解开系统的纠结,使之成为一些可在其他系统中重用的组件。 

Ø 粘滞性(Viscosity):做正确的事情比做错误的事情要困难。 

Ø 不必要的复杂性(Needless Complexity):设计中包含有不具任何直接好处的基础结构。 

Ø 不必要的重复(Needless Repetition):设计中包含有重复的结构,而该重复的结构本可以使用单一的抽象进行统一。 

Ø 晦涩性(Opacity):很难阅读、理解。没有很好的表现出意图。

一、 僵化性

僵化性是指难以对软件进行改动,即使是简单的改动。如果单一的改动会导致有依赖关系的模块中的连锁改动,那么设计就是僵化的。必须要改动的模块越多,设计就越僵化。

大部分的开发人员都以这样或者那样的方式遇到过这种情况。他们会被要求进行一个看起来简单的改动。他们看了看这个改动并对所需的工作做出了一个合理的估算。但是过了一会儿,当阿门实际进行改动时,会发现有许多改动带来的影响自己并没有预测到。他们发现自己要在庞大的代码中搜寻这个变动,并且要更改的模块数目也远远超出最初的估算。最后,改动所花费的时间要远比初始估算长。当问他们为何估算的如此不准确时,他们会重复软件开发人员惯用的悲叹,“它比我想象的要复杂的多啊....

 

二、 脆弱性

脆弱性是指,在进行一个改动时,程序的许多地方就可能出现问题。常常是,出现新问题的地方与改动的地方并没有概念上的关联。要修正这些问题就又会引出更多的问题,从而使开发团队就像一只不停追逐自己尾巴的狗一样(忙的团团转)。随着模块脆弱性的增加,改动会引出意想不到的问题的可能性就越来越大。这看起来很荒谬,但是这样的模块使非常常见的。这些模块需要不断的修补——它们从来不会被从错误列表中去掉,开发人员知道需要对它们进行重新设计(但是谁都不愿意去面对重新设计中的难以琢磨性),你越是修正它们,它们就变得越糟。 

三、 牢靠性

牢靠性使指,设计中包含了对其他系统有用的部分,但是要把这些部分从系统中分离出来所需要的努力和风险是巨大的。这是一件令人遗憾的事,但却是非常常见的事情。

 

四、 粘滞性

粘滞性有两种表形形式:软件的粘滞性和环境的粘滞性。

当面临一个改动时,开发人员常常发现会有很多改动的方法。其中,一些方法会保持设计;而另外一些会破坏设计(也就是生硬的手法)。当那些可以保持系统设计的方法比那些生硬手法更难应用时,就表明设计具有高的粘滞性。做错误的事情时容易的,但是做正确的事情却很难。我们希望在软件设计中,可以容易地进行那些保持设计的变动。

当开发环境迟钝、低效时,就会产生环境的粘滞性。例如,如果编译所花费的时间很长,那么开发人员就会被引诱去做不会导致大规模重编译的改动,即使那些改动不再保持设计。如果源代码控制系统需要几个小时去check in仅仅几个文件,那么开发人员就会被引诱做那些需要尽可能少check in的改动,而不管改动是否会保持设计。

无论项目具有哪种粘滞性,都很难保持项目中的软件设计。我们希望创建易于保持设计的系统和项目环境。

 

五、 不必要的复杂性

如果设计中包含有当前没有用的组成部分,它就含有不必要的复杂性。当开发人员预测需求的变化,并在软件中放置了处理那些潜在的变化的代码时,常常会出现这种情况。起初,这样做看起来像是一件好事。毕竟,为将来的变化做准备会保持代码的灵活性,并且可以避免以后再进行痛苦的改动。    糟糕的是,结果常常正好相反。为过多的可能性做准备,致使设计中含有绝不会用到的结构,从而变得混乱。一些准备也会带来回报,但是更多的不会期间,设计背负着这些不会用到的部分,使软件变得复杂,并且难以理解。

 

六、 不必要的重复

剪贴(cut)和粘贴(copy)也许使有用的文本编辑(text-editing)操作,但是它们却是灾难性的代码编辑(code-editing)操作。时常,软件系统都是构建于众多的重复代码片段之上。例如:Ralph需要编写一些完成某项功能的代码。他浏览了一下他认为可能会完成类似工作的其他代码,并找到了一块合适的代码。他将那块代码copy到自己的模块中,并做了适当的修改。Ralph并不知道,他用鼠标获取的代码是由Todd放置在那里的,而Todd是从Lilly编写的模块中获取的。Lilly是第一个完成这项功能的,但是她认识到完成这项功能和完成另一项功能非常类似。她从别处找到了一些完成另一项功能的代码,cutcopy到她的模块中,并做了必要的修改。

当同样的代码以稍微不同的形式一再出现时,就表示开发人员忽视了抽象。对于他们来说,发现多余的重复并通过适当的抽象去消除它们的做法可能没有高的优先级别,但是这样做非常有助于使系统更加易于理解和维护。

当系统中有重复的代码时,对系统进行改动会变得困难。在一个重复的代码体中发现错误必须要在每个重复体中一一修正。不过,由于没有重复体直接都有细微的差别,所以修正的方式也并不总是相同的。

 

七、 晦涩性

 晦涩性是指模块难以理解。代码可以用清晰、富有表现力的方式编写,或者可以用晦涩、费解的方式编写。代码随着时间而演化,往往会变得越来越晦涩。为了使代码的晦涩性保持最低,就需要持续的的保持代码清晰并富有表现力。

什么激发了软件的腐化???

在非敏捷环境中,由于需求没有按照初始设计预见的方式进行变化,从而导致了设计的退化,但是通常情况下,要求的改动都是很急迫的,并且进行改动的开发人员对于原始的设计思路并不熟悉(如某些公司的系统本身就是维护性的系统),因而虽然对设计的改动可以工作,但是它却以某种方式违反了原始的设计,随着改动的不断进行,这些违反渐渐的积累,设计就开始出现臭味了。

解决之道

保持尽可能好的设计,用面向对象的一下原则来指导实践:

ü SRP 单一职责原则

ü OCP 开放─封闭原则

ü LSP Liskov 替换原则

ü DIP 依赖倒置原则

ü ISP 接口隔离原则

ü REP 重用发布等价原则

ü CCP 共同封闭原则

ü CRP 共同重用原则

ü ADP 无环依赖原则

ü SDP 稳定依赖原则

ü SAP 稳定抽象原则

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值