Language, Expression and Design



September 2016

hara 2.4.0 released

by Chris Zheng,

I've just pushed version 2.4.0 of hara to clojars. I haven't done much open source in the last couple of months so not much old code has changed. There is a fix to maintain clojure 1.9 compatibility. No bug fixes. I think it's mostly good.

The biggest change is me. To be more specific - my outlook. The 'new' parts of the library are replacements for two canonical workhorses - fs and midje.

I have mixed feelings about this - hara used to be a bunch of namespaces that were purely utility - to provide methods that other libraries lacked. I wanted to respect the canon and so resisted implementing my own. The only canonical library that I challenged in the past was my reimplementation of Stuart Sierra's component library. Initially it started as a joke but the more I worked on it, the more I liked it. Although there are now many dependency injection systems to choose from, my version is still pretty awesome.

However, I want to bring this post back to the topic: Growth. The nature of hara is changing for me. On last check, the repo currently has:

  • 140 source files
  • 1106 checks spread over 116 test files
  • 71 deployables to clojars
  • 23 major packages, of which 21 has documentation

In order to develop and maintain such a code base, I spent a long time (over 3 years in between other projects) experimenting and building my workflow. It has paid off. hara provides the architectural backbone of vinyasa, lein-repack and hydrox - 3 libraries that allow me to work the way I do. Now that the development process has been established and validated by me, I believe can be taken further still.

At the breakout stage of any lifecycle, the supports that contained the necessary ingredients for early growth starts become major obstacle for future growth. As a project hara is now quite capable of standing up by itself, I feel like its time to take out the supports and let the library run free.

The newest additions are:

I've been a little lazy to do documentation - but it will come.

Writing hara.test was a bittersweet experience. I have been one of the biggest fanboys of midje and it's author, Brian Marick. The library, as well as Brian's videos on TDD changed me for good. I went from someone that couldn't write a test to save his life to being an absolute testing pedantic. Most people think I'm friendly until they get into a debate with me about Test Driven Development. I really should stop.

hara.test took only 3 days to write - though I had thought about how I was going to write it for a the longest time. It worked swimmingly. I replaced midje.sweet with hara.test, spent another 5 to 6 hours debugging the library as well as reimplementing a couple of stray tests and it worked - all 1106 of them.

hara.test is essentially midje--. It's got just enough functionality in order to keep my tests working. It only has one type of arrow => and the 4 different checkers that I use to write my tests. I'm not a sophisticated tester. I like to keep things simple and easy to read. Most functions I write are small, with limited range and so frameworks like test.check and clojure.spec have not become an integral part of my testing cycle, especially for a utility library like hara. Having said that, I definitely see their use and will do so accordingly.

I initially wanted to use fudje but decided against it in the end because of it's dependence on clojure.test. To be perfectly honest, I'm neither a fan of the clojure.test api or its codebase. To it's credit, a lot of stuff has been built on top of clojure.test and it's become even more popular recently because of test.check and clojure.spec as well as the stalling developmental-cycle of midje.

I don't think I've ever liked going down the popular route. For people that know me, I'm picky, especially when it come down to style. I'm one of those that prefer style over substance, especially at the beginning stages. I didn't want to be bound to anything that may prove to be an impediment in the future - so reimplementation was my only option.

Here it is - the only thing to show for after all that talk - the most current CI result from travis:


Btw, I didn't realise you can use aliases to overwrite leiningen tasks until I tried:

:aliases {"test" ["run" "-m" "hara.test"]}

comments powered by Disqus