不要误解设计--耦合控制与TDD的作用

  代码的耦合度,是指代码中的单元代码的紧密程度,其中一个单元代码的更改对其它单元代码的影响力与作用。代码间的耦合度越高,系统就在变动时就更加难以控制,但并非不能控制,只是你将为此付出巨大的代价。
  软件的设计,不仅是理清思路,更多的意义是将软件中的逻辑结构进行合理地描述,力图减少各单元代码间的影响力,使得系统在控制上更加容易,减少出错的机会。

  根据现实而言,系统是一个客观的东西,现在科学终究其力,也无法探索出任何完整系统的内部结构,也不可能对其进行详尽的描述,因为在量子级别上的测不准性,已经使得系统具有太大的不可观测性。

  那么软件设计的本质在哪儿?软件开发是一门科学,这句话的含义不仅仅是一个定义,它说明了“软件开发是一门科学
        科学的本义是什么?想想牛顿的万有引力,想想爱因斯坦的相对论吧。
  它们都建立在宏观的物理学之上,无论是万有引力公式还是能量等于质量乘以光速的平方,都意味着对系统的描述,而这个系统并不是原来的完整系统,他们的公式描述是建立在人的脑海里的一个宏观系统。
  目前在哲学上深入了现代科学的观点是:人的大脑的作用是建立对现实世界在意识中的一种映射。这种反映可能是现实的,可能是不现实的,没有人知道自己大脑中的反映有哪些是正确的,因为“正确”的本身含义就很模糊概念。
  试想一下,太阳系中的众多行星与卫星加上宇宙尘埃对间的影响力,如果都一一进行分析,那么计算两颗行星间的作用力,将是一件十分恐怖的工作。
  但现实是:我们可爱的高中生们大多数能够计算出两颗行星间的作用力,这是为什么呢?
  这是因为对系统本身层次上的抽象,对于九大行星来说(是不是有第十颗我不知道,一直是传说),其它的作用力是微不足道的(至少现代科学是这样认为的),所以可以把太阳系的模型进行简化地抽象,忽略系统中其它细节的存在,从而让系统能够有一个简洁明了的抽象,以至于高中生都可以对行星间的作用力进行计算。

  软件的设计是对系统的描述,而这个系统的细化程度,是由根据用户的需求与设计人员思考来制定的。而且一个复杂系统,从不同的角度去观察与抽象,就可以得到不同的理解,也就可以得到不同的分析结果。各分析结果在相对而言,都不是错误的,只是个人视角的问题罢了。
  由于人与人间有着不同的观念,软件设计的设计者的职责就是力图理解用户想要构造的系统的想法,并与用户交互,对系统进行仔细的了解,然后再用不同的角度观察它,力图把系统的构架简洁地描述出来。
  代码所代表的现实单元间的耦合性,如果在现实中是有的,永远也不会消失,只是被系统的构造者或设计人员给在他的理解层次上给忽略掉了,正确地估计单元间的耦合性,是系统设计成功的关键,也是提供项目进度与复杂性控制的一个良好参考。
  根据现实经验,白盒的系统的微小变化,通常只会导致黑箱系统的微小改变,因为在中间层次开发人员的努力,可以在很大的一部分上消除白盒系统中变化对黑箱系统的影响。
  说白了一些就是,由于有代码编写人员的参与,在明确的流程与代码结构中,内部的细微调整,并不会使得输入与输出有太大的改变,它对系统中的其它部分的影响也将会根据振荡原理,变得越来越小(一定程度的健壮系统可以承受并化解外力对系统的部分影响)。
    
  在实际代码编写中,设计对代码及代码对设计中的变化的影响,并不如我们想像得那么复杂,因为合理的设计,一般情况下都可以满足用户当时的合理需求,而最可怕的应该是用户需求的更换有可能对颠覆设计者对系统的理解,这个影响是巨大的。
  另一方面,代码人员间的交互,也是头痛的问题,这不是通过文档就可以解决的,软件的外部文档,更多的机会是给项目管理者看的,而不是给设计者与其它代码人员看的。长期以来,代码的清晰性与可读性都在实践中进行着规范,比如较通用的代码编写规范就是一个好的例子,大家都遵守了后,相互交流起代码更易理解。
  
  保证代码的清晰性与保证软件单元之间的耦合最低,虽然有关系,但却不密切。因为毕竟它们是两个不同层次的东西,面向的中心也完全不一样。
  换而言之,你在一个类中,无论写多少代码,如果它与外部有联系,这个耦合度就一定存在,随着复杂程度的增加,耦合度也会长。在这种情况下,就需要对软件进行重构,使用耦合度较高的代码合并成为一个单元,但合并为一个单元,不一是指合并为一个类或一个方法,它指的是一组类的群集,这与设计模式中描述的模式是一样的。

        在TDD的使用中,我们是应该把代码写在类中,还是应该写在被测试类的外部,这都是一样的,根据上面原因,可以明白,代码间的耦合度不会因为你把它从类的内部提升到外部就会消失。
  实际上,使用TDD的耦合是NUnit本身的框架与程序集间的直接耦合,它们永远不会消失。
  不过,虽然NUnit本身的框架与程序集间的直接耦合虽然繁多,但因为在测试与被测试代码之间,开发人员会尽量使他们的调用更加直接,所以它们之间的耦合度较弱。
  关于降低测试代码与被测试代码间耦合度的问题,请参考,<<十种构建可测试代码的方法>>。

        另外说一下:
       TDD本身由于并不是方法学,也不是开发过程,它只是一种方法,一种实现手段,所以它在软件开发中,是对系统内部进行细部的调整。正如它自己所描述的是:测试驱动开发。
  它是假设在外力存在的情况下,系统是否经得起外力考验的方法。这与现代不少机械的生产是一样的,如轿车的的挡风玻璃抗击力测试力,就是让高速射出的一只冷冻的鸡击向玻璃,只要在指定的情况下,该玻璃如不会碎,就可以证明该玻璃抗击力是合格的。然后,无论什么材质的挡风玻璃,只要能够通过该测试,都可以认为此玻璃的抗击力测试是成功了的。
  TDD在软件开发的过程中,也是起到这样一个作用,只要愿意,你可以把此方法插入到你喜欢的软件开发过程,用软件的开发中的视度来看,它是一个有很强集成能力的“插件”。
  TDD把自己定位是定位在那些开发人员可以触摸,测试人员不易触摸的范围之内的,也就是曾经提到过的函数与方法级别的保证的测试手段,也正因为这样,我们不要认为它是一个复杂的东西而不敢接触,也不要因为TDD炒得火热,就认为它好到惊天动地、鬼哭神嚎的地步。

  国内IT业的浮躁是冰冻三尺非一日之寒的事,但我们是否应该带个头,先冷静一下自己呢?
posted @ 2005-01-09 20:17  一根神棍研古今  阅读(2525)  评论(4编辑  收藏  举报
Web Counter