Tag Archives: domain specific language

笔记:DSL之二 使用DSL

这篇笔记的内容来自MF http://martinfowler.com/dslwip/UsingDsls.html 

领域特殊语言(Domain Specific Language)定义

a computer programming language of limited expressiveness focused on a particular domain.

关注特定领域表述有限的计算机程序语言

四个重要元素

  • computer programming language:A DSL is used to humans to instruct a computer to do something, as well as helping communication between humans.
    计算机语言 DSL帮助用户与计算机交互,同时辅助人与人的交流。
  • language nature: A DSL is a programming language, and as such should have a sense of fluency where the expressiveness comes not just from individual expressions but also the way they can by composed together.
    语言属性 DSL是一个程序语言,拥有流畅的表述形式,且能够组合完成逻辑。
  • limited expressiveness: a general purpose programming language provides lots of capabilities, supporting varied data, control, and abstraction structures. All of this is useful but makes it harder to learn and use. A DSL supports a bare minimum of features needed to support its domain. You can’t build an entire software system in a DSL, rather you use a DSL for one particular aspect of a system.
    有限的表述 与通用语言相比,DSL应当只对针对的领域做有限的支持,因此,不应当用DSL实现一个完整的应用。
  • domain focus: a limited language is only useful if it has a clear focus on a limited domain. The domain focus is what makes a limited language worthwhile.
    领域关注 当明确针对一个特定领域时,有限语言显得非常有用。

DSLs的边界

DSLs的边界很难明确定义,有些语言和工具,在针对特殊问题是表现了DSL的某种特性,但是他们并不能算做DSLs

If a uses a DSL for its purpose then it stays a DSL, but if someone uses a DSL in a general purpose manner, then it’s no longer a DSL (in this usage).

这种模糊并不关键,只要工具有用就行了,使用DSL的观点设计和使用软件,是否能够给软件工程带来总体上的优越性是我们主要关注的课题。

DSL片段与独立程序

DSL可以是一个独立的程序,构建于整体模型之上;也可以是一段执行片段,比如正则表达式,嵌入程序中的SQL等等。

使用DSL的理由

加快开发效率(Improving Development Productivity)

DSL产生了更加简洁,有效的代码,更好的遵守DRY原则,同时有限的语言也避免了很多程序错误的产生。

促进与领域专家的沟通 (Communication with Domain Experts)

这里不是说一个COBOL式的幻想,我们不主张让领域专家来用DSL编写业务规则,程序就能够运行。不过DSL简洁生动的语法,的确更容易被领域专家阅读和接受,从而缩小业务模型与程序模型之间的差距。

在执行上下文中改变 Change in Execution Context

在执行上下文中改变。从而极大的提高了系统的配置化程度,提升其应用功能价值。

可替换的计算模型 Alternative Computational Model

基于领域模型之上,可以更加灵活的设计计算模型,从而完成业务沉淀。

DSLs存在的问题

  • 学习曲线
    任何一项技术都是有难度的
  • 构建花费
    构建DSL要求更加精确,但其花费并不是在DSL,而在构建模型本身。
  • 设计难度
    DSL很难设计,因为它就像类库一样,因此,这种难度也不是DSL带来的,应当是问题域本身的难度。
  • 新的DSL的学习难度
    DSL构建出来的语言也是需要学习的,不过这取决于DSL本身的设计。
  • DSL版本迁移
    API已经有很多重构的工具和方法可以使用,DSL还缺乏这些东西,当然内置式的DSL完全可以用载体语言来实现。

DSLs生命周期

很多不同的方式:

Model –> API –> DSL

DSL –> senarios –> functions

Frameworks –> controllers –> DSL

笔记:DSL之一 简介

打算从今天开始,系统的学习一下DSL相关技术。

这个系列的所有文档都来自于MF的BLIKI中的Domain Specific Languages,其余文字都是对其的理解和整理。

关于什么是DSL,之前的文章有提到过。

简单的说

DSL与通用语言相区别,是为特定目的而生的语言,它并不是什么新东西,历史几乎和计算机的历史一样长。

DSL的应用广泛而常见,比如CSS,比如Wiki。DSL通过分析特定问题域提炼动态模型,从而标准化问题处理流程。

恩,先从MM图看起:

image

重点概念

DSL的类型

DSL可以分为内部DSL(Internal DSLs)和外部DSL(Internal DSLs),主要区别在于其与实现语言的关系。

内部DSL的语法是其实现语言的子集,典型的如Ruby;外部DSL通常是定制的特殊语法,如HQL。

Language Workbenches 也是DSL实现的方式之一,特定的平台有其特殊性。

API风格的区别

传统意义的程序语言,在实现具体逻辑的时候,往往是一种命令查询风格API ;而DSL通常是口语化接口

程序比较,都用Java实现

命令查询风格

    Event doorClosed = new Event("doorClosed", "D1CL");
    Event drawOpened = new Event("drawOpened", "D2OP");
    Event lightOn = new Event("lightOn", "L1ON");
    Event doorOpened = new Event("doorOpened", "D1OP");
    Event panelClosed = new Event("panelClosed", "PNCL");

    Command unlockPanelCmd = new Command("unlockPanel", "PNUL");
    Command lockPanelCmd = new Command("lockPanel", "PNLK");
    Command lockDoorCmd = new Command("lockDoor", "D1LK");
    Command unlockDoorCmd = new Command("unlockDoor", "D1UL");

    State idle = new State("idle");
    State activeState = new State("active");
    State waitingForLightState = new State("waitingForLight");
    State waitingForDrawState = new State("waitingForDraw");
    State unlockedPanelState = new State("unlockedPanel");

    StateMachine machine = new StateMachine(idle);

    idle.addTransition(doorClosed, activeState);
    idle.addAction(unlockDoorCmd);
    idle.addAction(lockPanelCmd);

    activeState.addTransition(drawOpened, waitingForLightState);
    activeState.addTransition(lightOn, waitingForDrawState);

    waitingForLightState.addTransition(lightOn, unlockedPanelState);

    waitingForDrawState.addTransition(drawOpened, unlockedPanelState);

    unlockedPanelState.addAction(unlockPanelCmd);
    unlockedPanelState.addAction(lockDoorCmd);
    unlockedPanelState.addTransition(panelClosed, idle);

    machine.addResetEvents(doorOpened);

口语化风格

   doorClosed. code("D1CL");
    drawOpened. code("D2OP");
    lightOn.    code("L1ON");
    panelClosed.code("PNCL");

    doorOpened. code("D1OP");

    unlockPanel.code("PNUL");
    lockPanel.  code("PNLK");
    lockDoor.   code("D1LK");
    unlockDoor. code("D1UL");

    idle
        .actions(unlockDoor, lockPanel)
        .transition(doorClosed).to(active)
        ;

    active
        .transition(drawOpened).to(waitingForLight)
        .transition(lightOn).   to(waitingForDraw)
        ;

    waitingForLight
        .transition(lightOn).to(unlockedPanel)
        ;

    waitingForDraw
        .transition(drawOpened).to(unlockedPanel)
        ;

    unlockedPanel
        .actions(unlockPanel, lockDoor)
        .transition(panelClosed).to(idle)
        ;

DSLs实现模型

实现DSL,主要是针对特定问题域进行动态状态建模,模型可以是任意的:对象模型,结构化模型或者其他的任何实现模型;程序语言通常会很关注语法以及语义,DSLs中的建模主要就是为了建立问题域的描述语义。

DSLs实现方法

代码生成(Code-Generation)和解释运行(Interpretation)是DSL的两种实现方式,前者在编译时处理模型,后者在运行时应用模型。

从实现的角度来讲,前者更加快捷方便,而后者更加精致有效;短期看代码生成可以很快应用,长期看解释运行更能形成效益。