I asked a good friend of mine to review my post on route naming in Pedestal. He’s not familiar with Clojure and said that he wanted to hear about how I chose Om and Pedestal. I had considered including a summary of these choices, but it felt out of place, detracting from the main point of how I worked through a development problem. While I don’t think my reasons for choosing these libraries are novel, I think they’re worth noting, so from the perspective of someone relatively new to web application development in Clojure, I’m noting them here.
React is a remarkable web UI library. Among its other features, it introduces a virtual DOM updated by the application. A separate rendering module propagates these changes to the DOM only when the browser wants to redisplay the page. I find this decoupling of logic from display compelling. Application speed is no longer a function of how fast the page can be redrawn.
Om is a ClojureScript interface to React. David Nolen has spent a great deal of time thinking about the problems React, GraphQL,, and Falcor are trying to solve, and applied a healthy dose of Clojure. David discusses his motivations for Om Next, the second interation of Om, on Episode 093 of the Cognicast podcast.
Ring is an interface for writing web server applications as servlets. It follows on the tradition of WSGI in Python and Rack in Ruby. An incoming request is treated as an argument to a handler function, and the response is the function’s return value. Middleware features (such as authentication on the way in or compression on the way out) are functions wrapped around this base handler function. There are a large number of Ring middleware libraries which address a lot common needs. Ring is also single-threaded and blocking. A long-running request will block the web server instance.
HTTP Kit addresses the blocking issue by using an event-driven model to support asynchronous concurrency. It’s also Ring compliant so it can take advantage of Ring middleware libraries. Node.js and Nginx are both examples of how performant asynchonous event-driven concurrency can be. HTTP Kit has been shown to support up to 600K concurrent connections.
However, neither Ring nor HTTP Kit take advantage of one of the benefits of Clojure on the Java virtual machine. The JVM has a very solid thread implementation, making it easy to handle multiple requests, and Clojure’s concurrency models make it simple to avoid the pitfalls of thread synchronization. With multi-core machines the norm, why not use them?
Pedestal also has a different approach to request handling. Rather than wrap functions around functions, interceptors are inserted in an execution queue, each interceptor intercepting the inbound request and the request context on its way to the handler. The response returned by the handler is passed back up through the execution queue where it’s again processed by the interceptor chain. At each stage along the queue this context is just data, which can be potentially moved from one thread to another. The request is decoupled from the thread of execution.
And while Pedestal isn’t Ring compliant, the developers recognize that the value
in the existing Ring middleware ecosystem and have made it possible to use
Ring middleware as interceptors in the interceptor chain. Also,
Pedestal request maps are similar to Ring: The
is even required in the
Leiningen Pedestal service template. Pedestal
provides the library benefits of Ring and the concurrency benefits of Clojure
on the JVM. I find that quite compelling.
So there you have it. It’s still very early in my experience with Pedestal and Om. I want to stay aware of the investment I’m putting into learning these new tools and hope to avoid succumbing to the sunk cost fallacy. And who knows? A year or two from now I may look back and wonder What was I thinking? Well, this blog post will be here to answer that.