Java 应用开发中代码生成工具的作用

  • Srini Penchikala
  • 张龙

2009 年 9 月 14 日

话题:Java架构语言 & 开发

近来,随着各种代码生成工具的不断涌现(如SpringSource的 Spring RooSkyway Builder Community Edition 6.3 及Blu AgeM2Spring等),人们又将注意力转移到了这些代码生成工具在企业级 Java 应用开发中所起的作用。

模型驱动开发(MDD)正获得越来越多的关注,而在一个典型的 Java 应用中有些内容完全是可以自动生成的。典型的 Java Web 应用包含数据访问对象(DAO)类、XML to Java 映射文件、Spring、Log4J 配置文件等,这些内容其实都是能够自动生成的。

Roo 是个双向代码生成框架,可以生成 Spring Web 应用所需的大多数基础代码。Roo 提供了一个命令行 shell,同时具有 tab completion、上下文感知操作以及命令行提示等特性;它还会以标准的目录格式构建Spring应用,管理构建配置文件、辅助开发者创建领域对象并能为基于 REST 的 Web UI 自动生成 Web 层代码。

Skyway Builder Community Edition 6.3于上个月发布,它提供了对 Spring MVC 的支持,可以根据新建或现有的领域模型生成基于 Spring 的 Java CRUD 应用。它集成了 Spring DSL,还能生成 Spring MVC 与Spring Web Flow应用代码。Skyway Builder 商业版 Skyway Builder Enterprise Edition (EE) 6.3 集成了 IBM Rational Software Architect以将 UML 转换为 Spring 应用代码。此外,它还提供了对 DWR(JavaScript/JSON)的支持,可以通过 Spring services 开发 RIA 应用;还能够通过JET技术定制项目级的代码生成模板。

IBM 的 MDD 工具(叫做 Rational Rhapsody)支持 UML2 与 SysML、需求跟踪、应用代码生成以及针对测试进行设计(DFT)等特性。Rhapsody 是个双向的模型驱动解决方案,可以通过需求图、用例图、序列图、活动图以及状态图捕获项目需求。接下来用户就可以根据模型创建对需求的跟踪链接,这种链接能自动提供跟踪、影响分析以及覆盖文档等功能。Rhapsody 还支持模型驱动测试(MDT),所谓模型驱动测试,实际上是一种新的方法论,它将 MDD 的优点引入到了测试过程中。凭借 MDT,工程师可以不断对设计进行模拟以及早定位错误,同时还可以自动化单调乏味的测试、进行基于需求的测试以验证设计是否符合需求,它还能通过 IBM Rational Rhapsody Automatic Test Generation Add On根据设计自动创建覆盖率测试。

最近 Blu Age 凭借其产品 M2Spring 也加入到了代码生成工具的阵营。M2Spring 联合使用了MagicDraw UML 与 Blu Age Agile Model Transformation 进行建模及自动生成基于 Spring 架构的应用代码。它能够在服务层(业务规则、应用服务及 Web Service)、表示层(用户界面、用户角色及安全策略)和持久层(业务对象、DAO 实现及 DAO finder)上生成 Spring Web 应用所需的类和其他代码。M2Spring 支持多种模型与 JEE 技术,如 UML 2.2、OCL 2.0、XMI 2.1、EMF UML2 2.x XMI、Struts、Spring 及Hibernate.

还有一些开发工具也支持代码生成,如 Project Lombok和 Spoon。Lombok 具有如下一些特性:自动生成默认的 getter/setter 方法、自动化的资源管理(通过@Cleanup注解)及注解驱动的异常处理等。

InfoQ 采访了 Spring Roo 的项目经理 Ben Alex 以深入了解 Java 应用开发中代码生成工具所起的作用。Ben Alex 说到大多数的开发者每天都在使用代码生成,无论是通过 Eclipse 的“getters/setters”特性还是从别的地方拷贝过来一段代码,本质都是如此。其主要动机是尽快为特定的需求实现解决方案,避免每次都花费时间研究最佳的解决办法。现代的代码生成工具的动机也是如此,只不过将应用范围扩大了,从简单的“getters/setters”自动生成到提高应用生产力的层次上,比如构建多层的应用。就像是“getters/setters”自动生成一样,现代的代码生成工具也非常容易使用,其生成的代码与我们自己动手编写的差不多,同时我们还可以轻松修改生成的代码。

在使用代码生成工具之前,开发者需要注意哪些方面呢?

开发者可以像评估 IDE 工具那样来评估代码生成工具。要是我的话,我就会问这个软件会提升个人生产力么?学习和使用曲线如何?我所在的组织允许使用这个软件么?一旦使用之后,要是不想用了能行么?软件的维护力度如何?是否有相应的社区呢?软件的质量如何(未解决的缺陷、最终用户的博客以及架构性的资讯信息数量等等)?能否通过插件的方式轻松增加新的功能呢?

除了像使用 IDE 时可能会遇到的问题外,你还需要问自己特定于代码生成工具的问题:从长远来看,这个代码生成工具会持续不断地维护我的代码么(比如提供了哪些双向支持)?操作代码生成工具的方式对我的知识、技能与经验有哪些要求?与我经常使用的 IDE 的协作能力如何?能否与新版本的 IDE 协作良好,抑或是安装了新版本的代码生成工具或是 IDE 时会不会导致崩溃的情况发生?生成的代码是否自然、干净、一致且高效呢?其使用方式是否足够灵活以便让我能按照自然的方式工作?其是否完全是自动化的,还是需要我做一些额外的工作?新版本的代码生成工具(或是插件)不会搞乱我的项目吧?

在大多数应用中,开发者都需要手工编写业务逻辑与验证规则代码,而这些代码都不太容易自动生成,那代码生成工具是如何解决这个问题的呢?

Hunt 与 Thomas 在 The Pragmatic Programmers 一书中提到了两类代码生成方式:被动的与主动的。

所谓被动生成方式就是只运行一次代码生成工具来生成结果,然后手工维护生成的代码。很多开发者都在 IDE 的帮助下使用过被动生成方式,如“getters/setters”生成器。被动生成方式的输出结果都是由开发者决定的:他们可以通过命令来生成想要的东西。被动生成方式的缺憾在于开发者必须要手工维护生成的代码,因为生成工具不会再对生成好的代码进行更新了。在你修改了生成代码所依赖的某些内容后这个问题就会变得尤为明显,因为此时生成的代码将会出错,而用户通常都会删掉代码并重新运行生成工具。

所谓主动生成方式就是每次运行时都会产生相应的结果,它需要一种方式来存储控制信息,这样就能运行并生成所需的结果。控制信息技术的差别非常大,但通常都是自动获取的元数据(比如来自于源代码解析与绑定)与通过 Java 注解、JavaDoc 标记、XML 文件、特殊的 GUI 配置等信息构成的用户首选项的组合。有了这些高质量的主动生成工具(比如 Roo),开发者可以像往常一样在标准的源文件中编写自己的逻辑,同时生成工具会检测到源文件的改变并只自动更新受影响的这些文件。因此我们无需告诉系统(比如 Roo)想要编写客户化代码了,因为这一切已经成为系统的一部分了。

如何将优秀的架构与设计实践应用到既有自动化的代码生成又有手工编写代码的应用开发过程中呢?

很多现代的自动生成工具都用来生成最初的应用骨架。这意味着所生成的应用反映了嵌入在生成工具中的最佳实践。接下来,通过正常的对生成器的操作又会不断鼓励用户使用这些最佳实践,因为后面生成工具所生成的代码也反映出了同样的架构模式。这种一致性对于那些团队成员水平参差不齐或是项目需要长期维护的组织来说是个巨大的优势。

自然,用户肯定要问的一个问题就是嵌入在生成工具中的那些最佳实践真的是最佳的么?对于该问题的答案就是:被众多用户与项目所用的生成工具通常都是最佳的,因为大量的设计反馈都会被集成到工具中。用户还可能会审视实际的架构、仔细审阅其可测试性、可维护性、设计完整性、可复制性、避免独占等等。此外,大多数高质量的代码生成工具都会让一些知名的组织来对其生成的架构进行认证(比如 SpringSource 就将 Roo 架构作为最佳实践)。

相对于传统的代码生成框架,其他手段比如 Grails(大多数代码都是在执行期生成的)效果如何呢?

Grails、Rails 及 Django 等框架提供了一种被动的代码生成方式,它们会生成初始的应用骨架和特定的代码如 Web 控制器。接下来会在运行期(通过动态语言或反射技术)执行主动代码生成工具在开发期所执行的动作。

静态语言编译期技术相对于动态语言运行期技术相比具有很多优点,同时一些缺点也是显而易见的。它们是两种完全不同的开发方法,没有谁比谁强的说法,也没有哪一种方法能适合于所有的项目。SpringSource 拥有 Roo 和 Grails,因此用户可以选择感兴趣的进行开发,无论选择哪一个都能享受到生产力提高所带来的乐趣,同时也都能利用 Spring 的巨大优势。

您是如何看待常规的模型驱动软件开发(MDSD)与特定的代码生成技术呢?

我深信寻求更高层次编程抽象的目标将会继续下去,然而当前的趋势(根据不断涌现的新框架的数量及采取这些框架的开发者数量得到的结论)则聚焦在编程语言的革新与 DSL 上。这些生成工具之间的一个主要区别在于其 DSL 方式,一些工具以简单的命令为特色(像是“create-controller”)而另一些则提供了高级的 shell(如 tab completion、上下文感知、命令隐藏等)。这些高级的 shell 不仅降低了使用难度,而且还简化了日渐强大的(以及更高的抽象层上)命令的使用。

综上所述,代码生成工具依旧会在软件开发中扮演着重要角色。静态语言仍将占据着统治地位(来源:Tiobe),同时这些语言还是需要借助于代码生成技术来提升程序员的生产力。甚至是动态语言框架也会在某些地方使用代码生成技术,如初始化应用结构、关键的应用代码等等。像更高层的 DSL、高级的 shell、创新性的编译单元分离及高质量的双向支持等未来趋势会一直支撑着下一阶段的代码生成技术革命。



 InfoQ 还采访了 Skyway 团队的 Jack Kennedy 以了解软件开发中的代码生成技术。现在很多项目都使用了敏捷与精益软件开发方法学,如ScrumXP或是Kanban,那对于这类项目,代码生成技术会起到什么作用呢?就这个问题,Jack 回答到:

不管采用何种开发方法,基于模式的代码生成与自动化技术始终都会影响到软件开发生命周期的各个阶段(分析 / 设计 / 构建 / 测试 / 部署)。代码生成由需求中的概念性元素开始,然后将其转换为具体的基于模式的设计,最后又将设计转换为基于模式的代码与测试单元。对于敏捷与精益软件开发方法来说,使用基于模式的代码生成与自动化技术的动因是相当重要的。尽管这些开发方法对于小项目来说还是非常成功的,但在整个软件产业当中要想更加充分地采用这些开发方法还是面临着相当大的挑战,首当其冲的便是处理更大、分布式、复杂需求的能力。问题的中心在于对高素质开发人员的渴求以及缺少对大项目投入产出估算的能力。将基于模式的代码生成与自动化技术引入到软件开发的整个生命周期当中可以为组织提供如下好处:提升新手的能力并通过久经考验的组件来降低估算工作量。由于现代方法学一直强调持续集成与可论证的开发迭代,因此通过最小的投资和一致的质量来生成功能应用已经成为迫在眉睫的任务了。

代码生成骨架既可以节省时间、降低人力需求,又能保证代码质量,因为大多数应用代码(对于 Web 来说,就是 Log4J 与 Spring 配置文件等内容)都是自动生成的。这是代码生成工具的最大价值所在么?

基本上来说,软件生成平台通过自动化开发任务且遵循着目标部署环境的实现需求而为用户创造价值。其背后的隐式价值所在就是一致性、高质量及重用性。这种价值可以通过系统输入的代价与输出的成果之间的对比来进行衡量。总的来说,目标就是将代价最小化的同时保证价值的最大化。过去,代码生成工具仅仅被限制为根据生成系统所接收的“概念”而产生相应的代码。对于数据建模来说,这通常意味着可以使用一种格式来创建数据模型,然后生成该数据模型的“类”实现。很多 UML 解决方案都提供了这类生成工具(而且是专有排外的)。然而,在这种情况下,很多团队都发现投入产出比并不太好。

由于企业应用的实现技术已经简化了很多,同时软件的生成技术也已经很成熟了,与之对应,能够自动生成的功能范围得到了极大的扩展。具备生成基于 CRUD 应用能力的代码生成工具让很多开发者转向了现代的 RAD 开发环境与工具,这些工具包含了 DSL 与生成技术。这是生成技术的一个转折点,然而却还不能代表最终的价值所在。随着工业界不断提供更广泛的生成选项与输入格式,我们将会看到有越来越多的开发者转向代码生成技术。

你如何看待模型驱动开发与代码生成技术的未来?

未来一段时间的重点将放在填平传统的 MDD 方法 / 工具与新涌现的 DSL 之间的沟壑上,使快速应用开发成为可能。当前所用的 DSL 将会变得更加强大,当然复杂性也会不断攀升,它会整合安全、验证及应用流。生成技术将会跨越简单的“代码生成”阶段,转而成为构建与部署过程中的一个标准组成部分。可以从 UML 和 DSL 上获取的软件资产类型还将不断增加,同时还会跨越更广的技术栈集合以生成更多的应用代码。

随着开发者不断看到可以从这些简单的语法当中自动生成大量的功能,DSL 还将继续繁荣下去。这些 DSL 的工具选项将变得更加复杂,同时还将提供多种不同的输入方式与格式,包括文本与可视化元素。我们期望最后这些软件供应商会在生成并运行基于 DSL 的应用部署上展开激烈的竞争。

本文主要向各位读者介绍了代码生成工具在我们日常开发中所起的作用,不知各位在日常开发中是否使用过代码生成技术,请抽出一点时间参加 InfoQ 的小调查,谢谢!

查看英文原文:Role of Code Generation in Java Application Development

Java架构语言 & 开发