AI实践哪家强?来 AICon, 解锁技术前沿,探寻产业新机! 了解详情
写点什么

Obie Fernandez 谈敏捷 Ruby DSL

  • 2007-04-16
  • 本文字数:2107 字

    阅读完需:约 7 分钟

Software-Engineering Radio (一个向资深软件开发者提供音频节目的站点)最近就DSL(特定领域语言)和Ruby 语言如何使得编写内部DSL 变得更加方便等问题采访了InfoQ 的专家Obie Fernandez ,摘要如下:

DSL 是一种专注于某一特定领域的语言,使用通用语言(如 C 或者 Java)当然可以得到与 DSL 相同的功能。但是这样会产生大量繁琐的代码并导致大量的领域知识被隐藏在通用语言构造中(如 for 循环,if 条件,方法调用,import 声明等等)。

生成以及维护通用语言编写的代码本身也是问题所在:专家们必须将他们的知识变为代码。通常这些专家(销售人员,经理或者园丁)缺少编程知识,这意味着他们必须与程序员进行协作。当然,这也意味对代码的任何一次修改都包括许多繁琐的步骤:如果一个领域专家需要改变某些功能,她必须首先与程序员进行交流,由程序员实现这些修改,然后领域专家检查这些代码是否表现出期望的行为,诸如此类。

对于上述问题,其中一个可能的解决方案是开发一种适应特定环境的语言,非技术人员可以用它来解决问题。这种语言较通用语言更简洁并且仅仅提供目标领域所需要的类型以及特定的语言构造。

在访谈中, Obie 将 DSL 类比为自然语言中的俚语或者行话。全世界喜爱咖啡的人对下面这句话一定非常熟悉:

Venti half-caf, non-fat, no foam, no whip latte

在正常的对话中,上述语言不能传递正确的语义。并且世界上大多数的咖啡馆里可能仅仅提供最普通的牛奶加咖啡。但是在合适的场所使用上述语言(例如,星巴克),它将让你使用最少的词语喝到想要的饮料并且很少会造成误解。

有多种方式可以实现 DSL。其中一个选择是定义一种语法并使用解析器生成工具(如 ANTLR 或者 YACC)来生成解析器。通过它可以将 DSL 代码转化为某种可以被解释的数据结构(语法树)。其中一个例子是 Make 文件,它被用来定义构建过程(编译,打包,部署)。另一种方式是使用 XML 而不是解析器,它将对于解析器生成工具的依赖变为对于 XML 解析器的依赖,有许多工具可以用来支撑 XML 处理(使用 DOM 解析器可以得到类似语法树的数据结构,同时使用 XPATH 来提取数据,等等)。Ant,是一个基于 XML 的 DSL, 构建过程被定义为 XML 格式。Make 和 Ant 就是 _ 外部 _DSL 最典型的实现。

另一个解决方案是 _ 内部 _DSL, 它不需要使用任何解析器生成工具以及 XML 解析器,取而代之的是使用现有的合法的通用语言的构造,很明显,这种语言的构造必须非常灵活才可以容纳各种简练的 DSL 代码。

内部 DSL 的终极解决工具非 LISP 以及类 LISP 语言莫属,原因是 LISP 灵活的语法,它可以被概括为:

  • 原子
    几乎任何字符都可以成为原子,如foo:::bar:::甚至加号都是合法的原子
  • 零个或多个原子组成的序列
    放入圆括号中

LISP 宏特性使得开发者可以很轻易的在 LISP 中定义 DSL 并且将其解释或者展开为可以执行的通常的 LISP 代码。

另外一种适于使用内部 DSL 的语言是 Ruby, 没什么可惊奇的,想想 Ruby 丰富的语法吧,它是 Ruby 得以支持内部 DSL 的部分特性。下面是 Obie 在 PPT 上所使用到的观点以及相应的示例代码:

  • 方法调用中括号可以省略。这看起来没什么大不了的, 但是它使得下面的声明成为合法的 Ruby 代码: order = latte venti, half_caf, non_fat, no_foam, no_whip 在上面的例子中,latte(拿铁咖啡)以及我们所需要的特别的口味儿都是方法调用的一部分。latte 方法返回一个将咖啡各个属性进行了初始化的对象。

  • 类的定义在载入时可以被动态执行 class RuleSet < ActiveRecord::Base has_many :commends, :dependend => :delete_all # ... more... end 这是一个内部 DSL 在 Rails 的 ActiveRecord 中的例子。has_many 调用会在类第一次被载入时执行。这个调用被用来设定类的关联以及行为,例如,它可以通过 define_method 调用向类添加一些方法。这样这段 DSL 代码的用户可以使用非常简洁,描述性的方式来定义类某些方面的行为。事实上,这与 LISP 宏有很多相似的地方,他们都在代码被载入时进行工作。

  • 简洁的代码块书写格式(Block)块是自包含的 Ruby 代码。它可以被保存,当作参数传递并在以后执行,这个概念也被称做是匿名方法,lamda 演算或者闭包(Closures),在 Ruby 中向方法传递块非常简洁紧凑,它使得实现特定语言构造变得非常容易, Rake 是与 Make 和 Ant 非常相似的构建工具,我们来看一个例子:

    task :default => [:test] task :test do ruby "test/unittest.rb" end 上面的类使用了我们在这里提到的所有的三种概念。task 是一种方法调用,但是没有圆括号让它变的更具描述性。task 调用在载入时被执行,对内部数据结构进行设置。test 任务的逻辑在块中进行定义(在 do 和 end 之间的代码),并在适当的时候被执行。

在 Ruby 中,内部 DSL 使得编写简洁和描述性的规范变得非常容易。正如我们从 has_many 例子中看到的,内部 DSL 也可以很容易的与通常命令式的 Ruby 代码进行混合。

译者简介:胡凯是 InfoQ 中文站的志愿者翻译。2006 年加入 ThoughtWorks ,通过在 ThoughtWorks 多个国家和多个项目的敏捷实践,坚定地站在了敏捷阵营中,目前在进行 CruiseControl 相关的敏捷开源项目。他和许多敏捷开发者一样活跃在敏捷中国 CruiseControl-China 社区中。

2007-04-16 20:001092

评论

发布
暂无评论
发现更多内容

高级前端常考手写面试题(必备)

helloworld1024fd

JavaScript

Backbone前端框架解读

京东科技开发者

Vue 前端 前端架构 企业号 2 月 PK 榜 backbone

从React源码角度看useCallback,useMemo,useContext

goClient1992

React

从React源码来学hooks是不是更香呢

goClient1992

React

react源码分析:实现react时间分片

flyzz177

React

用javascript分类刷leetcode16.set&map(图文视频讲解)

js2030code

JavaScript LeetCode

什么是WMS系统?

SAP虾客

wms

实现Promise的原型方法--前端面试能力提升

helloworld1024fd

JavaScript

融云 x 易车:携手八载,打造高效连接用户的汽车服务平台

融云 RongCloud

让远程成为本地,微服务后端开发的福音

北京好雨科技有限公司

Kubernetes 微服务 云原生 企业号 2 月 PK 榜

前端工程师leetcode算法面试必备-二分搜索算法(上)

js2030code

JavaScript LeetCode

文盘Rust -- rust 连接云上数仓 starwift

京东科技开发者

rust Clickhouse 语言 rust语言 企业号 2 月 PK 榜

2023年国家级重大人才工程引进申报

科兴未来News

创新创业 江苏工博会 博士后 #人才政策# 启明计划

ChatGPT背后的经济账

OneFlow

人工智能 深度学习 大模型

lua中实现判断是否为局域网IP

ModStart

社招前端一面经典手写面试题

helloworld1024fd

JavaScript

react源码分析:深度理解React.Context

flyzz177

React

谈谈我对于关键思考的理解

阿里巴巴中间件

阿里云 关键

如何实现OpenHarmony的OTA升级

OpenHarmony开发者

OpenHarmony

一文搞懂Redis

京东科技开发者

redis hash Zset Redis 协议 企业号 2 月 PK 榜

带你实现react源码的核心功能

goClient1992

React

Verilog HDL函数与任务的使用

timerring

FPGA

前端刷完这12道滑动窗口,就可以出山面试了

js2030code

JavaScript LeetCode

用户行为分析模型实践(三)——H5通用分析模型

vivo互联网技术

大数据 数据分析 数仓建模

几个常见的js手写题,你能写出来几道

helloworld1024fd

JavaScript

使用 NineData 快速构建企业容灾备份

NineData

数据库 数据管理工具 数据备份 运维开发 企业容灾

百度工程师带你了解Module Federation

百度Geek说

JavaScript 微前端 企业号 2 月 PK 榜

react源码分析:组件的创建和更新

flyzz177

React

一口气讲完了Redis常用的数据结构及应用场景

小小怪下士

Java redis 程序员

湖仓一体电商项目(十九):业务实现之编写写入DWS层业务代码

Lansonli

数据湖 湖仓一体电商项目

Obie Fernandez谈敏捷Ruby DSL_Ruby_Werner Schuster_InfoQ精选文章