Monday, 26 May 2014

Maven's great, before you get annoyed with a feature, find out why it was implemented.

I have always liked Apache Maven, however I recently found a few issues with it that irritated me.  This post was going to moan about them, but after further reading I have come to realise that these issues are not as simple as I first thought.  They are in fact conscious decisions associated with a very complicated problem domain.

Fist off, why is maven great?

The best thing about maven is the standards it imposes on you.  This has the obvious downside of it feeling restrictive at times.  However, the benefits are huge.  The standard directory layout, standard build phases and of course the standard dependency management have been around so long now that we tend to take them for granted.  Unless a project uses custom or obscure plugins or overridden many default settings, each project looks and builds in a familiar way.  As mentioned on, " ... [it's] only necessary to learn a small set of commands to build any Maven project".

It almost feels redundant to mention (as it's been the case for so long) but these standards help so much when learning a new code base.  The sight of a pom.xml almost comforts me when browsing a new code base!

Issues/Problems I have had, but have now come to understand


Sometimes an artifact in your local repo is ignored - this can be confusing

A while ago I thought I was loosing my mind when maven complained that it could not find an artifact despite it clearly being in my local repository.  It turns out that since I was now using a different maven repo, it no longer trusted the artefact from the previous repo.  I thought this was very strange but as Jason van Zyl states: "Artifact A downloaded from X is not the same thing to Maven 3 as A downloaded from Y".  This extra complexity seemed so ridiculous at first, however non-deterministic builds are surely a lot worse.

Arguments against this behaviour:
  • Adds confusion. 

Arguments for this behaviour:
  • To avoid non-deterministic builds.

While pros and cons of this feature can be discussed (I do wonder how often "Artifact A" actually differs in repos "X and Y") one thing is clear... a better error message is definitely required, see here.

Transitive dependencies are the wrong scope - your project can start depending on libraries without you realising it

I didn't realise this until it was pointed out by a colleague recently, however a compile (default) scoped dependency should bring in its dependencies (transitive dependencies) with a runtime scope and NOT compile.  See the asterisk in the dependency scope table.  If this was the case, you wouldn't find your code silently increasing its dependencies (i.e. not explicitly listed in your pom.xml) during development.  This can lead to a bit of a mess that is easy to get into given the fact that IDEs obviously obey maven's rules when showing you what you can import.  If you can import it and want to, you do so without realising your code is now tied to another library that it wasn't before.
I now realise that I have lived with this "feature" for so long that I have come to accept that dependencies can become unwieldy without an extremely close eye.

Arguments against this behaviour:
  • To stop your project silently depending on a library.

Arguments for this behaviour:
  • To make importing libraries easier, i.e. to stop you having to explicitly list transitive dependencies when you extend a class that in turn extends a class from another library.