十年前,“组件软件”一词意味着相对具体和明确的事物。少数几个软件组件框架或多或少地为大多数人定义了这个概念。而今天,在软件行业中,很少有比“组件软件”更不精确的术语了。现在,存在着许多不同形式的软件组件,用于许多不同的目的。10年前的技术和方法已经发生了根本性的演变,并且大量涌现的新技术和方法已经重新定义了我们之前对组件软件的理解。
在亚马逊上搜索这个词,可以找到500多个标题。无数的公司和开源项目使用组件软件来描述他们所做的事情。任何关于组件软件主题的总结或历史概述都理应放在一本多卷书中。因此,本文仅着眼于组件软件概念如何演变的关键点,以及我们可能对未来抱有的期望。
我在 Webopedia 上找到一个略显过时的组件软件定义,它与我10年前的记忆一致。
组件软件有时也称为组件件,是被设计为在更大型应用程序中作为组件工作的软件。一个很好的类比是个人计算机的构建方式,它是由一系列标准组件组成的:内存芯片、CPU、总线、键盘、鼠标、磁盘驱动器、显示器等。由于组件之间的所有接口都是标准化的,因此可以在单个系统中混合来自不同制造商的组件。
类似地,组件软件的目标是标准化软件组件之间的接口,以便它们也可以无缝地协同工作。OLE 和 OpenDoc 这两个标准旨在帮助程序员开发可以协同工作的组件。许多分析师认为,组件软件是面向对象编程的自然延伸,并且它将在未来几年成为标准的编程范例。1
这个定义相当不精确,但它抓住了该概念背后的核心动机。维基百科上一个更新的定义指出:
软件组件是一个宽泛定义的术语,指的是用于封装软件功能的软件技术。Clemens Szyperski 和 David Messerschmitt 给出了以下五个标准,用于定义一个软件组件应该是什么:
一个更简单的定义可以是:组件是根据规范编写的对象。规范是什么并不重要:COM、JavaBeans 等,只要对象符合规范即可。只有遵守规范,对象才能成为组件并获得诸如可重用性等特性。2
从字面意义上讲,这些定义在 1996 年和今天同样适用。同样,组件软件背后的核心动机也保持了相当的一致性:
在过去 10 年中发生巨大变化的是我们对组件软件概念如何映射到软件工程实践的理解。
1996 年,我领导一个团队负责架构一个新的分布式应用系统。当时,组件软件方法通常意味着使用 COM 或 CORBA 技术。然而,作为一种名为 Java 的新技术的追随者,我们决定在很大程度上不使用 COM 和 CORBA 提供的组件服务,而是在关系数据库和 JVM 之上构建了我们的组件框架(使用 Java/RMI 进行对象调用)。我们的框架包括基本的组件管理和注册功能,以及基于 SGML(随后是 XML)的数据抽象层。我们还开发了一个容器组件,可以为我们称为适配器的其他组件的子类提供资源和生命周期管理。此外,我们还集成了第三方脚本组件:一个基于 COM,另一个基于 Java。
最终,Java beans、XML 库和应用服务器相继出现,并提供了许多我们以前自己实现的功能。到 2000 年,我们已经将我们的产品发展为在 EJB(Enterprise JavaBeans)容器内运行——部分原因是为了利用应用服务器的组件框架提供的服务,部分原因是为了满足客户和业务合作伙伴的期望。虽然有好处,但我们也发现了使用该框架的缺点。我们曾经相当简单的自定义组件变得更加复杂——仅仅是为了满足框架的要求。与框架开销相关的工作似乎在我们总工作量中所占的比例越来越大。我们的工具和测试基础设施的复杂性也大大增加。最令人沮丧的是,我们意识到我们支付的大部分框架开销税是为了支持我们不需要的需求。
2003 年,我和几位以前的团队成员开始开发一款新产品。当时主要的组件框架是 .NET 和 EJB。然而,与 1996 年相比,这些选项的许多其他变体已经可用。更重要的是,我们的选择不仅限于单个框架,还包括在其他框架内工作的特定用途的组件框架。甚至我们选择使用的开发工具(Eclipse)本身也是一个丰富的组件软件框架。同样重要的是,我们可以将大量预构建的、有用的和低成本的组件集成到我们的产品中。
自 2003 年以来,新型组件系统和有用组件数量的增长只会加速。我们今天构建的产品与我们在 90 年代后期构建的产品之间最鲜明的对比是,我们嵌入但并非自己编写的组件所贡献的功能比例很高。
在这 10 年中,我对组件软件的看法发生了巨大的变化。尤其有三个趋势非常突出:
回到 1996 年,软件系统的大部分复杂性都存在于自定义创建的组件中。组件框架提供非常基本的服务,例如组件注册表和组件之间的调用代理。将应用服务器引入框架,可以将软件开发中一些最复杂的部分(例如线程、内存和事务管理)的责任从自定义组件转移到框架中。然而,这些好处中的一部分被为了使用框架提供的新服务而对组件设计提出的新接口和其他要求所抵消。总的来说,框架提供的服务的快速增加超过了相关的开销以及它们给组件开发带来的额外复杂性。
然而,在过去的三年中,组件系统在简化自定义组件的构建方面取得了长足的进步。为 EJB 或 .Net 容器编写的组件比以前简单得多。更新、更轻量级的容器正在将这一趋势推向更远。Java 世界的一个重要趋势是使用 POJO(Plain Old Java Objects,普通的 Java 对象)作为基本的组件构建块,而不是像 EJB 这样特殊的和更复杂的结构。一类全新的轻量级容器(例如,Spring、Pico、Nano)使用依赖注入模式(也称为控制反转)将诸如对象创建和链接等复杂职责从组件转移到容器。
AOP(面向切面编程)是另一种最近的方法,它侧重于将通用关注点从单个组件转移到框架中。AOP 的特别关注点是系统中跨越(或横跨)许多组件的关注点。典型的例子是日志记录。与其让每个组件都实现日志记录支持,不如将集中实现的功能编织或加入到所有组件中。通过 AOP 方法,诸如安全性或事务支持之类的其他关注点可能会通过框架添加到一组组件中。
这些趋势不仅限于 .NET 或 Java 相关的框架。ROR(Ruby on Rails)的拥护者非常热衷于简化 Web 应用程序开发。Rails 方法是将应用程序的责任最大程度地推入框架,并让开发人员编写尽可能少的代码来实现期望的结果。
1996 年,领先的组件框架 (CORBA) 的核心组件被称为代理(broker)。这个术语反映了一种概念性的观点,即强大且自主的组件社区作为对等方进行交互,而框架仅充当促进者。在 2006 年,容器(container)是首选的描述性名词,而概念性的观点是,框架为极简主义组件社区提供了一个丰富、滋养的环境,这些组件执行专注的任务,并且对框架为它们管理的许多职责一无所知。
诸如 ROR 之类的新型组件系统之所以能够比它们的一些前辈实现更大的简单性,原因之一是它们在所做的事情上更加专注。COM 和 CORBA 的目标是通用性。它们试图成为所有潜在类型交互组件的“世界语”。在 1996 年,似乎存在一个隐含的假设,即任何组件软件框架都必须解决可能出现的任何和所有软件开发挑战。此外,早期的框架受到预期长时间运行的非常庞大、复杂系统的功能需求的驱动。
今天的软件开发是由许多服务于更窄需求的较小项目驱动的。因此,提供更简单编程模型的特殊用途组件框架蓬勃发展。ROR 是一个框架的示例,它特定于一种特定类型的应用程序——在本例中,是相当简单的、由关系数据库支持的 Web 应用程序。这种应用程序模式非常常见,并且由许多其他基于组件的方法提供服务,例如 PHP/MySQL、ASP.NET、WebWorks 和 JSF。
除了特定于特定应用程序类型的组件框架之外,现在还有各种可用于特定功能的框架。例如,许多组件框架主要关注用户交互。当前 Web 2.0 的大部分炒作都与富客户端组件框架有关,例如许多基于 AJAX/Flash 的框架。这些框架提供了特定于用户界面和处理与分布式应用程序服务器端通信的构建块。实现的服务器端可以使用完全独立的组件框架来实现。
在 Web 应用程序的服务器端,框架内的框架很常见。一个 Apache Web 服务器可以加载任意数量的组件,例如 PHP 或 Perl 模块。然后,该模块可以依次加载特定于 PHP 或 Perl 的模块来完成特定任务。可以在两个级别添加新组件。
Eclipse 是一个有趣的组件框架示例,因为它提供了一个特定于应用程序和功能的框架,同时也是一个功能正常的应用程序。Eclipse 框架专门用于面向 IDE 的应用程序的客户端。曾经,几乎每个面向开发的应用程序都有自己的类似 IDE 的客户端。如今,许多应用程序只是将插件组件添加到 Eclipse 并使用它来满足应用程序的客户端需求。Eclipse 可以用作单个应用程序的专用客户端,也可以用作开发人员用于访问许多应用程序的中心客户端。
组件框架的爆炸式增长以及不同框架中交互组件的复杂拓扑结构,得益于我们将组件粘合在一起的方式的进步。过去,绑定组件的方法特定于组件所在的框架,数据在组件之间传递或共享的方式也是如此。这种情况使得所有组件都位于同一框架内非常理想。接口技术和实践在过去 10 年中取得了长足的进步,支持跨异构组件框架的紧密和松散耦合方法。
XML 数据表示和 Web 服务 API 代表了支持松耦合的接口技术的最佳示例。Web 服务 API 为组件交互提供了一种与框架无关的方式。例如,它们为在一个组件框架中开发的基于浏览器的客户端与在不同组件框架中开发的应用程序的服务器组件进行通信提供了一种便捷的方式。在 1996 年,可用的粘合技术(例如 ASN.1 和 IDL(接口定义语言))使得跨框架组件集成极其困难。
SOA(面向服务的架构)是过去五年中最突出的方法之一,是组件软件实践的一个例子。任何 SOA 实现中的服务都满足组件定义标准(但是,任意组件可能不符合服务的资格)。在典型的 SOA 实现中,组件都实现为服务,框架由 Web 服务 API 和一组框架服务组成。
基于互联网的服务是软件应用程序中越来越多地使用的一种重要组件类型。过去,如果想向 Web 应用程序添加购物车和支付处理功能,则需要在 Web 应用程序中安装相应的组件。而今天,可以选择让 Web 应用程序调用亚马逊提供的服务上的 Web 服务 API,并将亚马逊服务用作本地安装的组件。
已安装组件或基于服务的组件之间的区别可以是透明的。例如,您可以通过下载组件在本地设备上运行、链接到远程服务或通过两者的某种组合来扩展 Web 浏览器的功能——而无需知道实际使用了哪个选项。
1996 年,组件软件是与高级软件开发专业人员直接相关的事物。要使用组件软件,您必须具备扎实的计算机科学概念基础,并且必须投入大量精力来理解您正在使用的任何组件框架(例如,COM 或 CORBA)的具体细节。而今天,组件软件几乎是每个软件技术用户都会接触到和参与其中的事物。
随着简单性的提高,更新的组件框架降低了使用它们所需的软件开发技能。在许多框架中,添加、配置和使用组件只需要非常少的技术技能,而创建新组件则需要更高的技能。例如,要向基于 Apache/PHP 的 Web 应用程序添加和配置组件,通常需要修改配置文件,然后通过脚本调用组件功能。许多不同的基于组件的应用程序系统(例如,Drupal 内容管理系统、SugarCRM 系统等)都提供类似的功能。
几乎每个使用 Web 浏览器的人都安装了插件、附加组件和/或扩展程序(并且知道这些东西是什么)。Firefox 列出了超过 1,200 个扩展程序和插件,Internet Explorer 也存在类似数量的扩展程序和插件。Outlook 和其他办公效率应用程序的情况也类似。显然,这些扩展程序是组件软件的示例。
组件软件的使用示例涵盖了从高级开发人员到应用程序的初级用户的范围。组件导向的软件应用程序开发的一个有趣的新领域是使用基于服务的 SaaS(软件即服务)应用程序。以混搭形式进行的服务组合是一种组件软件开发。现在有来自 Google、Yahoo、Amazon 和 EBay 等提供商的大量服务 API,用于组合其他服务交付的应用程序。今天,借助 Salesforce.com 的 AppExchange、Intuit 的 QuickBase、Coghead 或 JotSpot 等服务,可以在无需安装任何软件或无需高级编程技能的情况下创建和部署软件应用程序。这些产品中的每一个都支持组件或服务重用的一种形式。
毫无疑问,我们今天对组件软件的看法与 10 年前截然不同。在许多方面,软件中的组件化现在在更大程度上类似于最初愿景所基于的机械和电子系统中的组件化。存在大量组件,可以在大量组件系统中使用,这些组件系统可以组装成可工作的应用程序——这类似于将电子组件放在电路板上放入设备中,或将机械零件放入子组件和系统中。与电子或机械系统一样,组件软件系统与具有不同技术技能水平的人员相关。今天,许多软件功能仅通过组件组装和配置来交付——由只有有限技术技能的人员完成。
然而,在许多方面,组件软件世界已经超越了其电子或机械领域的前辈。由于物理约束较少,组件软件系统可以支持拓扑结构、组件类型和组件的使用,而这些在电子或机械领域中没有类似之处。即使是简单的软件系统,也在使用多个级别的组件层次结构(即,系统内的系统内的组件……)进行构建。诸如 Web 服务之类的接口抽象正在促进跨越系统和层次边界的组件交互。例如,有些软件系统由组件组成,它们看起来和行为起来就像单个组件(即使对于其内部的组件而言也是如此)。尝试想象机械系统中的递归。同样,物理学大大限制了机械或电气系统中集中式共享服务的使用。在软件系统中,机会比比皆是,并带来了效率数量级提高的可能性。
然而,组件软件的兴起正在以意想不到的和根本性的方式挑战软件工程的实践。组件框架的众多以及新框架的高速涌现,使得技能短缺和快速再培训比以往任何时候都更加关键。
所需的技能类型也发生了变化。软件工程越来越关注系统组合的挑战,而不是编写实现算法、数据结构或其他功能的特定代码块。软件应用程序的功能和质量取决于工程团队执行编写优秀代码以外任务的能力(例如,子系统选择和提供商资格认证、组件和子系统的组合以及异构系统的测试)。从商业和开源以及打包和 SaaS 提供商处获取更多功能的能力带来了力量和挑战。当系统由独立管理的服务组成时,如何保证整体系统行为(例如,性能、可靠性和安全性)?使用受各种开源或商业许可模式约束的组件会产生什么后果?哪些标准重要,哪些不重要?哪些提供商可能成功?哪些会失败?这些问题并不新鲜,但在以组合为导向的世界中更加关键。今天,大多数软件工程团队都没有充分准备好回答这些类型的问题。
因此,我们的挑战不仅在于改进组件软件技术,还在于开发成功部署该技术所需的方法论、培训、课程和经验基础。
1. http://www.webopedia.com/TERM/c/component_software.html.
2. http://en.wikipedia.org/wiki/Component_Software.
GREG OLSEN 是 Coghead 的首席技术官兼创始人,Coghead 是一家新的 SaaS(软件即服务)提供商。此前,他与人共同创立了 Extricity,这是一家企业对企业集成平台提供商,后被 Peregrine Systems 收购。在 Peregrine,他担任开发副总裁,负责指导新平台的工作。在 Extricity 之前,他在 EIT(企业集成技术公司)管理项目,EIT 是最早的互联网技术公司之一。他的博士研究专注于分布式工程团队的计算支持。他拥有斯坦福大学的博士和硕士学位,以及加州大学圣巴巴拉分校的硕士和学士学位。
最初发表于 Queue 第 4 卷,第 5 期—
在 数字图书馆 中评论本文
Satnam Singh - 使用容器对容器进行集群级日志记录
本文展示了如何使用开源工具实现集群级日志记录基础设施,并使用与用于组合和管理被记录软件系统相同的抽象来部署该基础设施。收集和分析日志信息是运行生产系统以确保其可靠性并提供重要审计信息的必要方面。已经开发了许多工具来帮助聚合和收集特定软件组件(例如,Apache Web 服务器)在特定服务器(例如,Fluentd 和 Logstash)上运行的日志。
Peter Kriens - OSGi 如何改变了我的生活
在 1980 年代初期,我发现了 OOP(面向对象编程),并深深地爱上了它。像往常一样,这种爱意味着说服管理层投资这项新技术,最重要的是,送我去参加酷炫的会议。所以我向我的经理推销了这项技术。我向他描绘了美好的未来,有一天我们将从现成的类创建应用程序。我们将从存储库中获取这些类,将它们放在一起,瞧,一个新的应用程序就诞生了。今天我们或多或少地认为对象是理所当然的,但如果我说实话,我在 1985 年向我的经理推销的东西从未真正实现。
Len Takeuchi - ASPs:集成挑战
使用 ASP 的组织和向 ASP 提供增值产品的第三方供应商需要与它们集成。ASP 通过提供基于 Web 服务的 API 来实现这种集成。通过 Internet 与 ASP 集成和与本地应用程序集成之间存在显着差异。与 ASP 集成时,用户必须考虑许多问题,包括延迟、不可用性、升级、性能、负载限制和缺少事务支持。
Chris Richardson - 解开企业 Java 的难题
关注点分离是计算机科学中最古老的概念之一。这个术语是 Dijkstra 在 1974 年提出的。1 它很重要,因为它简化了软件,使其更易于开发和维护。关注点分离通常通过将应用程序分解为组件来实现。但是,存在跨领域关注点,这些关注点跨越(或横跨)多个组件。这些类型的关注点无法通过传统的模块化形式来处理,并且会使应用程序更加复杂且难以维护。