软件工厂的问题和新方法

发表于:2007-04-28来源:作者:点击数: 标签:问题本页新方法内容工厂
本页内容 是什么让我们裹足不前 目前的经济模型 长期的软件开发问题 我们怎么前进呢? 系统重复利用 模型驱动的开发 组装开发 过程框架 总结 是什么让我们裹足不前 为什么我们无法提高软件开发的自动化水平?主要有两个原因: 返回页首 目前的经济模型 第一
本页内容
是什么让我们裹足不前 是什么让我们裹足不前
目前的经济模型 目前的经济模型
长期的软件开发问题 长期的软件开发问题
我们怎么前进呢? 我们怎么前进呢?
系统重复利用 系统重复利用
模型驱动的开发 模型驱动的开发
组装开发 组装开发
过程框架 过程框架
总结 总结

是什么让我们裹足不前

为什么我们无法提高软件开发自动化水平?主要有两个原因:

目前的经济模型

第一个原因就是目前的商业持续再使用经济模型。在上一篇文章里,我们讨论了语言框架模式,它描述了通向自动化的进展:

在开发完一些问题领域系统后,我们标识了一套可再利用的领域抽象,为了利用这些领域抽象我们文档化了一套模型。

我们开发了一个运行环境,如同一个框架或者服务器,去编辑领域抽象和模型。我们通过示例、调整,配置和集成由运行环境定义的组件来构建一个领域系统。

然后我们定义了一种语言,同时创建了一些支持这种语言工具,比如编辑器、编译器、和调试器去自动执行装配过程。这些使我们更快的响应需求的变化,一旦有部分实现已经发生,也能够容易改变。

这个模型的头两部分大多数组织都能够做到,第三部分却不能做到。开发基于语言的工具目前是相当昂贵的,因此经济意识仅仅在宽而平的领域,例如用户接口构造和数据访问,这些必要的投资由庞大的用户群体来分期清偿。由于这个原因,语言框架模型的商业实现几乎都由平台卖主来提供。这个经济模型是由抽象的范围和价值交替的。如Jackson所述,抽象的价值会随着问题域的特性而增长 。抽象的水平越高,领域应用就越窄,但是在该领域解决问题的价值越多,如图1所示:

softwarefactwo_fig1

图1 抽象的范围与价值交互图

我们正处在软件产业的发展时期,框架和工具必须能更好的垂直交汇,以实现更高的生产力。它们必须为更小的问题种类提供更多价值。这违反了目前的经济模型,因为垂直交汇的框架和工具太小了以至于不能支持平台运行,同时由于需要去发展它们的领域知识主要在终端用户组织那里,这些组织也一般不是软件供应者。

长期的软件开发问题

第二个原因是伴随着软件开发方法和实践的长期问题。四大问题阻碍了其解决至少20年了,主要是整体性构架、没有必要的一般性、一次性开发和过程的不成熟性。

整体性构造

我们不能够通过在重大商业规模上的组装来实现开发。问题不是我们不能够认识机会。通过组装的开发是工业先锋先见之明的一部分已经数十年,当然自从面向对象产生,如果不早一点。我们也没有为了实现这些目标正去投资。组装的开发已经是学术和商业投资于面向对象和基于组件开发的目标。Garlan和其他人有如下建议:

通讯协议和组件实现技术联系相当紧密,它使跨平台边界变得困难,包括同一种产品不同版本或者不同配置。

弱的组件规约和包装技术使厂商很难交流一些关于组件和它们之间交互的信息,使得用户很难预知由组装导致的软件属性。例如,假如有一套任意的组件,一般很难知道它们做什么,它们之间的依赖是什么,它们消耗什么资源,它们体现什么功能,它们导致了什么安全风险。未声明和有冲突的设想使构架不匹配,使组装变得困难和不可能,降低了系统的操作质量

封装的技术,它在开发期间设定了组件边界,使组件在组装、开发或执行期间为了稍微不同的组件能有一定的联系都变得很难。

软件产业中供应商之间的联系较之于其他产业显得不成熟,由于缺乏有预见性、持续性和对用户和厂商都有益的复用技术的技术和实践。

没有必要的一般性

目前的软件开发方法和实践一般提供了更多的自由度,对绝大多数应用程序是必须的。绝大多数商业应用程序,比如由基础模型组成的。它们从数据库中读取数据,封装有商业规则,体现给用户,使用户在商业规则的控制下进行操作,最后将结果写回数据库。当然,这只是个简单的应用,现实中的商业应用一般包含了各种挑战,比如和老式系统的交互,巨大的数据量,非常多的并发用户,高质量的服务约束,这一切使得实现这些基础模型比我们说的难多了。已经开发了许多商业应用程序的人会意识到,虽然有一些东西使得项目具有唯一性、特殊性,但是绝大多数项目之间是相似的。我们需要利用其一般性,用第三代语言(3GLs)如c#和java去开发更多的小部分典型商业应用程序吗?当然不是,那为什么呢,我们需要排他性的依赖它们吗?

第一个原因是未成熟的建模语言标准。UML,在某种意义上说很适合文档化建模,但是不适合模型驱动的开发,因为它缺乏必要的集中性、可扩展性和语义的严格性,从而有效产生软件代码的和其他方面的自动化。另外一个原因是很难产生软件代码和双向工程,不能够和软件生命周期的其他方面集成建模。CASE工具试图通过模型来自动进行软件开发。这些工具都因为许多原因而惨败。也许最重要而有明显的原因是无法按照承诺从与平台无关的模型为多平台生成代码,当平台技术改变时允许客户保护其已有的投资。它们试图通过生成大量的源代码来填补抽象和平台之间的鸿沟,如图2所示。不同于程序语言编译器,它们不能够有效开发平台特性,生产出一些无用的、无效的、缺乏公共命名的代码。同样,双向工程的方法也是脆弱的,很难整理已产生的代码,或者集成一些必要的手工代码去完成复杂的行为。当它们在开发过程进行的差不多时,由于这些原因导致了开发者放弃模型而用手工的方式去写代码。迭代开发的实践激化了这些问题,因为每一次迭代增加了新的需求,或者改变了原有的需求,导致了模型、自动生成的代码和手工代码的修改。

softwarefactwo_fig2

图 2 幼稚的代码生成

CASE工具不能按照交付时的承诺利用模型捕获的元数据集成软件生命周期。它们提供的例子也是不具有说服力的。比如,通过需求来捕获的信息将被用来用例测试测试用具开发。测试结果将用来作为缺陷记录,划定组件缺陷范围。关于架构的依赖信息用来检验配置,在执行环境中自动提供资源。分析设计阶段的努力试图标准化软件生命周期的信息模型,由于它们和实现特别紧密,所以即便是小小的改变也得看众多卖主的意见,这些最后被证明是站不住的。通过开发工具来捕获信息在软件生命周期中集成也是差的。一个问题的原因是文件和常住信息数据库之间的紧张关系。模型不能成为第一类开发工件,直到它们完全成为了基于文档的软件开发。其他的一个问题是错误的关注标准工具的构架而不是信息交互格式。工具的集成要求各供应商同意一致的交互格式。构架标准是不需要的,正如基于XML信息交互的不透明组件服务的成功。

一次性开发

我们不能够完成重要商业水准的重复利用,超出了我们平台的技术。主要原因是我们绝大多数软件产品是和其他软件产品孤立的,没有联系。我们把每一个产品看成是唯一的,尽管绝大多数产品之间的相同点大于其不同之处。如果在软件产品计划时期能够将多版本、多产品综合考虑,那么我们在软件开发阶段的投资回报将会更多。因此,我们很少在识别、收获、包装和分配可利用资产方面做重要的商业投资。重复利用有时是暂时的,但那不是系统的。假如将组件联系起来再利用而不是为每一个组件都做一次设计是低效的,暂时的重复利用几乎就是矛盾的。重复利用很难做到,除非事先能够明确的计划好。

过程的不成熟

我们不能够在计划和预算下持续的开发软件,说明我们的软件过程不成熟。大多数都倾向两种极端之一。他们过度的规范,优化复杂管理,以管理不能变化为代价,或者过度的许可、优化管理变化,以复杂管理为代价。一个成熟的软件过程首先必须是自动的,因为工具不能够自动定义任务。

我们怎么前进呢?

通过应用重要的新方法能够克服阻碍从技术到生产转变的经济和技术问题,这些方法在对付复杂性和变化方面采取了新的方式。这些新的方法目前也存在,同时在商业产品方面表现出了明显的潜力,尽管它们大多数还不成熟。主要在四个方面:系统重复利用、组装开发、模型驱动开发、过程框架。让我们逐一进行考虑。

系统重复利用

软件开发中一种最重要的新方法是定义软件产品族,它们的成员在变化,但是却共享着许多共性的特征。像Parnas,这样一个族提供了一种环境使成员中共性的问题能够集体解决。通过识别和区别特性,这些特性或多或少的存在于多产品和那些变化中,我们能够采用一种系统的方法去重复利用。一个软件产品族由组件或整个产品组成。比如,一个族应当包含不同的应用程序投资管理,包含不同用户管理框架,用户管理框架是由应用程序投资管理和用户关系管理应用程序使用的。

软件产品族是由系统整合业者(SIs)开发的, 从一个用户到一个用户移植应用程序,或者改进已存在的应用程序来创建新的应用程序。他们也通过独立的软件供应商开发软件产品族, 开发区域多应用程序像CRM,或者多版本应用程序通过维护和改进。他们也通过IT组织来开发软件产品族,改进已存在的应用程序,开发多关系的应用程序,或者多版本应用程序通过维护和改进。

软件生产线的实践

软件生产线开发软件产品族,通过标识共同特性和填写特殊领域变化的表格,使软件产品族中成员的开发变得更快、更便宜、更少的风险。而不是寄希望于暂时的重复利用,他们系统的捕获如何开发家族成员的知识,使重复利用资产变得可能,在家族成员开发过程利用那些资产。作为一个家族的产品开发,可以重复利用需求、构架、框架、组件、测试和其他资产。

当然,开发一个生产线需要成本。换句话说,生产线体现了经典的成本-利益权衡。 等式一边的利益不能够通过在支持有限发布的市场上生产许多备份来增加收益时,但是可以通过生产许多相关的、唯一性的产品来增加收益,如许多案例研究所述[CN01]。利用软件生产线是通向软件工业化的第一步。使它们的创建和运行变得更加便宜是第二步。图3在一条生产线上描述了主要任务的执行、工件生产和利用。

softwarefactwo_fig3thumb

图3 软件生产线

生产线开发者应用开发资产去开发软件族成员的方式正如平台开发者创建设备驱动和操作系统以供应用程序开发商使用一样。开发产品资产的一个重要的步骤是开发一个或者更多的区域模型,这些模型描述了由生产线提供的共同问题特性和描述不同的表格。这些模型共同定义生产线的范围,被用来限定预期的软件族成员。软件族成员的需求就是源自于这些模型,提供了一种方式使需求的变化和构架的、实现的、执行的、开发过程的、项目环境的、和软件生命周期的其他部分的变化相互联系。

模型驱动的开发

在前一篇文章里,我们看到了提高抽象水平是一个重要的过程。我们也同时看到了,它减少了抽象的范围,因此实现的时候也减少了开发者的控制。失去控制的损失是权力相应的增加。大多数商业应用程序开发者,比如宁愿使用更高水平的像这些用C#和.NET框架的抽象,而不是组装语言和系统调用。更高水平的抽象产生许多好处,包括更高的生产率,更少的缺陷,更易维护和改进。

不幸的是,我们看到了提高抽象水平和工具非常昂贵。假如我们能够找一些方法使它变得更快、更便宜、更容易,不过我们能够为小的问题域提供更高水平的自动化。这就是模型驱动开发(MDD)的目标。模型驱动开发利用模型驱捕获高层次的信息,通常是非正式的表述,自动实现,或者通过编译模型来执行,或者通过它们使人工开发执行变得容易。这是重要的,因为信息目前在低层的工件里还找不到,比如源代码文件、很难进行跟踪,维护和持续改进。

一些开发活动,比如构建、配置和调试目前都是通过利用从源代码文件和其他实现工件中捕获的信息来实现部分或者完全的自动化的。利用通过模型捕获的信息,MDD也能够提供更多可扩展的自动化活动,和更多自动化优化表格,比如模型调试和自动化配置工具。以下是一些例子:

日常的任务,比如从一种东西生产另外一种东西,通常能够充分的自动化。比如,测试用具通常能够从用户界面模型自动生产,使页面之间进行转换以模拟用户的活动。

其他任务,比如解决工件之间的差别,能够部分实现自动化。比如,表中的列和表单的域中可能是满满的问题待用户去解决,然后由用户决定自动进行校正。

适配器,比如Web service wrappers 在实现技术里能够从模型到桥的差别自动生成。模型也能够用来表示,协议配置,和其他适应的集成机制。

模型可以用来定义工件配置,这些工件由配置单元组成,使配置过程自动化。模型的配置环境能够用来约束设计,以便能够正确的实现设计。

模型能够用来描述配置部件的配置,捕获操作特征的信息,比如下载平衡,失败恢复,资源分配策略,自动化管理活动,数据收集和报告。

特有领域语言

为了MDD,我们不再对一些末端语言如4GLs感兴趣,也不对用一种高水平的语言以实现所有方面的开发感兴趣。这些战略的弱点已经被充分证明。我们也不再对会议上提交的模型感兴趣,还有笔记。不幸的是,模型通常用来编成文件供人来用而不是计算机。这些造成了一种印象,模型不是第一类用源代码的开发工件。我们对用工具来处理模型感兴趣,我们也计划用同样的源代码方式去用它们。用这种方式,文档设计的模型不能用语言来表达。模型必须是准确的不含糊的。同时,为了提高抽象水平,建模语言必须着眼于小的区域而不是一种通用的编程语言。有如下要求:

语言设计的目标必须明确规定,以便熟悉领域的评审人员能够评价语言和决定它是否实现了目标。

这种语言必须要能使工作在该领域的人员能够捕获业务概念。用于开发和装配Web服务的语言必须包含一些概念如Web服务、Web方法、协议和基于协议的连接。同样的,一种语言用来可视化和编辑C#源代码必须包含一些概念(像C#那样),比如类、成员、域、方法、属性、事件和代理。

这种语言必须让其用户熟悉其概念的名称。比如,一个C#开发人员发现一个拥有域和方法的类的模型比发现个拥有属性和操作的类的模型更自然。

语言的符号,是图片或者文字,必须要容易用来解决问题。人们日常作的事情必须容易用概念来表达。比如,它必须要容易用一种可视化和C#源代码编辑的语言来操作一个继承。

这种语言必须要有一套定义好的规则,叫做语法,管理组成概念的表达式。这样使得用工具检测表达式是否正确变得可能,同时帮助用户写概念。

每一个表达式的语义都必须定义完好,以便用户能创建其他人也理解的模型,工具能够从模型中产生合法的实现,从模型中捕获的元数据当用来处理任务时能够做其所期望的事情,像配置服务器

满足这些标准的语言称为领域专用语言(DSL),应为它为那些特殊领域概念进行建模。DSL比一般的建模语言更加严格。像一种编程语言,它也有文字或者图片符号。SQL和HTML就是DSL的两个例子,分别为关系数据定义和Web页面定义服务。

图 4 是两个说明DSL的图示的例子,是Microsoft Visual Studio 2005 Team System的一个屏幕截图。左边的DSL描述了组件,像Web服务。它被用来实现组件开发和配置自动化。右边的DSL描述了数据中心的逻辑服务类型。它被用来设计和实现数据中心配置。Web服务开发是通过把服务部件拖到逻辑服务器上。逻辑服务器上资源需求和可用之间的不同,充满了确认错误和图示。

softwarefactwo_fig4thumb

图4 领域专用语言

增量代码生成

高效代码生成的关键是少生成概念上差别小的代码。这样就可以允许工具利用平台特点,生产集中的、高效的、平台特性的实现。一种使代码生成增加更多的方式是让模型更切近平台,如图5 所示。比如,用编程语言类型系统定义的专用编程语言比使用类型系统定义的建模语言能实现更加真实的建模。这个模型现在变成了一个代码视图,开发者图形化操作程序结构像操作类和方法定义一样。这个工具体现了在代码中难以看到的关系和依赖,节省了为程序结构生成代码的时间和努力。它使得实现了像基于关系收集的编程风格,或者提供高级的特性像重现和模式构造、应用和评估。

softwarefactwo_fig5

图5 编程语言建模

当然,通过限制在可用的平台上进行抽象,这减弱了建模的作用,或者作用不大像编程风格。 那我们如何工作在较高的抽象层呢?我们使用了更加抽象的模型,通过框架或者转换使平台和模型更紧密,如图6所示。让我们逐一看看这些。

softwarefactwo_fig6

图6 使用高层抽象

我们可以用框架去实现模块中的高层抽象,用这些模块在框架扩展点去生成小段代码。相反,模型帮助用户完成框架通过可视化框架概念和用直觉的方式体现扩展。当开始用微软的操作系统时,比如构建图形应用是困难的。随后,Microsoft Visual Basic通过表单和控制概念使得图形应用变得更加容易。

我们可以创建更低层次的DSL描述语言,代替构架或模型语言。为了领导这种革命性的变革,我们还可以利用两个以上的DSL描述语言跨越更宽的跨度,用最高层次的DSL语言描述的模型可以通过提炼转换成可执行的软,如图6所示。这说明了编译器如何工作,如何将高级语言像c#和java转换成中间代码像字节或IL,通过JIT编译成目标平台的二进制格式。

组成机制

当然,手写的代码必须通常和框架代码结合产生一个完整可执行程序。一些不同的机制可以用来做这些东西。它们之间重要的区别是帮定时间。

softwarefactwo_fig7

图 7 设计时间的组成

运行时绑定的两个优点是,通过接口使手写代码和框架代码结合起来,允许通过对象置换来实现动态配置。同时,委派类允许手写代码通过再生来进行保护。一个比较小的缺点是运行时间经常是方法调用。在组件编程模型中,一些基于运行时绑定的机制非常流行,如图8所示。它们在大规模的商业产品中都非常成功。

在编译之前,在同一个工件中的设计时间主要是手写代码时间和框架代码两者的时间,如图7所示。这包括为了避免用户修改框架代码的编辑经验的约束(比如,用只读区域的编辑器)。在其他工具中,用户在一个特别的窗口中添加手写代码。通过异步回调,运行时绑定合并手写代码和框架代码。一种基于代理的运行时绑定机制通过设计模型来描述, 比如、以下从Gamma, et. al.: events (Observer), adapters (Adapter), policy objects (Strategy), factories (Abstract Factory), orchestration (Mediator), wrappers (Decorator), proxies (Proxy), commands (Command)?and?filters (Chain of Responsibility) [GHJV95]. 运行时绑定的两个优点是,通过接口使手写代码和框架代码结合起来,允许通过对象置换来实现动态配置。同时,委派类允许手写代码通过再生来进行保护。一个比较小的缺点是运行时间经常是方法调用。在组件编程模型中,一些基于运行时绑定的机制非常流行,如图8所示。它们在大规模的商业产品中都非常成功。

手写SUB类。用户提供手写代码在框架里的SUB类中。在框架代码中的抽象方法定义了显示覆盖点。比如,用户写了一个框架实体子集,域内通过模板方法模式引用了手写代码,和突出函数调用。

框架SUB类。用户在框架代码的父类中提供了手写代码。手写代码的一个抽象方法在框架代码中被重写。比如,一个框架实体域引入了关于手写代码的父类函数调用,和突出函数调用。

手写委托类。用户在委托类中提补充写代码。比如,一个框架实体在制定处调用一个手写实体,在设置属性值的之前或之后。其实是一种代理服务器模式。

框架委托类。用户补充手写代码去获得框架服务。比如,一个手写代码实体调用框架实体去设置或者得到属性值。

softwarefactwo_fig8

图8 运行时构成

在编译期间绑定合并手写代码和框架代码,如图 9所示。在编译期间利用部分规格和编译时合并是一种很好的方式。在Visual Studio 2005中的Visual Basic和C#语言就是编译期间构成。

softwarefactwo_fig9thumb

图 9 编译时构成

组装开发

平台无关协议领域的重要革新有,自描述,变量的封装,通过流程的组装和构架驱动的开发。

平台无关协议

Web服务技术成功了,早期的组件组装技术从实现技术中分离出用于特定和组装的组件却失败了。由于XML是一种管理信息的技术,不是一种构建组件的技术,Web服务利用封装去映射Web方法调用到本地方法调用,基于下面的组件实现技术。虽然CORBA试图用一种相似的策略,它的复杂性需要平台供应商的大量投资,为此也限制了它的使用范围。基于XML的简单协议明显降低了实现困难,确保它们的普遍性。通过编码远程方法调用请求像XML,它们避免了由平台特殊远程调用编码和参数集结所引起的协同工作问题。同时,通过获得广泛的工业标准认可,它们从一开始就设计了平台的协同工作能力。

自描述

通过改进组件包装来使推断,依赖,行为,资源消耗,性能和证明明显,自描述减少了构架不匹配的情况。它提供的元数据可以用来自动进行组件发现,选择,许可,获得,安装,调整,组装,测试,配置,部署,控制和管理。

自描述最重要的表格是用来描述组件推断,依赖和行为,因此开发者可以推出组件之间的交互,工具才能够验证组装。在面向对象中用途对广泛的规格表是类和接口声明。它们定义了类提供的行为,但是通过在方法签名中命名其他类和接口,仅仅说明了重要的推断和依赖。合约是一种丰富的规格说明。一个合约管理着组件之间的交互。它不知道何时去调用一个组件。一个合约描述了交互顺序,和响应协议非法和其他不可预知的条件。

当然,合约除非是强迫的否则也没有什么用。这有两种方法强制合约。

不用不匹配的合约来组装组件

用合约提供的信息去提供适配器,这种适配器使的组件之间直接交互,或者协调它们之间的交互。

Garlan建议使用标准适配技术菜谱和提供封装与数据转换的工具[Gar96]。一种最有希望的适配策略是发布部分组件,这些组件能够在组装期间通过封装各个方面来完成,这些方面提供了组装需要的代码。这种策略,称之为变量封装,描述如下。

关于自描述的另外一个重要方面是证明。假如组件能够证明仅仅有指定的依赖,消耗了指定的资源,在一定的条件下具有特定的功能特性,或者有一些公开的弱点,那么它能够推断由这些组件组装成的软件所具有的功能特性和操作特性。这已经在卡内基梅隆大学软件工程学院里进行研究,它被认为是可保证组件的可预见组装(PACC)。

变量封装

我们已经看到,静态封装减少了这种可能性--一个的组件通过静态绑定其功能方面或者没有功能或上下关联的内在方面能够用于特定装配。变量封装减少了构架之间的不匹配通过发布部分封装的组件,这些组件通过利用其功能性方面来选择和编制适当的非功能性方面,使得能够适应新的上下文关系,如图10所示。在特定组装中的组件形式能够通过它位置上的上下文来决定。通过使得组件边界更有弹性,和减少构架之间的不匹配可以改进灵活性。通过移除非功能性假设,能够允许功能性部分在组件边界上进行重制。有效的调整可以预先标识,在一些例子中甚至可以通过工具来自动完成。

softwarefactwo_fig10thumb

图10 变量封装

变量封装是面向切面编程的改写(AOP)。AOP是系统的不同方面各自进行先分离后组合的方法[KLM97]。变量封装在三个方面和AOP不同。

变量封装编入了封装的方面,然而AOP,作为普通的实践,编入了非封装的代码行。编入非封装方面,当组装不好的组件包时产生了同样的问题,叫做构架不匹配和不可预见。的确,基于方面编入源代码更倾向于这些问题而不是组件组装,因为组件至少有描述行为和一些防止无依赖的包装。AOP缺乏包装使得开发者难于推断个方面的兼容性和编入的功能特性,或者执行结果特性,几乎使得利用工具检查方面编入都不可能。

在组件开发期间AOP编入方面,但是变量封装编入却比他们晚,比如在组件组装或者配置期间。这非常重要,因为组件可能置入的上下文直到组件 发布时才知道。事实上,为了支持组装开发,如文章所述,第三部分必须能够预知组装和部署无依赖的开发组件。这需要一种正式的方式去分割方面,封装方面,说明方面和包装方面。变量封装也可以是累进的,它可以在不同的阶段发生。比如,我们可以绑定一些方面在组装期间,一些方面在开发期间,一些方面在运行期间。

变量封装是构架驱动的,然而AOP却不是。这些从功能内核分离出来的方面必须通过接口、抽象类、WSDL文件或其他形式的合约来明显定义。

流程管理组装

如果有充足的合约机制,服务可以通过流程管理引擎,比如Microsoft BizTalk Server,去管理它们之间交流的信息顺序,如图11所示。流程管理组装使得组装开发更加容易,因为服务之间的依赖远比二进制组件少。不像类,它们没有必要驻留在同一个执行中。不像组件,需要平台特定的协议,它们能够通过平台边界来组装。如果它们之间的合约是兼容的,两种服务之间可以相互作用。它们可以分别开发和部署,然后通过流程管理来进行组装。假如适当的拦截重道服务可用,它们甚至能够驻留在不同的管理和组织区域。换句话说,流程管理组装消除了不同组件之间的设计、编译、部署时间依赖。

softwarefactwo_fig11thumb

图 11 流程管理组装

流程管理组装实质上是一种仲裁,像Gamma的仲裁模式描述的那样。一个仲裁管理组件之间的交互流程。一个仲裁有强大的属性。其中一个功能是过滤或者翻译组件交互时的信息。另外一个功能是控制交互,如有必要可以通过多路调用来维持状态。这允许仲裁去推断交互,如有必要可以通过条件逻辑改变它们。仲裁同时能够执行一些有用的功能,比如日志,加强安全策略,不同技术或者同一种技术的不同版本之间的联系。一个仲裁同样能够成为组装的功能部分,加强商业规则或者执行商业功能,比如达成商业交易。

架构驱动的开发

当防止组装不匹配组件好过于构建非法的组装时,那么就没有必要提升匹配好的组件的可用性。这就是架构的目标。依照Shaw 和 Garlan,一个软件构架描述了组件的组装,它们之间的交互和可接受的构成模式,减少了良好设计的构架不匹配和约束设计决定的风险。

当然,开发软件架构是具有挑战性的。这使得很多架构师花费了许多年才能够精通有限的构架风格或者应用领域。如果没有在架构实践方面明显的进步和软件构架方面更多的信任,组装开发不能够在工业规模上实现。

这些是架构驱动的软件开发(ADD)的目标,包括:

用于描述、复述和使用架构的标准。

用于预知设计决定效用的方法。

模式或者架构风格,它用来整理设计专家意见,帮助设计者开发组件分割再现模式。

一个架构风格是一个粗糙的模型,它给抽象框架提供了一组家族系统。它定义了一套指定不同种类组件的规则,这些组件能够用来组装一个系统,不同种类组件的关系可以用在组装中、组装时的约束中和组装的设想中。比如,一个Web服务成分风格可用来指定组件提供端口。这些成分是Web服务定义好的,通过连接端口来建立联系,只有两个端口兼容才可以连接,通过HTTP用SOAP来进行通信。其他的架构风格包括:数据流、分层和MVC风格。一个架构风格通过提供频繁出现问题的解决方案,促进了划分和提高了设计重用,同时也有如下促进。

通过标识普通的架构元素来实现再使用,这些构架元素是基于这种风格的、被系统共享的。

通过定义标准构架来表示明白。

通过定义标准的通信机制来提高协同工作能力。

通过定义标准的表示法来提高可视化。

通过定义强制的约束来提高工具开发。

通过标识基于这种风格的系统突出特性来分析。

一个构架描述就是一个定义了软件构架的文档。 IEEE标准 1471,被推荐用来描述密集型软件构架,提供了描述构架的指导方针[IEEE1471]。根据这些指导方针,一个系统有一个或者更多的股东。一个股东有特殊的关注和关于系统某些方面的利益。为了对股东们有用,一个架构描述必须要求有能使股东们明白的形式和结构。ADS就是一个用来描述一个系统家族架构的模板。一个正式的场景定义了一个视图,这个视图可以描述软件产品的一部分;它也提供了一种模式,这种模式用来进行描述,定义范围,目标和听众,习俗语言和用来开发它的方法。

这些突出的元素用来详细说明一个场景包括:

一个标识符和其他介绍性的信息(比如,作者,日期,参考文件,等等)。

与场景的利害关系。

习俗、语言和基于场景用来产生视图的方法。

确认视图的一致性和完成测试。

一个视图从一个给定的场景描述了一个软件产品。一个视图是语义上接近的,意味着它从那个场景描述了一个软件产品。一个视图包含一个或者多个工件,每一个都根据场景需求来开发。一个视图是一个场景的实例,为了更好的成形视图必须和场景是一致的。一个视图遵循网页设计场景,比如,应该描述特殊软件产品的网页布局,应该用场景定义好的符号来描述网页布局。这些突出的元素用来详细说明一个视图包括:

一个标识符和其他介绍性的信息(比如,作者,日期,参考文件,等等)。

视图遵循的场景标识符。

用习俗、语言和场景定义的方法构建的软件产品描述。

为了明白视图和它的场景差别,考虑为商业应用程序进行逻辑数据库设计。逻辑数据库设计是应用程序的一个视图,更确切一点,是一个构成组件的视图。应用程序方面和用来描述它的语言都在逻辑数据库设计场景中规定好了。许多不同的商业应用程序能够规定下来,通过用相同的场景,产生了不同的视图,每个视图描述了一个为一些商业应用程序的逻辑数据库。这些视图能够描述同样的方面,用同一种语言,但是它们会有不同的内容,因此每个内容都描述了一个不同的应用程序。一个组装视图可以从相同的场景中分解出各个组件的视图。

根据IEEE1471,一个架构描述必须标识所用的场景和用这些场景的原理。作为特殊目标的ADS,可以通过列举其所用的一套场景来定义。比如,一个消费者对商业的Web应用程序的ADS可能需要一个对网页布局的场景和一个对商业数据布局的场景。每一个在架构描述中的视图,都必须遵循一个由ADS定义的场景。

过程框架

随着项目规模、地理分布或者时间而复杂度提高时,过程成熟的关键是保持灵活性。经验告诉我们很少有结构通过减少必须的工作量增加了灵活性。这原理能够在软件产品家族中应用,通过运用过程框架去管理复杂的产品同时不减少灵活性。

正式过程的一些困难是它们太抽象了。它们提供的指导对于老程序员是明显的,但是对于初学者就不怎么具体充分了。为了增加使用价值,它必须降低目前项目的细节,因为每一个项目在许多方面都是独特的,我们不可能产生一种能满足所有项目的过程。我们知道如何解决此类问题,我们可以为一个特殊产品家族定制和裁剪出一个正式的过程。如果没有专业供应商,以上的东西是不能在市场上成功的。一些供应商为了给特殊用户定制过程,通常从其他过程如XP添加一些有用的东西。其他的,尤其是系统集成者和ISVs,裁剪过程以适应特殊的产品或者咨询性的实践。每一个方式,高效使用任何过程的关键是使其对于一个给定的项目高度特殊化,以便它仅仅包含直接可用的资源。由这种定制产生的改变是非常复杂的,产生了和原来过程很少相似的结果。

一个高度集中的过程包括详细的项目信息,如工具配置、网络共享路径、开发者根据指导来工作、API文档、 关键过程的重要联系人物的名字像CM,缺陷跟踪和处理,关于check-in的小组策略,编程风格和同等检查,还有其他的关于项目和项目小组的细节特征。和其他形式的系统重用一起,仅当我们能够不止一次用它,这种定制才会有用。同样,重用高集中的过程资源通过消除工作增加了其灵活性,就如同其他的重用资源一样。如同Jacobson常说的,构建东西最快的方式是重用一些已经存在的东西,尤其可重用的资源能够定制和扩展。很多东西都可以系统地重用,开发过程也一样。

一个过程框架分解成一些更小的过程,这些过程附上了ADS的场景。每一个小的过程描述了产生视图的需求。它能够列举出关键的决策点,标识了每个决策点的转换联系,描述了必须和可选的活动,描述了每个活动所需的资源和产生的产品。每个工件处理之前都有一些约束,和一些后置条件,工件稳定时所需的不变环境。比如,我们需要在循环开始之前得到循环条件,在退出时得到结束条件。我们需要所有的代码都构建和测试正确。我们称这种架构为过程框架,因为它定义了可能合并过程的空间,依赖于给定项目的需求和环境,而没有必要为所有的项目都描述一个过程。当一个过程框架定义好了,小的过程能够组合成项目所需的任一工作流,包括自顶而下,自下而上,由里到外,测试编码和编码测试,任何组合或者混合流。

这些工作流可以由资源来驱动,允许通过PERT和CPM来进行优化,当资源可用时启动工作流。许多种类资源可以驱动计划,包括需求和源代码,开发人员和程序管理人员,配置管理产品或者缺陷跟踪系统,像在服务器上打开一个端口或者分配存储器的设备。这称为基于约束的计划。基于约束的计划利用少量的架构需求,平衡了灵活性的需求。基于约束的计划提供了指导,在开发工件上添加了约束,而不是规定过程。灵活性的产生,可以通过一个工作流在约束中动态产生来得到,适应大量环境变量,同时总结学习经验,减少知识再发现的费用和时间。

一个过程框架没有必要太大或者过细,可能包含或多或少的需要的细节。这提供了一种衡量过程大小的方式,依赖于环境。比如,一个小而灵活的小组可以使用小的框架,这种框架仅提供了一些主要的关键实践,如XP。一个大的组织,可以添加许多构建过程的细节,检查过程,测试过程或者组件共享规则。

总结

本文主要讲述了阻碍软件从技术到生产必然转变的长期问题,和能够克服这些问题的重要新方法。虽然每一个重要的新方法都有重要的前景,但是没有一个能够独自促进这种转变。关键的是集成这些重要的新方法到一个综合方法上。这是软件工厂的目标。在本文中,许多问题都讨论的很简单,可能使得读者没有明白或者需要更多的讨论。在《软件工厂:用模式、模型、框架和工具组装应用程序》由 Jack Greenfield 、 Keith Short, 、John Wiley 、 Sons编写的一书中,关于软件工厂有详细的讨论。

原文转自:http://www.ltesting.net