写点什么

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:001305

评论

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

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

flyzz177

React

开源依赖项管理指南

SEAL安全

12 月 PK 榜 依赖管理 传递依赖 开源依赖项

超1800万累计观看,多次占据热榜前列……“无障碍字幕直播间”带来的远不止这些!

猿始人

北京同仁堂两大名牌品种亮相帝都

联营汇聚

教你用JavaScript实现点击支付框

小院里的霍大侠

JavaScript 小白 编程开发 实战案例 初学者

云原生时代数据库运维体系演进

vivo互联网技术

数据库 运维 故障自愈

易观分析潘玉宇:信贷全流程化监管将成行业发展重点,银行间联合风控程度将逐渐加深

易观分析

银行 普惠金融

Verilog 时延与过程结构

芯动大师

Verilog语法 Verilog延时 Verilog过程结构

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

flyzz177

React

react源码分析:babel如何解析jsx

flyzz177

React

JavaScript刷LeetCode心得

js2030code

JavaScript LeetCode

卡塔尔世界杯出现了半自动越位识别技术、动作轨迹捕捉等黑科技。

汀丶人工智能

12月日更 12月月更 世界杯黑科技

【IntelliJ IDEA】【SVN】SVN详细的介绍和Idea中如何使用SVN

No8g攻城狮

ide svn Git Submodule git fetch IDEA DeBug

react源码中的生命周期和事件系统

flyzz177

React

React 之 Context 的变迁与背后实现

冴羽

JavaScript 源码分析 前端 前端框架 React

JDK自带命令优化

@下一站

代码优化 12月日更 12月月更 jvm优化 java程序优化

架构实战营 2-5 微信红包分析随堂测验

西山薄凉

「架构实战营」

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

flyzz177

React

用javascript分类刷leetcode3.动态规划(图文视频讲解)

js2030code

JavaScript LeetCode

【前端相关】服务端渲染和客户端渲染的比较

No8g攻城狮

CSS css3 前端 js 前端框架

2022年11月中国汽车智能网联月度观察

易观分析

汽车 智能网联

【其他】快出数量级的性能是怎样炼成的

No8g攻城狮

MySQL sql 数据库·

真希望你也明白runtime.Map和sync.Map

面向加薪学习

面试 并发 源码阅读 go语言 Map集合

跳板攻击中如何追踪定位攻击者主机(上)

郑州埃文科技

数据安全 网络攻击 跳板攻击

GaussDB(DWS)运维 :遇到truncate执行慢,怎么办

华为云开发者联盟

数据库 后端 华为云 12 月 PK 榜

2022-12-12:有n个城市,城市从0到n-1进行编号。小美最初住在k号城市中 在接下来的m天里,小美每天会收到一个任务 她可以选择完成当天的任务或者放弃该任务 第i天的任务需要在ci号城市完成,

福大大架构师每日一题

算法 rust 福大大

KCL - 让 Kubernetes 资源清单管理更容易

Peefy

编程 Serverless Kubernetes #开源 #DevOps

Flink核心组件

穿过生命散发芬芳

flink 12月月更

架构实战营 2-6 钱包高可用实战随堂练习

西山薄凉

「架构实战营」

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

flyzz177

React

前端工程师leetcode算法面试必备-简单的二叉树

js2030code

JavaScript LeetCode

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