如何设计领域特定语言,实现终极业务抽象?

如何设计领域特定语言,实现终极业务抽象?

在过去的几年里,我一直从事于各种领域定义语言的设计,包含unflow、guarding、datum、forming等。在我刚入门这个领域的时候,我从《领域特定语言》、《编程语言实现模式》等,一直研究到龙书等。我渐渐掌握了领域特定语言设计的一些技巧,也能快速(相对于过去)设计出一个领域特定语言。
所以,我在想我应该总结一下相关的套路。这样一来,也可以在未来验证现在的思路是否正确:
定义呈现模式。
提炼领域特定名词。
设计关联关系与语法。
实现语法解析。
演进语言的设计。
领域特定语言(英語:domain-specificlanguage、DSL)指的是专注于某个应用程序领域的计算机语言。
本文所写的皆是外部DSL,即『不同于应用系统主要使用语言』的语言。创建外部DSL和创建一种通用目的的编程语言的过程是相似的,它可以是编译型或者解释型的。
通用目的编程语言的源代码和外部DSL的源代码之间的主要区别在于,经过编译的DSL通常不会直接产生可执行的程序(但是它确实可以)。大多数情况下,外部DSL可以转换为一种与核心应用程序的操作环境相兼容的资源,也可以转换为用于构建核心应用的通用目的编程语言。——VaughnVernon
简单场景下的领域特定语言,只是将特定的源码转换为特定的数据结构。如JSON便是一种DSL,在Java语言里,需要将它转换为对应的数据类。复杂场景下的领域特定语言,可以直接编译为可执行程序。
外部DSL的麻烦点在于:
语法设计
语法解析
IDE支持
当然了,它的优点也很明显:
让不懂编程的业务专家(领域专家)快速编写核心逻辑。
领域逻辑与具体编程语言无关
平台无关。
更多的信息,建议去阅读《领域特定语言》一书。
领域特定语言嘛,从需求上就是对于业务呈现的简化。根据不同的呈现模式,去解析源码,得到我们所需要的数据结构。
如下是常见的的领域特定语言的使用模式[wiki_dsl]:
独立的工具,如Makefile
在编译时或实时转换为宿主语言
嵌入式领域特定语言
……
可以参见维基百科,我就不再去翻译了。
[wikidsl]:https://en.wikipedia.org/wiki/Domain-specificlanguage
从通用语言的编译过程来看:
词法分析器,分析输入的字符流,得到符号流。
语法分析,分析符号流,得到语法树
语义分析,分析语法树,得到新的语法树
中间代码生成器,分析语法树,得到中间表示形式
……
步骤1~4,对于通用语言和领域特定语言来说都是极为类似的。唯一拥有区别的是这个中间表示形式,对于领域特定语言来说,我们场景的原因,这里往往是我们所需要的数据结构。
当然了,从某种意义上来说,AST(抽象语法树)也是一种数据结构,只不过它是一种中间的数据结构。所以,有时候在设计的时候,我就偷懒直接输出中间表示了。
这个环节的过程,实现上和DDD(领域驱动设计)里的提炼问题域以获取领域知识是颇为相似的。同样的这个过程中,通过与领域专家的协作,我们才能获得更好的领域特定语言。
用例,或译使用案例、用况,是软件工程或系统工程中对系统如何反应外界请求的描述,是一种通过用户的使用场景来获取需求的技术。
在进行领域驱动设计协作时,我们需要与领域专家理解用户在这个过程中,进行的一系列操作,以提炼我们所需要的统一语言。而其中的用例能描述达到目标所需的步骤,包含用户和系统之间的交互。
在创建领域特定语言的时候,这个过程对于我们来说,也是类似的:与领域专家一起协作,从用例开始提炼。它也可以直接由现有的代码中提炼而来。
对于已有系统来说,用例可以由:
与领域专家交流获取。与领域专家聊天,是我们获得用例的最好方式。记录用例,从而获得关键信息。
从现有的代码中提取。
在ArchUnit中提取架构规划上的设计便是:
classes.that.resideInAPackage(“..foo..”)
.should.onlyHaveDependentClassesThat.resideInAnyPackage(“..source.one..”,”..foo..”)
对应的,我们在Guarding的设计是:
class(resideIn”..foo..”)dependentpackage(resideIn[“..source.one..”,”..foo..”])
在Guarding中设计的是针对主流的编程语言,所以在语法上会尽量与编程语言无关。
在获得了用例作为输入条件之后,我们就需要从中提取一些关键信息,如关键字、值、属性等等。
如下是我在设计GuardingDSL时,从ArchUnit提取的一小部分关键信息:
package:
dependOn
class:
implement
annotation
annotatedWith
expression:
and
or
not
equals
only
接着,我们就可以依据这些信息,展开它们的关联设计,进而设计我们的语法。
在设计领域特定语言时,我们主要以实现领域中的用例作为目标:
使用DSL描述一个用例
先不考虑语法实现,实现大部分用例的DSL草稿版本
对齐不同用例DSL中的差异
考虑一些非常规的用例,添加额外的属性
领域特定语言,所针对的是特定领域。在特定的领域里,都会使用特定的词汇来描述相关之间的关系。这个关系,便是我们设计语法的一个关键。
如在Java语言里,使用:implement、extends来表示两个类之间的关系。而为了表示包之间的关系,则会有:dependent、resideIn等等的关系。
实现用例并不是一个复杂的过程,只是要符合人类的思维习惯,并尽可能地简化设计。不过,觉得注意的是,我们应该留下一些证据来告诉未来的自己:我们当时是为什么考虑的。
在设计DSL时,我往往会创建一个sample文件,以记录过程中,对于不同的要素的思索。如我在设计GuardingDSL里,使用了一个0.0.1.sample文本文件,来描述早期版本的语法示例:
#正则表达式
package(match(“^/app”))endsWith”Connection”;
package(“..home..”)::nameshouldnotcontains(matching(“”));
#简化的比较
class::name.lenshould<20;
通过一些注释来让自己优化设计。
这一部分的过程,和我们学习编译原理时基本是一致的。不过呢,在编写领域特定语言的时候,我们一般会使用解析器生成器,而不是手写解析器。
设计领域特定语言的时候,在设计语法上的拘束不会像通用语言那么多。所以,自由设计的范围就大一点,有些内容也不一定需要像编程语言麻烦。诸如于:
分隔符
缩进的处理
语法块的开始和结束
……
PS:使用类似于编程语言的写法,对于写DSL的非编程人士来说可能会变成一种困扰。
经典的Lex&Yacc是你可以考虑的范围,在不同的语言里也有一些相似的实现。
对于我来说,以下是我常用的一些解析器生成器。
Antlr。支持主流的语言
Peg.js。JavaScript
Pest。Rust
Lalrpop。Rust
我还是比较习惯用Antlr,支持的语言较多。我与同事以及开源社区的小伙伴们,在下面的项目中都使用过Antlr:
Coca=Golang+Antlr
Unflow=Rust+Antlr
Lemonj=JavaScript/TypeScript+Antlr
Chapi=Java/Kotlin+Antlr
从使用上它们之间的差距并不大,但是都需要学习成本。
最后,让我们来谈谈一些有意思的东西,虽说是演进吧,但是,和设计暂时没有太大的关系。
经我大量发现,TDD是非常适合于编程语言的开发与设计。需求是未知的,易于发生变化的,还需要覆盖足够全的场景。
从实践的层面上来说,主要是有两种:
面向语法的测试。即,只让语法编译能通过,但是不报错。
面向功能的测试。即,验证某一部分的语法是正确的。
面向用例的测试。即,验证符合使用场景。
原先这部分的标题是,向下兼容。但是,我一直觉得向下兼容不是一个好主意。所以呢,我就想了想把在其它领域的经验搬了过来,于是呢,内容就变成了自动化语言迁移。
在关于版本的迁移上,我觉得Angular语言上关于版本的自动化迁移,是值得我们去借鉴的。当然了,采用这种设计的成本非常高,我们需要有一个专门的团队,使用工具自动化分析旧的系统,并使用工具来自动修改旧的代码。
文中相关DSL链接(欢迎加入Inherd一起编写DSL):
Unflow:https://github.com/inherd/unflow
Guarding:https://github.com/inherd/guarding
Forming:https://github.com/inherd/forming

主题测试文章,只做测试使用。发布者:最新稳定辅助网,转转请注明出处:https://www.744broad.com/14009.html

(0)
上一篇 2023年3月4日 下午12:09
下一篇 2023年3月4日 下午12:12

相关推荐

  • Linux 版 1Password 首个 Beta 版发布

    Linux 版 1Password 首个 Beta 版发布 DoNews10月22日消息(记者刘文轩)1Password是有名的密码管理工具,这款软件已经提供了多个系统的版本,然而在Linux平台,用户只能通过Chrome或Firefox浏览器的1PasswordX扩展程序使用。今年8月,1Password推出面向Linux平台的开发者预览版,这意味着Lin…

    RUST资讯 2023年2月19日
    70
  • 在80%特别好评的《亡灵巫师》里,甚至可以拼高达

    在80%特别好评的《亡灵巫师》里,甚至可以拼高达 “亡灵巫师”的名头,大家一定不会陌生。像投身于死亡与腐败的黑暗魔法当中,通过人类的绝望来获取新的力量《DOTA》里的罗坦德吉利,还有可以召唤死灵来攻击对手,也可以通过腐蚀魔法来伤害敌人《英雄无敌》山德鲁,都是让玩家们印象深刻的“亡灵巫师”。那你有没有想过,亡灵巫师是怎样将那些骷髅、骨架从墓穴深处复活重生?是炼…

    RUST资讯 2023年3月10日
    20
  • 关于Rust,你想知道的都在这里了

    关于Rust,你想知道的都在这里了 1、rust的开发推进非常有节奏,说每三个月发布一个版本,基本上都非常准时地做到了,roadmap里定好的东西,都按时按质按量出现了,体现了良好的工程管理;从这一点上,这几年出现的新语言鲜有管理得这么好的,有充分的理由让大家相信rust的前景:一切都会有的。2、rust原是一个servo的子项目,它的发展是servo推进的…

    RUST资讯 2023年2月26日
    40
  • 从它身上我看到了豪华手表的影子——OnePlus Watch 钴合金限定版详解

    从它身上我看到了豪华手表的影子——OnePlus Watch 钴合金限定版详解 对于智能手表,我们脑海中便是一块黑色或方或圆的小屏幕,一条硅胶表带。这样的设计虽然是智能手表最常见且最适用的模样,但绝不是它唯一的模样。智能手表也可以变得豪华、变得富有格调。前段时间,一加发布了旗下首款智能手表产品OnePlusWatch运动版,其运动版青春简约的外观与丰富的功能…

    RUST资讯 2023年2月24日
    100
  • 《使命召唤16》第二赛季官方先导预告 新枪新地图将至

    《使命召唤16》第二赛季官方先导预告 新枪/新地图将至 在经过多天的各方爆料之后,动视官方在今日正式公布了《使命召唤:现代战争》第二赛季官方先导预告,除了经典角色Ghost和经典地图“Rust”的回归外,还有众多海量内容即将登场,一起来了解一下吧。​在第二赛季经典角色“Ghost”将回归战场,第二赛季的故事背景中基地组织的特工再次窃取了核弹头,为了杜绝“维尔…

    RUST资讯 2023年2月14日
    50
  • 《真探》第二季独家剧评 主题与人物关系让观众看得云里雾里

    《真探》第二季独家剧评 主题与人物关系让观众看得云里雾里 时光网讯无论正当与否,《真探》第二季(以下称《真探2》)开播前凝聚了最高的期望值。首播季是一匹黑马,以它的深沉忧郁和文学化的质感闯入众人视线。在阴冷的谋杀案件背后,马修麦康纳与伍迪哈里森这对组合带来的表演时常是让人内心不安,又为之颤栗。但在第二季播出结束后,社交网络(更不要提传统的电视和媒体评论家)基…

    RUST资讯 2023年2月14日
    80
  • 在K8S上部署Polkadot验证节点

    在K8S上部署Polkadot验证节点 polkadot-k8s是一个用于快速搭建安全的Polkadot或Kusama验证节点的开源项目。Polkadot是一个支持分片的采用POS共识的区块链,Kusma是Polkadot的测试网络。在这个教程中,我们将学习如何利用自动化工具在GoogleKubernetesEngine上部署Polkadot验证节点,不需要…

    RUST资讯 2023年3月10日
    30
  • 一次满足三个愿望,TT G821飞行家三模键盘体验

    一次满足三个愿望,TT G821飞行家三模键盘体验 随着这两年无线的外设产品越来越多,如今无线化已经成为了外设的一大趋势。虽然平时我都是使用有线键盘为主,但是无线键盘那种干净利落的感觉确实是让人心痒痒。于是在一番纠结以后,我还是决定入手一把无线机械键盘。之所以会选择TTG821飞行家,其实原因很简单,因为它能够通吃有线/2.4GHz/蓝牙三种连接方式,而且在…

  • 2017 年值得学习的编程语言有哪些

    2017 年值得学习的编程语言有哪些 1.JavaScriptJavaScript继续着它令人难以置信的创新步伐。由于Web浏览器的快速发布计划的推动,JS标准每年都会更新。下一个版本,ES2017预计将于2017年中期完成。它将带来许多JS开发人员渴望的特性—用于处理异步函数的sync/await。感谢Babel,即使在今天,你也可以在每个浏览器中编写ES…

    RUST资讯 2023年2月16日
    90
  • 精品推荐—黑漆古光绪元宝

    精品推荐—黑漆古光绪元宝 清代银币、纸钞、铜币并行,至嘉庆年间发行新式银元,而光绪年间铸行金、银币更多。洋务运动也影响到铸币业,两广总督张之洞曾于光绪十三年(1887年)委托使英大臣在英国订购全套造币机器,并在广东钱局首铸机制银元和铜元。其后,各省纷纷仿效,购制国外机械铸造银、铜元。包括广东钱局在内,许多造币机均订购自著名的英国伦敦伯明翰造币有限公司。英国大…

    RUST资讯 2023年2月28日
    20
关注微信