What I learned after writing Clojure for 424 days, straight
Ok, not every day, but most working days
I’ve been working on Clojure projects at Juxt for more than a year now, but have never written about my experiences because:
- Before writing an article, I research the problems the community face on Reddit, HackerNews, GitHub issues, and Google trends.
- Clojure/Script never seemed to be problematic or in demand
- Not many people use Clojure/Script as their first language
- Those who do, do not need any guidance
- As a blogger, there was no incentive for me to write about it
Clojure has fundamentally changed my thought process. It affected how I write JS and how I code in general. So even though there are no evident marketing/ branding benefits in writing about Clojure, I’m still gonna do it.
What is Clojure & ClojureScript?
Let’s start with why Clojure sucks
When considering a new addition to the stack, it’s important to consider long term consequences. Clojure is a great language but it comes with its issues. Most of them have a way around.
It’s hard to find engineers
Not many people code Clojure and this comes up as a regular concern when I talk to someone about it.
This also seems to be the norm for other companies that rely on Clojure. Compared to Node.js or Python, the demand and supply for Clojure resources are minuscule. It’s hard to find Clojure jobs for the same reason.
It’s closely controlled by Rich Hickey & Cognitect
It’s hard to label this as a pro or con. Rich Hickey is a fantastic thinker and Clojure is an extremely mature language. However, there have been some conflicts in the community, where Cognitect refused to address concerns at the core level. That being said, the norm is to extend the language using libraries. I personally like it that way. Let Rich control Clojure. He’s good at it.
(It’s (flooded with (parenthesis)))
This XKCD is only accurate if you don’t have an insider perspective.
It’s true that parenthesis can be a problem sometimes, especially when you are getting started. I used to think that I’d have to type and match all these brackets manually. But that’s not the case. There are tools that help you with structural editing and after a few months, the brackets become invisible.
It’s has a slow startup time
Clojure runs on the JVM and has a significantly slower startup time compared to Node. Again, this is only a problem from an outsider’s perspective. We have REPL. You start the app only once, and it keeps running in the background. You can interactively include new changes, without having to startup every time.
It’s has a steep learning curve
Even more so if you are an experienced developer and have never worked with a LISP. The tooling is kinda complex. A majority of Clojure (46%) devs use Emacs which is hard to learn if you started your career with Sublime Text or Atom.
There is an old joke that still goes around, “Emacs is a great OS lacking a good text editor”. In my experiences, Emacs is a beast worth taming. Here’s what mine looks like (no tabs and no snappy “Goto anything” feature) still gets everything done.
If Emacs is too much for your appetite, there is a Cursive plugin for IntelliJ. You can also use VSCode.
Why did I start learning Clojure?
The first version of Reddit was also written in Common LISP.
I was curious as my day job included writing JS and Python and I often found myself stuck at language level features. I’ve always been on a lookout for a better tool. For the past 2 years, I have settled on Clojure and React and I don’t think I’d go any further.
Why I’d continue working with Clojure (probably forever)
In impressive jargon terms, it’s a functional lisp with built-in support for persistent data structures, async channels, and reactivity. It also has a superb standard library. Everything is built around a lean core.
ClojureScript, the version that targets js uses the google closure library (which is known to be faster than WebPack and sometimes even comparable to vanilla js).
Languages like Python focus on readability by making the code look like the English language. LISPs, on the other hand, ignore the English language semantics completely and enforce a structural syntax.
For example, the expression 2*7+3 can be represented in the image.
All LISP code is a list of primitives. Primitive being an element in the set of vector, map, string, number or symbol. The acronym LISP stands for List Processing. Your code is basically a tree with LISP.
The structural code allows for compiler optimizations that are not possible (or extremely hard) with English inspired code.
Immutability means that your variables will never be overwritten. When a change is required, the old variable stays as it is and a fresh copy is generated.
Rub some immutability on it. You’ll be fine.
This seemingly simple functionality helps to build complex pipelines. One of the toughest problems in programming (apart from naming and cache management) is handling side effects. Immutable data structures make handling side-effects less error-prone because the thing you are observing will never change. Ever.
Compiles to JVM and JS (and Graal)
You can easily write a Java-based backend and JS based frontend using Clojure. The interop is very straight forward.
Learn once, write anywhere, with a thin abstraction layer. Target all runtimes with one language.
REPL Driven Development
I didn’t quite realize the power of this feature until it became a part of my daily routine. And you’d probably have to experience it yourself to appreciate the ingenuity and genius of the REPL (or the Read Eval Print Loop).
The REPL basically lets you load parts of your code in an interactive runtime and play with it as if you were using it in your app.
For example, consider a database function that is tied to a controller that is called through a REST API. Now, your task is to optimize the query. In the real world, you’d make the changes to the DB function, let the code reload automatically (or manually), and then check the results of the REST API.
With a REPL, you can skip all the boring parts and bring the DB function and its dependencies to the REPL and edit it in real time. If you are interested in REPL driven dev, I’d highly recommend that you watch this talk by Stuart Halloway.
Relatively more succinct and productive
This is a very subjective claim, so take it with a grain of salt, but I find Clojure syntax to be more terse and expressive than all other languages I’ve ever used. This leads to smaller code basis and more productive teams.
Not typed, but spec’d
There is no native way to enforce types in Clojure, but we have a different way to enforce contracts, called specs. It’s so much more than a Java-like type system and it’s completely optional.
Clojurists don’t fix something that isn’t broken
Clojure lets you extend the syntax with first class support for macros. Consider the following example:
This can be converted into a
when macro as follows:
;; actual when source(defmacro when
"Evaluates test. If logical true, evaluates body in an implicit do."
[test & body]
(list 'if test (cons 'do body)))
and can now be used as:
Not sure if it makes sense to mention Rich Hickey as a Clojure feature, but once you get hooked to his talks and presentations, you change.
In conclusion; TL; DR;
If you’d like to learn more about Clojure, I’d highly recommend the following resources:
You might also like:
- Learn Clojure By Building a Drug Dealer API — Part 1
- Learn Clojure by Building a Drug Dealer API — Part 2
- Learn Clojure by Building a Drug Dealer API — Part 3 [endgame]
- Ethical, open sourced and profitable at the same time
- A simple UI hack to improve Onboarding UX [OCD]
- Reaching flow state with Clojure’s REPL