Tuesday, August 30, 2011

Java + Clean Code = Groovy

Some months ago, I read Martin Fowler's Clean Code and discussed it every once a while with several professional Java developers working for different companies. Retrospectively, these discussions were twofold astonishing to me.
  1. A great deal of these developers seemed to know Clean Code or at least some cachy claims out of it. No one disagreed with Fowler.
  2. Most of them heard about Groovy, few of them know about Groovy and almost none of them does actually use Groovy.
Maybe I got it wrong, but in my understanding is the bottom line of Clean Code more or less: write code which is short, concise, self-documentary, and leaves no room for interpretation to the reader. You may guessed it by the title, but my understanding of Groovy is not too far away from that.
Recently, I had to provide a comma-separated list of IDs as a command line argument to an application. The IDs were a consecutive sequence of integer numbers. Too lazy to copy and paste the numbers I thought about the effort to generate the list. How would you do it in Java? In fact, you wouldn't, right? The time it takes to create a Java class with a main method, iterating integers, concatenate them with a StringBuilder, dealing with an redundant comma at the beginning or the end, and finally compiling this class only for a single execution won't pay off. Alternatives: copy and paste or learning bash (awk, python, perl, ... insert your scripting solution of choice).
Enter Groovy.
$ groovy -e 'println ((12345 .. 12355).join(","))'
12345,12346,12347,12348,12349,12350,12351,12352,12353,12354,12355
My assumption is, even if somebody had no idea what Groovy is all about, just by looking at the command, she'll guess the outcome of the command correctly. But what if the task was a bit more involved as only listing consecutive integers? What about filtering and transforming result entries? Suppose, out of curiosity you want to list all the numbers between 1 and 1000 dividable by 17 and containing a 9 as digit. The numbers should be listed line by line with proper line numbers (rather academic example, I know).
What about Java? The proper way to deal with collection filtering and decoration would be to use commons-collection or guava or something similar or providing own implementations of AbstractCollections with lots of anonymous inner classes even for this simple task. The not so clean Java solution could look like the following code.
class Dummy {
    public static void main (String[] args) {
        String result = "";
        int counter = 0;
        for (int i = 17; i <= 1000; i += 17) {
            if (("" + i).contains("9")) {
                result += (++counter) + ": " + i + "\n";
            }
        }
        System.out.print(result);
    }
}
It will work, but it is rather ugly. Moreover, one has to create a file (insert your editor of choice), compile it (javac), and run it (java) just for a single execution (and afterwards delete it). Many different tools and commands for a trival task. In contrast, the Groovy inline script solution is very short, concise, and self-documentary (and does not produce trash in the file system):
$ groovy -e 'counter = 0
> println ((1 .. 1000)                            /* iteration*/
>     .grep{it %17 == 0 && "${it}".contains("9")} /* filter */
>     .collect{"${++counter}: ${it}"}             /* decoration */
>     .join("\n"))'                               /* concatenation */
1: 119
2: 289
[...]
14: 969
15: 986
My biggest problem when working with Groovy is to become aware of lots and lots of wasted hours spent with developing clean code Java solutions which were given by Groovy as language features out of the box in a very concise manner. Don't get me wrong. I'm a big fan of the Java language and I like solutions with lovely design patterns. However, for some problems the full featured Java design patterns sledgehammer approach seems to be a little overkill, considering the opportunities Groovy might add to your default toolkit. Since integrating Groovy is merely a matter of adding jars to the classpath and tweak the IDE appropriately, I am astonished how few people do actually make use of Groovy's opportunities.
Bad marketing, new technology anxiety, other limitations I'm not aware of? I simply don't get it.