An Introduce to DSL Programming
本文先介绍了元编程的概念,接着举了几个DSL的例子,最后总结了DSL开发的前景。
DSL的介绍
在讨论DSL之前,首先讨论一下元数据。
元数据指对数据信息的描述,比如Latex对排版的描述,Mac中的plist,gradle对Android项目的描述,Java中的注解,甚至通信领域中通过ASN.1对LTE报文的描述,都可以称作“元数据”。这种描述可以看作为一种抽象语法,即Abstract Syntax。如果这种抽象语法的描述只为特定领域设计,就被称作领域专属语言(DSL, Domain Specific Language)。
DSL的分类 | 举例 |
---|---|
内部DSL | Ruby, Lisp, Java(Annotation), Groovy, kotlin |
外部DSL | XML, SQL, JSON, Plist, Regex, Markdown, SCSS, React |
领域专属语言与通用语言是相对的,它一般用于解决特定的专业问题,适合不太懂编程但是又有简化工作需求的专业人员(比如金融、通信、机器人),以减少编码工作量。
在Java中,甚至不仅在JavaEE中,在Android中也使用范围非常广泛。主要有外部描述与自描述两种方法
- 使用xml, json, yaml等标记语言实现对数据的描述,比如通过XML描述如何依赖注入的Spring框架,通过XML实现免硬编码的AOP等,通过yaml发布/订阅微服务,这些一般用于企业项目,配置繁琐但是的确能够处理复杂的业务需求。Android中通过xml描述界面布局等,其实你自定义控件时的
app:xx
属性就是不经意间新建的元数据。 - 使用groovy, 注解实现对数据的描述,比如ORM框架,SpringBoot框架,SOA框架,通过注解描述信息,并最终通过动态代理将注解拼接为实际请求。
举例
下文将具体叙述如何通过DSL将业务与实现分离出来的。
硬件开发
在硬件开发中,一般先设计电路,再进行C的软件移植。在这个过程中,电子工程师精通电路设计而不懂C语言,如果在使用元数据以前,可能是这样的:比较小的团队可能需要一个同时精通C与电子领域业务的专家来支撑项目,工资高、新人培养难度大不说,极有可能产生单点故障;大的团队可能会将项目文档化,先让电子领域专家写设计原型,然后交给SE写文档,最后让开发照着文档填接口,这样最后的结果就是延长了开发周期,需求易变质,开会次数多。而这些文档、沟通其实是可以用计算机代劳的。
而使用元数据后,专家可以通过鼠标在软件平台中拖拽来设计芯片、电路等物理数据。软件平台的引擎对设计图进行解析,并能够生成准确的电子元件的C语言头文件。最后C语言开发者通过调用头文件这类SDK进行软件层的开发,进而对硬件进行控制。这样就实现了设计与开发分离,让传统行业(电子通信、电气、汽车等)与IT技术的合作成为可能,并节约了无谓的重复手工劳动时间。
领域专业知识 + 电路设计图(元数据,可能用xml进行描述)
|
|(元数据处理引擎处理)
|
硬件平台的C语言SDK代码
|
|(软件开发者,可以找便宜外包,不需要理解物理实现细节)
|
基于SDK的上层开发
JCommand: 通过注解定义Usage
在编写终端程序时,当输入外部参数为空时,一般要输出Help或者Usage信息,JCommand就是用于处理用户输入数据的Parser,通过定义注解元数据
static class Arguments {
@Parameter(names = { "-h", "--help" }, description = "Help message", help = true)
boolean help;
@Parameter(names = { "--conf-file" }, description = "Configuration file")
public String confFile;
@Parameter(description = "persistent://prop/cluster/ns/my-topic", required = true)
public List<String> topic;
@Parameter(names = { "-t", "--num-topics" }, description = "Number of topics")
public int numDestinations = 1;
}
当你运行程序时,比如输入下列参数,JCommand就会自动为confFile
对象映射并赋值。
./app -t 20 --conf-file /usr/etc/app.cfg
通过上述注解,简化了繁琐的入参命令Parse流程,代码看起来也更简洁。
XML: 通过自然语言编写
在Groovy中,通过DSL可以用易读的写法生成XML
import groovy.xml.MarkupBuilder
def s = new StringWriter()
def xml = new MarkupBuilder(s)
xml.html{
head{
title("Hello")
script(ahref:'https://xxxx.com/vue.js')
}
body{
p("Excited")
}
}
println s.toString()
最后将生成
<html>
<head>
<title>Hello</title>
<script ahref='https://xxxx.com/vue.js' />
</head>
<body>
<p>Excited</p>
</body>
</html>
这里相对于Java这样的动态语言,最为不同的就是xml.html
这个并不存在的方法居然可以通过编译并运行,它内部重写了invokeMethod
方法,并进行闭包遍历,少写了许多POJO对象,效率更高。
什么时候使用DSL
看了上面的DSL介绍,各位可能激动不已,跃跃欲试了,如果你正在看某个技术汇报胶片,甚至已经激动地打算全员推广DSL了,其实你忘记了DSL的风险,它只是看起来很美好
- DSL只是前端,无法承载大量业务。DSL与Word,网页,Android、iOS一样,只是业务展示的前端。DSL一般都是自己折腾,导致有学习成本(想想你学非常广泛的SQL,Regex花了多久时间?),如果扩大DSL的规模,方言过多,导致调试更加难理解,因此最终DSL的规模最终将被限制到脚本级。
- DSL可以替换设计模式中的样板代码,甚至可以自动化生成测试用例(比如Dagger生成MockServer与TestCase)
- DSL可以被静态工具类(Utils.java)代替。通用的业务可以被封装为工具类,只是代码更加冗长而已,而DSL只是加上了一层语法糖(比如Groovy的useCategory)。
- DSL不能解决动态部署/定制类业务。在企业软件开发中,很多人都喜欢动态可配置,甚至用XML创建了
<if>
等语法(想想ant脚本有多难用吧),也就是直接用XML写AST,这样最终结果痛苦不堪。这类DSL统统不如直接调用Java自带的JSScriptEngine直接eval(同时注意安全风险)。
DSL不是银弹
各位可能在DSL的书籍中看到通过DSL降低代码量的例子,但是众所周知,在总信息量不变的情况下,代码行数越短,它的“潜规则”信息量就越多,而这些一旦出现问题,很难定位。
- DSL语句与编译生成的“字节码”的过程是黑盒的,不但对内部工作不明朗,如果报错的话,不但堆栈行数无法与源码对应上,而且无法“断点”或者“日志”,这种代码安全感的缺乏,使用者要么自己造轮子,要么忍狠滚。
- DSL对设计者要求极高。DSL不但需要自己设计Parser(最简单的Groovy的MethodInvkoing写起来也比较麻烦),还要文档齐全,支撑充分,甚至要开源以帮助使用者定位。最终使用者可能并不买账,而是直接把你引以为豪的DSL再包装一遍。
总结
元驱动开发是高效分工的产物,通过DSL编写一个小范围内使用的语言,可以降低成本,提高程序可维护性。但是DSL一旦没玩好,反而是一个大坑。结合我做过的DSL项目,我的建议如下:
- 没有必要强行上,先用Java等传统代码实现特例
- 将通用的无状态代码下层为工具库/FAAS,有状态的代码分解为微服务
- 通过其它JVM语言,比如Groovy设计Clousre对工具类进行注入,或者对ScriptEngine进行bind设计DSL。
- 对DSL侧进行详细文档,甚至可以开源,而基线工具库不必开源
参考与推荐
下面列举了一些书籍与工具
- 松本行弘推荐的代码生成书籍-《Code Generation in Action》
- 松本行弘对编程的杂谈-《松本行弘的程序世界》
- 知名度很高的自我修炼实践-《程序员修炼之道:从小工到专家》
- Intellij开源的元编程工具 - www.jetbrains.com/mps/
- 王垠对编辑器与IDE的一些思考 - www.yinwang.org/blog-cn/201…
- 王垠对DSL的看法 – www.yinwang.org/blog-cn/201…
- 使用Ruby进行元编程的例子 – two simple ruby dsl examples introduction
- 更广义的提高效率 – 正确地做事(善用自动化)
今天的文章DSL编程技术的介绍分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/20097.html