1 软件重用
软件重用技术是一种重要的软件开发方法,虽然至今软件重用技术还不够成熟,离理想中的软件工厂还有很长的路要走,但现有的一些重用技术(例如,中间件 、 应用服务器等)已经改变了开发过程。
1.1 软件重用形式
软件产品与其他的产品不同,是抽象的,一旦产生就可以无限制地复制,因此重复利用软件产品的意义重大,可以节约大量的人力物力。软件重用指的是利用已经存在的软件元素建立新的软件系统,这其中的软件元素既可以是软件产品 、 源程序,也可以是文档 、 设计思想甚至是领域知识。软件重用可以直接提高软件的开发效率 、 降低软件的开发成本 、 缩短软件的开发周期 、 提高软件质量。
常见的软件重用形式包括:
(1)源代码重用
这是最简单也是最常见的重用形式,但由于软件系统的复杂性,很难大规模地重用已有源代码。
(2)架构重用
架构重用也很常见,随着软件架构风格和设计模式的推广和应用,架构重用已经对软件开发产生了重大的影响。
(3)应用框架的重用
随着软件技术的发展,应用框架的重用变得越来越普遍,很多成熟的软件公司都建立了自己的开发框架。在开源社区中,世界各地的技术爱好者也在不断地推出应用了各种新技术的开发框架,例如,应用了 AOP ( Aspect Oriented Programming ,面向方面编程)技术的 Spring 等。
(4)业务建模的重用
虽然不同的软件的业务领域各自不同,但人们还是总结出了一些常见领域的建模方法,重用这些领域模型可以降低因领域知识不足而造成的需求风险。
(5)文档及过程的重用
软件文档和软件过程也是软件开发中不可或缺的元素,有效地重用这些文档和过程也有助于提高开发效率和软件质量 、 降低开发成本。
(6)软件服务的重用
随着 Web 服务的提出,人们越来越关注服务的重用 。SOA ( Service-Oriented Architecture ,面向服务的架构)提出了面向服务的软件架构,并定义了相应的标准。
1.2 构件技术
构件又称为组件,是一个自包容 、 可复用的程序集。首先,构件是一个程序集,或者说是一组程序的集合。这个集合可能会以各种方式体现出来,如源程序或二进制的代码。这个集合整体向外提供统一的访问接口,构件外部只能通过接口来访问构件,而不能直接操作构件的内部。
构件的两个最重要的特性是自包容与可重用。自包容指的是构件的本身是一个功能完整的独立体,构件内部与外部的功能界限清晰明确,可以独立配置与使用。而可重用既是构件的特点,也是构件出现的目的。早在 1968 年 NATO 软件工程会议, Mcllroy 的论文 《 大量生产的软件构件 》 中,就提出了 “ 软件组装生产线 ” 的思想。从那以后,使用构件技术实现软件复用,采用 “ 搭积木 ” 的方式生产软件,就成为软件人员的梦想。
构件的开发者和使用者往往不是相同的人或组织,所以必须定义构件的标准才能够消除其中的障碍。随着构件技术的发展,目前应用比较广泛的构件标准有 CORBA、JavaBean/EJB、COM/DCOM。
(1)CORBA
CORBA(Common ObjectRequest Broker Architecture 公共对象请求代理体系结构)是由OMG组织制订的一种标准的面向对象应用程序体系规范。
CORBA 有很广泛的应用,它易于集成各厂商的不同计算机,从大型机一直到微型内嵌式系统的终端桌面,是针对大中型企业应用的优秀的中间件。最重要的是,它使服务器真正能够实现高速度 、 高稳定性处理大量用户的访问。现在很多大型网站后端的服务器都运行 CORBA。
(2)JavaBean/EJB
JavaBean在一般情况下指的是实体类,在大部分情况下和POJO是同义词,基本构成就是一些字段和与之对应的 setter、getter方法,如果一个JavaBean需要在不同的JVM的进程中进行传递,还需要实现Serializable接口。
EJB = Enterprise Java Bean,现在已经很少使用了。
(3)COM/DCOM
COM(Component Object Model) 提供了一个 Windows 平台上的对象通讯技术,并且逐渐成为应用程序之间彼此通讯及互动的技术主流,那么 DCOM(Distributed COM) 则是解决了计算机的通信和互动技术。
COM 的着眼点是在于同一台计算机上不同应用程序之间的通讯需求,跨到另外一台计算机之外,就不是一开始 COM 所设想到的领域。所幸跨程序的通讯和跨计算机的通讯差异仅在于通讯协议的处理 ( 也就是定位问题 ) ,对于数据交换上的处理并不会因此而有区别。所以要让 COM 的环境能更进一步延伸到跨计算机的领域,只要妥善解决计算机定位的需求,就有机会克服。同样幸运的是, COM 在一开始的设计中完全不去碰触跨计算机的问题,使得要在 COM 的架构之上再架上一层跨计算机的处理环境并不会去破坏到原本的架构。于是 COM 的网络延伸版本 DCOM(Distributed COM) 就此出现,负责让 COM 组件可以在网络环境下持续提供服务。 DCOM 最主要处理的是两个议题,第一个议题是网络通讯能力,第二个议题则是权限的问题。之前 COM 是在同一台计算机中找特定的组件,而 DCOM 则要更进一步去找网络上的某台计算机,之后沿用 COM 的机制找到计算机上的组件。
COM+倡导一种新的设计概念,把COM组件提升到应用层,把底层细节留给操作系统,使COM+与操作系统的结合更加紧密。COM+的底层结构仍然以COM为基础,但在应用方式上则更多地继承了MTS(Microsoft Transaction Server)的处理机制,包括MTS的对象环境、安全模型、配置管理等。COM+把COM、DCOM和MTS三者有机地统一起来,同时也新增了一些服务,如负载平衡、内存数据库、事件模型、队列服务等,形成一个概念新、功能强的组件体系结构,使得COM+形成真正适合于企业应用的组件技术。
2 基于架构的软件设计
基于架构的软件设计( Architecture-Based Software Design , ABSD )是一种架构驱动方法。这种方法有3个基础:
(1)功能的分解。在功能分解中, ABSD 方法使用已有的基于模块的内聚和耦合技术。
(2)通过选择架构风格来实现质量和业务需求。
(3)软件模板的使用。软件模板利用了一些软件系统的结构。
然而,对于设计方法来说,软件模板的使用是一个新概念,下面,我们进行简单的介绍。软件模板是一个特殊类型的软件元素,包括描述所有这种类型的元素在共享服务和底层构造的基础上如何进行交互。软件模板还包括属于这种类型的所有元素的功能,这些功能的例子有:每个元素必须记录某些重大事件,每个元素必须为运行期间的外部诊断提供测试点等。在软件产品线系统中,软件模板显得格外重要,因为新元素的引入是一个通用的技术,这种技术用来使产品线架构适应一个特定的产品。
ABSD 方法是递归的,且迭代的每一个步骤都是清晰定义的。因此,不管设计是否完成,架构总是清晰的,这有助于降低架构设计的随意性。
2.1 ABSD 方法与生命周期
图 1 描述了 ABSD 方法在生命周期中的位置。尽管我们没有描述一个需求获取 、 组织或跟踪的特定方法,但还是假设一个需求阶段至少部分地完成,从需求阶段(包括功能需求 、 质量和业务需求 、 约束等)获得了输出。 ABSD 方法的输出是三个视图的概念构件的集合,包括能够产生每个概念构件的假定 、 软件模板的集合和那些已经做出的具体实现的决策,我们把具体实现决策当作附加约束来维护。
在 ABSD 方法中,必须记录所有做出的决策及这些决策的原理,这有利于决策的可跟踪性和决策评审。
ABSD 方法的输入由下列部分组成:
(1)抽象功能需求,包括变化的需求和通用的需求;
(2)用例(实际功能需求);
(3)抽象的质量和业务需求;
(4)质量因素(实际质量和业务需求);
(5)架构选项;
(6)约束。
下面,我们描述需求阶段的假定输出,即 ABSD 方法的输入。
2.1.1 抽象功能需求
ABSD 方法假定需求阶段的输出之一是功能需求的抽象描述,包括这些需求的粗略变化的描述。当获取需求时,考虑所有最终用户是重要的。
对一个特定系统来说,通常有不同类型的最终用户。不同的系统管理员(数据库管理员 、 系统管理员 、 网络管理员等)都可以是最终用户。维护工程师也可以是系统的最终用户。总之,一个最终用户就是当系统运行时使用系统的任何人员。与抽象功能需求相联系的是对公共需求和与这些需求相关的粗略变化的描述,在设计阶段,理解这些需求之间的依赖关系是至关重要的。
我们必须在某种抽象级别上获取功能需求,产品的详细需求往往要等具体产品开发完成后才能知道。当详细需求明确时,抽象功能的获取为详细需求提供了分类。
2.1.2 用例
如前所述,用例是一个或多个最终用户与系统之间的交互的具体表述,在这里,最终用户既可以是操作人员,也可以是与系统进行交互操作的其他软件系统。虽然用例很容易找到和创建,甚至可能有成百上千个,但是,因为我们需要分析用例,所以必须限制用例的数量。在架构设计阶段,只有重要的用例才有用。我们必须对所创建的用例进行分组 、 设置优先级,以便筛选出最重要的用例,剩下的用例可以在设计阶段的任何时候创建。
2.1.3 抽象的质量和业务需求
我们必须对待构建系统的质量和业务需求进行编号,每个质量属性都包含一个特定的刺激,以及希望得到的响应。质量需求要尽量具体化。
2.1.4 架构选项
对每个质量和业务需求,我们都要列举能够满足该需求的所有可能的架构。例如,如果需求是支持一系列不同的用户界面,则可能的架构选择就是把不同的用户界面分解成不同的构件。又如,如果需求是保持操作系统的独立性,则可能的架构选择就是构建虚拟的操作系统层,接受所有的操作系统调用,并解释之为当前操作系统所能支持。
在这个时候,只需列举所有可能的选项,而不需要对这些架构选项进行决策,这种列举取决于设计师的经验,既可来自某些书籍介绍,也可直接来自设计师本身的实践。
2.1.5 质量场景
正如用例使功能需求具体化一样,质量场景使质量需求具体化。质量场景是质量需求的特定扩充。
与用例一样,质量场景也很容易找到和创建,可以创建很多个。我们必须对质量场景进行分组 、 设置优先级,只需验证最重要的质量场景。
2.1.6 约束
约束是一个前置的设计决策,设计过程本身包含决策。某些决策可以直接由业务目标导出而无须考虑对设计的影响。例如,如果一个公司在某个中间件产品上投入了大量资金,那么在产品的选择上就可以不必考虑其他决策。在需求获取阶段,约束主要来自系统的业务目标。
在某些特殊情况下,约束由遗留系统决定。今天,几乎没有软件系统不参考已有系统的,常见的情况是,新老系统同时并存,或者新系统替代老系统,但是必须尽可能重用老系统的功能。在设计阶段,虽然这些遗留系统处于被设计系统的外部,但设计师必须考虑遗留系统的特征。也就是说,在某种程度上,遗留系统影响着当前的设计,因此,理解遗留系统的结构和解决问题的技术都很重要。出于商业目的,可能要求重用遗留系统的构件,这种需求就变成了约束。
2.2 基于架构的软件开发模型
基于架构的软件开发模型( Architecture-Based Software Design Model , ABSDM )把整个基于架构的软件过程划分为架构需求 、 设计 、 文档化 、 复审 、 实现 、 演化等6个子过程,如图 2 所示。
2.2.1 架构需求
需求是指用户对目标软件系统在功能 、 行为 、 性能 、 设计约束等方面的期望。架构需求受技术环境和架构设计师的经验影响。需求过程主要是获取用户需求,标识系统中所要用到的构件。架构需求过程如图 3 所示。如果以前有类似的系统架构的需求,我们可以从需求库中取出,加以利用和修改,以节省需求获取的时间,减少重复劳动,提高开发效率。
(1)获取需求
架构需求一般来自三个方面,分别是系统的质量目标 、 系统的业务目标和系统开发人员的业务目标。软件架构需求获取过程主要是定义开发人员必须实现的软件功能,使得用户能完成他们的任务,从而满足业务上的功能需求。与此同时,还要获得软件质量属性,满足一些非功能需求。
(2)标识构件
在图 3 中虚框部分属于标识构件过程,该过程为系统生成初始逻辑结构,包含大致的构件。这一过程又可分为三步来实现。
第一步:生成类图。生成类图的 CASE 工具有很多,例如 Rational Rose 就能自动生成类图。
第二步:对类进行分组。在生成的类图基础上,使用一些标准对类进行分组可以大大简化类图结构,使之更清晰。一般地,与其他类隔离的类形成一个组,由泛化关联的类组成一个附加组,由聚合或组合关联的类也形成一个附加组。
第三步:把类打包成构件。把在第二步得到的类簇打包成构件,这些构件可以分组合并成更大的构件。
(3)需求评审
组织一个由不同代表(如分析人员 、 客户 、 设计人员 、 测试人员)组成的小组,对架构需求及相关构件进行仔细的审查。审查的主要内容包括所获取的需求是否真实反映了用户的要求,类的分组是否合理,构件合并是否合理等。
必要时,可以在 “ 获取需求 — 标识构件 — 需求评审 ” 之间进行迭代,在图 3 中以虚线箭头表示。
2.2.2 架构设计
架构需求用来激发和调整设计决策,不同的视图被用来表达与质量目标有关的信息。架构设计是一个迭代过程,如果要开发的系统能够从已有的系统中导出大部分,则可以使用已有系统的设计过程。软件架构设计过程如图 4 所示。
(1)提出软件架构模型
在建立架构的初期,选择一个合适的架构风格是首要的。在这个风格基础上,开发人员通过架构模型,可以获得关于架构属性的理解。此时,虽然这个模型是理想化的(其中的某些部分可能错误地表示了应用的特征),但是,该模型为将来的实现和演化过程建立了目标。
(2)把已标识的构件映射到软件架构中
把在架构需求阶段已标识的构件映射到架构中,将产生一个中间结构,这个中间结构只包含那些能明确适合架构模型的构件。
(3)分析构件之间的相互作用
为了把所有已标识的构件集成到架构中,必须认真分析这些构件的相互作用和关系。
(4)产生软件架构
一旦决定了关键的构件之间的关系和相互作用,就可以在第2阶段得到的中间架构的基础上进行细化。
(5)设计评审
一旦设计了软件架构,我们必须邀请独立于系统开发的外部人员对架构进行评审。
2.2.3 架构文档化
绝大多数的架构都是抽象的,由一些概念上的构件组成。例如,层的概念在任何程序设计语言中都不存在。因此,要让系统分析师和程序员去实现架构,还必须得把架构进行文档化。文档是在系统演化的每一个阶段,系统设计与开发人员的通信媒介,是为验证架构设计和提炼或修改这些设计(必要时)所执行预先分析的基础。
架构文档化过程的主要输出结果是架构需求规格说明和测试架构需求的质量设计说明书这两个文档。生成需求模型构件的精确的形式化的描述,作为用户和开发者之间的一个协约。
软件架构的文档要求与软件开发项目中的其他文档是类似的。文档的完整性和质量是软件架构成功的关键因素。文档要从使用者的角度进行编写,必须分发给所有与系统有关的开发人员,且必须保证开发者手上的文档是最新的。
2.2.4 架构复审
从图 4 中我们可以看出,架构设计 、 文档化和复审是一个迭代过程。从这个方面来说,在一个主版本的软件架构分析之后,要安排一次由外部人员(用户代表和领域专家)参加的复审。复审的目的是标识潜在的风险,及早发现架构设计中的缺陷和错误,包括架构能否满足需求 、 质量需求是否在设计中得到体现 、 层次是否清晰 、 构件的划分是否合理 、 文档表达是否明确 、 构件的设计是否满足功能与性能的要求等等。由外部人员进行复审的目的是保证架构的设计能够公正地进行检验,使组织的管理者能够决定正式实现架构。
2.2.5 架构实现
所谓 “ 实现 ” 就是要用实体来显示出一个软件架构,即要符合架构所描述的结构性设计决策,分割成规定的构件,按规定方式互相交互。架构的实现过程如图 5 所示。
图 5 中的虚框部分是架构的实现过程。整个实现过程是以复审后的文档化的架构说明书为基础的,每个构件必须满足软件架构中说明的对其他构件的责任。这些决定即实现的约束是在系统级或项目范围内做出的,每个构件上工作的实现者是看不见的。
在架构说明书中,已经定义了系统中构件与构件之间的关系。因为在架构层次上,构件接口约束对外唯一地代表了构件,所以可以从构件库中查找符合接口约束的构件,必要时开发新的满足要求的构件。
然后,按照设计提供的结构,通过组装支持工具把这些构件的实现体组装起来,完成整个软件系统的连接与合成。
最后一步是测试,包括单个构件的功能性测试和被组装应用的整体功能和性能测试。
2.2.6 架构演化
在构件开发过程中,最终用户的需求可能还有变动。在软件开发完毕,正常运行后,由一个单位移植到另一个单位,需求也会发生变化。在这两种情况下,就必须相应地修改软件架构,以适应新的软件需求。架构演化过程如图 6 所示。架构演化是使用系统演化步骤去修改应用,以满足新的需求。
主要包括以下七个步骤:
(1)需求变动归类首先必须对用户需求的变化进行归类,使变化的需求与已有构件对应。对找不到对应构件的变动,也要做好标记,在后续工作中,将创建新的构件,以对应这部分变化的需求。
(2)制订架构演化计划在改变原有结构之前,开发组织必须制订一个周密的架构演化计划,作为后续演化开发工作的指南。
(3)修改 、 增加或删除构件在演化计划的基础上,开发人员可根据在第一步得到的需求变动的归类情况,决定是否修改或删除存在的构件 、 增加新构件。最后,对修改和增加的构件进行功能性测试。
(4)更新构件的相互作用随着构件的增加 、 删除和修改,构件之间的控制流必须得到更新。
(5)构件组装与测试通过组装支持工具把这些构件的实现体组装起来,完成整个软件系统的连接与合成,形成新的架构。然后对组装后的系统的整体功能和性能进行测试。
(6)技术评审对以上步骤进行确认,进行技术评审。评审组装后的架构是否反映需求变动,符合用户需求。如果不符合,则需要在第2到第6步之间进行迭代。
(7)产生演化后的架构在原来系统上所作的所有修改必须集成到原来的架构中,完成一次演化过程。