DSL编程技术的介绍

DSL编程技术的介绍本文先介绍了元编程的概念,接着举了几个DSL的例子,最后总结了DSL开发的前景。 在讨论DSL之前,首先讨论一下元数据。 元数据指对数据信息的描述,比如Latex对排版的描述,Mac中的plist,gradle对Android项目的描述,Java中的注解,甚至通信领域中通过AS…

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

领域专属语言与通用语言是相对的,它一般用于解决特定的专业问题,适合不太懂编程但是又有简化工作需求的专业人员(比如金融、通信、机器人),以减少编码工作量。

通过DSL将业务与开发分离


通过DSL将业务与开发分离

在Java中,甚至不仅在JavaEE中,在Android中也使用范围非常广泛。主要有外部描述与自描述两种方法

  1. 使用xml, json, yaml等标记语言实现对数据的描述,比如通过XML描述如何依赖注入的Spring框架,通过XML实现免硬编码的AOP等,通过yaml发布/订阅微服务,这些一般用于企业项目,配置繁琐但是的确能够处理复杂的业务需求。Android中通过xml描述界面布局等,其实你自定义控件时的app:xx属性就是不经意间新建的元数据。
  2. 使用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项目,我的建议如下:

  1. 没有必要强行上,先用Java等传统代码实现特例
  2. 将通用的无状态代码下层为工具库/FAAS,有状态的代码分解为微服务
  3. 通过其它JVM语言,比如Groovy设计Clousre对工具类进行注入,或者对ScriptEngine进行bind设计DSL。
  4. 对DSL侧进行详细文档,甚至可以开源,而基线工具库不必开源

参考与推荐

下面列举了一些书籍与工具

  1. 松本行弘推荐的代码生成书籍-《Code Generation in Action》
  2. 松本行弘对编程的杂谈-《松本行弘的程序世界》
  3. 知名度很高的自我修炼实践-《程序员修炼之道:从小工到专家》
  4. Intellij开源的元编程工具 - www.jetbrains.com/mps/
  5. 王垠对编辑器与IDE的一些思考 - www.yinwang.org/blog-cn/201…
  6. 王垠对DSL的看法 – www.yinwang.org/blog-cn/201…
  7. 使用Ruby进行元编程的例子 – two simple ruby dsl examples introduction
  8. 更广义的提高效率 – 正确地做事(善用自动化)

今天的文章DSL编程技术的介绍分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/20097.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注