Loathe it or leave it
I first encountered the Maven (version 1) tool for building Java projects when I was writing a book on the Portlet API and had to build the Pluto Portlet Container in order to deploy portlets. At the time I was migrating between my flat with a reasonable broadband connection, and my then girlfriend's house where I was subsisting on a wafer thin GPRS internet connection that frazzled out of existence whenever the next door neighbours switched on their Christmas tree lights.
I took a real dislike to Maven at that point. The problem for me was that practically everything I did caused it to try and download a bunch of JAR dependencies from the internet. Coming from an Apache Ant build where cobbling any old set of Jars together would usually get you a workable build, I didn't really see the point in this tool.
I also disliked the way that there was nothing explicit in the configuration file to tell you what it was liable to do. And the online documentation was fragmentary, and quite honestly Pluto itself was (ironically) a bit of a dog, so it's hard to say exactly where Maven's peculiarities and Pluto's inadequacies merged. I haven't touched Pluto since then, so perhaps that's better now.
Anyway, I came away with the impression that Maven was Ant's inferior second cousin, possibly with a bit of inbreeding in the family.
Second impression
Roll on 2006 and I was working on a big fat Java project that had some problems with dependencies. Actually that's an understatement. All of its problem seemed to be related to dependencies.
When a team has too much work to do, there is a tendency for the least competent member of the team to be saddled with "managing the build" on the basis that this is where they can do the least damage. God what a misconception; the reverse is true - a good build manager is worth their weight in gold (and actually a good flesh and blood build manager is about as rare as a solid gold one). Anyway, the end result of a hopeless case being put in charge of the build was that by the time I arrived the build output had achieved a sort of wild quantum indeterminacy, and wildly differing versions of individual libraries were duplicated throughout the various modules.
The whole thing was an absolutely hopeless mess, and this was all built with good old Ant.
It wasn't me that fixed it. A couple of my colleagues pulled a few heroic all-nighters and got the build scrubbed of all the misversioned and duplicated Jar files, and generally dragged the build.xml file into some sort of rigorous order. From that point on one of them kept a sharp eye on any Jars checked into the build - a drain on his time, but essential to the sanity of the team.
In the course of a meeting about the best way to manage this problem, one of these developers mentioned their experiences with Maven (version 2) in a positive light, because of its dependency management capabilities. We decided at the time that the manual cleanup was the best approach, probably influenced by my distaste for my previous experience with Maven, but I think in retrospect that we should have gone for the conversion to Maven 2.
What's it all about.
Possibly Maven 1 was a good tool that I didn't get a good impression of, but regardless, since then I've had several very positive experiences with Maven 2. The reason it hasn't caught on as quickly as it should have is, I think, mostly because Maven doesn't have a very clear marketing message and the documentation is very patchy.
I can't fix the documentation (well not right now), but I can give you my spin on marketing it.
First and foremost Maven is a dependency management tool.
Correctly used, Maven will ensure that you only have one version of each library (Jar) that your code depends on, and that you know exactly which versions you are using. This information is embodied in the configuration file, so if you haven't got the library when you kick off a build, it will obligingly go and download it from a suitable repository.Secondly, Maven is a standard project directory structure.
This one takes a bit of persuasion. Maven works on the basis of a "standard" project layout. In the best object oriented spirit you "program" only the differences between your one and the standard one into the configuration. Now, if you're used to Ant, this seems pretty nasty at first - you're used to seeing everything explicitly configured; javac targets, jar targets, war targets and so on and so forth, but it rapidly becomes second nature and has been pretty well thought out.Thirdly, Maven is a build framework.
This one is easy. You can build plugins for Maven and use them to do any build task you like. In this sense Maven is exactly like Ant - you can write your own Ant tasks and use them as targets. On the other hand when you put the requisite entry in a Maven configuration file (analogous to Ant's build.xml it's usually called pom.xml), it will go off and download and "install" the plugin for you - your user doesn't need to do any of this manually, which is quite different from Ant!Fourthly, and least important, Maven is a documentation tool.
But, quite frankly, it's a rubbish one. All those pages on the Apache website where you can't find the download link and the documentation isn't really there? That's template generated Maven documentation and it's hard to imagine anything less useful for the general consumer of documentation. Documentation is only as good as its author and Maven (obviously) doesn't have much of a creative bent.
However Maven IS quite good at incorporating the outputs of all your unit tests (JUnit's unit tests are kicked off automatically, and other test types can be incorporated via plugins). Frankly I think the fact that it forces1 you to run the tests at all is the strongest feature here - I can't remember when I last bothered to look at the generated test outputs, but I notice immediately that the build's failing because a set of tests didn't pass, and off I go to fix them.
Marketing? Me? With my reputation?
So when I say that Maven has a marketing problem, I'm really thinking about the documentation problem of those ghastly Maven generated websites. They certainly made me reluctant to get to grips with it until I was forced to. The Maven developers are quite naturally proud of the capabilities of their tool, but unfortunately they're so keen to propound its qualities that they fail to nail down the specifics. For example, here's the first paragraph on the Maven homepage:
Maven is a software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project's build, reporting and documentation from a central piece of information.
Sounds lovely. What's a software comprehension tool? Doesn't project management mean gantt charts? Reporting? That's for managers. Big yawn. Not a mention up front of its real strengths in dependency management. Sure there are some links to click on if you want to read about "What Maven is", its main features, or indeed the Frequently Asked Questions, but frankly I found the first two a cure for insomnia and the latter suggestive of the problems inspired by the tool rather than the solutions.
Other problems
So now we know what Maven is good for, what are its deficiencies?
Configuration files
Well, as I've mentioned, the configuration files don't tell you how to use it, so you have to acquire a bit of familiarity with the tool before you really start to get anywhere. Once you do, however, it's rather cool. For example, working from my current machine I can kick off the following tasks:
dcminter@treacle:~$ mvn clean # Remove any old build artifacts
dcminter@treacle:~$ mvn install # Compile, Jar, and War as necessary. Run
# all unit tests, if they pass put the
# generated files into the local repository2.
dcminter@treacle:~$ mvn tomcat:redeploy # Uses a plugin to deploy the generated WAR file
Ignore the bit up to the $ sign - that's the Unix prompt, and for unaccountable reasons my laptop is called "Treacle". Anyway, I think that demonstrates that the actual commands aren't very complicated - but their effects are. You need to know that "install" will perform the standard "install" functionality of Maven (compiles the source files and turns them into a Jar file), but will also perform the standard "install" functionality of any installed plugins - in my case this means it will use the tomcat plugin to build a WAR file and put that in the repository too.
The plugins can add their own tasks that don't fit into the "standard" lifecycle. You can configure Maven to run them as a side effect of tasks like "install", or just kick them off manually as I have above.
Secondly, Maven is a standard project directory structure.
Wait, didn't we have that as a "pro" of Maven rather than a "con" ? Sure, but it's a reason why people don't necessarily like it on first encounter. The problem is that you probably have some preferred directory structure already that you're used to, and you don't particularly want to change it. For example, you use Eclipse and you like to have all your web artifacts in ${project}/WebContent but Maven wants it to live in ${project}/src/main/webapp/.
My advice to you here, first and foremost, is: "suck it up". You had to get used to that weird Eclipse WebContent directory in the first place, didn't you? Use something different. If you complain because your favored IDE won't let you change the directory, then really, you could as easily call that a problem with the IDE rather than Maven. But still, supposing for the sake of argument that your IDE is a fixed constant and it won't let you change its idea of what constitutes a reasonable directory structure, you can change the Maven defaults, it's just not the most desirable outcome.
Benefits of Maven's standard project directory structure redux (Director's Edition)
Suppose for the sake of argument that you bend over and take Maven's 14" standard directory structure (I should stop reading Hani's blog), what's in it for you?
Familiarity. Maven projects tend to get roughly the same layout. So you do one Maven project, and get a little used to where things are. On your next project you will be roughly familiar with where everything is. This will be true even if the second project is at another company, or from another company.
This is particularly important if you're an open source developer - the single biggest barrier to entry for a new project is the unfamiliarity to the interested developer. How the hell do I start, what libraries do I need, and where on earth is the file that I need to edit in order to change the background colour on the welcome page to puce for the good of humanity?
In Maven you know all these things. You start by kicking off a Maven install. That will download all the dependencies, so you don't need to figure out what libraries are required at all. If they're in your local repository that'll take seconds - if they're not, you get to footle around the web until it's done3. At this point you're in a position to get up and start contributing, because you've just built the project and you know where the source files live. I've joined companies where it took three days to get to that point! With Maven you've just reduced it to a matter of minutes.
Oh and incidentally, you can generate an Eclipse compatible .project and .classpath file for your Maven projects with the command mvn eclipse:eclipse (and zap them with mvn eclipse:clean). It's pretty neat.
In Conclusion
I used to hate Maven and now I have seen the light, Hallelujah (wave thurible throw holy water). You too can be a Maven for only $4.99 with this double DVD commemorative edition dinnerplate and/or cravat.
Ok, it's not quite that exciting. But it's a really useful tool and you shouldn't dismiss it like I initially did.
I don't have a comments section up and running as yet, but if you want to correct anything, or just violently disagree with my opinions, drop me an email: dave@paperstack.com. I will probably write a few more bits and pieces about Maven in the near future, so this is your chance to correct my misconceptions.
1 Actually it doesn't force you - the magic incantation to prevent the tests from kicking off is to add the flag -Dmaven.test.skip=true to a build. This is verbose enough to dissuade you from doing it frivolously but easy enough to remember that a failing test doesn't stop you from compile-testing some bit of sandbox code when you're working on a bugfix.
2 Repository = The place Maven expects to find files that it needs for the build - such as Jar files. For stuff you build, you get a "local" repository on your machine. Standard files like JUnit's JAR, or the various JAR files required to run Hibernate or Spring can usually be fetched from the iBiblio Maven repository and this is where Maven looks by default - look Ma, no configuration!
Typically in a corporate environment you'll also have a "company" repository where company libraries can be available to developers without making them available to the whole world. This is also a good place to put libraries that aren't yet in the iBiblio repository because they were created by Maven agnostic or anti developers, or because there are license restrictions (e.g. some of the Sun javax.* libraries can't be freely distributed.)
Files fetched over the network, be they from iBiblio, third party repositories (a variety of non-standard plugins can be downloaded from the Codehaus Mojo project's repository for example), or from your corporate repository are cached in your local repository so that downloads are kept to the absolute minimum. Snapshot (unversioned in-development) dependencies will be downloaded as and when they're updated, but not otherwise.
3If you're on GPRS wet-string-band at this point, and you haven't done a mvn install previously, there's nothing I can do to save you from the tedium of downloading missing libraries. However, if you have done one previously, you can provide Maven with the --offline flag and it won't try to talk to teh intarweb. In the unlikely event that you've got all the necessary (versioned) libraries available for your build and they're just not in the repository it's possible to add them, but that's sufficiently unlikely that I won't bother to address it here. Maven will prompt you when it can't find a dependency and offers up the appropriate incantation to add a local Jar file anyway.