做网站租服务器多少钱,公司培训网站建设,天骏手表网站,wordpress 积分会员十三、代码验证 要保证架构的稳定和成功#xff0c;利用代码对架构进行验证是一种实用的手段。代码验证的核心是测试#xff0c;特别是单元测试。而测试的基本操作思路是测试优先#xff0c;它是敏捷方法中非常重要的一项实践#xff0c;是重构和稳定核模式的重要保障。…十三、代码验证 要保证架构的稳定和成功利用代码对架构进行验证是一种实用的手段。代码验证的核心是测试特别是单元测试。而测试的基本操作思路是测试优先它是敏捷方法中非常重要的一项实践是重构和稳定核模式的重要保障。 面向对象体系中的代码验证 代码验证是保证优秀的架构设计的一种方法同时也是避免出现象牙塔式架构设计的一种措施。我们在上一篇稳定化中提到说架构设计最终将会体现为代码的形式因此使用形式化的代码来对架构进行验证是最有效的。 由于是代码验证因此就离不开编写代码而代码总是和具体的语言、编译环境息息相关的。在这里我们主要讨论面向对象语言代码示例采用的Java语言。利用面向对象语言来进行架构设计有很多的好处 ◆ 首先面向对象语言是一种更优秀的结构化语言比起非面向对象语言它能够更好的实现封装、降低耦合、并允许设计师在抽象层次上进行思考。这些因素为优秀的架构设计提供了条件。 ◆ 其次面向对象语言可以允许设计师只关注在框架代码上而不用关心具体的实现代码。当然这并不是说非面向对象的语言就做不到这一点只是面向对象语言的表现更优秀一些。 ◆ 最后面向对象语言可以进行很好的重用。这就意味着设计师可以利用原有的知识、原有的软件体系来解决新的问题。 此外利用Java语言还可以获得更多的好处。Java语言是一种面向接口的语言。我们知道Java语言本身不支持多重集成所有的Java类都是从Object类继承下来的。这样一个继承体系一旦确定就很难再更改。为了能够达到多重继承的灵活性Java引入了接口机制使用接口和使用抽象类并没有什么不同的地方一个具体类可以实现多个接口而客户端可以通过申明接口类型来使用如下面这样 List employeesnew Vctor(); 如果需要将Vctor换成LinkedList那么除了上面的创建代码其它的代码不需要再做更多的修改。而Vctor这个具体类除了实现List这个接口以外还实现了Cloneable、Collection、 RandomAccess、Serializable。这说明除了List接口之外我们还可以通过以上所列的接口来访问Vector类。因此接口继承能够成为类继承的补充手段发挥十分灵活的作用。同时又避免了多重继承的复杂性。但是接口中只能够定义空方法这是接口的一个缺陷。因此在实际编程中接口和抽象类通常是一起使用的。我们在Java的java.util包中看到Collection接口以及实现Collection接口的AbstractCollection抽象类就是这方面的例子。你可以从AbstractCollection抽象类或其某个子类中继承这样你就可以使用到AbstractCollection中的缺省代码实现由于AbstractCollection实现了Collection接口你的类也实现Collection接口如果你不需要利用AbstractCollection中的代码你完全可以自己写一个类来实现Collection接口这个例子中不太可能发生这种情况因为工具类的重用性已经实现设计的非常好了。Java中有很多类似的例子。Java语言设计并不是我们讨论的重点更加深入的讨论可以参看专门的书籍这里我们就不作太多的介绍了。 以上花了一些篇幅来讨论面向对象设计和面向接口设计的一些简单的预备知识。这些知识将成为代码验证的基础。 接口和架构 这里的接口指的并不是Java中的Interface的概念它是广义的接口在Java语言中具体表现为类的公有方法或接口的方法。在COM体系或J2EE体系中还有类似但不完全相同的表现。对于一个系统的架构来说最主要的其实就是定义这些接口。通过这些接口来将系统的类联系在一起通过接口来为用户提供服务通过接口来连接外部系统例如数据库、遗留系统等。因此我们为了对架构进行验证的要求就转化为对接口的验证要求。 对接口进行验证的基本思路是保证接口的可测试性。要保证接口具有可测试性首先要做的是对类和类的职责进行分析。这里有几条原则可以提高接口的可测试性。 1、 封装原则 接口的实现细节应该封装在类的内部对于类的用户来说他只需要知道类发布出的公有方法而不需要知道实现细节。这样就可以根据类的共有方法编写相应的测试代码只要满足这些测试代码类的设计就是成功的。对于架构来说类的可测试性是基础但是光保证这一条还不够。 2、 最小职责原则 一个类接口要实现多少功能一直是一个不断争论的问题。但是一个类实现的功能应该尽可能的紧凑一个类中只处理紧密相关的一些功能一个方法更应该只做一件事情。这样的话类的测试代码相应也会比较集中保证了类的可测试性。回忆在分层模式中我们讨论的那个例子实现类为不同的用户提供了不同的接口这也是最小原则的一个体现。 3、 最小接口原则 对于发布给用户使用的方法需要慎之再慎。一般来说发布的方法应该尽可能的少。由于公布的方法可能被客户频繁的使用如果设计上存在问题或是需要对设计进行改进都会对现有的方法造成影响。因此需要将这些影响减到最小。另一方面一些比较轻型的共有方法应该组合为单个的方法。这样可以降低用户和系统的耦合程度具体的做法可以通过外观模式也可以使用业务委托模式。关于这方面的讨论可以参考分层模式。较少的接口可以减轻了测试的工作量让测试工作更加集中。 4、 最小耦合原则 最小耦合原则说的是你设计的类和其它类的交互应该尽可能的少。如果发现一个类和大量的类存在耦合关系可以引入新的类来削弱这种耦合度。在设计模式中中介模式和外观模式都是此类的应用。对于测试尤其是单元测试来说最理想的情况是测试的类是一个单纯的类和其它的类没有任何的关系。但是现实中这种类是极少的因此我们能够做的是尽可能的降低测试类和其它的类的耦合度。这样测试代码相对比较简单类在修改的时候对测试代码的影响也比较小。 5、 分层原则 分层原则是封装原则的提升。一个系统往往有各种各样的职责例如有负责和数据库打交道的代码也有和用户打交道的代码。把这些代码根据功能划分为不同的层次就可以对软件架构的不同部分实现大的封装。而要将类的可测试性的保证发展为对架构的可测试性的保证。就需要对系统使用分层原则并在层的级别上编写测试代码。关于分层的详细讨论请参见分层模式。 如果你设计的架构无法满足上述的原则那么可以通过重构来对架构加以改进。关于重构方面的话题可以参考Martin Fowler的重构一书和Joshua Kerievsky的重构到模式一书。 如果我们深入追究的话到底一个可验证的架构有什么样的意义呢这就是下一节中提到的测试驱动和自动化测试的概念。 测试驱动 测试驱动的概念可能大家并不陌生。在RUP中的同样概念是测试优先设计test-first design而在XP中则表现为测试优先编程test-first programming。其实我们在日常的工作中已经不知不觉的在进行测试驱动的部分工作了但是将测试驱动提高如此的高度则要归功于敏捷方法。测试驱动的基本思想是在对设计或编码之前先考虑好或写好测试代码这样测试工作就不仅仅是测试而成为设计或代码的规范了。Martin Fowler则称之为specification by example 在敏捷测试领域。一种做法是将需求完全表述为测试代码的形式。这样软件设计师的需求工作就不再是如何编写需求来捕获用户的需要而是如何编写测试来捕获用户的需要了。这样做有一个很明显的好处。软件设计中的最致命的代码是在测试工作中发现代码不能够满足需求发生这种情况有很多的原因但是其结果是非常可怕的它将导致大量的返工。而将需求整理为测试代码的形式最后的代码只要能够经过测试就一定能够满足需求。当然这种肯定是有前提的就是测试代码要能够完整、精确的描述需求。做到这一点可不容易。我们可以想象一下在对用户进行需求分析的时候基本上是没有什么代码的甚至连设计图都没有。这时候要写出测试代码这是很难做到的。这要求设计师在编写测试代码的时候系统的整体架构已经成竹在胸。因此这项技术虽然拥有美好的前景但是目前还远远没有成熟。 虽然我们没有办法完全使用以上的技术但是借用其中的思想是完全有可能的。 首先测试代码取代需求的思想之所以好是因为测试代码是没有歧义的能够非常精确的描述需求因为代码级别是最细的级别并紧密结合架构。因此从需求分析阶段我们就应该尽可能的保持需求文档的可测试性。其中一个可能的方式是使用CRC技术。CRC技术能够帮助设计人员分析需求中存在的关键类并找出类的职责和类之间的关系。在RUP中也有类似的技术。业务实体代表了领域中的一些实体类定义业务实体的职责和关系也能够有助于提高设计的可测试性。无论是哪一种方法其思路都是运用分析技术找出业务领域中的关键因素并加以细化。 其次测试驱动认为测试已经不仅仅是测试了更重要的是测试已经成为一种契约。用于指导设计和测试。在这方面Bertrand Meyer很早就提出了Design by Contract的概念。从软件设计的最小的单元来看这种契约实际上是定义了类的制造者和类的消费者之间的接口。 最后软件开发团队中的所有相关人员如果都能够清楚架构测试代码那么对于架构的设计、实现、改进来说都是有帮助的。这里有一个关于测试人员的职责的问题。一般来说我们认为测试人员的主要职责是找出错误问题在于测试人员大量的时间都花费在了找出一些开发人员不应该犯的错误上面。对于现代化的软件来说测试无疑是非常重要的一块但是如果测试人员的日常工作被大量原本可以避免的错误所充斥的话那么软件的质量和成本两个方面则会有所欠缺。一个优秀的测试人员应该把精力集中在软件的可用性上包括是否满足需求是否符合规范、设计是否有缺陷、性能是不是足够好。除了发现缺陷注意我们这里用的是缺陷而不是错误测试人员还应该找出缺陷的原因并给出改正意见。 因此比较好的做法是要求开发人员对软件进行代码级别的测试。因此给出架构的测试代码并要求实现代码通过测试是提高软件质量的有效手段。在了解了测试驱动的思路之后我们来回答上一节结束时候的问题。可验证架构的最大的好处是通过自动化测试能够建立一个不断改进的架构。在重构模式中我们了解了重构对架构的意义而保证架构的可测试性并为其建立起测试网下一节中讨论则是架构能够得以顺利重构的基本保证。我们知道重构的基本含义是在不影响代码或架构外部行为的前提条件下对内部结构进行调整。但是一旦对代码进行了调整要想保证其外部行为的不变性就很难了。因此利用测试驱动的思路实现自动化测试自动化测试是架构外部行为的等价物不论架构如何演化只要测试能够通过说明架构的外部行为就没有发生变化。 针对接口的测试 和前文一样这里接口的概念仍然是广义上的接口。我们希望架构在重构的时候能够保持外部行为的稳定。但要做到这一点可不容易。发布的接口要保证稳定设计师需要有丰富的设计经验和领域经验。前文提到的最小接口原则其中的一个含义就是如此发布的接口越多今后带来的麻烦就越多。因此我们在设计架构设计类的时候应该从设计它们的接口入手而不是一上手就思考具体的实现。这是面向对象思想和面向过程思想的一大差别。 这里我们需要回顾在稳定化这一模式中提到的从变化中寻找不变因素的方法。稳定化模式中介绍的方法同样适用于本模式。只有接口稳定了测试脚本才能够稳定测试自动化才可以顺利进行。将变化的因素封装起来是保持测试脚本稳定的主要思路。变化的因素和需要封装的程度根据环境的不同而不同。对一个项目来说数据库一般是固定的那么数据访问的代码只要能够集中在固定的位置就已经能够满足变化的需要了。但是对于一个产品来说需要将数据访问封装为数据访问层或是OR映射层针对不同的数据库设计能够动态替换的Connection。 测试网 本章的最后一个概念是测试网的概念。如果严格的按照测试优先的思路进行软件开发的话。软件完成的同时还会产生一张由大量的测试脚本组成的测试网。为什么说是测试网呢测试脚本将软件包裹起来软件任何一个地方的异动测试网都会立刻反映出来。这就像是蜘蛛网一样能够对需求、设计的变更进行快速、有效的管理。 测试网的脚本主要是由单元测试构成的。因此开发人员的工作除了编写程序之外还需要编织和修补这张网。编织的含义是在编写代码之前先编写测试代码修补的含义是在由于软件变更而导致接口变更的时候需要同步对测试脚本进行修改。额外的工作看起来似乎是加大了开发人员的工作量。但在我们的日常实践中我们发现事实正好相反一开始开发人员虽然会因为构建测试网而导致开发速度下降但是到了开发过程的中期测试网为软件变动节约的成本很快就能够抵消初始的投入。而且随着对测试优先方法的熟悉和认同构建测试网的成本将会不断的下降而起优势将会越来越明显 ◆ 能够很容易的检测出出错的代码为开发人员扫除了后顾之忧使其能够不断的开发新功能此外它还是代码日创建的基础。 ◆ 为测试人员节省大量的时间使得测试人员能够将精力集中在更有效益的地方。 此外构成测试网还有一个额外的成本如果开发团队不熟悉面向对象语言那么由于接口不稳定导致的测试网的变动会增大其构建成本。 总结 从以上的讨论可以看出架构和代码是分不开的架构脱离了代码就不能够称得上是一个好的架构。这是架构的目标所决定的架构的最终目标就是成为可执行的代码而架构则为代码提供了结构性的指导。因此用代码来验证架构是一种有效的做法。而要实现这个做法并不是一件容易的事情我们需要考虑代码级别的架构相关知识我们讨论的知识虽然局限在面向对象语言但是在其它的语言中同样可以找到类似的思想并利用它们为架构设计服务。 要保证架构的稳定和成功利用代码对架构进行验证是一种实用的手段。代码验证的核心是测试特别是单元测试。而测试的基本操作思路是测试优先它是敏捷方法中非常重要的一项实践是重构和稳定核模式的重要保障。 面向对象体系中的代码验证 代码验证是保证优秀的架构设计的一种方法同时也是避免出现象牙塔式架构设计的一种措施。我们在上一篇稳定化中提到说架构设计最终将会体现为代码的形式因此使用形式化的代码来对架构进行验证是最有效的。 由于是代码验证因此就离不开编写代码而代码总是和具体的语言、编译环境息息相关的。在这里我们主要讨论面向对象语言代码示例采用的Java语言。利用面向对象语言来进行架构设计有很多的好处 首先面向对象语言是一种更优秀的结构化语言比起非面向对象语言它能够更好的实现封装、降低耦合、并允许设计师在抽象层次上进行思考。这些因素为优秀的架构设计提供了条件。 其次面向对象语言可以允许设计师只关注在框架代码上而不用关心具体的实现代码。当然这并不是说非面向对象的语言就做不到这一点只是面向对象语言的表现更优秀一些。 最后面向对象语言可以进行很好的重用。这就意味着设计师可以利用原有的知识、原有的软件体系来解决新的问题。 此外利用Java语言还可以获得更多的好处。Java语言是一种面向接口的语言。我们知道Java语言本身不支持多重集成所有的Java类都是从Object类继承下来的。这样一个继承体系一旦确定就很难再更改。为了能够达到多重继承的灵活性Java引入了接口机制使用接口和使用抽象类并没有什么不同的地方一个具体类可以实现多个接口而客户端可以通过申明接口类型来使用如下面这样 List employeesnew Vctor(); 如果需要将Vctor换成LinkedList那么除了上面的创建代码其它的代码不需要再做更多的修改。而Vctor这个具体类除了实现List这个接口以外还实现了Cloneable、Collection、 RandomAccess、Serializable。这说明除了List接口之外我们还可以通过以上所列的接口来访问Vector类。因此接口继承能够成为类继承的补充手段发挥十分灵活的作用。同时又避免了多重继承的复杂性。但是接口中只能够定义空方法这是接口的一个缺陷。因此在实际编程中接口和抽象类通常是一起使用的。我们在Java的java.util包中看到Collection接口以及实现Collection接口的AbstractCollection抽象类就是这方面的例子。你可以从AbstractCollection抽象类或其某个子类中继承这样你就可以使用到AbstractCollection中的缺省代码实现由于AbstractCollection实现了Collection接口你的类也实现Collection接口如果你不需要利用AbstractCollection中的代码你完全可以自己写一个类来实现Collection接口这个例子中不太可能发生这种情况因为工具类的重用性已经实现设计的非常好了。Java中有很多类似的例子。Java语言设计并不是我们讨论的重点更加深入的讨论可以参看专门的书籍这里我们就不作太多的介绍了。 以上花了一些篇幅来讨论面向对象设计和面向接口设计的一些简单的预备知识。这些知识将成为代码验证的基础。 接口和架构 这里的接口指的并不是Java中的Interface的概念它是广义的接口在Java语言中具体表现为类的公有方法或接口的方法。在COM体系或J2EE体系中还有类似但不完全相同的表现。对于一个系统的架构来说最主要的其实就是定义这些接口。通过这些接口来将系统的类联系在一起通过接口来为用户提供服务通过接口来连接外部系统例如数据库、遗留系统等。因此我们为了对架构进行验证的要求就转化为对接口的验证要求。 对接口进行验证的基本思路是保证接口的可测试性。要保证接口具有可测试性首先要做的是对类和类的职责进行分析。这里有几条原则可以提高接口的可测试性。 1、 封装原则接口的实现细节应该封装在类的内部对于类的用户来说他只需要知道类发布出的公有方法而不需要知道实现细节。这样就可以根据类的共有方法编写相应的测试代码只要满足这些测试代码类的设计就是成功的。对于架构来说类的可测试性是基础但是光保证这一条还不够。 2、 最小职责原则一个类接口要实现多少功能一直是一个不断争论的问题。但是一个类实现的功能应该尽可能的紧凑一个类中只处理紧密相关的一些功能一个方法更应该只做一件事情。这样的话类的测试代码相应也会比较集中保证了类的可测试性。回忆在分层模式中我们讨论的那个例子实现类为不同的用户提供了不同的接口这也是最小原则的一个体现。 3、 最小接口原则对于发布给用户使用的方法需要慎之再慎。一般来说发布的方法应该尽可能的少。由于公布的方法可能被客户频繁的使用如果设计上存在问题或是需要对设计进行改进都会对现有的方法造成影响。因此需要将这些影响减到最小。另一方面一些比较轻型的共有方法应该组合为单个的方法。这样可以降低用户和系统的耦合程度具体的做法可以通过外观模式也可以使用业务委托模式。关于这方面的讨论可以参考分层模式。较少的接口可以减轻了测试的工作量让测试工作更加集中。 4、 最小耦合原则最小耦合原则说的是你设计的类和其它类的交互应该尽可能的少。如果发现一个类和大量的类存在耦合关系可以引入新的类来削弱这种耦合度。在设计模式中中介模式和外观模式都是此类的应用。对于测试尤其是单元测试来说最理想的情况是测试的类是一个单纯的类和其它的类没有任何的关系。但是现实中这种类是极少的因此我们能够做的是尽可能的降低测试类和其它的类的耦合度。这样测试代码相对比较简单类在修改的时候对测试代码的影响也比较小。 5、 分层原则分层原则是封装原则的提升。一个系统往往有各种各样的职责例如有负责和数据库打交道的代码也有和用户打交道的代码。把这些代码根据功能划分为不同的层次就可以对软件架构的不同部分实现大的封装。而要将类的可测试性的保证发展为对架构的可测试性的保证。就需要对系统使用分层原则并在层的级别上编写测试代码。关于分层的详细讨论请参见分层模式。 如果你设计的架构无法满足上述的原则那么可以通过重构来对架构加以改进。关于重构方面的话题可以参考Martin Fowler的重构一书和Joshua Kerievsky的重构到模式一书。 如果我们深入追究的话到底一个可验证的架构有什么样的意义呢这就是下一节中提到的测试驱动和自动化测试的概念。 测试驱动 测试驱动的概念可能大家并不陌生。在RUP中的同样概念是测试优先设计test-first design而在XP中则表现为测试优先编程test-first programming。其实我们在日常的工作中已经不知不觉的在进行测试驱动的部分工作了但是将测试驱动提高如此的高度则要归功于敏捷方法。测试驱动的基本思想是在对设计或编码之前先考虑好或写好测试代码这样测试工作就不仅仅是测试而成为设计或代码的规范了。Martin Fowler则称之为specification by example 在敏捷测试领域。一种做法是将需求完全表述为测试代码的形式。这样软件设计师的需求工作就不再是如何编写需求来捕获用户的需要而是如何编写测试来捕获用户的需要了。这样做有一个很明显的好处。软件设计中的最致命的代码是在测试工作中发现代码不能够满足需求发生这种情况有很多的原因但是其结果是非常可怕的它将导致大量的返工。而将需求整理为测试代码的形式最后的代码只要能够经过测试就一定能够满足需求。当然这种肯定是有前提的就是测试代码要能够完整、精确的描述需求。做到这一点可不容易。我们可以想象一下在对用户进行需求分析的时候基本上是没有什么代码的甚至连设计图都没有。这时候要写出测试代码这是很难做到的。这要求设计师在编写测试代码的时候系统的整体架构已经成竹在胸。因此这项技术虽然拥有美好的前景但是目前还远远没有成熟。 虽然我们没有办法完全使用以上的技术但是借用其中的思想是完全有可能的。 首先测试代码取代需求的思想之所以好是因为测试代码是没有歧义的能够非常精确的描述需求因为代码级别是最细的级别并紧密结合架构。因此从需求分析阶段我们就应该尽可能的保持需求文档的可测试性。其中一个可能的方式是使用CRC技术。CRC技术能够帮助设计人员分析需求中存在的关键类并找出类的职责和类之间的关系。在RUP中也有类似的技术。业务实体代表了领域中的一些实体类定义业务实体的职责和关系也能够有助于提高设计的可测试性。无论是哪一种方法其思路都是运用分析技术找出业务领域中的关键因素并加以细化。 其次测试驱动认为测试已经不仅仅是测试了更重要的是测试已经成为一种契约。用于指导设计和测试。在这方面Bertrand Meyer很早就提出了Design by Contract的概念。从软件设计的最小的单元来看这种契约实际上是定义了类的制造者和类的消费者之间的接口。 最后软件开发团队中的所有相关人员如果都能够清楚架构测试代码那么对于架构的设计、实现、改进来说都是有帮助的。这里有一个关于测试人员的职责的问题。一般来说我们认为测试人员的主要职责是找出错误问题在于测试人员大量的时间都花费在了找出一些开发人员不应该犯的错误上面。对于现代化的软件来说测试无疑是非常重要的一块但是如果测试人员的日常工作被大量原本可以避免的错误所充斥的话那么软件的质量和成本两个方面则会有所欠缺。一个优秀的测试人员应该把精力集中在软件的可用性上包括是否满足需求是否符合规范、设计是否有缺陷、性能是不是足够好。除了发现缺陷注意我们这里用的是缺陷而不是错误测试人员还应该找出缺陷的原因并给出改正意见。 因此比较好的做法是要求开发人员对软件进行代码级别的测试。因此给出架构的测试代码并要求实现代码通过测试是提高软件质量的有效手段。在了解了测试驱动的思路之后我们来回答上一节结束时候的问题。可验证架构的最大的好处是通过自动化测试能够建立一个不断改进的架构。在重构模式中我们了解了重构对架构的意义而保证架构的可测试性并为其建立起测试网下一节中讨论则是架构能够得以顺利重构的基本保证。我们知道重构的基本含义是在不影响代码或架构外部行为的前提条件下对内部结构进行调整。但是一旦对代码进行了调整要想保证其外部行为的不变性就很难了。因此利用测试驱动的思路实现自动化测试自动化测试是架构外部行为的等价物不论架构如何演化只要测试能够通过说明架构的外部行为就没有发生变化。 针对接口的测试 和前文一样这里接口的概念仍然是广义上的接口。我们希望架构在重构的时候能够保持外部行为的稳定。但要做到这一点可不容易。发布的接口要保证稳定设计师需要有丰富的设计经验和领域经验。前文提到的最小接口原则其中的一个含义就是如此发布的接口越多今后带来的麻烦就越多。因此我们在设计架构设计类的时候应该从设计它们的接口入手而不是一上手就思考具体的实现。这是面向对象思想和面向过程思想的一大差别。 这里我们需要回顾在稳定化这一模式中提到的从变化中寻找不变因素的方法。稳定化模式中介绍的方法同样适用于本模式。只有接口稳定了测试脚本才能够稳定测试自动化才可以顺利进行。将变化的因素封装起来是保持测试脚本稳定的主要思路。变化的因素和需要封装的程度根据环境的不同而不同。对一个项目来说数据库一般是固定的那么数据访问的代码只要能够集中在固定的位置就已经能够满足变化的需要了。但是对于一个产品来说需要将数据访问封装为数据访问层或是OR映射层针对不同的数据库设计能够动态替换的Connection。 测试网 本章的最后一个概念是测试网的概念。如果严格的按照测试优先的思路进行软件开发的话。软件完成的同时还会产生一张由大量的测试脚本组成的测试网。为什么说是测试网呢测试脚本将软件包裹起来软件任何一个地方的异动测试网都会立刻反映出来。这就像是蜘蛛网一样能够对需求、设计的变更进行快速、有效的管理。 测试网的脚本主要是由单元测试构成的。因此开发人员的工作除了编写程序之外还需要编织和修补这张网。编织的含义是在编写代码之前先编写测试代码修补的含义是在由于软件变更而导致接口变更的时候需要同步对测试脚本进行修改。额外的工作看起来似乎是加大了开发人员的工作量。但在我们的日常实践中我们发现事实正好相反一开始开发人员虽然会因为构建测试网而导致开发速度下降但是到了开发过程的中期测试网为软件变动节约的成本很快就能够抵消初始的投入。而且随着对测试优先方法的熟悉和认同构建测试网的成本将会不断的下降而起优势将会越来越明显 能够很容易的检测出出错的代码为开发人员扫除了后顾之忧使其能够不断的开发新功能此外它还是代码日创建的基础。 为测试人员节省大量的时间使得测试人员能够将精力集中在更有效益的地方。 此外构成测试网还有一个额外的成本如果开发团队不熟悉面向对象语言那么由于接口不稳定导致的测试网的变动会增大其构建成本。 总结 从以上的讨论可以看出架构和代码是分不开的架构脱离了代码就不能够称得上是一个好的架构。这是架构的目标所决定的架构的最终目标就是成为可执行的代码而架构则为代码提供了结构性的指导。因此用代码来验证架构是一种有效的做法。而要实现这个做法并不是一件容易的事情我们需要考虑代码级别的架构相关知识我们讨论的知识虽然局限在面向对象语言但是在其它的语言中同样可以找到类似的思想并利用它们为架构设计服务。