How I Use Clojure to Build and Scale my SaaS

How I Use Clojure to Build and Scale my SaaS

I was first introduced to Clojure in grad school where I was taking a course on building large scale software applications. We were building a clone of the card game Hearthstone, and in particular the game engine. If you have played that game, you know there are a lot of state changes happening when cards are played, affecting other cards on the deck, and so on. Even though I had no previous experience with programming in Lisp, I got up to speed quickly.  After a few weeks I really started to enjoy the syntax, or rather, the lack of it. You see, everything in Clojure is just data, so there is no syntax. A few hundred lines of code and a couple of Rich Hickey key notes later, I was hooked.

I really liked writing Clojure and decided I would use it to build something I had been pondering on for a long time, a simple and enjoyable CRM system for small businesses. Fast forward a few years an I'm now running my own SaaS business called Wobaka, on 100% Clojure code (ok, GitHub says it's 97.9% Clojure but who's counting?). I wanted to share a few things I particulary enjoyed and that has helped me build and scale.

Development environment

I've yet to find a development environment that is as lovely to work in as Clojure/Script with Figwheel. You see, Clojure has this lovely data type called atom which may contain any kind of data that can be updated atomically. The cool thing is that Clojure, and in this case a library called Figwheel can reload your entire code in memory but keep the state of these atom data structures. Now, if you're a frontend developer you probably know where I'm going with this. We can reload the entire application code without even touching the state. Figwheel uses this to make hot reloading an amazing experience where you can keep all your state but still get real time updates in the browser when your code changes.

I can't go back from this.

Adding an input while keeping form state

The REPL

Oh the REPL. I think it's one of the most missunderstood things in Clojure. You see, this REPL is not just a command prompt. You can start it from within your editor, compile your Clojure project and run anything from anywhere. I personally use Emacs but there are great plugins for VSCode and other editors as well.

Want to run all tests in a file? There's a command for that. Want to run a line of code? Just place the cursor and hit Ctrl-x-e. You can even document your code with code samples using special comments.

My personal workflow is often to run things in a comment and then move it to a test when I'm done with the function.

Again, it's hard to go back from this.

Running any code, instantly

Shared code between client and server

Clojure can run both on JavaScript (client) as ClojureScript, and on the JVM (server). This makes it super easy to write shared code that can run anywhere. You can also use special forms to define code that should only run on the client or on the server.

Clojure Spec

Clojure Spec is a library for specifying structure and shape of data. Once you've defined your data you can use it for validation, to specify types for functions using contracts, to generate tests automatically and more. It's just another thing that makes programming in Clojure so enjoyable. Of course specs also works in ClojureScript so you can easily share your data type specification in your client and server code! This is especially handy for data validation.

Inline tests

I'm a big proponent for inline tests and write all my tests in the function specifications. I think this results in an up to date test suite, better tests and better overall test coverage as it is just more convenient to write them. You can also use the tests as documentation which, combined with the REPL makes for a brilliant environment.

Adding a test to a function is as simple as adding a map with a test attribute.

Inline tests

Stability

Since the beginning of my project I have had zero breaking changes in dependencies. The JVM has been very stable and even though I used to be sceptical to everything Java, I've come to really appreciate it as a big plus now.

No more JavaScript burnout

Gone are the days of continously updating 100s of NPM packages. I love open source but taking care of a large JavaScript project with a lot of dependencies can cause a lot of frustration.

But what about the parenthesis?

Honestly, I've come to prefer the way Lisp uses parenthesis compared to other languages, such as the C family. (foo (bar "Hello, World!")) vs foo(bar("Hello, World")), which have the most parenthesis? (hint: same!).

Clojure is fun!

I love writing Clojure for a living and I'm truly thankful to Rich Hickey and the Clojure team and community.

If you're looking for a CRM system you'll actually enjoy using, go ahead and give Wobaka a try!