作者:杨荫堂(广智公司技术部)

    敏捷方法是相当具争议性的论调,一方面以其反传统的做法饱受一部分人质疑,同时又因为在一定的范围内取得成功而获得相当一部分人的青睐。

    其实很早以前我们就曾经用过敏捷方法来改进我们的开发过程——XP方法,并取得不错的效果。其实XP方法是敏捷方法的一部分,当时应用的结队编程在提高新人融入,重构在提高产品质量方面,都取得比较明显的效果。我们过去取得的经验这次不再重复,这一次先从另一角度开始说说敏捷方法对软件开发过程中架构设计的研究。记住一点,我们并不是为了架构设计而研究架构设计,我们的目的在于敏捷方法学的应用。

    架构设计是一种权衡。一个问题总是有多种的解决方案。而我们要确定唯一的架构设计的解决方案,就意味着我们要在不同的矛盾体之间做出一个权衡。我们在设计的过程总是可以看到很多的矛盾体:开放和整合,一致性和特殊化,稳定性和
展性等等。任何一对矛盾体都源于我们对软件的不同期望。可是,要满足我们希望软件稳定运行的要求,就必然会影响我们对软件易于扩展的期望。我们希望软件简单明了,却增加了我们设计的复杂度。没有一个软件能够满足所有的要求,因为这些要求之间带有天生的互斥性。而我们评价架构设计的好坏的依据,就只能是根据不同要求的轻重缓急,在其间做出权衡的合理性。

    下面阐述敏捷方法当中的一些思想:


一、目标

我们希望一个好的架构能够:


1、重用:

    为了避免重复劳动,为了降低成本,我们希望能够重用之前的代码、之前的设计。重用是我们不断追求的目标之一,但事实上,做到这一点可没有那么容易。在现实中,人们已经在架构重用上做了很多的工作,工作的成果称为框架(Frame?work),比如说Windows的窗口机制、文件处理机制等。但是回想我们在商业规则建模方面,有效的框架还非常的少,我觉得这个是我们一个努力的方向。


2、透明:

    有些时候,我们为了提高效率,把实现的细节隐藏起来,仅把客户需求的接口呈现给客户。这样,具体的实现对客户来说就是透明的。


3、扩展:

    我们对延展的渴求源于需求的易变。因此我们需要架构具有一定的扩展性,以适应未来可能的变化。可是,如上所说,扩展性和稳定性,扩展性和简单性都是矛盾的。因此我们需要权衡我们的投入/产出比。以设计出具有适当和扩展性的架构。


4、简明:

    一个复杂的架构不论是测试还是维护都是困难的。我们希望架构能够在满足目的的情况下尽可能的简单明了。但是简单明了的含义究竟是什么好像并没有一个明确的定义。使用模式能够使设计变得简单,但这是建立在我熟悉设计模式的基础上。对于一个并不懂设计模式的人,他会认为这个架构很复杂。对于这种情况,我只能对他说,去看看设计模式。


5、高效:

    不论是什么系统,我们都希望架构是高效的。这一点对于一些特定的系统来说尤其重要。例如开单操作、前台报表打印、预览。这些都是实时操作性比较强,对性能要求比较高的模块,因此,高效的算法,尽量减少不必要的交互就成为这些模块的设计基本思路。

6、安全:

    安全并不是我们文章讨论的重点,却是架构的一个很重要的方面。


二、规则

    为了达到上述的目的,我们
可以对架构设计制定一些简单的规则:

1、功能分解:
    顾名思义,就是把功能分解开来。为什么呢? XP提倡"Once and only once",它反对拷贝旧代码修改的现象。为了做到这一点,我们通常要把功能分解到细粒度。很多的设计思想都提倡小类,为的就是这个目的。

    所以,我们的程序中的类和方法的数目就会大大增长,而每个类和方法的平均代码却会大大的下降。可是,我们怎么知道这个度应该要如何把握呢,关于这个疑问,并没有明确的答案,要看个人的功力和具体的要求,但是一般来说,我们可以用一个简单的动词短语来命名类或方法的,那就会是比较好的分类方法。

    我们使用功能分解的规则,有助于提高重用性,因为我们每个类和方法的精度都提高了。除了重用性,功能分解还能实现透明的目标,因为我们使用了功能分解的规则之后,每个类都有自己的单独功能,这样,我们对一个类的研究就可以集中在这个类本身,而不用牵涉到过多的类。

2、根据实际情况决定不同类间的耦合度

    虽然我们总是希望类间的耦合度比较低,但是我们必须客观的评价耦合度。系统之间不可能总是松耦合的,那样肯定什么也做不了。例如一个进货单的类和一个供应商的类,总会有点关系,否则业务流程也走不过去。而我们决定耦合的程度的依据何在呢?简单的说,就是根据需求的稳定性,来决定耦合的程度。对于稳定性高的需求,不容易发生变化的需求,我们完全可以把各类设计成紧耦合的(我们虽然讨论类之间的耦合度,但其实功能块、模块、包之间的耦合度也是一样的),因为这样可以提高效率,而且我们还可以使用一些更好的技术来提高效率或简化代码。可是,如果需求极有可能变化,我们就需要充分的考虑类之间的耦合问题,我们可以想出各种各样的办法来降低耦合程度,但是归纳起来,不外乎增加抽象的层次来隔离不同的类,这个抽象层次可以是具体的类,也可以是接口,或是一些类。我们可以借用Java中的一句话来概括降低耦合度的思想:"针对接口编程,而不是针对实现编程。" 这也是“依赖倒转原理”的中心思想。而具体实现可以参考大庆的六层结构模型,我在这里就不再班门弄斧。

    设计不同的耦合度有利于实现透明和扩展。对于类的客户(调用者)来说,他不需要知道过多的细节(实现),他只关心他感兴趣的(接口)。这样,目标类对客户来说就是一个黑盒子。如果接口是稳定的,那么,实现再怎么扩展,对客户来说也不会有很大的影响。这样就可以缓解甚至是避免那种牵一发而动全身的问题。


3、够用就好

    敏捷方法很看重刚好够用的问题,现在我们结合架构设计来看:在同样都能够满足需要的情况下,一项复杂的设计和一项简单的设计,哪一个更好。从敏捷的观点来看,一定是后者。因为目前的需求只有10项,而你的设计能够满足100项的需求,只能说这是种浪费。如果在设计时完全没有考虑成本问题,不考虑成本问题,就是对开发团队的不负责,对客户的不负责。