新闻资讯

新闻资讯 行业动态

前端 DSL 实践指南——内部 DSL 的一些迷思

编辑:008     时间:2020-02-20

为何选择 JavaScript 作为宿主语言

从风格案例可以看到,宿主语言直接决定了内部 DSL 的「语法」优化的上限。正如 ROR 之于 Ruby、Gradle 之于 Groovy,典型的前期选择大于后天努力。而前端开发最趁手的语言 JavaScript 其实在构建内部 DSL 时具备了很大的优势,因为它那些大杂烩般的语言特性:

  • 借鉴 Java 语言的数据类型和内存管理,抽象度高。
  • 基于对象,且拥有方便的对象字面量表示等,数据表达力一流。
  • 函数为第一等公民(first class),可以有一些泛 FP 的应用。
  • 使用基于原型(prototype)的继承机制,并且可扩展原始类型如 Number。
  • Proxy、Reflect 等新特性加持下具备了极强的元编程能力。

放荡不羁的语言特性使得它几乎可以 Hold 住任何内部 DSL 的构建风格,另外它那活跃到离谱的社区也奠定了天然的开发者基础。

JavaScript 存在的天然缺陷就是它那衍生自 C 的语法,导致噪音较强,使用一些变种语言(如 CoffeeScript)可以扭转一些这种劣势。

库(接口)还是内部 DSL

外部 DSL 的边界问题往往是 DSL 与 GPPL 的区别,这个在社区中的争议并不算很大。而关于内部 DSL 的讨论,特别是与库(接口)的差异问题就一直都没消停过,确实存在模糊的部分。

实际上 DSL 也有个别名叫流畅接口,所以它本身也属于接口封装或库封装的一种模式,目标是极限表达力。但它相较于传统接口封装,有几个显著设计差异点:

  • 语言性。
  • 不受传统编程最佳实践的束缚:如命令-查询分离、迪米特法则等。

比如在内部 DSL 中,得到代码如 foo.should.be.a.number 就像是一个在既定语法下有关联的整句,而不是命令式代码的集合。而 jQuery 中 html 即是查询方法(.html())也是命令方法(.html('content to set')),这显然背离了命令查询分离的原则。它们设计的首要目标是「极限流畅的表现力」,而非职责清晰、降低耦合度等传统的封装抽象准则。

其实本文更认同松本行弘先生在《代码的未来》中引述的观点,这也算最终解开了作者对于内部 DSL 的疑惑和心结:

库设计就是语言设计

编程语言只确定了基本语法框架和少量词汇,库设计应该将其与充当词汇池的类、方法、属性甚至变量相结合,并将它们按语义有机结合起来,最终真正实现「在限定任务下,编程工作者只需要关注 What,而无需关注 How」的设计目标。这也就是 2.weeks.ago 的魔力所在,编程(语言)的发展方向就应该如此,才能达到更高的抽象维度。

所以与其尝试去为内部 DSL 划分一个明确的边界,不如根据它的要求去改善你的接口设计。这里引申另一个更激进的观点:

Programming is a process of designing DSL for your own application.



原文链接:https://segmentfault.com/a/1190000021791568

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

回复列表

相关推荐