《领域特定语言》一2.3DSL的问题

2.3DSL的问题

前面已经讨论了何时该采用DSL,接下来就该谈论什么时候不该采用DSL,或者至少是使用DSL应注意的问题。
从根本上说,不使用DSL的唯一原因就是,在你的场景下,使用DSL得不到任何好处,或者,至少是DSL的好处不足以抵消构建它的成本。
虽然DSL在有些场合下适用,但同样会带来一些问题。总的来说,我认为通常是高估了这些问题,一般人们不太熟悉如何构造DSL,以及DSL如何适应更为广阔的软件开发图景。还有,许多常提及的DSL问题混淆了DSL和模型,这也伤及了DSL的优势。
许多DSL问题只是与某种特定DSL风格相关,要理解这些问题,我们需要深入理解这些DSL是如何实现的。所以,这些问题留待后面讨论,在这里,我们只看宽泛的问题,这同当前讨论的问题是一致的。

2.3.1语言噪音

在反对DSL的观点中,我最常听到的是称为语言噪音的问题:担心语言难于学习,因此,使用多种语言会比使用一种语言复杂得多。必须了解多种语言,会让工作更为困难,新人加入的门槛也提升了。
当人们谈及这种担心时,他们都会有一些共同的误解。首先,他们通常混淆了学习一门DSL的心血与学习一门通用语言的心血。DSL远比一门通用语言容易,因此,学习起来也要容易得多。
许多批评者知道这一点,但依然反对DSL,即便它们相对容易学习,在一个项目上有多种DSL也增加了理解的难度。这里的误解在于,他们忘了一点,一个项目总有一些复杂的地方,难于学习。即便不用DSL,代码库中仍然有许多需要理解的抽象。通常,这些抽象应该在程序库里,以便于掌握。即使不必学习多种DSL,也不得不学习多个程序库。
所以,真正的问题在于,相比于学习DSL底层模型而言,学习DSL会难多少。我认为,相对于理解模型而言,学习DSL 所增加的成本相当小。确实,因为DSL的的价值就在于,让人们理解和使用模型更容易,所以使用DSL就应该能降低学习成本。

2.3.2构建成本

相对于底层的程序库而言,DSL增加的成本并不大,但这始终是成本。代码需要写,尤其是还要维护。所以,同其他代码一样,它也要做好自己的本职工作。并非所有程序库都值得用DSL封装。如果命令–查询API够用,就没有必要在上面提供额外的API。即便DSL有用,就边界效应而言,构建和维护也需要花费太多的工作量。
DSL的可维护性是一项重要的考量因素。如果团队中的大多数人都觉得难以理解,即使是一种简单的内部DSL,也会带来很大的麻烦。外部DSL更是让许多人望而却步,一个解释器就足以让很多程序员打退堂鼓。
人们不习惯构建DSL,这也让添加DSL的成本变得更高。人们要学习新技术。虽然不应该忽略这些成本,但我们也应该清楚,这个学习曲线的成本能够分摊到未来使用DSL的过程中。
还有一点要清楚,DSL的成本大于构建模型的成本。任何复杂的地方都需要某种机制管理其复杂性,如果复杂到要考虑DSL,几乎肯定复杂到可以从模型中获益的程度。DSL有助于思考模型,降低构建成本。
这会带来一个相关问题,鼓励使用DSL会导致构建出一堆糟糕的DSL。实际上,我盼着构建出一堆糟糕的DSL,就像有很多糟糕的命令–查询API的程序库一样。问题在于,DSL会不会把事情弄得更糟。一个好的DSL可以封装一个糟糕的程序库,把它变得更易用(如果可能的话,我更愿意修正程序库本身)。糟糕的DSL对于构建和维护而言,就是浪费 资源,但这种说法对任何代码都适用。

2.3.3集中营语言

集中营语言(ghetto language)问题与语言噪音问题正好相反。比如,一家公司用一种内部语言编写公司内的很多系统,这种语言在其他地方根本用不上。这种做法会让他们很难找到新人,跟上技术变化。
在分析这个问题时,首先要澄清一点,如果整个系统都是用一种语言编写的,那它就不是一种DSL(至少按我的定义),而是一种通用语言。虽然可以用许多DSL技术构建通用语言,但我强烈建议,不要这样做。构建和维护一种通用语言是一个巨大的负担,它会迫使你在这个集中营中做大量工作,甚至挣扎一生。不要这么做。
我相信,集中营语言问题并非空穴来风,它隐含了一些现实问题。首先是,一种DSL总是存在着无意中演化成一种通用语言的危险。我们有一种DSL,然后,逐步为它添加新功能;今天添加条件表达式,明天又添加循环,最终图灵完备了。
对此,唯一的抵御就是坚决防范。确保我们对DSL针对问题的受限范围有个清晰的认识。质疑任何不在此范畴内的新特性。如果想做得更多,可以考虑采用多种语言,综合运用,而非强求一种DSL不断膨胀。
框架也面临着同样的问题。好的程序库都有一个明确的目的。如果产品定价库包含HTTP协议的实现,从本质上说,我们也就要忍受同样错误之苦:未能分离关注点。
第二个问题是,自行构造本应从外部获得的东西。这个问题同样适用于DSL和程序库。比如,如今,很少有要自己构造对象–关系映射(object–relational mapping)系统。我有一条关于软件的通用规则,不是自己的业务,不要自己写─总要先看看是否从别的地方可以找到。特别是,随着开源工具的崛起,基于既有开源工作量进行扩展,肯定比从头打造更有意义。

2.3.4 “一叶障目”的抽象

DSL的有用之处在于,它提供了一种抽象,我们可以基于这种抽象来思考领域问题。这种抽象非常有价值,我们更容易表述领域行为,效果远胜于依据底层构造进行思考。
然而,任何抽象(包括DSL和程序库)总是伴随着风险─它可能让我们“一叶障目,不见泰山”。有了这种“一 叶障目”的抽象,我们就会苦苦思索,竭尽全力把外部世界塞入抽象之中,而非另寻它路。我们常常会见到这种情况:遇到一种不符合抽象的事物,殚精竭虑地让其符合,而不是修改抽象,让抽象更容易接纳新的行为。一旦我们满意了这个抽象,觉得尘埃落定,“一叶障目”也就随之而来。到这种时候,对于颠覆性的变化,难免心生忧虑。
“一叶障目”是任何抽象都会面临的问题,不仅是DSL,但DSL可能让这个问题变得更严重。因为DSL提供了一种更为舒适的方式操作抽象,一旦适应,更不愿意做出改变。如果采用DSL与领域专家交流,问题可能会更严重,通常,他 们在习惯之后更不愿意做出改变。
如同对待任何抽象一样,应该视DSL为一种“不断演化,尚未完结”的事物。

时间: 2024-09-12 08:14:57

《领域特定语言》一2.3DSL的问题的相关文章

《领域特定语言》一导读

前 言 在我开始编程之前,DSL(Domain–Specific Language,领域特定语言)就已经成了程序世界中的一员.随便找个UNIX或者Lisp老手问问,他一定会跟你滔滔不绝地谈起DSL是怎么成为他的镇宅之宝的,直到你被烦得痛不欲生为止.但即便这样,DSL却从未成为计算领域的一大亮点.大多数人都是从别人那里学到DSL,而且只学到了有限的几种技术. 我写这本书就是为了改变这个现状.我希望通过本书介绍的大量DSL技术,让你有足够的信息来做出决策:是否在工作中使用DSL,以及选择哪一种DSL

如何设计一门编程语言(十) 正则表达式与领域特定语言(DSL)

几个月前就一直有博友关心DSL的问题,于是我想一想,我在gac.codeplex.com里面也创建了一些DSL,于是今天就来说一说这个事情. 创建DSL恐怕是很多人第一次设计一门语言的经历,很少有人一开始上来就设计通用语言的.我自己第一次做这种事情是在高中写这个傻逼ARPG的时候了.当时做了一个超简单的脚本语言,长的就跟汇编差不多,虽然每一个指令都写成了调用函数的形态.虽然这个游戏需要脚本在剧情里面控制一些人物的走动什么的,但是所幸并不复杂,于是还是完成了任务.一眨眼10年过去了,现在在写Gac

《领域特定语言》一第1章 入 门 例 子1.1 哥特式建筑安全系统

第1章 入 门 例 子 落笔之初,我需要快速地解释一下本书的内容,就是解释什么是领域特定语言(Domain– Specific Language,DSL).为达此目的,我一般都会先展示一个具体的例子,随后再给出抽象的定义.因此,我会从一个例子开始,展示DSL可以采用的不同形式.在第2章里,我会试着把这个定义概括为一些更广泛适用的东西. 1.1 哥特式建筑安全系统 在我的童年记忆里,电视上播放的那些低劣的冒险电影是模糊却持久的.通常,这些电影的场景会安排某个古旧的城堡.密室或走廊在其中起着重要的作

《领域特定语言》一第2章 使用DSL 2.1定义DSL

第2章 使用DSL 看过上一章的例子后,即便尚未给出DSL的一般定义,对于何为DSL,你也应该已经有了自己的认识.(第10章中有更多例子.)现在,要开始讨论DSL的定义及其优势与问题.这样就可以为下一章讨论DSL实现提供一些上下文. 2.1定义DSL "领域特定语言"是一个很有用的术语和概念,但其边界很模糊.一些东西很明显是DSL,但另一些可能会引发争议.这一术语由来已久,不过,正如软件行业中的很多东西一样,它也从未有过一个确切的定义.然而,就本书而言,定义是非常有价值的.领域特定语言

《领域特定语言》一1.3 为格兰特小姐的控制器编写程序

1.3 为格兰特小姐的控制器编写程序 至此,我们已经实现了状态机模型,接下来,就可以为格兰特小姐的控制器编写程序了,如下所示: Event doorClosed = new Event("doorClosed", "D1CL"); Event drawerOpened = new Event("drawerOpened", "D2OP"); Event lightOn = new Event("lightOn&quo

《领域特定语言》一2.4 广义的语言处理

2.4 广义的语言处理 本书是关于领域专用语言的,但它也涉及语言处理技术.之所以二者重合,是因为在普通的开发团队里,用到语言处理技术的情况,90%都是为了DSL.但是,这些技术也可以用于其他方面,若不讨论这些情况,将是我的失职.我曾遇到过这方面一个很好的例子,那是在一次拜访ThoughtWorks项目团队时.他们有一个任务,要与某第三方系统通信,发送的消息以COBOL copybook定义.COBOL copybook是一种用来描述记录的数据结构格式.因为系统中有很多地方要用到,所以我的同事Br

《领域特定语言》一1.2 状态机模型

1.2 状态机模型 一旦团队达成共识,认为对于指定控制器如何运作而言,状态机是一个恰当的抽象,那么,下一步就是确保这个抽象能够运用到软件自身.如果人们在考虑控制器行为时,也要考虑事件.状态和转换,那么,我们希望这些词汇也可以出现在软件代码里.从本质上说,这就是领域驱动设计(Domain–Driven Design)中的Ubiquitous Language [Evans DDD] 原则,也就是说,我们在领域人员(那些描述建筑安全该如何运作的人)和程序员之间构建的一种共享语言.对于Java程序来说

《领域特定语言》一3.5 宏

3.5 宏 "宏"(第15章)是一种工具,既可以用于内部DSL,也可以用于外部DSL.宏曾经得到广泛应用,但如今已不那么常见了.在大多数情况下,我建议尽量避免使用宏,但偶尔,它也有一些用处.所以,接下来,就谈论宏的运作方式以及使用时机. 宏有两种风格:文本宏和语法宏.文本宏最容易理解,简单说就是文本替换.使用文本宏会带来便利,一个很好的例子就是,在CSS文件中指定颜色.除了少数几种特定情况外,CSS强制我们以颜色代码指定颜色,比如#FFB595.这样的代码并不表意,更糟糕的是,如果要在

《领域特定语言》一2.2为何需要DSL

2.2为何需要DSL 至此,我希望,对什么是DSL,我们已经有了一个很好的共识,接下来的问题是,为何要考虑采用DSL.DSL只是一种工具,关注点有限,无法像面向对象编程或敏捷方法论那样,引发软件开发思考方式的深刻变革.相反,它是在特定条件下有专门用途的一种工具.一个普通的项目可能在多个地方采用了多种DSL─事实上很多项目这么做了.在1.4节中,一直强调,DSL只是模型的一个薄壳,这个模型可能是程序库,也可能是框架.这句话提醒我们,当考虑DSL的优劣时,一定要分清它是来自DSL的模型,还是DSL本