写点什么

如何判断真伪 Ruby DSL?

2007 年 6 月 21 日

在 Ruby 社区中,“领域特定语言(Domain Specific Language,DSL)”已经成为一个非常流行的时髦词汇。Make 的替代工具 Rake 就是其中一个人气很旺的例子,尤其在Martin Fowler 撰文介绍它之后,它更是声名鹊起。DSL 这个词同样也用于描述Ruby on Rails 中ActiveRecord 组件的某些概念。

实际上,DSL 这个概念和Ruby 没有什么关系,早在Ruby 之前它就已经问世了很长的一段时间了。通常,我们用它来描述拥有特定的语言构造(Construct)、适用于表述某个特定领域的概念的一门语言。举例而言,Make 这个构建工具就包含了自己的一门语言,允许以声明的方式定义构建目标(Build Targets)和这些目标的构建方式,以及目标之间的依赖关系。此外的一个概念就是内部DSL,内部DSL 使用的是一门已有语言的语法,这个已有语言称为宿主语言(Host Language),比如Ruby。我们使用宿主语言的各种方式来构建语言构造,使其看起来像一门截然不同的语言。上面提到的Rake 就使用了这种方式,使得下面的代码成为可能:

task :codeGen do<br></br> #do the code generation<br></br>end正如你所能看到的,宿主语言应当非常灵活,才能允许 DSL 看起来截然不同。

然而,近来 DSL 这个字眼似乎有被滥用的趋势,导致它所代表的意思越来越含糊不清。似乎在一段代码中把方法调用的括号省掉以后,我们就可以大大方方地给这段代码贴上 DSL 的标签。是这样吗?O’Reilly 的博客作者 chromatic 贴出一个半开玩笑的列表,作为判断一段代码是否为 DSL 的依据——或者说,至少在我们给这段代码贴上 DSL 标签的时候,我们可以根据这些标准看看。其中的几条是像这样的:

  1. 除了 Ruby 以外,你还用过哪门语言写过代码没(PHP 和 HTML 不算数)?如果没有的话,那这是一门 DSL。
  2. 你所聪明地去掉括号的定义型语法特性是否一系列函数参数?如果是这样的话,那这是一门 DSL。
  3. 代码是否主要就包含一系列的键 - 值对?欢迎来到 DSL 的国度,你就是其中的一员!

chromatic 列表中的第 5 项特别说到:

  1. 你是否曾经认真使用过“……这代码读起来就像英语!”这样的话?你最好去一趟医院,因为你已经患 DSL 流感了!

关于创建 DSL,存在着一个非常流行的支持论调:DSL 使我们得以编写出易于阅读及理解的代码,并且不会将代码的意思隐藏在如 for 循环、条件语句之类的语言构造之后。然而, David A. Black 对此提出了一个不同的观点

下面这个: with Employee "123-45-6789" do<br></br> dock_salary 1000<br></br> warn_about :misconduct<br></br>end 并不是一门领域特定语言,它是领域特定语言。注意在这里我少用了“一门”这个词。它是领域特定的没错,而且也使用了类似语言的构造,但它并不是一门语言。它只是 Ruby 的代码,使用直表其意的方法名称和易懂的语义,从而有助于领域特定用语(Idioms)的使用。

使用一个针对领域的词汇表来命名代码元素并不是件新鲜事,相反,对于设计人来说它应当是一个显而易见的选择。

那么,DSL 这个字眼是有害或者有误导作用的么?未必。 Smalltalk 开发人员 Blaine Buxton 对此发表观点说

我一直就不理解:到底 DSL 出了什么大问题?当然,我并不是反过来说 DSL 不好。但我相信 DSL 是一个良好的面向对象设计的绿色副产品。所以,我曾经觉得所有在这方面的讨论和技巧挺烦人的。我心里一直这么跟自己说:“如果你的设计非常好,那么它 [DSL] 就自然而然产生了。” 但是我该好好敲敲自己的脑壳了。良好的设计又重新成为流行趋势,对此我应当感到高兴才对。你知道吗?我确实感到高兴。现在,我不再对那些讨论感到厌烦了。相反,我开始慢慢品味这些讨论的结果了。我甚至为之前保佑负罪感。你看,DSL 一直都是 Smalltalk 的一部分。对于我们 [Smalltalk 程序员] 来说,它再自然不过了,因为这就是我们学会写 [Smalltalk] 代码的方式。我记得我已经把“代码读起来应当像交谈(Code should read like a conversation)”这句至理名言吞进肚里,变成我思维的一部分了。而现在社区里面新一代的人们已经发现这个事实,并且在使用它,这真是太酷了。

含有可被扭转 / 改变的语法,从而可以写出更加简练的代码的语言是很有用的,但良好的设计仍然取决于开发人员本身。

这一点存在另外一面。有一些 DSL 使用 Ruby 的构造及 Ruby 语法中比较罕见的一些情况。尽管这可以让开发人员实现出某种特定形式的代码,但是并不意味着这是一种良好的设计。毕竟,虽然代码只要写一次,但需要经过多次阅读和修改,这个事实毫无疑问到现在都还没有人能否认。

最近在Urban Honking 上的一篇文章引发了对这个话题的一次辩论。文章揭示了为什么HTML 解析库 Hpricot 使得下面一段代码成为可能:

Hpricot(my_document)从根本上说,这里使用了一个叫做<strong>Hpricot</strong>函数创建了 **Hpricot类 ** 的一个新对象,并对my_document进行解析。然而,Smalltalk 领域的博客作者 James Robertson 表示反对

Urban Honking 费了九牛二虎之力,解释了为什么使用 Ruby 的一些语法技巧得出类似Hpricot(my_document)这样的东西会是一件好事的原因。在这里我提个问题:如果你偶然在代码中碰到这样的技巧性写法,你会明白这代码是干嘛的吗?

在解释如何提高代码质量之后,他接着说:

我已经用 Smalltalk 用得聪明过头好多次了;这绝不是一个好主意。

Stuart Halloway 也站出来声援这个观点

如果你打算改变一门语言的惯用法,那么你得先有一个很有说服力的理由。我同意 James 的观点,这个例子不够令人信服。

接着,他又针对 API 设计的多种不同解决方案给出了一个颇有意思的纵览,并且阐述了如何设计出一套可以用来编写出表义清晰代码的 API。

亲爱的读者,您又是持什么样的看法呢?对于使代码更容易阅读的良好设计和使用能让我们少敲几下键盘、但令代码难于维护的编程技巧之间的界限,你又是如何划分的呢?如果你需要审视自己是否已从良好设计的航线上迷失,并且误入 Hacking 以及灵活运用语法技巧的百慕大,存在什么有效的方法吗?

查看英文原文: What’s a Ruby DSL and what isn’t?

2007 年 6 月 21 日 09:301295
用户头像

发布了 117 篇内容, 共 97400 次阅读, 收获喜欢 0 次。

关注

评论

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

即将步入职场,忐忑而又期待的新人菜鸟

菜农阿飞

成长 新人

用行动解决情绪,情绪永远是累赘

熊斌

情绪控制 团队协作

什么是 MQ ?

itfinally

系统设计 MQ

高仿瑞幸小程序 01 初建项目,引入Vant Weapp

曾伟@喵先森

小程序 微信小程序 前端 vant

死磕Java并发编程(7):读写锁 ReentrantReadWriteLock 源码解析

七哥爱编程

Java并发 读写锁 ReentrantReadWriteLock

高仿瑞幸小程序 00 准备工作

曾伟@喵先森

小程序 微信小程序 前端 瑞幸

周报 01|多点分享,少点创作

强劲九

学习 读书

Go语言获取程序各类资源的绝对路径的方法

良少

Python go 路径 动态 绿色

每日一道python面试题 - Python的函数参数传递

志学Python

Python 爬虫 面试题 python 爬虫 python3.x

如何写排版优雅简洁的文章?

池建强

写作 排版

程序员陪娃漫画系列——魔方

孙苏勇

程序员 生活 程序员人生 陪伴 漫画

初步了解MyBatis

Java收录阁

mybatis

目标:2020年学会写文章

wiflish

KubeFATE: 用云原生技术赋能联邦学习(一)

亨利笔记

人工智能 学习 FATE KUBEFATE

爬虫(108)Python 3.8的超酷新功能(接近一万字,请耐心享用,而且建议收藏)

志学Python

python 爬虫 python3.x python升级

我愿沉迷于学习,无法自拔(二)

孙瑜

深度思考 个人成长

HashMap 的 7 种遍历方式与性能分析

Bruce Duan

Java 性能 hashmap 遍历

Windows Terminal添加右键菜单

simon

Windows Terminal 右键菜单 终端 开发者工具 命令行

3NF建模&维度建模

常海峰

GroupBy 用法的三重境界,面试终结者

Hyun

数据库 sql 大数据 性能优化 数据分析

运维常见问题及排查思路

编程随想曲

运维

Hive 中的 GroupBy, Distinct 和 Join

tkanng

sql 大数据 hadoop hive

一些想法

Z

kettle(Pentaho Data Integration) 使用"最佳"实践

稻草鸟人

Java kettle

​成功的人,都是 “狠角色”

非著名程序员

程序员 提升认知 成功学 自律

游戏夜读 | 2020周记(3.27-4.3)

game1night

这里有一个慢 SQL 查询等你来优化

石头

MySQL 数据库 性能优化 后端

爬虫(107)Python 3.7的超酷新功能(接近一万字,请耐心享用,而且建议收藏)

志学Python

Python 最佳实践 python 爬虫 python3.7 python升级

每天打卡python面试题 - 在一行中捕获多个异常(块除外)

志学Python

Python 面试题 python 爬虫 python3.7

关于5G RCS的产品猜想

机器鸟

C++中glog源码剖析以及如何设计一个高效 log模块

程序喵大人

c++ 编程语言

InfoQ 极客传媒开发者生态共创计划线上发布会

InfoQ 极客传媒开发者生态共创计划线上发布会

如何判断真伪Ruby DSL?-InfoQ