《领域特定语言》一2.5 DSL的生命周期

2.5 DSL的生命周期

为了介绍DSL,开篇先描述一个框架,及其命令–查询API,基于这个API,构建一层DSL以简化操作。我用这种方式,是因为我觉得这种方式有助于理解DSL,但这并不是人们在实际中使用DSL的唯一方式。
另一种常见的方式是先定义DSL。在这种模式下,可以先从一些场景开始,按照期望DSL的样子,把这些场景写下来。如果语言是业务功能的一部分,最好和领域专家一起做─这是一个好的开始,使用DSL作为一种沟通媒介。
有人喜欢从语句开始,他们期待这些语句能够语法正确。这意味着,对内部DSL,要符合宿主语言的语法; 对外部 DSL,语句要能够解析。其他DSL开始时比较非正式,然后再对照DSL进行修改,以得到一种合理的语法。
以这种方式实现状态机,我们要和了解客户需求的人一起坐下来,想出一套关于控制器行为的例子,这些例子可以基于人们过去的需求,也可以基于我们对他们期望的理解。对于每个例子,尝试用DSL的形式把它们写下来。随着处理到不同的情况,我们就要修改DSL,支持新的能力。最后,我们就会得到一套合理的用例,以及对这些用例的伪DSL描述。
如果用的是语言工作台,就要在工作台之外完成这一阶段,用一个纯文本编辑器,或者一个普通的绘图软件,也可以是纸和笔。
一旦有了一套典型的伪DSL,就可以着手实现它了。这里的实现包括以宿主语言设计的状态机模型、 模型的命令–查询API、DSL的具体语法以及DSL和命令–查询API之间的转换。实现方式有很多种。有人喜欢一次做一点,横跨所有元素:构建少量模型、添加DSL驱动模型,然后用测试把所有东西串起来;也有人倾向于先构建和测试整个框架,然后在其上构建一层DSL;还有人喜欢先准备好DSL,然后构建程序库,再使它们适配。作为一个增量主义者,我倾向于端到端地实现薄薄几层的功能,因此,我会采用三种做法中的第一种。
我会从我所见的最简单的一个用例出发。采用测试驱动开发的方式,编写一个支持这个用例的程序库。然后,通过DSL实现这个用例,把它同之前构建的框架连起来。我很乐于对DSL做出一些修改,使其易于修改,当然,我会拿着这些修改与领域专家沟通,确保我们对于共同的沟通媒介有同样的理解。做完一个,我会继续做下一个。就这样,我逐渐演化着框架、测试优先,然后逐渐演化着DSL。
这并不是说模型优先的路线是一个糟糕的选择,事实上,这种做法往往可以做得很漂亮。模型优先常常发生在一开始没有考虑DSL,或者不确定是否需要DSL的情况下。这时,我们会先构建框架,用了一段时间之后,我们觉得DSL是一 个有益的补充。在这个例子里,已经有一个可用的状态机模型,而且许多客户已经开始使用。这时,我们意识到,要增加一个新客户困难重重,因此决定尝试DSL。
基于模型发展DSL的方法有两种。对于“语言生长”(language–seeded)的方式,要慢慢地在模型之上构建DSL,把模型几乎视为黑盒。首先看看目前所有的控制器,然后草拟出每个控制器的伪DSL。然后,就像前面提及的情况那样,一个场景一个场景地实现DSL,通常,我们不会对模型做任何深入的修改,尽管给模型添加一些方法能够更好地支持DSL。
对于“模型生长”(model–seeded)的方式,要先给模型加入一些连贯方法(fluent method),让模型更易于配置,然后逐渐把它们抽成DSL。这种方式更适用于内部DSL,可以视之为模型的一次重量级重构,派生出内部DSL。“模型生长”的方式最吸引人的方面在于,它是逐步进行的,构建DSL并不需要显著的成本。
当然,在很多情况下,我们甚至连框架都没有。写了几个控制器之后,我们才意识到,有很多通用功能。然后,就会重构系统,拆分模型与控制代码。这个拆分是至关重要的一步。虽然做这件事时,脑海中已经有了DSL,但我依然倾向于首先完成拆分,然后在其上构建DSL。
至此,我要强调一件事,希望我的担心是多余的。一定要保证所有的DSL脚本都保存在某种形式的版本控制系统里。DSL脚本是代码的一部分,所以,就像其他东西一样,它也应该放到版本控制里。文本化DSL的一大优势在于,它们可以很好地与版本控制系统协作,也就很容易跟踪系统行为的变化。

时间: 2024-12-21 22:27:16

《领域特定语言》一2.5 DSL的生命周期的相关文章

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

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

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

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

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

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

《领域特定语言》一导读

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

2.6 设计优良的DSL从何而来 审核本书的人常常问我,有没有一些"设计优良语言"的技巧.毕竟,语言设计很特别,我们不希望这个世界上充斥着糟糕的语言.我想分享一些好的建议,但我坦白,真没什么好办法.如同任何写作一样,DSL的总体目标就是对读者要清晰.我们希望本书的典型读者,可能是程序员,抑或是领域专家,能够尽可能快速清晰地理解DSL里句子的意图.虽然我觉得可能无法告诉你如何做到这一点,但是我的确觉得在工作中牢记这一点非常有价值.总的说来,我是迭代设计的粉丝,这次也不例外.尽早从目标受众

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

2.3DSL的问题 前面已经讨论了何时该采用DSL,接下来就该谈论什么时候不该采用DSL,或者至少是使用DSL应注意的问题.从根本上说,不使用DSL的唯一原因就是,在你的场景下,使用DSL得不到任何好处,或者,至少是DSL的好处不足以抵消构建它的成本.虽然DSL在有些场合下适用,但同样会带来一些问题.总的来说,我认为通常是高估了这些问题,一般人们不太熟悉如何构造DSL,以及DSL如何适应更为广阔的软件开发图景.还有,许多常提及的DSL问题混淆了DSL和模型,这也伤及了DSL的优势.许多DSL问题

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

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

《领域特定语言》一1.4 语言和语义模型

1.4 语言和语义模型 在这个例子之初,我谈到了构建一个状态机模型.这种模型的存在,以及它同DSL的关系,是至关重要的.在这个例子里,DSL的角色就是组装状态机模型.因此,当解析定制语法的版本时,遇到: events doorClosed D1CL 会创建一个新的事件对象(new Event("doorClosed","D1CL")),把它保存在一边(在一个 "符号表"(第14章)里),这样,遇到doorClosed=>active时,就可