One of my coworkers was trying to understand the differences between libraries, frameworks, and DSLs and asked me
…how do I know what i’m using when all these things are
interacting and being used within each other, etc
To some degree, you don’t, and it doesn’t matter, but that’s not a very helpful answer. So let me step back and talk about what each of these are.
Libraries are the simplest. A library is just a collection of code intended to be reused. They’re typically packaged using a package manager, but it doesn’t need to be “packaged”. It could be just some file of useful code that you load into your code like any other source file.
A library is the hardest to “know” you’re using because it generally provides some new classes or methods. Unless you happen to know where those clasess and methods came from you don’t know you’re using it. In languages like Ruby where you can alter code at runtime a library could change the behavior of existing code; no new methods, no new code, things just behave differently.
DSLs are Domain Specific Languages. The greatest example, in my opinion is SQL. For example
select name from students where age > 7
Without any SQL knowledge you can probably guess that there’s a list of students somewhere, and running that line will return the names of each one who is older than 7.
SQL is very powerful, but it’s very focused on querying and manipulating tables of data. It makes that very easy, but it’s really crappy at everything else. That’s pretty typical of a DSL.
In the Ruby world we have a lot of DSLs but people tend to not recognize them as such. For example, an RSpec test might have something like this
describe "Math" do context "double" do it "should return twice the input" do expect(Math.double(2)).to eq 4 end end end
Like SQL it’s pretty easy to guess what it does.
You might be thinking “But rspec’s just Ruby code. That’s just Ruby methods.” This is true. RSpec is a DSL written in Ruby. It’s not limited to Ruby though. I could port RSpec to most languages and maintain the same syntax.
You can think of a DSL as a collection of commands that simplify instructing the computer to do something in a focused domain.
How do you know when you’re code from a DSL instead of your core language? If you are dealing with a non-trivial set of commands, that aren’t part of the core language, and are all focused on helping with one specific aim, you’re probably using a DSL.
RSpec, is a DSL, that’s packaged up as a library, that can be added to your project. Loading the library teaches the Ruby compiler how to understand the RSpec DSL.
Neha Choudhary described it like this:
If I told you to cut a piece of paper with dimensions 5m by 5m, then surely you would do that. But suppose I ask you to cut 1000 pieces of paper of the same dimensions. In this case, you won’t do the measuring 1000 times; obviously, you would make a frame of 5m by 5m, and then with the help of it you would be able to cut 1000 pieces of paper in less time.
That sounds a lot like a DSL, and from some perspectives there is overlap. But a framework doesn’t make it easier to do only one thing. It provides a large infrastructure to facilitate the connection of things in many domains.
I like to think of them like skeletons. Skeletons are collections of bones. Some bones are for protection. Some facilitate locomotion. Some facilitate eating. Collected together they are a framework with areas specialized for holding digestive bits, and areas specialized helping us move around, and so on. Creatures can exist without them, but once you have a skeleton lots of things become easier to accomplish. Code can exist without frameworks, but frameworks make it easier to create code that does big complex things.
Let’s look at Rails (a web development framework) as an example.
Rails (like most web frameworks) provides infrastructure to:
- facilitate object relational mapping to store the data you’ve collected about some object in your system in a database, and then take the data in a database and convert it back to objects in your system.
- facilitate the handling of HTTP requests from a web server and make it easy to query all their relevant pieces (form data, headers, query string data, cookies, etc.)
- facilitate the handling of those http request objects it created for you
- template management (in various templating DSLs, haml, erb, etc)
- facilitating the connection of templates to the things handling the requests
- testing (of models, of controllers, of views)
- and many, many more things.
You could say that almost all of those involve some DSLs. Making a class a descendent of
ActiveRecord::Base connects it to a database table, gives it a getter and setter method that corresponds to every column of that database table, functions to update, validate, save, delete, etc. There are even methods for describing the relationship between other classes tied into tables like
All those methods are part of a DSL for manipulating the data in database tables. Just like SQL. But, that DSL doesn’t know anything about manipulating HTTP requests, even though Rails does.
Rails is a Framework, made of a collection of DSLs, packaged in a Library.
So, how do you know when you’re using a Library, a DSL, or a Framework?
The only way you’re not using a library is if you’re writing something that only uses code from the smallest beating core of your language.
Most languages come with a “Standard Library” which is a collection of classes to save people from writing a lot of obnoxious low level code. For example: most languages have a
Date class (or something like one). That’s part of the Standard Library. Compilers have no need of a
Date class. They can do their job just fine without one. That’s a convenience library for the humans.
Are you using a DSL? If using methods defined as part of a Framework then there’s a good chance you are. Frameworks are frequently collections of things that could be classified as DSLs. If you’re using a set of commands that would be useless for anything other than one focused domain, then you’re probably using a DSL.
Are you using a framework? That’s the easiest. Did you load a framework? Are you calling methods defined in that framework? Then yes, you’re using a framework.
If you are using methods defined in a framework, that are also a DSL, then you’re using all three, because frameworks are collections of code intended to be reused.
Ultimately, it doesn’t matter what you’re using, but there is value in knowing where the commands you’re calling come from. When you start another project, you will know what libraries to pull in to give you those commands again without having to create them from scratch.