诊断Java代码:设计可扩展应用程序,第3部分

对应于我们上一篇“ 诊断 Java 代码”中所讨论的透明盒可扩展性,黑盒可扩展性是指,在源代码既不能查看也不能修改时,可以扩展软件系统的方法。通常通过系统配置或使用特定于应用程序的脚本语言来进行这样的扩展。在本专题中,Eric Allen 讨论了何时设计黑盒可 扩展性的系统是有意义的,并提供了如何有效地实现这一设计的一些想法。阅读了本文后,您将知道何时使用黑盒并掌握如何实现它的一些技巧。

我已在以前的文章中谈到了代码重用设计策略的重要性(主要是因为各种信息处理任务的差异和相应费用的增加),所以如果您已确定将系统可扩展性作为您的目标,那么请先问一下自己“系统的可扩展性应该达到什么程度,我能实现怎样的可扩展?”然后,考虑下列方面:

对添加可扩展性的权衡,因为添加扩展性可能会降低性能或测试能力。

通常,测试性最好的系统就是最简单的系统;添加可扩展性常常增加了复杂性。

规划成功的可扩展设计的一个关键知识是,要知道您计划以后如何扩展系统。

在本系列的 第一篇文章中,我曾概述了系统可以呈现的可扩展性的各种形式 — 黑盒设计与两种 白盒设计( 透明盒与 开放盒)。 第二篇文章中,我详细介绍了透明盒可扩展性的使用及实现,透明盒是一种恰当的介于黑盒与开放盒设计之间的设计方法。

这个月,我希望继续我们的“旅行”,展开讨论黑盒可扩展性。

在黑盒中探索方向

黑盒设计是一种可扩展性,它涉及到定制应用程序的用户配置,使该应用程序以对特定环境最有用的方式执行。当用这种方法扩展应用程序时,就不必查看原始的源代码了。

我们都使用过提供这种可扩展性的应用程序。例如,下面这两个应用程序:

Netscape 的插件功能

在用 Emacs Lisp 配置方面,Emacs 具有无限能力

近期,几乎每个新的应用程序都提供了某种程度的黑盒可扩展性。

如何识别一个配置脚本

在继续之前,让我尝试区别配置脚本与程序的其它输入之间的不同。不幸的是,这里真的没有什么明显的差别。程序接受的一组输入(及程序解释这些输入的方法)都可以而且应该视作一种语言。但是您应该了解配置脚本的几个显著特征。

与其它程序输入(每次使用应用程序时,都可以改变程序输入)不同,配置脚本趋向于更为稳定。这些脚本一般有一些缺省值,这些缺省值最初将由用户设置,并在很长一段时间内不会重置这些值。实际上,常在最初安装程序时设置这样的脚本。更改脚本的缺省值很可能会对程序在其它输入上的行为有重大影响。而且,因为永久 存储这些输入的值,所以在随后的程序调用中会检索它们。

明智地选择配置

现在,您可能询问的下一个问题是“何时向应用程序添加这种可扩展性是有意义的呢?”

答案并非是添加尽可能多的可扩展性。毕竟,这种方法的最终结果是:给定适当的脚本(类似于 �berapplikation),单个应用程序就会执行用户所需的每个任务。

可以论证,开发环境属于这一类,但是用户/开发人员所需的“脚本”可能会非常长且复杂。这个极端示例说明了对黑盒可扩展性的基本权衡 — 应用程序提供的黑盒可扩展性越强,用户针对特定环境而配置它所必须执行的工作就越多。

通常,最好对应用程序确定的要求范围更窄一些,但仍可以通用,然后再针对更具体的环境。正如许多“极限编程(Extreme Programming)”小组所演示的那样,缩小项目的范围很可能还会使您真正地成功完成项目(而且还是准时的!)。

某些环境需要黑盒

不过,在某些环境中,您可以非常确定其中需要某一形式的黑盒可扩展性,而且您无需使用户负担过重就能提供这一可扩展性。在许多情况下,这仍需要先实现具有较窄范围的应用程序的不可扩展版本,然后再在另一个版本中添加可扩展性。

您可能觉得这有点自相矛盾。毕竟,添加可扩展性的所有目的是减少实现系统中新功能的花费。如果知道要扩展应用程序,那为什么不在开始时就构建可扩展性呢?因为构建不具备可扩展性的应用程序通常要便捷得多。

最初您能提供的应用程序版本越简单,客户就能越快地将它用于至少是他们的部分任务中。接着,您可以从 版本 1.0的销售中获得收益,来支持开发更具可扩展性的版本。

确定复杂性

考虑这一问题的关键是,您是否希望应用程序的可扩展版本在相当大的程度上要更为复杂。有时,设计应用程序的最简单最自然的方法就是合并可扩展性。

这里最好的示例之一是税收计算应用程序。这样的应用程序可以用于许多组税单。使用哪组特定表单取决于特定的用户;因此,使用特殊用途的配置语言来描述各种表单是很自然的。如果不是这样,而将这些税单硬连接到程序中(即,通过表单的类层次结构,其中每个表单有一个单独的 类),并不会减少复杂性。

但是,一旦用黑盒可扩展性这一方法设计了应用程序,则不必修改,甚至不用查看源代码,就能够方便地添加新的表单(当下一财政年度必须这样做时)。

还有其它一些应用程序示例,它们的黑盒可扩展设计是最简单的。可以想到的示例有:Web 浏览器,电视调度查看器(类似数字电视服务使用的查看器)和依赖于公理数据库的自动化定理证明器。

值得自豪的语言

现在,假设您已决定为应用程序的某些方面提供一种配置语言。在决定这样做时,需要确认的最重要一点是:要知道您是真的在设计一种语言。必须考虑与编程语言设计者有关的相同类型的问题。例如:

您的语言应该有一个正式的、定义明确的语法和语义。

该语言的解释器应该包括解析器,它会拒绝除语言中语法上有效规范以外的所有内容。

可能的话,应该允许进行某些与环境有关的检查,如类型检查。

请注意,这不是一个详尽的清单;还有许多其它注意事项。

某些人喜欢忽略其中一些步骤,即,不用太担心只接受语法上有效的代码。这是很普遍的。通常的结果是:很难跟踪这些语言的配置脚本中确实会突然出现的许多错误。(在我所写的“破坏者数据错误模式”一文中讨论了这一问题;请参阅 参考资料。)

遗憾的是,忽略这些步骤而产生的问题不仅仅是错误。一些最有破坏性的计算机安全性攻击(包括“红色代码(Code Red)”病毒)都是因未能正确解析输入而引起的。Ross Anderson 的 Security Engineering一书(请参阅 参考资料)包括了大量关于操作系统的环境中这样的攻击的讨论。

使用 XML 的优点

幸运的是,成功设计这样的语言已不再象以前那样困难了。XML 是用来实施这一任务的绝好工具,因为有许多现成的 XML 解析器和开发工具。

这些第三方组件不仅可以使您的工作更简便,而且还使开发人员能够更方便地将您的配置脚本重用于其它应用程序。例如,可以为药品大全应用程序编写各种分子的 XML 描述,然后可以(由无权访问原始应用程序的源代码的另一方)将这些描述重用于药品设计开发工具中。

顺便提一下,以这种方式重用代码也是必须很好定义配置语言的语义的另一个原因。如果程序的含义只能通过挖掘解释器的详细信息来确定,则重用脚本的花费会高得多。请参阅 参考资料,那里有几个非常好的 XML 工具的链接。

使用 XML 的缺点

使用 XML 存在一些缺点。用 XML 编写的脚本非常冗长,而且对某些形式的信息(如可执行代码)编码会很笨拙。同样,使用 XML 工具需要一些资源上的开销和投资,在某些情况下,这些开销和投资可能过多。在这样的情况下,我更愿意使用 S 表达式(S-expressions)作为语言的元级别(meta-level)语法。

S 表达式:XML 的替代方式

S 表达式是仅用一种形式的括号完全括起来的表达式。其名称源于编程语言 Scheme(对,“S”表示“Scheme”)。

所有 Scheme 程序都由 S 表达式构成。Scheme 和其它类似 Lisp 的语言最初都是由 AI 社区设计的,以便于由用语言本身的程序反身处理(reflective processing)语言。但是,使用 S 表达式的许多优点并不依赖于处理语言 — 使用任何语言(包括 Java 语言)也可以简单地处理这些表达式。

待续

现在,如果您记得以下内容,源代码的可用性在实现可扩展性的过程中应该不是太大的障碍:

如何识别配置脚本

如何选择合适的配置

如何识别哪些环境需要黑盒

如何确定可扩展版本的复杂性

当提供配置语言时,您实际在构建一种语言

下一次,我将演示配置语言的一个简单示例,它由 S 表达式构成,并有一个针对该语言的 Java 解释器。

我爱你….为了你的幸福,我愿意放弃一切—包括你。

诊断Java代码:设计可扩展应用程序,第3部分

相关文章:

你感兴趣的文章:

标签云: