To pick the right application you have to test a lot of software. To test it you have to spend time learning it. When yet another application forced me to learn its entirely unique domain specific language (DSL) I realized I hated DSLs. But this is more than a personally antipathy, I realized that DSLs are bad design. In this post I will show why.
What is a DSL?
DSLs are special purpose programming languages designed to address the problems of a single domain. R is a DSL for the statistics domain. PDF is a DSL for document rendering. In contrast, Java and C are general purpose languages that can be used to solve problems in a variety of domains. In a DSL the syntax is designed to mimic the terminology of the problem domain and therefore, at least in theory, make it easier for people to write code for that domain.
In practice DSLs do not make it easier, they make it harder. This is not to say that DSLs are never a good idea. I think they do make sense in certain domains. What I am arguing against here is the common use of DSLs. DSLs should be the exception rather than a common practice.
The Problem of Suboptimization
DSLs are bad design because they are examples of a an error called suboptimization. Suboptimization comes from systems theory and it means that you cannot optimize a system by optimizing it sub-systems individually. In fact, if you optimize sub-systems by themselves you will likely harm the overall system. DSLs are a way of optimizing a sub-system without regard for the global system.
Automated configuration management (CM) is a domain. Ansible and Puppet, for example, provide DSLs for CM. But automated CM is only one part (a sub-system) of IT. IT is a much larger system that includes many, many sub-systems. It includes software systems, network systems, hardware, processes, people, interactions with other business units and so on. IT managers are looking to optimize IT globally and not just one sub-system.
And here is the problem with DSLs. They optimize for their domain at the expense of IT as whole.
Problems Caused by DSLs
The goal of IT service management can be summed as the desire to provide the highest quality service at the lowest cost. For the resources invested, IT managers want the greatest possible return. They aren’t unique in this, everyone wants this. We all want the greatest return for the least investment. This is why we automate in the first place.
Now, imagine you are a system administrator that has to maintain 50 different applications. What is the minimum you would need to learn to be able to properly configure and mange these applications? At one extreme, call this the ideal, each application uses the same configuration language with only minor variation to account for different domains. Once you learn this universal configuration language very little effort is needed to handle all 50 applications.
At the other extreme, each of the 50 applications has its own completely unique DSL. This is the nightmare scenario. Each DSL is highly optimized for its own domain but now you, the systems administrator, have to learn 50 different languages to be productive. The DSL may be better for one domain but it is not better for the system administrator who has to master 50 . The DSL developer is looking at the problem from a narrow perspective–their domain of interest–not from the perspective of the systems administrator.
This is equivalent to the distinction between a programming languages and a programming library. When using libraries, the syntax remains the same only the objects and functions change. With programming languages the the objects and functions change and so does the syntax. Learning a new library is significantly easier than learning a new language. Learning a DSL is like learning a new language. It’s a lot of work.
DSLs are not Easier
Paradoxically, the automated CM DSLs are supposed to be easier for the systems administrator than general purpose languages. First, this idea is condescending to system administrators. System administrators are perfectly capable of learning Ruby or Python or Node.js. Second it isn’t even true. The CM DSLs are complex and take a lot of time to master. They are only easy to use for the simple cases. Want to install a RPM? That’s easy. How about if you want the system to automatically reboot if the RPM you just installed was a kernel update? Now you will find that that simple DSL isn’t so easy anymore.
The larger issue though is return on investment. What do you gain from the time spent? For DSLs you gain understanding of one domain, for general purpose languages you gain the ability to solve problems in any domain. If, instead of a one-off unique DSL, these CM tools were built as Ruby libraries, then the administrator has only one language to learn, Ruby. And then, not only can they use that for CM, they can use that skill to write test scripts (RSpec), and web pages (Ruby on rails), and inventory management scripts, and monitoring scripts, and security test and so on.
There is the initial cost of learning the language. Once paid, the incremental cost is the comparatively small cost of learning a new library. The initial cost of learning a DSL does not provide any incremental benefit. It’s single purpose. There is always an up front cost. The only question is what long term benefits you gain from that initial cost.
The Management Perspective
That initial cost is also an issue for managers. The time it takes an administrator to become proficient in an application is a cost. It’s an investment towards a future benefit. Paying the costs of training an administrator as a Ruby developer is a good investment if that skill is reusable across many domains. Paying to train the administrator on an ephemeral DSL-du-jour is not a good investment. There is little chance it will be around in a few years.
And, of course, people change jobs. How difficult will it be to hire a new administrator that knows the DSL used by one of your applications? If its a popular general purpose language like Python or Ruby then it won’t be hard at all. If it’s the Salt DSL it may be a challenge.
DSLs have other problems. They are usually “stove-pipes”: good at one thing but poor at integrating with others. To use the CM example again, CM is not an isolated activity. It should be possible to write CM code alongside other code. For example, to link CM code with a database or with unit tests or with any of the things that general purpose programming libraries make possible. CM code is just code. It’s not special. If the CM code were libraries this integration would be easy. As a DSL it is either impossible or it requires a special API (yet one more thing for the administrator to learn).
I don’t think the DSL authors have considered the long term evolution of their DSLs either. If the DSL survives in the long term then it will be under constant pressure to expand its capabilities. Users will request feature after feature until at some point the DSL will be nearly indistinguishable in from a general purpose language. This happened to R and it will happen to any of the the CM DSLs that survive. IT infrastructure and administration is complex. To cope with complexity requires a language with a lot of features.
Conclusion: A Better Way
I think the alternative to DSLs is to follow the standard and proven practice of using libraries. There is already a general purpose DSL, it’s called object oriented programming (OOP) . I have written about this before. The DO library is example of what I think is a better approach: CM as a library of custom objects rather than a DSL. It’s not a full blown CM like Chef nor does it even appear to be still alive but its API is great:
There is a similar library for node.js called node-control.
A standard OOP approach is also good because it exposes the conceptual object model of the application. Your domain objects map to your API. For example, CM objects might be “environment’, “role”, “server”, etc. And then you can code easy to understand and explicit commands like
server.addRole( webserverRole) or
server.setIPAddress( "22.214.171.124"). These basic objects are often obscured by DSLs due to syntactic cleverness and implicit assumptions (which are also examples of poor design).
Whether OOP is used or not the key is to leverage the administrator’s existing programming knowledge by using libraries instead of DSLs. This is better for the administrator and better for IT management.