Thursday, November 12, 2009

The Groovy Times

It has been so long since my last post here. I've twittered away like the rest of my peers. I guess I could dish out details from my personal life of the past year now. To examine my interrupt. I won't.

I've been using Groovy a lot in my work on the Swedish Legal Information System. While the things I find interesting in this work deserve many separate posts, I'll just spend this one to drop some nice stuff about groovy.

"Why Groovy", you might ask? Oh dear. For "political" reasons (this is an entire topic of its own), I have to use Java. But the language Java is often so much overwork and ceremony; riddled with convoluted ways to make explicit patterns and formalisms. Dynamic languages are pragmatic. Sure they have flaws, but I find the compromise acceptable. There are probably thousands of articles discussing this, and I prefer to debate it elsewhere (mostly with friends over lunch/dinner/beer).

I must deliver the bulk in Java, and Groovy is impressively close to Java, but with so much more expressive power (ease of use). (More than necessary? My pythonic side says "probably".) I've worked a lot with Jython the last decade, and some with JRuby. Groovy trumps them both (IMHO) when it comes to java library and java culture interoperability. I can spike, explore, and make tests in groovy. Then I add all this horrendous checked exception handling, spinkle some semicolons for the grumpy old compiler, and finally explode-a-pop all the def:s to bulky types when things need to "harden" (to fulfil the contract of delivering .java...; the tests are left in groovy). Not a big deal (especially since I use an editor that makes code editing a breeze). And groovy cross-compiles nicely with traditional cruft.

So what have I used more specifically? Spock. Check it out. Rewrite ten of your JUnit4 tests in it, and if you go back, write ten more. Don't go back. If you're already testing with say JRuby, I won't push you, but I assure you Spock is worth looking at. Specs become liberatingly clear and thin. Data-driving some of them is pure joy. Mocking is dead simple. (Sorry, I won't put code examples here now: look at the spock docs for that. Try them out!)

For building, we do not use Gradle (not yet at least), but that scary beast of mindnumbing declarativity (which I'm usually for), dreadful xml (which I can handle due to prolonged exposure) and conflated purposes (no excuse here) known as Maven 2. It seemed paramount in the surroundings when we started, and won't go away soon. I use it as little as possible (and it is quite impressive when you let it do its thing).

Which leads me to the last thing I want to mention: how to use Groovy's very convenient, builtin Grape system (and its @Grab mechanism) together with my local maven2 artifact repo. That one in <~/.m2>, where all my local packages have been mvn install:ed (along with the umpteen dependencies).

The thing was, when I started, I naively thought things would kind of work at least semi-automagically. I've spent my time in CLASSPATH hell. I wanted groovy to tap into the local m2. Then I was disillusioned again, and attempted to run experimental groovy scripts via GMaven. Didn't fit my use cases at all (that thing is great at compiling, I leave it at that). I shellscripted the path from mvn dependency:build-classpath, then built pathing jars, then just felt quite uneasy (such moves work, but it's not particularly clean).

When Grape appeared I tinkered with the Ivy config in <~/.groovy/grapeConfig.xml>. It surely looks so simple. I couldn't figure it out. Benhard could. Neat.. But alas, that solution copies all the dependencies from the local m2 repo to grape's ivy repo. And I could not get it to grab my new local SNAPSHOT-stuff as they landed either (in spite of eleventy ivy attributes claiming to force all kinds of checks).

Then it appeared, from a combination of fatigue and taking a step back (cue magic "aahh").

Use Groovy's Grape with your Local Maven File Repo

Locate $HOME/.groovy/grapeConfig.xml. If it doesn't exist, see the Grape docs for how the default version should look.

Then add, directly after (xpath) ivysettings/settings, the following directive:

  <caches useOrigin="true"/>

And, in (xpath) /ivysettings/resolvers/chain, after the first filesystem, add:

<filesystem name="local-maven2" m2compatible="true">
<ivy pattern="${user.home}/.m2/repository/[organisation]/[module]/[revision]/[module]-[revision].pom"/>
<artifact pattern="${user.home}/.m2/repository/[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]"/>

With that in place (pardon the line width), Grape (and thus @Grab) will happily use anything it finds in your local m2 file repo, without copying the jar:s. (It will still download other stuff to use to the default ~/.groovy/grapes/, which is fine by me.)

That's it for now. There are lot's of cool stuff with Groovy, if you're in a Java environment and want to ackowledge that without giving up modern power.

Three years ago I looked at Scala for the first time, and found it quite interesting. Then I got a bit spooked by the academic machinations of it. Lately that interest has been quite rekindled though, and the future will show what will come of that. I am very happy to have used Groovy so far though, and I would certainly recommend it. Scala may yet be for tomorrow, Groovy is for the Java user of right now.

(Of course, I recommend to continuously look beyond the JVM as well. Simplicity is hard to reach in increments without designing for it from the start. But things will reasonably evolve in most "camps".)