关于DSL对前端领域应用前景的讨论

博客分类: 前端

关于DSL对前端领域应用前景的讨论

背景

在阅读公司 react 应用程序时,要从 router页面组件局部组件vuex 或者 reduceAPI 请求,如果代码和依赖关系很多,那么阅读效率就会很低下。

可不可以开发一个工具,把源代码的依赖关系进行可视化展示,来提高阅读效率?

最近无意中接触了 DSL,感觉 DSL 理念可以解决上述问题

DSL 是什么

DSL 其实是 Domain Specific Language 的缩写,中文翻译为领域特定语言(下简称 DSL);而与 DSL 相对的就是 GPL,这里的 GPL 并不是我们知道的开源许可证,而是 General Purpose Language 的简称,即通用编程语言,也就是我们非常熟悉的 Objective-CJavaPython 以及 C 语言等等。

GPL 相对,DSL 与传统意义上的通用编程语言 CPython 以及 Haskell 完全不同。通用的计算机编程语言是可以用来编写任意计算机程序的,并且能表达任何的可被计算的逻辑,同时也是 图灵完备 的。

但是在里所说的 DSL 并不是图灵完备的,它们的表达能力有限,只是在特定领域解决特定任务的。

另一个世界级软件开发大师 Martin Fowler 对于领域特定语言的定义在笔者看来就更加具体了,DSL 通过在表达能力上做的妥协换取在某一领域内的高效。

有限的表达能力就成为了 GPLDSL 之间的一条界限。

几个栗子

其实在 DSL 在前端领域已经应用很多了,在这里会举几个例子进行介绍:

DSL 特性

上面的几个 🌰 明显的缩小了通用编程语言的概念,但是它们确实在自己领域表现地非常出色,因为这些 DSL 就是根据某一个特定领域的特点塑造的;而通用编程语言相比领域特定语言,在设计时是为了解决更加抽象的问题,而关注点并不只是在某一个领域。

上面的几个例子有着一些共同的特点:

虽然了解了 DSL 以及 DSL 的一些特性,但是,到目前为止,我们对于如何构建一个 DSL 仍然不是很清楚。

构建 DSL

DSL 的构建与编程语言其实比较类似,想想我们在重新实现编程语言时,需要做那些事情;实现编程语言的过程可以简化为定义语法与语义,然后实现编译器或者解释器的过程,而 DSL 的实现与它也非常类似,我们也需要对 DSL 进行语法与语义上的设计。

总结下来,实现 DSL 总共有这么两个需要完成的工作:

  1. 设计语法和语义,定义 DSL 中的元素是什么样的,元素代表什么意思
  2. 实现 parser,对 DSL 解析,最终通过解释器来执行

HTML 为例,HTML 中所有的元素都是包含在尖括号 <> 中的,尖括号中不同的元素代表了不同的标签,而这些标签会被浏览器解析成 DOM 树,再经过一系列的过程调用 Native 的图形 API 进行绘制。

设计原则和妥协

DSL 最大的设计原则就是简单,通过简化语言中的元素,降低使用者的负担;无论是 RegexSQL 还是 HTML 以及 CSS,其说明文档往往只有几页,非常易于学习和掌握。但是,由此带来的问题就是,DSL 中缺乏抽象的概念,比如:模块化、变量以及方法等。

抽象的概念并不是某个领域所关注的问题,就像 Regex 并不需要有模块、变量以及方法等概念。

由于抽象能力的缺乏,在我们的项目规模变得越来越大时,DSL 往往满足不了开发者的需求;我们仍然需要编程语言中的模块化等概念对 DSL 进行补充,以此解决 DSL 并不是真正编程语言的问题。

在当今的 Web 前端项目中,我们在开发大规模项目时往往不会直接手写 CSS 文件,而是会使用 Sass 或者 LessCSS 带来更强大的抽象能力,比如嵌套规则,变量,混合以及继承等特性。

nav {
    ul {
        margin: 0;
        padding: 0;
        list-style: none;
    }

    li {
        display: inline-block;
    }

    a {
        display: block;
        padding: 6px 12px;
        text-decoration: none;
    }
}

返回到背景中问题

对这个工具可行性分析:

  1. 对源代码进行 AST 解析,分析出代码之间的依赖关系,以组件为单位;
  2. 把解析结果转化成 DSL,其表现形式为 json;
  3. 找个可视化插件,进行显示;

上述工具最困难的其实是在第一步,解析的深度问题,直接可以影响结果,目前想到的是以组件为单位,相对简单点,但是针对性比较强