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 consid­ered including a summary of these choices, but it felt out of place, detracting from the main point of how I worked through a devel­op­ment prob­lem. While I don’t think my reasons for choosing these libraries are novel, I think they’re worth noting, so from the perspec­tive of someone rela­tively new to web appli­ca­tion devel­op­ment in Clojure, I’m noting them here.

First off, I like Clojure. Immutabil­ity, dynamic but strong data typing, simple syntax, Java interop providing access to the wide array of battle-tested Java libraries, strong concur­rency prim­i­tives—all great stuff. Clojure­Script brings a lot of this good­ness to JavaScript runtimes, along with taking advan­tage of the Google Closure compiler which includes dead code elim­i­na­tion as well as your everyday mini­fi­ca­tion. So I’m predis­posed to looking for client and server libraries for Clojure.

Why Om?

React is a remark­able web UI library. Among its other features, it intro­duces a virtual DOM updated by the appli­ca­tion. A sepa­rate rendering module prop­a­gates these changes to the DOM only when the browser wants to redis­play the page. I find this decou­pling of logic from display compelling. Appli­ca­tion speed is no longer a func­tion of how fast the page can be redrawn.

The primary draw­back is that it’s JavaScript. Don’t get me wrong, the language has a lot going for it. Up until ES6, the syntax was quite limited and simple. Func­tion scope can take some getting used to. And while proto­type inher­i­tance can be a unusual for those coming from more common object inher­i­tance models, you can choose to avoid inher­i­tance. Having func­tions as first class objects makes func­tional program­ming straightforward.

That said, I find struc­turing Javascript appli­ca­tions more diffi­cult than I’d like. Call­back hell can make reading code diffi­cult and following appli­ca­tion logic painful. ES6 has features which address some of this but at the cost of intro­ducing new syntax which in turn adds its own cogni­tive load.

Om is a Clojure­Script inter­face to React. David Nolen has spent a great deal of time thinking about the prob­lems React, GraphQL,, and Falcor are trying to solve, and applied a healthy dose of Clojure. David discusses his moti­va­tions for Om Next, the second inter­a­tion of Om, on Episode 093 of the Cogni­cast podcast.

Why Pedestal?

I see three fron­t-run­ning web server options in Clojure: Ring, HTTP Kit, and Pedestal.

Ring is an inter­face for writing web server appli­ca­tions as servlets. It follows on the tradi­tion of WSGI in Python and Rack in Ruby. An incoming request is treated as an argu­ment to a handler func­tion, and the response is the func­tion’s return value. Middle­ware features (such as authen­ti­ca­tion on the way in or compres­sion on the way out) are func­tions wrapped around this base handler func­tion. There are a large number of Ring middle­ware libraries which address a lot common needs. Ring is also single-threaded and block­ing. A long-run­ning request will block the web server instance.

HTTP Kit addresses the blocking issue by using an even­t-­driven model to support asyn­chro­nous concur­rency. It’s also Ring compliant so it can take advan­tage of Ring middle­ware libraries. Node.js and Nginx are both exam­ples of how perfor­mant asyn­cho­nous even­t-­driven concur­rency can be. HTTP Kit has been shown to support up to 600K concur­rent connections.

However, neither Ring nor HTTP Kit take advan­tage of one of the bene­fits of Clojure on the Java virtual machine. The JVM has a very solid thread imple­men­ta­tion, making it easy to handle multiple requests, and Clojure’s concur­rency models make it simple to avoid the pitfalls of thread synchro­niza­tion. With multi­-­core machines the norm, why not use them?

Pedestal also has a different approach to request handling. Rather than wrap func­tions around func­tions, interceptors are inserted in an execu­tion queue, each inter­ceptor inter­cepting 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 execu­tion queue where it’s again processed by the inter­ceptor chain. At each stage along the queue this context is just data, which can be poten­tially moved from one thread to another. The request is decou­pled from the thread of execu­tion.

And while Pedestal isn’t Ring compli­ant, the devel­opers recog­nize that the value in the existing Ring middle­ware ecosystem and have made it possible to use Ring middle­ware as inter­cep­tors in the inter­ceptor chain. Also, Pedestal request maps are similar to Ring: The ring.util.response namespace is even required in the Leiningen Pedestal service template. Pedestal provides the library bene­fits of Ring and the concur­rency bene­fits of Clojure on the JVM. I find that quite compelling.

Summary

So there you have it. It’s still very early in my expe­ri­ence with Pedestal and Om. I want to stay aware of the invest­ment 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.