Review of Clojure
Table of Contents
It's been over a year since I first decided to pick up clojure so it's time for a review. Overall, I like the language. It remains my favorite language for side projects and one that I look forward to using. But it does have it's flaws. In this post I hope to give an honest review of clojure.
1. The Good
1.1. A Well Designed Language
The design of the language is one of the most pleasant aspects of the language. There just doesn't seem to be a lot of cruft. Just about every function you come across has a purpose and there is not a lot of overlap between functions (ie they are highly orthogonal).
There is an interesting phenomenon that happens when you write clojure due to it's good design. It's very easy to tell when you have written your code correctly and when there is room for improvement. If your code is long, there's a lot of boilerplate or you feel it takes a lot of functions to represent a single idea, there's probably a better way to write it. I've found that code written in clojure tends to converges to it's correct state quicker and with less effort than any other language.
1.1.1. Light on Syntax
Clojure does not have a lot of syntax compared to most languages. This means there is less visual noise in the code and that makes it easier to catch bugs just by reading the code.
1.1.2. Maps
Representing your data correctly is the most important part of writing software. I find maps are almost always the best tool to represent data. Maps receive the care and attention they deserve in clojure. Clojure has the best support for maps of any language I've used from the syntax to all of the built in functions to manipulate maps. And of course they are immutable like the rest of the data structures in clojure. Here's a quick example of how you might use them:
(def person {:name "zach" :age 100}) (defn greet [person] (print (str "Hello, " (:name person))))
1.1.3. Anonymous Functions
Clojure is a functional language which means functions are also first class citizens of the language. That means functions can be created and passed around just like data. This is important because like maps, functions are one of the most intuitive tools for modeling computation.
Functions and maps compose great in clojure. I could of written the map example as:
(def person {:name "zach" :age 28 :greet (fn [p] (str "Hello, " (:name p)))}) ((:greet person) person)
Anonymous functions are available in most languages today but aren't always done right. For example, python has lambda expressions but they are limited to one line. One of Clojure's strengths is that anonymous functions are comfortable to use.
1.1.4. Immutability
Writing idempotent code is one of the best practices you can pick up. It makes it much easier to reason about your code. One of the best tools for doing this is immutable data structures. All of Clojure's basic data structures are immutable which means you don't have to waste mental cycles to ensure immutability like you do in some other languages. But not all data structures are immutable. If you do need some mutable state clojure has you covered.
1.2. Interactive Development
Interactive development is the best way I've found to develop software. It is not the only way, there are situations where other approaches are better, but most of the time it produces the best results in the least amount of time. And it's fun. Being able to see the results of your code as you write it makes it more enjoyable.
Clojure with emacs and cider knocks this out of the park. With this tooling I'm always one keystroke away from testing out the code I just wrote.
1.3. Community
Two aspects of the community worth highlighting are:
- There are some really thoughtful and intelligent people in the community. This really helps to steer the language in the right direction (or keep it from being pulled in the wrong direction).
- Clojure packages are awesome. The stuff that's coming out of clojure isn't being done anywhere else. This is actually what made me try clojure. I went through the awesome clojure repo on github and came across instaparse and had to try it out. And I've continued to have this experience with many other packages. A couple that come to mind (and there are plenty more!): meander, zipper, hyperfiddle and one of my favorites, clerk .
2. The Bad
2.1. Debugging
I wish debugging in clojure was more interactive. Personally, python is my favorite language to debug because you can drop into a repl when an error is thrown. Clojure doesn't' do this (although there is a program called flowstorm that supports this).
And another common debugging issue with clojure is it's stack traces. They just aren't that helpful due to lot's of noise and vague or hard to understand errors. Personally, this issue isn't as big as the lack of interactive debugging but it is a common complaint.
2.2. Association With the Bad Parts of LISP
LISP like languages (which clojure is) can have a "cult like" aspect to them. This is due to a minority within the community that claim LISP languages are the best thing in the world. They claim it gives you super developer powers (macros!) but they fail to acknowledge it's shortcomings. Unfortunately, I felt a bit of this from the LISP community while learning clojure. Engineering is about trade offs and failing to acknowledge and communicate these to other people makes LISP languages (including clojure) come off as toy languages. This causes people not to try the language or, try the language and be disappointed it's not perfect before they have a chance to understand it's strengths.
2.3. Career Opportunities
There are not a lot of clojure jobs out there so I would not recommend clojure to anyone that is worried about employment. I have yet to see any opportunities that compare with ones in other languages.
2.4. Performance Limits
This is a bit of a nit but clojure, a high level and dynamic language, sitting on top of the JVM, doesn't give you low level access to write high performance code. To be clear, the code runs fast, it's just not the fastest. I find this to be an acceptable trade off but do get annoyed by it every once and a while.
As pointed out, clojure allows you to easily interop with java so if java is performant enough for you use case then clojure will be just fine!
3. Takeaway
Clojure isn't perfect. It has some rough edges like debugging and writing highly performant code that could be improved. I find it's limits of career opportunities and an unfortunate cult like status a bit of a turn off.
But, it makes up for those issues. It's interactivity and well thought out design are a joy to use. And the projects being worked on in clojure at the moment are some of the most exciting in all of tech. I really enjoy using the language and will continue to go out of my way to use it.