June 20, 2020

Why Clojure, not language X

Why Clojure, not language X

In this blog post I am going to go all fan-boyish and flirty about my current main programming language - a powerful and elegant language called Clojure.

But before that, I have a conviction to make. In the past I have tried to persuade some of my friends to change their main development stack from PHP to python. When python was less mainstream, I was a very strong proponent of python. But as they say, people change, perspectives too.

Wait, why did you change?

Simply put, the journey changes you dear.

Early at my adventure, I was introduced to C, the programming language through a book by Herbert Shield. I was a newbie back then and was in a quest to make simplistic 2D games in libSDL. I have wasted countless hours learning how implement lists and doing safe dynamic allocation and free. Imagine my joy, when I came in touch with PHP as my brother involved me in his freelance web development endeavors. No more memory management? No more implementing your own data structures? What’s not to like about PHP?

As I was enjoying PHP, I started to tackle more and more complex projects with it. At one point, I had written a multi-process job distribution system for PHP, to implement parallel processing for some business software. Not once but twice, I had to solve this problem. First version was on top of PHP’s POSIX process APIs. Second time, based on sockets and custom wire protocols, so that it worked on Windows too. When the third time I was facing the same problem, I had to give up. I moved to a language with builtin multiprocessing capabilities - python.

Don’t get me wrong. Python is a fantastic language. Compared to PHP, it had rather elegant string, list and regex APIs. Also, a super rich standard library which let us venture into a lot of previously inaccessible programming domains with ease. Our company started doing more internet applications, instead of just web applications.

But Python have warts. A lot of it in fact. To name a few:

  • The GIL(Global interpreter lock). Python’s threading is just smokes and mirrors.

  • Python’s promise of multiprocessing is something that barely works. Good luck making a background daemon that you are not willing to restart every couple of days with cron script. The 'multiprocessing' module was simply not designed for that. Anyone serious about getting running a job queue or shared memory was doing it with celery or redis.

  • The deployment story is really really sad. I learned so many things: setup.py, requirements.txt, pip, eggs, wheels, virtualenvs, pipenv etc. And yet, none gave me a solution that would simply let me drop my files from development machine to the deployment server. There was this ritual of making virtualenvs and hooking your systemd script with it. We took a walk backward in this front, compared to PHP. Arguably, the whole container movement was started from Python and Ruby’s lack of sane distribution and deployment strategy.

So, in a nutshell, change is part of me growing as a developer. The more experienced I became, the problems I was willing to tackle became more complex. Naturally, I met the upper limits of my tools.

From skepticism to enlightenment

Yes. Like most of us, I resisted change for a long time. I have known about Clojure for long, at least for 6 years. But only later, around 3 years back, I took it seriously and started to use it in my day to day programming.

At first, my productivity took a nose dive. I didn’t have all the awesome string APIs I was comfortable in python. Even writing a for loop became tremendous challenge. Not to mention that it does not have variables! Yes, it really doesn’t.(If you misuse vars and atoms, you might say that it has something analogous. But that’s just dirty and illiterate.) After a couple of months of struggling, I slowly regained my proficiency. Another couple of months later, I began to understand what Clojure is all about. It is about tackling complexity with an elegant approach.

Clojure, because …​

There are hundreds of blog-posts detailing technical merits of Clojure. Specially, Rich Hickey himself produced some legendary talks detailing the philosophy behind Clojure. I am not going to go into that. Rather, I am going to talk about how it benefited me, personally.

Clojure is for dumb developers

And I am one of them. Contrary to what most people think, programming in Clojure does not require you to understand arcane magic. It’s rather the opposite. Once you take hold of the simplistic programming model it offers, writing Clojure becomes very straightforward. Also, it mostly prevents and discourages you to make you own mess. No hidden and interdependent states sprinkled all over your class inheritance tree. You just open a name-space, look at each function which are most of the time pure(it’s output depends upon it’s input and lacks and side effect). As simple as that.

Clojure is exceptional for a contractor

If you are a contractor or a freelance developer who works to solve problems of all spectra, you will feel right at home with Clojure.

  • In back-end, you will be able to leverage the whole Java ecosystem. But, most of the time, for most Java libraries, there is a sweetened Clojure layer or a better abstracted idiomatic pure Clojure library to do the same job. Some examples -

    • For a client, we used OpenCV to capture images from a video stream and used YOLO v4 with coco dataset using Apache MXnet. Yes, all from Clojure.

    • There is a pure Clojure browser automation library - etaoin, which makes the whole process a child’s play.

    • Ever wondered, if you didn’t want and SQL ORM, but needed a secure way to dynamically generate and organize SQL? Go look for - HoneySQL.

  • In front-end, Clojurescript can leverage most of the JavaScript ecosystem. In fact, there are inventions specific to Clojure which will blow your mind, namely - reagent, re-frame and hiccup. If you thought react was cool enough, you are in for a surprise.

  • If you are juggling between multiple projects, the context switch from one to another usually takes some significant amount of time. For a well structured Clojure project, the task of switching mental context is much easier. Again, thanks to functional programming with immutable data-structures, which encourages you to simplify the inter-dependency between your modules. Most Clojure programs are just a collection of pure functions who do only one thing based on their inputs with occasional non pure functions explicitly handling global states and side effects.

  • REPL driven development really works! Instead of waiting for the whole big picture to take form in your memory, you can build it piece by piece, one pure function at a time.

Most Clojure libraries are very transparent

Most of us think that library authors are some super-programmers who are beyond all judgment and rarely makes mistakes. This is not true. Popular libraries do contain bugs, and some of them are very obscure. With enough years behind your back, you are bound to find some of them.

But, what do you do after you find out the bug? Are you capable enough to do the mental gymnastics to keep track of all the class inheritance and state juggling in your mind to find out the real cause of the issue and submit a proper bug report, let alone a pull request? In the python world, this is very hard to do. Unless I was very invested in the library, I never bothered to report anything at all - as discovering the source of bug was very hard to do. I just implemented a workaround and moved on.

The same is not true for Clojure. The idioms of Clojure dictates how a good library is coded - it’s just a collection of pure functions spread out into some convenient namespaces. Finding and fixing bugs becomes a child’s play.

After moving to Clojure, I started to read library sources, getting involved in other peoples projects - despite me being a very reclusive individual; both in online and in real life.

It’s not all a bed of roses, is it?

As an engineer, I think it’s only ethical to tell you the flip side of the coin. But I am not going to tell you those. Why? Because they won’t be fair. Clojure gives you 95%, and maybe lacks the 5%. If I am going to complain and bitch about that 5%, it will blow out to your face and you will be focused on the downsides. That’s human nature.

You see 5 downsides of Clojure and 5 downsides of language X and then make up a a mental defense to not switch. Nobody tells you the comparative weight of the pain points. To be honest, pain is subjective and it’s very difficult to weigh and compare them. So, you will have to trust me on that.

The pains you need to endure to change your mental model is totally worth it. 😌

There - I said it. Like a true salesman! 😅

Tags: PHP , Python , C , Advocacy , Clojure , Programming