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 back end.
This back end is a pretty simple service. First, it provides an API that combines and transforms data retrieved from different services so the client can present it. Secondly, it listens to events and notifies the clients accordingly. Both of these use cases could benefit from or require asynchronous processing.
At Shutl, Ruby is our default programming language, so usually it would be a very straightforward decision to choose Sinatra and Sidekiq. But the team is always willing to try new things, and Clojure has caught our attention for some time. Our back-end project sounded like a good opportunity to test out Clojure. It wasn’t a critical component, but it could potentially grow bigger. The logic would be pretty simple, mostly about transforming data, and our design goals — concurrency and parallelization — 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 setup:
- 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. Clojure therefore makes it very easy to use Java libraries and gives you access to the great ecosystem of Java libraries, like Logback. For some of them (I am looking at you, Hystrix), wrappers also allow a more idiomatic usage.
How we worked
Coming from a Ruby perspective into Clojure, we needed a different mindset 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, allows 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 since the fall of 2015, 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 recently we decided to use Clojure as the back-end language for a new product… stay tuned!