3.5 管理性能表现

性能是重要的评判标准,但不管你怎么想,我认为它并不是最重要的评判标准。性能低下的应用程序其性能可以通过横向或纵向增加资源来提高;但是,如果实现了一个完全不关心沟通和维护性的混乱系统,你将注定受困于它。

话说回来,设计应用程序的时候你还是很有必要考虑性能因素的。实事求是地说,良好的DSL设计不见得一定拖累应用程序的性能表现。有些动态语言,如Groovy和Ruby,确实比Java慢一点。但应用程序开发者和架构师需要在速度和其他特质之间取舍,考虑代码的可维护性、表现力、对未来变化的适应性等,并在它们与速度之间进行权衡。

应用程序并非每一部分都需要快如闪电,有些部分的维护性比速度更重要。例如,应用程序的配置参数一般只需要处理一次,这可能是在应用程序启动的时候进行。所以,与将配置写入代码来加速应用程序启动相比,我们不如将一部分配置参数外部化,以更易读的形式呈现给用户。改善表现力的好处远远大于应用程序速度损失可能导致问题的坏处。

目前着力于改善JVM上动态语言执行性能的自发行动十分活跃,因此我们更应该选择这些语言来设计DSL。如果现在就注重提高代码的表现力,等到Groovy和Ruby的语言运行时在JVM上的性能提高了,我们的代码也能自动享受到性能改善的益处。

大家完全清楚Groovy和Ruby代码比相同功能的Java代码要慢一些,要是没有好处,谁会用它们来设计DSL呢?这些语言好维护、易读,而且能很好地适应变化,而当宿主语言本身具备充足的表达能力时,DSL的成长历程将顺利得多。我们并非贬低性能的重要性,只是说这些因素和单纯的执行速度同等重要。你设计的领域语言,其演变道路和生命线由所有这些因素共同决定。

像Scala那样的静态类型语言性能几乎等同于纯Java。3.2.2节介绍的DSL包装器集成模型,其性能基本和纯Java应用程序没有区别。

脚本引擎因为运行在沙盒环境下,多少会慢一些,不过反正你也不会用脚本来执行强调性能的任务。脚本式的DSL主要用于处理轻量级领域逻辑,使用者也以最终用户和领域专家为主。内嵌式DSL(内部DSL)主要实现成宿主语言的库,所以并不会拖累性能。外部DSL没有依靠和束缚,可以自由实现其语言机制。在大多数现实的应用程序中,外部DSL不需要设计得像完整的高级语言那么复杂,而且有解析器生成器(YACC、ANTLR)和(Scala、Haskell语言中的)解析器组合子等工具帮忙,如果善加利用,并不难构建出必要的语言设施。

最后,请记住一条性能调优的黄金法则:多点基准测试,慢点优化性能。