Language, Expression and Design



August 2014

rethinking clojure.contrib

by Chris Zheng,

I used to be a huge fanboy of the c++ boost library even though I used probably 2% of the actual functionality provided (and understood even less than that). In the end, I chose python instead because I got sick of waiting half a day for boost to build. However, what amazed me about boost was the way the code was organised. At the time, I was fascinated by just how intricately all the libraries were linked to one another. Exploring the boost modules was more or less like exploring a finely weaved lattice. It was very beautiful (for c++ anyways) in the way these modules fit and depended upon each other in such a tight knit way.

clojure.contrib had a boost-like feel to it before it got split-up into seperate repos. I came to clojure just when clojure.contrib was being phased out. At that time, I really didn't pay too much attention to the libraries because I was playing around with the 'sexier' libraries with colorful websites like noir and korma.

In 2013 however, I felt an itch to write a conditional restart library because I heard so much about how useful it was in common lisp. After looking at a whole bunch of common lisp code examples, I realised clojure already had an existing implementation done back in 2010, in a relatively obscure contrib module called errorkit.

So I poured though the contrib.errorkit source code to write ribol. Like honestly, I could not believe that the code was written back in 2010 and then was left there unmaintained and unloved for so long. My experience with errorkit was not the last time I would look into the old contrib codebase for inspiration.

As I studied the contrib codebase, I realised that there were so much amazing code nuggets that have been plain forgotten and cast to the wayside. The reason was that some of these files were too small to be deemed important enough to be managed as a seperate project and so were just cast out. Other contrib projects just copied and pasted relevant functionality from the smaller projects. contrib was no more.

I've made a couple of announcements regarding hara in the past but haven't given a reason for its existence beyond the fact that it is yet another utilities framework for clojure.

Let me give the real reason. hara is my homage to boost and the old clojure.contrib. I am particularly biased about how utility libraries should be built (imo, they should be built and tested as a huge monolithic project). These days, there are too many smallish clojure projects that are functionally disparate, having insipid and crappy names yet internally very similar to each other and many times implementing the same functions over and over again. I'm just really sick of them. For example, how many file watcher implementations do we really need? I think ever since I wrote that blog post, I've seen another raft of file watcher libraries being released. When is enough enough?

The current functionality in hara is pretty limited at the moment. However, I'm working on steadily growing its foundations. The key advantage to using hara, as well as building functionality on top of hara is that the entire project, and all its utility functions have been built and tested as a cohesive single unit. Only after it has been tested and documented does the the library get chopped up using lein-repack.

As a single monolithic project, hara will be automatically split into roughly 40 smaller projects that will know about their interpackage dependencies. These 40 projects are each bite-sized. But they are utility libraries and are meant to be small.

Below is the outcome of running lein repack split on the project:

lein repack split

Running lein repack install will install all 40 projects into your local maven repo.

lein repack split

And my favorite: lein repack push will deploy all 40 something jars onto clojars. It's not something that I do very often. I promise I'll record it for the next release =)

comments powered by Disqus