This is a card in Dave's Virtual Box of Cards.

DSL (Domain-Specific Language(s))

Page created: 2024-10-17

Let me get this out of the way: GUIs (Graphical User Interfaces) are great. A good one can be an amazing time-saver over the equivalent text-based interface.

But the reverse can also be true: there are some things that are incredibly simple at the Unix command line that are incredibly difficult to express with a GUI.

If you’ve ever been forced to use a GUI to perform a repetitious task over a large number of items, you know how insane it can be - you know exactly what you want to accomplish, but the GUI requires that you click-click-click like an animal in a cruel science experiment. (With a Web application, this is often even more painful because of the round-trip delay to wait for the server to respond over the network.)

By comparison, a DSL requires a (usually very small) bit of learning up front, but will typically outpace the GUI in productivity almost immediately.

A recent example of a DSL I created is my Sequence Timer. I think a lot of people would have pictured this application with some number fields and a ton of buttons to add/remove/edit the times and sequences, right?

Anyone who thinks it would have been easier to create a GUI for the Sequence Timer has obviously never made a UI. UIs are hard! Even the tiny bit of GUI in the Sequence Timer was much harder than designing and implementing the DSL!

If I’d made it with a pure GUI, I’d probably still be working on it.

Pros and Cons

A DSL has, at a minimum, these advantages:

  • Can express more than a simple GUI

  • Almost always faster to use than the GUI (once over the learning curve)

  • Can use outside tooling (text editor, script to generate DSL code)

  • Can be transfered as text (email a setup to yourself or others)

  • Comments!!!!!!!!!!!!!! (see whole section below)

And these disadvantages:

  • Learning curve

  • The temptation to make the DSL expressive and "powerful" (language design is hard)

And these points, which are both advantages and disadvantages (the figurative double-edged sword):

  • Favors expert users

  • Can be used in clever ways the designer never imagined

As simple as possible

A DSL generally is not and probably should not be complex. Otherwise, you’re probably losing the advantage of a DSL - which is to make it as easy as possible to perform this one specific task.

If it turns out you need a whole general-purpose programming language, just embed a proper general-purpose language like Tcl or Lua. (Or take the time to design something equally elegant.)

A DSL can be stupidly simple. Again, I’ll reference my incredibly simple sequence "language" for the Sequence Timer. I created the timer to help me count repetitions of exercises in a physical therapy program.

Most of the exercises are divided into the traditional "sets" and "reps" with rests between sets. Often, there are "holds" of a certain time for each rep. That’s a total of three layers of counting.

In pseudo-language, you might think of this as a nested loop:

set(x) {
    rep(y) {
        hold(z)
    }
}

Or to flatten it out, you might express "2 sets of 5 reps, hold for 3 seconds" as:

2x{ 5x{ 3s }}

That’s pretty cool because you can imagine allowing arbitrary nesting so that even the sets may be repeated some number of times.

But the fact is, I simply don’t have this need. So I removed all but one "layer" for reps.

One rep looks like this:

5x 3s

And two sets of these looks like this:

5x 3s
5x 3s

That’s right, I copy-and-paste for my third layer of repetition. Wild for a programmer to admit, huh?

(And, actually, that turns out to be useful because I ended up wanting to give myself separate instructions for some of the sets, which would have been a whole other level of complexity to manage with a nested structure.)

This was a choice, a balance between complexity/simplicity versus expressiveness/power. And I’m perfectly happy with my choice for this tool.

Because another thing about this timer is that I have to visualize the times when it’s actually running, and making a visual representation of arbitrarily nested repeating items was absolutely not in my time budget for this tool. (One layer was plenty.)

Because it is text, the DSL makes it incredibly easy to add the repetition by either copy-paste or, if I needed, a script.

Further, I can write and test the exercise plan on my desktop computer and then transfer them to my phone where I’ll actually be playing it while I do the exercises. Because it’s text, I can just email it to myself. If this had been a GUI, I would have needed to serialize the data structure and create an import/export feature, etc.

So is HTML <textarea> the most powerful UI for the Web? Maybe. :-)

Comments!!!!!!!!!!!!!!

Another thing that I think is very often overlooked in GUIs is that they very rarely allow for "out-of-band" explanations of why certain choices have been made.

A DSL that allows for comments gives the author of a script the ability to explain the choices made. This is a HUGE advantage.

(This is another reason vanilla JSON is a terrible, awful, bad choice as a configuration language - no comments! And I don’t care that you already have a library for JSON; in my experience, a parser for a line-based foo: bar configuration format with comments is incredibly easy to make and infinitely nicer to use.)

Screenshots vs code blocks

This overlaps somewhat with the transferability I mentioned above (being able to copy a set of DSL instructions from one machine to another).

Explaining how to change a setting in Microsoft Windows is often a mixture of screenshots and paragraphs of text trying to explain what to do in the interface shown in the screenshot. If you’re lucky, someone will have drawn arrows or circled things in the screenshot. (Or maybe you have to watch a video and keep pausing it to perform each step.)

Explaining how to change a setting in Linux is often a bit of text showing the command line to type followed by a paragraph explaining what the command does.

I know a lot of people are scared of command line interfaces, but you have to admit, one of these two knowledge transfer (documentation) methods is way easier to create and maintain.

So it is with a DSL. Supplying an example script with good comments (see above) can be a completely self-contained, self-explained, and infinitely transferable object.

Also, I find that GUIs tend to change way more often than DSLs. So not only is it harder to maintain documentation, it’s also more likely to be needed.

Back to pl-design and programming in general.