When we decided to build our Shutl iOS application we had some decisions to make. One of these decisions was the technology to use to build the backend.
This is a pretty simple service. Firstly, it provides an API that combines and transforms data retrieved from different services so the client can present it. Secondly, it listen to events and notifies the clients accordingly. Both of the use cases could benefit or require asynchronous processing.
At Shutl, Ruby is our default programming language so usually it would be a very straightforward decision, we would choose Sinatra and Sidekiq. But the team is always willing to try new things and Clojure has caught our attention for a while. The project sounded like a good opportunity to test it. It wasn’t a critical component but could potentially grow bigger. The logic would be pretty simple, mostly about transforming data, and as concurrency and parallelisation was one of our design goes, this played to Clojure’s strengths. So we decided to give it a shot.
As complete beginners, we took a look at the Clojure ecosystem. Although some web frameworks exist in Clojure, the general approach seems to be combining small libraries that do one thing well.
After some research, this was our initial set up:
- Ring running Jetty as a web server and Compojure as the routing library.
- Midje as the test framework.
- Korma to access the database and Ragtime to run migrations.
- core.async for the asynchronous processing.
- java-apns, a Java client to use the Apple Push Notification service.
- Logback, a successor of log4j.
- Hystrix and Hystrix-clj for resilience and fault tolerance.
One big advantage of using Clojure is that it runs on the JVM and offers idiomatic forms to invoke Java code. This makes it very easy to use Java libraries and giving you access to the great ecosystem of Java libraries, like Logback. For some of them (I am looking at you, Hystrix) there are also wrappers that allow a more idiomatic usage.
How we worked
Coming from a Ruby perspective into Clojure, a different mindset is required but we were halfway there. We embraced immutability a long time ago, functions as first-class citizens are a familiar concept and Ruby is also dynamically typed.
There were only two things we had to get used to: zero objects and lots of parentheses. The first one was easier than expected, it is kind of easy to get used to the way you write code in Clojure. You write small, concise functions and then you combine them. So simple, so easy. But what about the syntax?
I am not going to lie, it can be overwhelming at the beginning. Then, as you use it, you discover one of the things I love the most about Clojure: it is a very simple language. But simple doesn’t mean powerless, just the opposite. Being a dialect of Lisp, the core of the language is very small but the standard library is complete and well documented.
Clojure allows you to focus on what really matters – what your code is supposed to do – rather than on learning how to do things. This simplicity combined with the use of the REPL allow you to easily test and increase your knowledge.
And a tiny, little detail: it is fun.
A few months later, the application went live and everybody was happy. It has been running in production for a few months now, we haven’t had any issue and it is performing really well.
Obviously, we still have lots to learn. We didn’t use every single feature in the language (did somebody say writing macros?) but just because we didn’t need them. We are very proud of what we built.
All in all the experience was very positive. It was so positive that last week we decided to use Clojure as the backend language for a new product… stay tuned!