Clojure and what could've been

Epistemic status: Anecdotes and opinions.

I’ve used Clojure for over a decade now: I first learned it in 2012 and started using it professionally in 2013. I’ve been reflecting on what has happened and what the future looks like. In this post, I want to share a few musings about it.

Missed opportunity: production REPLs

REPL is so central to Clojure that people even talk about REPL-driven development. It’s not just about having a prompt for typing commands like in Python1. Instead, it’s a way of connecting your editor to a running Clojure system.

Usually this is done only during the development. You could connect to the REPL of production system to debug or maintain it, if you dare. There are stories about adventurous Clojure developers doing to hotfix a running system.2 Usually these stories end with a word of caution: the devs will tell you about a time when they forgot to commit the fix to the version control system and the changes were lost the next time the system was restarted.

You used to be able to do it, anyway. Nowadays when the standard model of deploying software is ephemeral containers in a Kubernetes cluster, the production REPL is less meaningful. If you need to apply the same hotfix to eight different containers and Kubernetes can re-schedule them at any moment, there isn’t much point to this. Your services are now cattle, not pets.

At Metosin, we had this belief that a small but skilled team using sharp tools can deliver better software faster than an ordinary team relying on standard tools. The recent blog post by Tailscale about their database choices seems like an example of this: SQLite is an unusual choice for their setup, but they know what they’re doing and it’s working great.

I wonder if we’ve missed a similar opportunity here. Ephemeral containers have their benefits, especially for scaling, but do they always outweight the productivity benefits of using production REPLs for debugging?3

FaaS did not kill Clojure

A few years ago, Function-as-a-Service (FaaS) platforms such as AWS Lambda were surging in popularity. I thought it could be the end of Clojure for web services. Replacing all the glue code of web services with an API gateway and some lambdas seemed like a big win: all your code is about the business logic; the infrastructure has been abstracted away. I didn’t see what Clojure could offer here: it’s startup time was slow and REPL-driven development didn’t fit the FaaS platforms.

I was wrong. People still develop long-running server software just as they did in 2015. AWS Lambda became a popular tool scripting AWS services and for connecting them to each other, but it didn’t replace traditional web backends. As far as I understand, the startup time problems have been mitigated, too, and Clojure lambdas are a feasible choice nowadays.

Thinking back, I expected AWS Lambda developer experience to be rapidly improved. This didn’t happen and it still clunky if you have a lot of lambdas. Frameworks such as Serverless tried to smooth it out, but they never hit the big time. Is this another missed opportunity?

JavaScript is taking over ClojureScript

There’s a lot to like about developing browser applications with ClojureScript. Tools such as shadow-cljs and Google Closure Compiler are great – I’ll take them any day over configuring webpack. There are a bunch of good libraries such as Reagent, and of course the language itself is nice.

Despite the rough spots such as JavaScript interop and awkward testing tools, for a long time ClojureScript was a clear winner over JavaScript for me. Today, I’m not so sure about it. JavaScript language, tooling, and ecosystem have improved immensely over the last decade.4

In some ways, the JavaScript experience is superior now. One essential feature is async/await syntax for asynchronous programming. It’s much smoother than using core.async or promises and looks like we’re not going to have it in ClojureScript.

Another one is TypeScript. JavaScript ecosystem is strongly embracing TypeScript and it’s enabling powerful static analysis. I’m not seeing an easy way for ClojureScript to benefit from that.

JavaScript has improved so much that it’s harder for me to look over ClojureScript’s rough spots now. I certainly feel that JavaScript is overtaking ClojureScript. Time will tell if I’m wrong once again.

  1. Python REPL leaves a lot to be desired if you’re used to Clojure REPLs, but to give it credit, Python has popularized another innovative way of interacting with a live system: notebooks↩︎

  2. As a teenager, I fixed my websites by editing the PHP files directely on the server over SFTP. Now that was continuous delivery. ↩︎

  3. Another thing I wonder about is what Erlang and Elixir are doing here. Their support for distributed systems is on the next level. If you have seen a good article on how Erlang and Elixir people deploy and interact with their production systems, please send it my way! ↩︎

  4. Admitedly you may still need to use webpack, and it’s still difficult to configure. ↩︎

Comments or questions? Tweet to me or send me an e-mail.