There are a few reasons teams choose to implement some piece of functionality as a microservice. To me the most important ones are:
- Code re-use: multiple teams can take advantage of what you built. e.g: search, file storage, or pub/sub.
- Ability to scale the feature independently of the applications using it.
- Freedom in technology choice.
This post focuses on the third point above.
Freedom in technology choice
This is a very important property of a microservices oriented architecture. Microservices are meant to be small. How small is usually up to the company/team culture but I've heard of microservices no larger than 100 lines of code and others of a few thousand (if this is Java, I'd still consider it small).
Since microservices are meant to be small, developers are encouraged to use whatever technology they think is best. If it turns out to have been a bad choice that's Ok - we learned that and will take the new knowledge into account for future projects. In some cases the team might even decide to re-write the microservice in a language that is better suited since it's most likely only a few hundred lines of code.
This is all fine and dandy. However If you have total freedom in the choice of technology why would you choose Clojure over [insert your favourite programming language here]?
I'm so glad you asked!
A modern Lisp
"Lisp, made with secret alien technology." — lisperati.com
Clojure is a modern Lisp for the Java Virtual Machine. Targeting the JVM has many advantages:
- The JVM has had a couple of decades of manpower poured into making it fast; And it is damn fast.
- There is a plethora of robust libraries in an extensive range of problem domains. Focus on the problem you're trying to solve rather than re-inventing the wheel.
- The JVM is widely used across both small and large businesses; being on the JVM means much greater adoption.
So, the JVM is great, and we are already using Java. Why switch?
Well, Java comes with its own set of trade-offs. It lacks many features other platforms take for granted - such as lambdas, though that's been rectified in Java 8. Its type system is overly restrictive and its type inference is less than ideal. Java also doesn't have data structure literals, making it even more verbose.
Additionally the usual development feedback cycle in Java is too long. It involves multiple JVM restarts a day in order to run your applications and/or tests - even if all you did is change a single line (HotSwap does mitigate some of this). Experiments become hard given the amount of structure required just to get started. Finally, the lack of an interactive development environment is a deal breaker.
What is it like to be a Lisp?
"Lisp isn't a language, it's a building material." — Alan Kay
Being a Lisp means being extremely flexible, taking an opinionated data driven approach to programming and providing utmost malleability through the power of macros. It's important to note here that Lisp macros are very different from, say, C macros. C macros are a simple way to replace names found in the source code with the macros defined and processed by the C pre-processor.
Clojure macros on the other hand are a way to manipulate Clojure code itself - yes you can transform the AST! - including the ability to control when and if things get evaluated at all.
The beauty of experimentation
“Within a couple weeks of learning Lisp I found programming in any other language unbearably constraining.” — Paul Graham, Road to Lisp
All this power would have gone to waste if we would have to go through the traditional development cycle of: change the source -> re-compile/re-start the runtime -> run the code to see the results/run tests -> rinse, repeat.
One of the main reasons for which I became a software developer is the thrill of creation. Writing some code and immediately seeing the result of your labour is an amazing experience! I believe we should do whatever we can to reduce the time it takes to see the results of something we just created. Clojure - and indeed, most Lisps - ship with an advanced REPL (Read-Eval-Print-Loop) environment that is tightly integrated with many editors such as Emacs, Vim, IntelliJ and Eclipse.
But what does it mean for day to day development?
My normal Clojure workflow involves starting a REPL session in Emacs - though the same applies to IntelliJ, Vim and Eclipse - and generally leave it running for the duration of whatever task I'm working on. It's not uncommon to have a REPL session running for days or even weeks. This completely eliminates the drawback of the JVM startup time as I can change code in my editor and immediately re-evaluate it in the running REPL using a simple keyboard shortcut.
This makes developing in Clojure a lot more experiment-driven. The cost of exploration is minimal and as such you end up growing your application through the REPL. This applies to tests as well, the same low cost approach works for running them. After all they're just functions.
Functional Programming and Concurrency
"Choose immutability and see where it takes you" — Rich Hickey, Clojure creator
One of the places where Clojure sets itself apart from other Lisps is in its opinionated approach to functional programming. Just like in many other languages, Clojure supports higher-order functions. This means functions are first-class citizens and can be both used as arguments as well as return values from other functions.
However in Clojure data is immutable by default. If you create a map, a list, a vector, what have you, it is immutable by definition and cannot be changed once created.
This has a number of benefits:
- immutable data-structures are thread-safe by default, making developing concurrent software simpler;
- you get history with minimal effort;
- there is no need to worry about other code paths changing your data. It simply won't happen;
This is a very hand wavy post and it's honestly hard to describe in words all the benefits I've listed so far so I recommend you watch this video by Bruce Hauman where he programs the Flappy Bird game interactively with Clojurescript - it's a great example of the sort of workflow I described in this post.
If you're interested in learning more about Clojure I can also highly recommend the Sydney Clojure User Group. We're a good bunch and welcome attendees of any experience levels.
If you're not in Sydney you can find your local user group in the official user groups listing in the Clojure website.