ENTERPRISE

The drive toward DSLs : Taking a DSL apart—what makes it tick?

6/8/2012 11:33:59 AM
We’ve looked at building DSLs from the point of view of the outward syntax—how we use them. What we haven’t done is cover how they’re structured internally—how we build and integrate them into our applications.

In general, a DSL is composed of the building blocks shown in figure 1.

Figure 1. A typical DSL structure


A typical DSL is usually split into several distinct parts:

  • Syntax— This is the core language or the syntax extensions that you create.

  • API— This is the API used in the DSL; it is usually built specifically to support the DSL and its needs.

  • Model— This is the existing code base we reuse in our DSL (usually using a facade). The difference between the API and the model is that the model usually represents the notions in our application (such as Customer, Discount, and so on), whereas the API focuses on providing the DSL with convenient ways to access and manipulate the model.

  • Engine— This is the runtime engine that executes the DSL and processes its results.

The language and the API can be intrinsically tied together, but there is a fine line separating the two. The API exposes the operations that DSL users will use in the application. Usually you’ll expose the domain operations to the DSL. You express those operations through the language, but the API is focused on enabling a good syntax for the operations, not on providing the operations themselves.

We need to understand what features of the language we can use and what modifications we’re able to make to the language to better express our intent. Often, this is directly related to the API that we expose to the DSL. As I mentioned earlier, if you’re working in a domain-driven design manner, you’re in a good position to reuse the same domain objects in your DSL Often, though, the API will be composed of facades over the application, to provide the DSL with coarse-grained access into the application (fine-grained control is often too fine grained and is rarely useful in a DSL).

Keeping the layers separated

Several times in the past I have tried to combine different parts of the DSL—typically the syntax and the API—usually to my regret. It’s important to keep each layer to itself, because that brings several advantages.

It means you can work on each layer independently. Enhancing your API doesn’t break the syntax, and adding a method call doesn’t require dealing with the internals of the compiler.

You can use the DSL infrastructure from other languages, as well. Why would you want to do that? Because this will avoid tying your investment in the DSL into a single implementation of the syntax, and that’s important. You may want to have several dialects of a single DSL working against a single infrastructure, or you may decide that you have hit the limits of the host language and you need to build an external DSL (or one using a different host language). You’ll still want to use the same infrastructure across all of them. Having an infrastructure that is not tied to a specific language implementation also means that you can use this infrastructure without any DSL, directly from your application.

A typical example of using the DSL infrastructure without a DSL language would be an infrastructure that can also be used via a fluent interface to the application and via a DSL for external extensibility.


The execution engine is responsible for the entire process of selecting a DSL script and executing it, from setting up the compiler to executing the compiled code, from setting up the execution environment to executing the secondary stages in the engine after the DSL has finished running (assuming you have a declarative DSL).

Extending the Boo language itself is probably the most powerful way to add additional functionality to a DSL, but it’s also the most difficult. You need to understand how the compiler works, to some extent. Boo was built to allow that, but it’s usually easier to extend a DSL by adding to the API than by extending the Boo language. When you need to extend Boo to enrich your DSL, those extensions will also reside in the engine and will be managed by it.

The API is part of the DSL. Repeat that a few times in your head. The API is part of the DSL because it composes a significant part of the language that you use to communicate intent.

Having a clear API, one that reflects the domain you’re working in, will make building a DSL much easier. In fact, the process of writing a DSL is similar to the process of fleshing out a domain model or ubiquitous language in domain-driven design. Like the domain itself, the DSL should evolve with your understanding of the domain and the requirements of the application.

DSLs and domain-driven design are often seen together, for that matter.

Use iterative design for your DSLs

When sitting down to design a DSL, I take one of two approaches. Either I let it grow organically, as new needs arise, or I try to think about the core scenarios that I need to handle, and decide what I want the language to look like.

There are advantages to both approaches. The first approach is the one I generally use when I am building a language for myself, because I already have a fairly good idea what kind of a language I want.

I use the second approach if I’m building a DSL for general consumption, particularly to be used by non-developers. This isn’t to say you need to spend weeks and months designing a DSL. I still very much favor the iterative approach, but you should seek additional input before you start committing to a language’s syntax. Hopefully, this input will come from the expected audience of the DSL, which can help guide you toward a language that’s well suited for their needs. Then, once you start, assume that you’ll not be able to deliver the best result in the first few tries.

If you build a DSL when you’re just starting to understand the domain, and you neglect to maintain it as your understanding of the domain and its needs grows, it will sulk and refuse to cooperate. It will no longer allow you to easily express your intent, but rather will force you to awkwardly specify your intentions.

Other  
  •  The drive toward DSLs : Choosing between imperative and declarative DSLs
  •  Visual Studio Team System 2008 : Creating new report (part 2)
  •  Visual Studio Team System 2008 : Creating new report (part 1) - Report server project
  •  Visual Studio Team System 2008 : TFS reports for testing - Bugs
  •  Extra Network Hardware Round-Up (Part 3)
  •  Extra Network Hardware Round-Up (Part 2) - NAS Drives, Media Center Extenders & Games Consoles
  •  Extra Network Hardware Round-Up (Part 1)
  •  Networking Jargon Explained (Part 2)
  •  Networking Jargon Explained (Part 1)
  •  The Micro Revolution
  •  Computing Yourself Fit (Part 4)
  •  Computing Yourself Fit (Part 3)
  •  Computing Yourself Fit (Part 2)
  •  Computing Yourself Fit (Part 1)
  •  Touch Interaction - Multi-Touch: An Evolution
  •  Think the Brighter Side to Piracy
  •  These Companies Would Still Be Here In 5 Years
  •  Build Up Your Dream House with PC (Part 4)
  •  Build Up Your Dream House with PC (Part 3)
  •  Build Up Your Dream House with PC (Part 2)
  •  
    Most View
    Macbook Pro: The Inner Beauty (Part 1)
    Silicon Nanophotonics
    Tiptoeing Into Social Media (Part 2)
    New Products For March 2013 (Part 1)
    Global Invacom ODU32 Kit - Test Integrated Reception Systems
    Build A $600 PC
    The Best PC Deals Around – May 2013 (Part 2)
    ASUS PadFone – Layers Of Excellence
    Samsung Series 3 NP355V5C - Affordable Gaming-Friendly Laptop
    Group Test: HTC One X vs. Sony Xperia U vs. Samsung Galaxy S III vs. Huawei Ascend P1 (Part 1)
    Top 10
    G.Skill DDR3 SDRAM 32GB Review (Part 6)
    G.Skill DDR3 SDRAM 32GB Review (Part 5)
    G.Skill DDR3 SDRAM 32GB Review (Part 4)
    G.Skill DDR3 SDRAM 32GB Review (Part 3)
    G.Skill DDR3 SDRAM 32GB Review (Part 2)
    G.Skill DDR3 SDRAM 32GB Review (Part 1)
    Macbook Pro With 13in Retina Display Review (Part 3)
    Macbook Pro With 13in Retina Display Review (Part 2)
    Macbook Pro With 13in Retina Display Review (Part 1)
    Kensington Folio Trio For iPad