My first 90 days with Clojure

Written by edwthomas | Published 2017/06/06
Tech Story Tags: clojure | clojurescript | programming | functional-programming | web-development

TLDRvia the TL;DR App

About a year ago, I quit my day job to build something that I wanted to for a long time. I had tinkered around with Clojure but was intimidated by the thought of building a website from scratch, using a language I barely knew. This post is about some of the bumps in the road that I hit in the first three months of my journey into the world of Clojure.

An editor for real programmers

Even though most Clojure developers will tell you that you should simply use an editor that you are comfortable with, there’s a subtle push towards using Emacs. From an entire chapter in a popular (and really good) book devoted to just Emacs, to comments about how productive you can be with it, the signs are everywhere. I spent such an ungodly amount of time trying to fall in love with Emacs that I was spending more time trying to learn it and customize it to my liking (and there are seemingly endless ways to do that), than writing any code.

I finally gave up and ditched Emacs in favor of Cursive. I also played around with LightTable, Atom and SublimeText. For various reasons, none of them worked for me as well as Cursive did. This is not a diss at Emacs. It’s been around since the 70’s for a reason. Maybe at some point in the future, I’ll give it a shot again. Plus, you have to admit, C-x M-c M-butterfly is awesome.

https://imgs.xkcd.com/comics/real_programmers.png

Forcing an object-oriented peg into a functional hole

I did what most people would do when faced with something unfamiliar — make sense of it by morphing it into something they already know. For me, this meant taking patterns that worked in an object-oriented setting and applying them to my Clojure programs. Take namespaces for instance. I wasted time diagramming, like a Class Diagram, what namespaces would look like, what functions it would expose and how it would interact with other namespaces. It was only when I started forcing myself to think in terms of simple data structures that I felt like I was moving forward with my understanding of Clojure. And the tool that helped me was the REPL.

Using the REPL was as big a change to my development workflow, as switching to Git once was. Load up what you need in your REPL, create a data structure to store some test data and start writing functions that act on that data to achieve your final result. Execute your function in the REPL to get immediate feedback. Want to see how your function would behave if the data changes? Just update the inputs to your function right there in the REPL and see what happens. To me, the REPL was like an interactive testing environment, except that I wasn’t simply writing tests that fail first. I was incrementally and interactively building my application, by creating small functions. Once I was satisfied with what I had, I would take what was in the REPL and add them to a namespace that made sense to me at that time, knowing that my codebase was robust enough to sustain any refactoring in case I needed to move functions around.

Diagramming how different namespaces depended on each other, became less important. I realized that the patterns and tools, like Class Diagrams, that I thought helped me understand the “big picture”, only delayed what I should have been doing in the first place — writing code that works and incrementally building my application by composing simple, pure functions. Which brings me to….

Purity of thought and function

More than anything else, this is the one that got me as a beginner. Everything I read about functional programming and pure functions made me feel inadequate as a Clojure developer when I looked at my code. Pretty much everything you do in a web application — render elements in a UI, update the database, trigger an email etc — requires side effects.

To paraphrase Simon Peyton Jones - a program without side-effects only makes the box hot.

How could functions be pure when any meaningful change to your application requires a side effect? The key insight for me was to not worry about the side effect itself but ensure that functions that have side-effects are isolated.

Assume, you were writing a function that handles a user registration feature. You would typically validate the user input, check if the email address is already taken, update the database if that check passes and return a response. This code could be written like so. All you need to know is that user-data is a hash map containing the email and password.

(-> user-datavalidated-user-datacheck-if-email-is-takenregister-userresponse)

In simplistic terms, ->is a macro that takes the response from one function and passes it as the first argument to the one below it. So validated-user-data is a function that takes user-data as an input and validates the values. The result of that is passed to the function below it and so on. check-if-email-is-taken will only trigger a call to the database if the email address is deemed valid by the previous function. Similarly, register-user will only trigger a database insert if the previous function determines that the email address has not been taken.

Of these functions, validated-user-data and response are pure and are named using nouns that describe their response. They depend purely on their input and as long as the inputs remain the same, their response will be the same. The other two functions are named using verbs to indicate that they have side effects and their names describe the action they perform. I’m not smart enough to come up with this convention myself. If you are new to Clojure, do yourself a favor and read this awesome blog post.

Side effects of being lazy

I’m sure most new Clojure programmers face the lazy sequence issue at some point. Operations like map,filter,for etc yields a lazy sequence.

From the docs….A lazy sequence is one that isn’t realized (computed) all at once. Instead, its values are only realized when you ask for them.

An oft-cited example of this is range, which returns an infinite sequence. If you execute range in the REPL with some arguments, you will get what you expect.

Execute range without any arguments and you also get what you expect (if you read the docs) because the docs state that range will return an infinite sequence.

Clearly, you can’t use range without any arguments, right? Not quite. You could write code that looks like this (take 10 (range)).

take ensures that the (infinite) lazy sequence returned by range only realizes what is asked of it i.e. the first 10 elements of the sequence.

As you saw the with OutOfMemoryError above, the REPL causes lazy sequences to be realized. This is what tripped me up because the REPL gave me a false sense of eager evaluation.

I ran into this issue when I had to render a collection in my UI code. I had to wrap each element of the collection in a row and I used a for to process the collection. Even though everything should have worked, nothing was being rendered. A few hours later, I realized that the rendering issue was related to lazy sequences. I “fixed” it by forcing an eager evaluation using doall. Even with my limited experience in Clojure, I knew that was not the right way. I should never have used a lazy sequence operation for a side effect (which rendering something in the UI is). The solution is to use alternatives like doseq, reduce and transduce.

While I admit there are still a few comments in my code that says something like, “Fix this!!! Should not use a lazy sequence here!!” (we all have comments like that in our code, right?), I have made an effort to only use pure functions with computations that are lazy.

What’s Clojure’s killer app?

It’s often said that the reason Clojure is not as mainstream as Ruby is that it doesn’t have a popular web framework like Rails. The Clojure community favors libraries versus frameworks. Instead of having an opinionated framework that forces you to follow its patterns, Clojure allows a developer to pick and choose from a seemingly endless variety of little libraries that only do one thing. Want database migrations? Use Migratus. How about a DSL for SQL? You could choose HoneySQL. How about a library that abstracts the handling HTTP requests and responses using functions? There’s Ring. Want a build tool? There’s Leiningin or Boot.

While I initially struggled with trying to figure out which library to use for a specific task, I eventually started to enjoy the freedom and flexibility the mixing and matching of libraries gave me. For those who don’t enjoy or care for that kind of freedom, there are some web frameworks out there. Luminus would be my choice if I were to start over.

The benefits of not giving up

I may have been able to build a website from scratch faster with Java, Ruby or Groovy but I most certainly would not have had this much fun. Just the process of figuring out Clojure was almost as enjoyable as coding with it (and I’m still learning).

So if you are just starting out with Clojure, hope this post helps you in some way. There will be times when you curse at the error messages. Actually, you will curse at the error messages all the time (they are that bad). There will be times when you read posts that claim it is a dying language. Your friends might make fun of parentheses like this…

https://imgs.xkcd.com/comics/lisp_cycles.png

Ignore all that noise. Just stick with it. In the end, it will make you a better programmer because learning Clojure will force you to think about solving your problem in ways you didn’t know existed.

Here is a list of resources that I found immensely helpful while I was learning Clojure.

  1. https://stuartsierra.com— Stuart’s blog is a must read for anyone trying to learn Clojure. A good chunk of what I learned was a direct result of reading his blog.
  2. http://www.spacjer.com/blog/2014/09/12/clojurescript-javascript-interop/— My app uses ClojureScript/re-frame in the front-end. I bookmarked this page and went back to it every time I had to interact with a JavaScript library.
  3. https://yobriefca.se/blog/2014/05/19/the-weird-and-wonderful-characters-of-clojure/— I’m not sure how current this is but this blog post helped me a lot. I mean try searching for “what is ~ used for in Clojure”.
  4. https://clojure.org/api/cheatsheet— Great way to quickly browse the functions/macros in Clojure. Love the way the operations are categorized into meaningful sections.
  5. https://www.clojure-toolbox.com/— Like I said before, the Clojure community favors libraries over frameworks. This site lists most of those libraries and tools.
  6. http://cljsjs.github.io/— Unless you are working with ClojureScript, you will not need this site. It took me a while to understand what was going on here but it was very helpful.

Published by HackerNoon on 2017/06/06