服务粉丝

我们一直在努力
当前位置:首页 > 财经 >

【第2884期】DSL,创造属于自己的语言

日期: 来源:前端早读课收集编辑:cadeli

前言

DSL, 领域特定语言,即一种为特定领域所设计的编程语言。今日前端早读课文章由 @cadeli 分享,公号:WeChatFE 授权。

正文从这开始~~

本文参考腾讯问卷实践 —— 背景知识与问题介绍

想必大家都有过创建一份调查问卷的经历,调查问卷通常可以为各个问题之间设计一定的逻辑,比如下图

如果用户第一题选择了第一个选项,那么会导致第二道题目的出现。

作为一个想要发布一份问卷的用户,也就是用研,他可能需要到问卷的发布页面去点点点进行页面逻辑的配置,这不仅费时费力,而且会有一个问题,如果遇到一些比较专业且复杂的逻辑难以在 UI 上进行简单的交互,这时候可能就需要找问卷的开发者单独定制。然后就是下面的一连串沟通成本!

用研:Hey,麻烦帮我开发一个问卷

开发:说一下这次的需求

用研:这次是一份调查 xxxx 的问卷,我先会在第一题咨询 xxx,如果用户 xxx,那就会 xxx。。。。

开发:这里没懂,这里没懂,这里没懂,这里没懂。。。。

用研:好的我解释一下,好的我解释一下,好的我解释一下,好的我解释一下

作为开发者,没有相应领域的知识,需要理解用研的需求会比较困难;作为用研,没有开发的能力导致需求修改需要频繁与开发对齐,花费大量时间。那么有没有一种方法,可以让用研不依赖开发,就可以自己定制问卷呢,答案就是 DSL。

什么是 DSL

DSL 全称为 Domain Specific Language,译为领域特定语言,即一种为特定领域所设计的编程语言。可以简单的理解为设计 DSL 就是设计一套语法来描述一系列的相关行为。抽象到比较低级的层面,C++、JavaScript 就是机器指令集的 DSL;在比较高级的层面举例的话,markdown 就是文档编写的 DSL,sql 语句就是数据库查询的 DSL。为什么不直接用机器指令编写代码,而要使用高级语言如 C++ 等,就是因为高级语言对于开发者的门槛更低,更容易上手,更有迹可循。究其原因,DSL 是为人类设计的,而指令是为机器设计的。

内部 DSL 和外部 DSL

下面通过一个简单的例子来说明内部 DSL 和外部 DSL 的区别。我们要怎么描述两个星期前这一个时间呢。很容易想到以下三种解法:

解法一:

 new Date(Date.now() - 1000 * 60 * 60 * 24 * 7 * 2);

解法二:

 2 weeks ago

解法三:

 (2).weeks().ago();

作为一个前端程序员,敏锐的你肯定第一眼就看出来了第一种写法就是标准的 js 代码,可以直接在浏览器就能跑出结果。第二种像是一种自然语言,第三种类似一种伪代码。第二和第三种其实就是外部 DSL 和内部 DSL 了。很明显,第二种解法和第三种解法是不能直接运行的,因为 DSL 需要在特定的环境下运行。

很显然 DSL 比编程语言更加直观,而外部 DSL 又比内部 DSL 更加直观,不信你可以问问自己的男 / 女朋友,看他们更倾向使用哪种语法(没有男 / 女朋友的也可以去问问自己的产品)

为什么有外部 DSL 和内部 DSL 的区别呢?外部 DSL 可以理解为是一门独立的语言,比如解法二,你为了让它能够正常运行,就必须编写一套编译器来支持它运行。而对于内部 DSL(解法三),你可以利用拓展现有的语言环境来支持这种语法,比如说我只要在 js 注入这段逻辑

 Number.prototype.weeks = function() {
return this * 1000 * 60 * 60 * 24 * 7
}
Number.prototype.ago = function() {
return new Date(Date.now() - this)
}

就可以让解法三运行出结果了。受限于语言环境,内部 DSL 的语法也看起来比较别扭,需要遵循宿主语言的语法规则。

什么场景用 DSL

DSL 的设计与开发也是有一定的成本的,那么什么时候需要用 DSL 呢?概括性的总结就是,

当用户不是系统的开发者,但又需要定制逻辑的时候,就需要一门 DSL。

比如问卷的定制,再比如数据库的自定义查询。展开来说,如果一件事情有大量的重复,需要频繁的进行多方的沟通,需要很多的 GUI 操作,那么你就有可能需要一门 DSL。

e.g. 一份问卷 DSL

这是一份用研提出的问卷需求

这份问卷是这样的,首先会在第一题询问有没有发烧,如果选择了没有发烧,就直接跳转到结束页;然后如果选择了有, 显示第二题。第二题询问体温多少度,如果体温低于 37 度也 跳转到结束页...

然后我们提取出逻辑相关的内容

第一题:选择了没有发烧,跳转到结束页

选择了有,显示第二题

如果体温低于 37 度,跳转到结束页

转成伪代码表述

 if Q1A1 then branch to END
if Q1A2 then show Q2
if Q2A < 37 then branch to END

稍微整理一下,你就可以设计出一套问卷 DSL 语法了

 if Q1A2 then show Q2
if Q2A gt 37 then show Q3

设计你的 DSL

上面讲了那么多,设计完语法之后就要动手来实现了。学过大学编译原理的我们都知道,高级语言转机器指令需要经过一系列过程:

词法分析 -> 语法分析 -> 语义分析 -> 生成抽象语法树 -> 中间代码 -> 优化 -> 目标代码

学过是学过,但要把书本上的理论知识,比如正则表达式、状态机等等再实现一次,门槛有点过于高了。

好在有一位伟人说过,不要重复造轮子。热衷于开源的大牛们开发出了一个专门用来生成 DSL 解析器的解析器生成器,利用它们,我们可以快速地设计实现自己的 DSL 而不需要熟读编译原理。比较流行的有 PEG.js 和 jison。本文使用 PEG.js 进行举例,试着实现了上文中设计的问卷 DSL 中的其中一句 if Q1A2 then show Q2 ,原理大同小异,这里实现的比较粗糙,仅做抛砖引玉。

1、安装引入 npm 包 npm i pegjs

2、遵循 pegjs 规则设计语法

 const grammar = `
/* 定义输入的语法格式,这里为 if xxx then xxx */
Start
= 'if' _ exp:Expression _ 'then' _ op:Operation {
/* 返回一个 输入为所有题目,输出为过滤后的题目 的函数 */
return new Function('questions', 'const result = [questions[0]];' +
'if(' + exp + ')' + op + 'return result;');
}

/* 定义Expression类型如何翻译 */
Expression "expression"
= 'Q'q:[0-9]'A'a:[0-9] {
return 'questions[' + q + '-1].answer === ' + a
}

/* 定义Operation类型如何翻译 */
Operation "operation"
= 'show Q'q:[0-9] {
return '{result.push(questions['+ q + '-1]);}'
}

/* 定义 _ 如何翻译 */
_ "whitespace"
= ' '
`;

3、parser = pegjs.generate(grammar) 生成 DSL 编译器

4、然后就可以使用 parser.parse 来对输入 DSL 进行解析生成对应的逻辑处理函数啦

完整 demo 已放到 codepen,大家可以在阅读原文处进行在线编辑尝试实现更多的腾讯问卷的 DSL,或者创造属于自己的 DSL~

PEG.js 同时也支持在线生成解析器并下载下来,这样就不需要在项目中安装 PEG.js 库

不轻易用 DSL

DSL 看起来很牛逼很高大上,事实上使用起来需要很大的成本,如你所见,你需要设计一套自己的语法,并为之编写生成解析器提供给用户使用;用户在使用你的 DSL 的时候,你极大可能需要提供一个 DSL 编辑器使得用户的编写体验更流畅并提供语法检查,还需要编写文档供用户查阅;对于用户来说,虽然不需要直接学习编程语言,但是不论设计的多好的 DSL,依然存在学习成本,依然需要花费一定的时间才能上手你设计的 DSL。

在想要使用 DSL 的时候,先问一问自己,能不能不使用 DSL,有没有现成的标准 DSL,能不能使用内部 DSL。

当你确信没有更好的解法了,那就拥抱 DSL 吧。

关于本文
作者:@cadeli
原文:https://mp.weixin.qq.com/s/cP_jWDObNIuchmA1SOSwqg

这期前端早读课
对你有帮助,帮” 赞 “一下,
期待下一期,帮” 在看” 一下 。

相关阅读

  • 流行词是词汇化的“共时”微缩

  •   流行词的形式丰富多样,流行前成词路径手段也相应齐全。从非词到词,再从非流行词到流行词的演变过程,可看作是语言演变长河中词汇形成的缩影,基本涵盖了词汇化语法化演变形式
  • 恳谈会丨呼和浩特市就业恳谈会

  • 每日推送的就业资讯有限?点“这里”了解更多恳谈会时间:2023年3月14日(周二)10:00-12:00地点:职业发展中心 东风汽车厅恳谈会内容为吸引清华大学优秀人才选择呼和浩特、投身呼和
  • 如果从今天开始准备考研英语...

  • 本文由蝶澈学姐原创,未经授权禁止转载那你还有足够的时间去冲击80+!3月第一天是我们的固定节目:规划系列。这个系列主要会给大家详细讲解和安排每个月的备考计划,针对各个学科也
  • 答题掘金。

  • 今天海外掘金社正式改名为答题掘金社。答题掘金社主要业务有三个板块国外问卷、国内问卷、百度问答。答题掘金社主要以答题为主,后期也会不定期的更新以及优化我们的掘金社。
  • 做问卷调查,工厂员工月入6000+

  • 如果你加到我的微信,那么就不难发现,我朋友圈每天都记录学员群里发生的新鲜事,比如他们今天赚了多少钱,有什么好的操作方法等等从去年10月份开始,我们陆续邀请问卷调查学员群里面

热门文章

  • “复活”半年后 京东拍拍二手杀入公益事业

  • 京东拍拍二手“复活”半年后,杀入公益事业,试图让企业捐的赠品、家庭闲置品变成实实在在的“爱心”。 把“闲置品”变爱心 6月12日,“益心一益·守护梦想每一步”2018年四

最新文章

  • 【第2884期】DSL,创造属于自己的语言

  • 前言DSL, 领域特定语言,即一种为特定领域所设计的编程语言。今日前端早读课文章由 @cadeli 分享,公号:WeChatFE 授权。正文从这开始~~本文参考腾讯问卷实践 —— 背景知识与问题
  • 【早说】损失后,怪谁?

  • Judge who is to blame for the loss, and see who is to blame for the loss.When a thing has a bad result, blame, blame, regret are useless, they can not change th
  • 旅游书用靖国神社作封面,大连理工出版社回应

  • 3月13日,有网友爆料称大连理工大学出版社出版的《日本旅行一本就够》,使用靖国神社作封面。今日,大连理工大学出版社发布关于出版图书问题的情况通报:近日,网上反映我社2014年出
  • 1英镑就卖!硅谷银行英国分行这笔交易有何玄机

  • 无论美联储政策未来怎么走,恐怕都难改金融领域周期性的疾病发作。全文1979字,阅读约需3分钟 撰稿 / 徐立凡(专栏作家) 编辑 / 刘昀昀 校对 / 贾宁▲资料图。人们在英国伦敦的一
  • 斯蒂文斯:不是有关事物的思想而是事物本身

  • 华莱士·史蒂文斯(Wallace Stevens,1879-1955),美国著名现代诗人,1879年10月2日 出生于美国宾夕法尼亚州的雷丁市。大学时就读于哈佛,后在纽约法学院获法律学位。1904 年取得律师