Groovy: The Defective "Swiss Army Hammer"

2013-10-06 in groovy grails gradle java

Gr- — (Javanese) Agglunative prefix, typically indicating expectation of a painful experience, often due to lack of forethought or impropper planning.

Example constructs include:

  • Groovy — Adjective. Characterised by a large number of hacks attempting to make things better, but which really only increase the number of problems by an order of magnitude. “That’s some groovy code you’ve got there. I especially like how it uses the query parameters to dynamically select the class and static method to execute.”

  • Grail(s) — Verb (almost always found in the singular present). To inflict suffering and confusion by means of unnecessary complexity, self contradiction, and annoying surprises separated by excrutiating waits. “It really grails me how this ‘convention over configuration’ framework requires three multi-thousand-line configuration files to run.”

  • Gradle — Noun. An obstensibly comfortable, metaphorical location in which something is cradled before finally succumbing to death. “After having been in gradle for a few months, we found that the code had become impossible to update, due to library version conflicts.”

Background

For over a year now, I have worked with a tech startup in Denver. (I will refrain from identifying the startup, as who they are is irrelevant to this blog, and their only connection to it is that it gave me experience with the tools in question.) The company is an almost pure-JVM shop. While I personally despise Java for a number of reasons that will become apparent as new posts are written, the platform does have the advantage of being predictable in its simplicity, so I’d normally consider this fact a mixed blessing.

Unfortunately, a lot of the code is written in Groovy. And is built with Gradle. And the two largest code-bases are Grails applications. While — thankfully — little of my work involves those two, and my team has converted most of the code we’ve inherited to pure Java, enough remains that I generally have to deal with Gr* on a weekly basis. And every week makes me hate at least one of them even more.

Groovy is a Java-based programming language which claims to be almost entirely backwards-compatible with proper Java at a source level, while adding in a lot of features that Java is missing (and some which it is merely “lacking”). It combines the performance of Ruby with the clarity of Forth, the type-safety of PHP, and the conciseness of vanilla Java.

Grails a “convention over configuration” web application framework built on Groovy, which attempts to be like Ruby on Rails (and was in fact originally called “Groovy on Rails”). In practise, it generally winds up being heavily configuration driven, exacerbates problems which were already severe enough in Groovy, and introduces more suprises than a Kinder Sorpresa factory.

Gradle is a Maven-like Java build tool which uses a Groovy-based domain specific language for configuration instead of XML. While it is far easier to get started with, primarily due to its simpler and smaller configuration, the developer pays for it with its insane memory usage — two to three times that of Windows XP — poor performance, and disturbing reliability issues, including silently passing builds if they fail for certain classes of errors. Groovy further complicates the picture by making it possible for libraries within the user code that Gradle is building to conflict with libraries Gradle is running with.

The Java Hammer

Since physical tools seem to have become a common way of complaining about programming tools, let’s extend Eevee’s wonderful analogy of the PHP toolbox.

Java’s toolbox consists of a hammer. A good one, but just that hammer and nothing else. The people who use the Java Hammer have devised common “patterns” to make do without the other tools — be it simply hammering screws into place, or using the hammer to make other tools when the need arises. So their front doors don’t collapse when you knock on them, but everything’s a bit bulky and the plumbing often shows through.

The Groovy Hammer

It would seem that the creators of Groovy looked at Java — its one tool being somewhat inconvenient — and then at all the other languages with a full suite of tools. But instead of making a box of separate tools, which obviously wouldn’t be usable exactly like the Java Hammer, they instead took inspiration from the Swiss Army knife, and attached more tools to the hammer. Except that they missed the single most important aspect of a Swiss Army knife that makes it usable — that only one tool is deployed at any given time.

So what we’ve ended up with is a hammer that also has a flat-head screwdriver, serrated pliers, and a saw. But the pliers are attached to the bottom, the saw extends in the same direction as the claw, and the screwdriver is attached to the centre of the head.

Then they say that it can be used just like the Java Hammer, but it has more features. After all, you can screw in a screw with the exact same paradigm you use to drive in a nail; you can use the pliers without changing your grip on the hammer; and it even has a saw!

But then you try to use the tools. Yes, the screwdriver works, but turning a screw with the hammer is incredibly tedious, since you need to use one hand to hold the head against the screw while using your other hand to slowly rotate the handle around the precarious axis. The pliers technically work, but you can’t do anything precise since you need to lug around all the weight on the other end of the hammer every time you want to rotate the tool. And the saw is basically useless since there’s no way to hold it such that you can apply both the necessary downward force and move it laterally along what you want to cut.

Furthermore, the new attachments make the hammer worse. After you get used to maiming yourself with the saw and stabbing yourself with the pliers, you start to tire of trying to use the screwdriver bit to drive in nails, so you resort to using it like a PHP Hammer since that actually gives you a larger surface and removes the possibility of injuring yourself on the saw. But then a native Java programmer sees it, assumes that that’s just the way one does things in Groovy, and begins using the side of the hammer to hammer in his screws.

The end result is that any code-base written primarily in Groovy nearly invariably becomes a tangled mess, fuelled by cargo-cult programming centred around uncertianty of how anything even works, be it the language, its libraries, or even the code-base being developed.

Categories of Wrongness

When considering things wrong with the Gr* triad, I will classify them according to the categories below. The description for each category describes why I think the issue is so important, and may shed more light on how various defects relate, or how they affect the functioning of a team or individual developer on a large-scale project.

A fractal of bad implementation

An astonishing number of Groovy’s issues stem not from short-sighted design decisions, but rather merely from a poor implementation. This often has the effect of leaking implementation details to the programmer, not to mention making development far more difficult, as one must reason about how code will interact with the bugs within the implementation itself.

By far, though, the worst part about this class of defect is that it compromises the programmer’s trust in the very tools that form the foundation of what he is working on. This makes the average Groovy programmer working on a large project overly cautious of using the language’s more advanced features, instead choosing to stick with the subset that is felt to be more stable.

It’s just like Java, but “better”!

Groovy tries to be a superset of Java. (The fact that it then goes and turns several of Java’s simplest semantics on their heads is a separate point entirely.) While this greatly lowers the entry cost of programmers migrating from vanilla Java, as all their familiar coding idioms continue to work unmodified, except when they don’t. Of course, this also means that Groovy inherits many of Java’s most fundamental problems as well.

I may also use this category to complain about a Java problem that Groovy partially inherits.

Not my favourite programming language

This category applies to problems or design decisions which make it more difficult to work with Groovy (or Grails or Gradle, even though those aren’t programming languages), while not substantially impacting larger-scale projects or inter-developer coöperation, nor creating additional security concerns. These problems typically are detected quickly, but cause frustration because it seems that they either shouldn’t happen or should be detected by the compiler.

Real Programmers don’t use X

Many examples of Groovy’s supposed superiority involve very small-scale examples that make it look like a concise and elegant language. In the Real World, however, these features end up being considered useless, impeding scaling of an application, or reducing the ability for multiple developers to coöperate, especially across time. In the end, the developers silently and implicitly agree not to use certain features of the language, slowly widdling it away to a core more akin to vanilla Java.

Considered harmful

While not as bad as PHP, Gr* have many quirks which compromise the the integrity of the application, either in terms of security or reliability. These are by far the most insidious defects of the tools — and of the surrounding culture — since they can generally remain undetected during development and testing, only to suddenly surface at some inconvenient time long after a dependence on the defective part of the tool has become solidly baked in.