【IT168 技术文章】
代码重复随时会产生麻烦,有些人可能对代码做了修改,但是忘了将修改应用于重复的源代码。产生的混乱可大可小,但是无论程度如何,重复都是麻烦的来源。在本文中,IBM 开发人员 Steve McDuff 建议使用配置驱动的开发来解决这个问题。
配置驱动的开发和模型驱动的开发之间的差异是,前者并不限制于代码的模型,比如类、字段和关系。配置驱动的开发(Configuration-driven development,CCD)包含应用程序中可以配置的所有内容。例如,如果体系结构指出某些业务规则必须一致地应用于整个应用程序,那么可以使用配置文件来配置和应用这些规则。
在本文中,我将介绍配置驱动的开发,并解释它如何解决代码重复和修改问题。
代码重复和修改
假设您正在开发的应用程序由以下组件组成:
1.一个数据库
2.带 Web 服务 API 的中间件服务器
3.带基于 Web 的用户界面的中间件服务器
4.使用中间件 API 的胖客户机
图 1. 一个简单的参数
在 图 1 中可以看到,一个简单的参数(比如字符串的长度)将会影响所有四个组件。它还会影响下面的用户文档和单元测试领域:
用户文档:
●胖客户机
●基于 Web 的用户界面
●Web 服务 API
单元测试领域:
●数据库
●Web 服务 API
●基于 Web 的用户界面
●胖客户机
图 2 说明了 图 1 所示的简单参数的总体影响。
真是让人吃惊,像字符串长度这么简单的东西竟然不只在四个位置上重复,而是在十个不同的位置出现。字符串长度参数只是一个例子;许多类型的业务规则对于典型的应用程序都有类似的影响。一些规则是几乎任何应用程序中都有的,比如字符串长度和数字的最小/最大值。其他规则专门用来满足特定应用程序的需要。应用程序是否使用签出/签入机制保持一致性?关于信息的这些规则是否从客户机和服务器获得?所有这些因素合在一起,即使是最简单的代码修改也很容易导致大混乱。
传统的解决方案
信息重复不是一个新问题,而且已经有许多工具和技术用来防止这个问题。在本节中,我将讨论对信息重复最常用的一些解决方案。
开发过程
一些开发团队将冗余信息修改纳入严格的开发过程中,以此解决信息重复问题。这个解决方案很繁琐,因为它需要监督和复查,但它是有效的。
设计良好的代码
设计良好的代码再加上对常量的重用,可以减轻代码重复问题。当应用程序的所有部分都用同一种语言编写时,代码驱动解决方案的效果优秀。
模型驱动的工具
模型驱动的开发的概念是以配置的形式读取应用程序模型。模型驱动的最大优点是,它们使与对象及其关系相关的繁琐任务自动化。下面是一些流行的模型驱动开发工具:
●Eclipse Modeling Framework(EMF):它存储类的布局和字段。它为应用程序生成 Java 类、网络接口,甚至还包括数据库映射。通过生成对象,EMF 使编写常用方法的繁琐部分自动化,比如获得器、设置器、相等、复制、克隆、串行化等等。EMF 使用可以存储许多对象定义的配置文件。在多用户环境中,合并这些文件可能导致一些问题。EMF 只能处理应用程序的对象、它们的关系和方法。对于处理定制的业务规则,它没有提供任何帮助。
●UML2:它通过类关系、字段和逻辑的图表描述和说明应用程序。UML 的优点是它与语言无关。在完成逻辑设计之后,从理论上说,可以用任何语言生成对象。
●Ruby on Rails:它从数据库模式中提取模型的配置。然后生成处理业务逻辑、基于 Web 的用户界面和单元测试所需的构架。生产效率的提高主要是由于数据库模式的修改会在代码中传播。
CDD 是如何工作的
我已经描述了配置驱动开发的基础。为了更好地理解它是如何工作的,我们来考虑一个来自真实世界的示例。在本节中,我将描述我的团队在开发 Rational Portfolio Manager 中采用的配置驱动开发解决方案。
在 XML 文件中存储配置
在配置驱动的开发中,开发人员主要在 XML 文件中进行所有修改。与应用程序相关的所有其他文件都从这些文件中读取它们的配置,要么是在运行时读取配置,要么是在构建时生成选择的组件。在 Rational Portfolio Manager 项目中,我们在配置文件中存储以下组件和信息:
应用程序对象
●它们的关系
●它们的文档
●它们的验证规则
●它们在签入/签出机制中的行为
●它们在应用程序安全框架中的限制
●它们的数据库映射
●它们在可视布局中的位置
错误代码
●它们的惟一标识符
●它们的文档
●它们在运行时生成的消息
●它们使用的参数
Web 服务接口定义
●暴露的方法
●文档
●它们使用验证规则时用到的参数
●它们在应用程序安全框架中的限制
图 3 显示典型的配置驱动构建过程。
所需的工具
下面的工具对于配置驱动的开发很重要:
编辑工具
在大多数情况下,简单的文本编辑器对于编辑 XML 文件已经足够了。优秀的 XML 编辑器会在修改文件时检验语法的有效性,并简化 XML 标记的编辑。
读取工具
为了从 XML 文件中获得信息,需要利用某种工具将 XML 文件直接装载到应用程序中。例如,可以使用 Java 库 Betwixt 将 XML 配置的上下文填充到 Java 文件。
用来生成工件的工具
在读取配置文件之后,下一个逻辑步骤是让产品的其他部分利用这些配置信息。这时有几种方法。第一种是将配置文件嵌入软件本身,这样就可以在运行时读取它们。另一个方式是使用工具(比如 Apache Commons 的 Java Velocity 引擎)生成代码和文档。
规则
大多数应用程序开发人员熟悉以下规则,但是与 Java 开发或极限编程中的做法相比,在配置驱动的开发中它们的应用方式有所不同。
1. 保持简单
配置文件必须容易理解和改进。尽管这似乎是理所当然的,但是有经验的 XML 用户常常使用不利于 CDD 方式的高级特性,比如那些使 XML 难以读取和理解的语法。
2. 根据需要进行改进
预定义的 XML 布局不会满足每个开发人员的需要。对这个问题的解决方案是,让 XML 布局能够适应需求。根据领域或软件体系结构的不同,类或字段定义中使用的 XML 属性有很大的差异。请记住,改进应该避免用户破坏 “保持简单” 规则。在上面的示例中,很容易发现许多配置参数在几乎所有其他产品中都没有用。市场上还没有工具能够简化它们的实现。
3. 尽早且经常进行验证
常识指出,在开发过程中越早发现错误,就越容易解决。根据这条原则,尽可能早些对配置进行详尽验证是有意义的。例如,可以使用 XSD 或 DTD 文件验证配置文件的 XML 结构。如果需要应用定制的验证规则,那么要毫不犹豫地实现自己的验证工具。尽管编写这些工具花费的时间并不是花费在最终产品的时间,但是这种投资是值得的。
好处、成本和限制
在采用一种新方法之前,最好是评估一下它的好处和成本,以及不应该 期望从中获得什么。本节概述这三个方面。
好处
减少重复
这种技术的首要好处显然是减少了信息重复,这会提高产品的可维护性和总体质量。
不依赖于特定厂商
由于只使用基本工具来编辑 XML,就不会将自己限制于任何厂商特有的工具。有许多开放源码工具可以用来读取和编辑 XML 文件。
源代码控制
市场上的一些解决方案将它们的输出存储为专有的 XML 格式,几乎不可能对这些文件进行合并。这些 XML 文件之间的引用也会导致问题。在任何时候只让一个团队成员有权修改配置文件是一种效率很差的方法。在多用户环境中,可以用源代码控制工具(比如 CVS、Subversion 或 Clearcase)处理手工编辑的 XML 文件。
对正确的任务使用正确的工具
市场上的大多数工具致力于解决一些非常常见的需求,但是每个产品都有特殊的需求。找到与所有这些需求匹配的工具很困难,甚至是不可能的。定制的配置文件可以只包含与您的项目相关的信息。
技术独立性
一些工具使用配置文件将应用程序与底层技术隔离开。例如,Hibernate 将数据库和对象之间的关系存储在配置文件中,从而将用户与特定厂商的数据库实现隔离开。尽管这种独立性并不完美,但是技术抽象常常是有好处的,因为它有助于以后改进应用程序。
成本
建立结构
建立结构的初始成本是不能忽略不计的。即使使用正确的工具,问题还是会出现。由于有初始成本,配置驱动的开发主要适合于中型和大型项目。
构建过程的复杂性
当从配置文件生成应用程序的组件时,构建过程会变复杂。通过适当的构建自动化,这个成本可以保持在相当低的水平。
限制和折中
业务规则的复杂性
基本概念很容易映射到配置文件中,但是复杂的业务规则就完全不同了。如果应用程序中的复杂规则常常出现小的变化,那么可以创建只存储这些变化的配置文件。考虑到效率,最好是将复杂的业务规则放在代码本身中,而将重复性的概念放在配置文件中。
基础设施成本
对于小型项目,建立基础设施的成本可能比项目本身的成本还高。另外,小项目不会经常受到信息重复的损害。
示例 XML 代码
清单 1 给出一个示例 XML 文件,它代表一个资源(或用户)结构。下面列出示例 XML 代码中的几个属性:
Class:Java 类的名称
Extends:父 Java 类的名称
Abstract:表示在 Java 术语中这个类是否是抽象的
TestReady:表示代码生成器是否应该为这个类生成单元测试
Field name:字段的 Java 变量名
Field type:字段使用的 Java 类型
Field label:用户界面上特定字段使用的标签
Field min and max:字符串或数字值的最小和最大长度
Field default:在创建对象时,应用于一个字段的默认值
Field composite:表示字段是引用还是复合的关系
Field valid types:表示抽象对象数组中可以包含的有效类型
Field mandatory:表示在创建对象时这个字段是否是强制的
Field readable:表示用户是否可以读取这个字段
继承的字段覆盖
清单 1. 代表资源(或用户)结构的示例代码
<object
class="sample.Resource"
abstract="false"
extends="sample.BaseObject"
testready="false"
documentation="A resource represents a user of the system.">
<rule
type="create"
documentation="To create a resource,
the user must have the administrator
security rights" />
<rule
type="update"
documentation="A resource has the right to modify
itself. Only administrators have the right to modify
resources otherwise." />
<rule
type="delete"
documentation="Administrators have the right
to delete a resouce." />
<field
name="active"
label="Active"
type="java.lang.Boolean"
default="true" />
<field
name="calendar"
label="Calendar"
type="sample.WorkCalendar"
composite="false" />
<field
name="contactGroupAssignments"
type="sample.ContactGroupAssignment[]"
composite="true">
<valid-type
class="sample.ContactGroupAssignment" />
</field>
<field
name="name"
label="Full Name"
type="java.lang.String"
mandatory="true"
max="35" />
<field
name="password"
label="Password"
type="java.lang.String"
min="3"
max="16"
readable="false" />
<!-- BaseObject -->
<inherited
name="parent"
mandatory="true">
<valid-type class="sample.ResourceFolder" />
<invalid-type class="sample.Project" />
</inherited>
</object>
使用这个配置文件,可以生成:
●数据库布局
●Web 服务接口
●Java 模型类
●用户文档
●简单的用户界面,其中使用标签和文档提供工具提示和帮助文件
●对配置中每个属性和规则进行单元测试的框架
结束语
在理想情况下,可以使用配置驱动的开发构建整个产品。开发过程由两个阶段组成:
1.构建需要的抽象工具。
2.使用配置文件构建应用程序,配置文件指出这些工具如何链接在一起,形成最终的产品。
配置驱动的开发并不是一种全新的思想,但是如何在通常受到限制的现代工作环境中有效地运用它是有挑战性的任务。在本文中,我介绍了一种实现有效且成功的配置驱动开发过程的简单有效的方法。
参考资料
学习
您可以参阅本文在 developerWorks 全球站点上的 英文原文 。
Explore model-driven development (MDD) and related approaches(Tracy Gardner 和 Larry Yusef,developerWorks,2006 年 3 月):了解模型驱动的开发以及相关的意图。
使您轻松地进行多线程应用程序编程(Ze'ev Bubis 和 Saffi Hartal,developerWorks,2002 年 2 月):了解一种解决代码重复问题的代码驱动方法。
让开发自动化: 持续检查(Paul Duvall,developerWorks,2006 年 8 月):从自动化专家处学习如何使用 CheckStyle、JavaNCSS 和 CPD 这样的检查程序捕获重复错误。
developerWorks Web 开发专区:阅读 developerWorks 上关于 Web 开发技术的更多文章。
Technology bookstore:浏览关于这些主题和其他技术主题的图书。
developerWorks 技术活动和网络广播:随时关注这些技术活动,以此加快学习进度并改进软件项目的品质和结果。
获得产品和技术
下载 Betwixt:下载并用 XML 配置的上下文填充 Java 文件。
下载 Velocity:生成代码和文档工件。
IBM 试用软件:使用可从 developerWorks 直接下载的软件构建您的下一个开发项目。
developerWorks Web 开发下载和产品区域:寻找更多的免费下载。
讨论
通过参与 developerWorks blog 加入 developerWorks 社区!
关于作者
Steve McDuff 是 Rational Portfolio Manager Web Services interface 的开发团队主管。