从配置文件到 DSL
DSL 是什么?一开始只是听说过,叫 Domain Specific Language,领域定制语言,也就是说,这种语言与特定领域相关的?于是我想起了什么 Cobol 之类的商业语言,也许对于一般的开发人员来说,它和我们没什么关系吧……不过,这个完全是一个误解,DSL 存在于各种领域,甚至, Web 开发、项目管理等。
而不知道从什么时候开始, Spring 项目的项目管理程序已经从 Maven 迁移到基于 Groovy 的 Gradle 了。初看上去, Maven 和 Gradle 并没有多大区别, Gradle 的依赖关系甚至完全照搬 Maven ,有一种多此一举的想法。而去年年初发布的 Android Studio ,也是采用 Gradle 进行项目管理。那么 Gradle 有什么优势?我觉得,从 Maven 上迁移,实际上是自定义工作的配置文件到 DSL 的转变。
配置文件
什么是配置文件?可以假想一个应用场景,如果写了一个可复用的模块,要应对不同的应用场景,很容易会想到使用配置文件进行参数的提取操作,使得模块内只包含所需的处理逻辑。
这个也是 Spring 框架在提出初期的做法,所有连接数据库、配置事物、配置事务类、引用事务类都是模版化的,每个 Web 应用中的组件几乎都使用相同的逻辑,只是名称不一样,于是, Spring 采用 Xml 结构化这些模版,只需提供类名等一些特别的参数即可。这个应该就是配置文件流行的起源。于是,对于项目管理、流程管理等等方面,都采用配置文件进行自定义的操作。但是,并不是所有的值都是 Number、String 之类的简单类型,还有复杂的 List 、 Set、 Map 甚至 Java Bean,于是,配置文件混杂 Java Bean 的时候出现了。在 Java 中,还引入了刚看起来费解的 Relection (反射)。对于反射,我觉得不仅仅翻译不好、就连 Reflection 本身我都难猜出来它是干什么的……
于是,应该也是大概两年前吧,刚接触 Java Web 开发的时候,就被这些名目繁多的配置文件弄乱了,写配置文件成为写代码外一项艰巨的工作,有时候配置文件甚至比代码本身还复杂。于是有一段时间十分厌恶配置文件……
去配置文件化
好像是从一年前(几乎是接触 Web 开发的同期)吧,看到某社区(应该是 OsChina.net )里面各位牛人写起自己的 Web 开发框架,大家都声称不需要配置文件、惯例由于配置(convention over configuration)等等,于是,开始接触了“无配置文件”的 Web 开发框架,发现 Spring 自己也玩起“无配置文件”的开发了,他们用的都是注解(Annotation)。
没有配置文件后,一切的事情都用代码解决了,但是 Struts 2 迟迟没有发布注解的版本(后来知道其实是发布了),于是改用 Spring MVC ,一切都注解(Annotation)解决~
但是,实习没多久,就发现问题了——我要找一些东西(例如 Request 的 Mapping、URL 等),基本上依靠自己的记忆以及遍历——因为 Annotation 分散在各处!
在项目初期节省了大量工作的 Annotation,却因为文档而又重新整理了。而且,对于 Spring MVC 来说,每个参数都需要写注解,MultiAction 类几乎不能复用。开始反思 Struts 2 的编程模型,实际上配置文件实在地减轻了我们的工作,并且使得设计更加简洁。
配置文件确实有其存在的必要。但涉及到逻辑处理时又必须混合编程语言这种混乱的局面如何解决?
DSL - 领域专用语言
实际上,像 Maven 这样的工具,对于自定义编译过程十分繁琐,甚至不可配置,例如使用 Clojure 编译器或者 JavaFX 等新出的技术,Maven 至今好像未有更好的方案。对于配置文件而言,在开发前必须很好地确定整个系统间的边界,抽取出几乎相同的过程。这是基于已知的情况,如果我们能够假定已知的情况就是最优的情况的话,那么配置文件是明智的。但是现实往往不是这样,于是,分散的 Annotation 能够灵活地适应情况,当然,问题也是有的。
准确的 DSL 的定义很难给出,这个词重新提出也许是目前脚本语言流行起来以后的一个趋势。我主要把 DSL 理解为配置文件的增强写法。DSL 把该领域中的语义抽取出来,作为“原语”,利用这些原语组合出应用层。而配置文件可以说是 DSL 的一个子集,只定义了其中的名词部分,而不包含动作、也不包含逻辑。配置文件是对名词逻辑的提取,而 DSL 则是对动词逻辑也进行提取。
而 DSL 之所以可以定义动作,和脚本语言的流行也有关系。Groovy 的 DSL 的定义提供了良好的基础,并且其语法结构(Builder)可以映射回传统 Java 的语义。而 Groovy 的语言结构,函数调用最后一个 Closure 可以写在括号外等特性,使得其定义的语言就好像语言本身的数据结构一样。于是,条件判断、循环结构等可以很自然地嵌入到配置中。
小结
从配置文件到 DSL 的实质,也是一个开闭原则的体现,只是配置文件只能对开放的名词逻辑进行配置,而 DSL 则对动词逻辑也提供了一定的支持。
可能对 DSL 的理解还不是很深入,只是把自己的一些了解以供讨论参考。