接口和架构
这里的接口指的并不是Java中的Interface的概念,它是广义的接口,在Java语言中具体表现为类的公有方法或接口的方法。在COM体系或J2EE体系中还有类似但不完全相同的表现。对于一个系统的架构来说,最主要的其实就是定义这些接口。通过这些接口来将系统的类联系在一起,通过接口来为用户提供服务,通过接口来连接外部系统(例如数据库、遗留系统等)。因此,我们为了对架构进行验证的要求,就转化为对接口的验证要求。
对接口进行验证的基本思路是保证接口的可测试性。要保证接口具有可测试性,首先要做的是对类和类的职责进行分析。这里有几条原则,可以提高接口的可测试性。
1、 封装原则
接口的实现细节应该封装在类的内部,对于类的用户来说,他只需要知道类发布出的公有方法,而不需要知道实现细节。这样,就可以根据类的共有方法编写相应的测试代码,只要满足这些测试代码,类的设计就是成功的。对于架构来说,类的可测试性是基础,但是光保证这一条还不够。
2、 最小职责原则
一个类(接口)要实现多少功能一直是一个不断争论的问题。但是一个类实现的功能应该尽可能的紧凑,一个类中只处理紧密相关的一些功能,一个方法更应该只做一件事情。这样的话,类的测试代码相应也会比较集中,保证了类的可测试性。回忆在分层模式中我们讨论的那个例子,实现类为不同的用户提供了不同的接口,这也是最小原则的一个体现。
3、 最小接口原则
对于发布给用户使用的方法,需要慎之再慎。一般来说,发布的方法应该尽可能的少。由于公布的方法可能被客户频繁的使用,如果设计上存在问题,或是需要对设计进行改进,都会对现有的方法造成影响。因此需要将这些影响减到最小。另一方面,一些比较轻型的共有方法应该组合为单个的方法。这样可以降低用户和系统的耦合程度,具体的做法可以通过外观模式,也可以使用业务委托模式。关于这方面的讨论,可以参考分层模式。较少的接口可以减轻了测试的工作量,让测试工作更加集中。
4、 最小耦合原则
最小耦合原则说的是你设计的类和其它类的交互应该尽可能的少。如果发现一个类和大量的类存在耦合关系,可以引入新的类来削弱这种耦合度。在设计模式中,中介模式和外观模式都是此类的应用。对于测试,尤其是单元测试来说,最理想的情况是测试的类是一个单纯的类,和其它的类没有任何的关系。但是现实中这种类是极少的,因此我们能够做的是尽可能的降低测试类和其它的类的耦合度。这样,测试代码相对比较简单,类在修改的时候,对测试代码的影响也比较小。
5、 分层原则
分层原则是封装原则的提升。一个系统,往往有各种各样的职责,例如有负责和数据库打交道的代码,也有和用户打交道的代码。把这些代码根据功能划分为不同的层次,就可以对软件架构的不同部分实现大的封装。而要将类的可测试性的保证发展为对架构的可测试性的保证。就需要对系统使用分层原则,并在层的级别上编写测试代码。关于分层的详细讨论,请参见分层模式。
如果你设计的架构无法满足上述的原则,那么可以通过重构来对架构加以改进。关于重构方面的话题,可以参考Martin Fowler的重构一书和Joshua Kerievsky的重构到模式一书。
如果我们深入追究的话,到底一个可验证的架构有什么样的意义呢?这就是下一节中提到的测试驱动和自动化测试的概念。