The Clojure web stack and the CRUD stack
Not infrequently, programmers new to Clojure ask on IRC for libraries or frameworks that implement the assumptions of Rails or Django. Clojure's ecosystem currently does not have a popular equivalent to these frameworks. I want to look at the current ecosystem, what Django provides1, and what the ramifications for Clojure's web stack are.
Clojure's web ecosystem is at this point centered on Ring and Compojure. Many people choose to work at the Noir level; Noir is a set of libraries that work with Compojure and friends, and a set of wrappers for defining pages. The most defining quality is that, following Clojure idioms, the ecosystem is a collection of small libraries that compose nicely. If you haven't looked at Clojure's web stack, you may find my introduction useful.
In contrast, Django (and Rails) provides a holistic, all inclusive framework. While Django sits on top of WSGI2, the majority of Django programmers and libraries never look that far down the stack. These frameworks prescribe a common solution for all the major components of a web app or site, such as models and ORM, routing, template rendering, authentication, etc. The ecosystem that grows up around these frameworks becomes coupled to the their assumptions. For example, libraries in the Django ecosystem package themselves as apps, and often provide models and views to be connected to the rest of the application.
The type of framework that Django and Rails provide is a kind of CRUD app stack. They are specifically focused on streamlining the development of a common class of site. Indeed the concept of convention over configuration is baking in the notion of default assumptions. The CRUD stack is a very powerful tool when you want to build a CRUD site. However, as anyone who has worked with a framework knows, the further your requirements take you from the assumptions, the more pain you encounter.
So why does Clojure not have a popular CRUD stack? I don't think this is a reflection on the quality of efforts that have occurred to produce one. Instead it is that the notion of a monolithic framework is antithetical to the ethos Clojure and Clojure programmers follow; we value small, composable components. Being able to select the best tool for the job and not have to work around some default assumptions is valuable.
It is worth keeping in mind that at this point Rails and Django are around eight years old and have huge ecosystems around them. They also do the CRUD stack well. Anything in Clojure would require a massive commitment of time and effort to play catch up, and in doing so would in all likelihood fall into the same sets of tradeoffs those stacks have made.
In Clojure's ecosystem you have to make these decisions yourself, and you will have to write a bit more code to glue components together. In exchange for doing a little more work you can produce a cleaner solution, and one that doesn't have to work around the assumptions inherent in a monolithic framework.
In my opinion, there is very little value in reproducing a CRUD stack in Clojure. If it is the solution you need, just use Django or Rails. You can always implement a Clojure service that sits behind your CRUD app and get the best of both worlds.
The value of a CRUD stack is getting CRUD done quickly. The value of a loosely coupled stack is being able to choose the best available tools for the problem domain and get it done right.
- Rails is similar, but I know Django better, so I am using it as my reference point.
- WSGI is Python's Web Server Gateway Interface. The Clojure equivalent is Ring. They both provide an abstraction over HTTP.