When you’ve put a lot of work into something, personal pride (or maybe a lack of humility!) can make it difficult to accept that a rival system is superior. It was for this reason that I started investigating Maven 2 with a degree of reluctance. Surely our custom-extended, all conquering [tag]Ant[/tag]-based build and dependency management system could not be bettered? Who is this new pretender to the throne? And what does it want?
Is It Some Kind of Bird?
No, despite sounding like one, [tag]Maven[/tag] is, according to it’s homepage, a “software project management and comprehension tool” (note: when referring to Maven you can assume I’m talking about Maven 2). It’s mainly used for build management and dependency management in Java projects, from the command line.
At the moment, Ant is king in DSI. It’s used to build, package and deploy enterprise apps, and everything in between. A lot of the configuration involved with Ant has been standardised (in centralised common-ant scripts), and these shared scripts create and rely on a standard DSI project structure. Dependency management is taken care of by a DSI-customized version of Savant (an extension of Ant itself). So a lot of configuration and customisation of Ant has been performed to get to where we are today. So why should we even consider throwing all that work away by switching to another system? We should consider it because Maven does all of the above out of the box.
Convention > Configuration
I won’t go into too much detail about how to use Maven (that’s done very well here), but I will give a brief overview. Maven favours convention over configuration. Put simply, it presumes that most projects will have the same configuration (just like our common-ant scripts do). In a Maven-based project I worked on recently for a UK-based customer, my project lead was “flabbergasted” when he initially brought down the project from the customer SVN repo and it built first-time in his local environment. It’s not often that he’s flabbergasted – proof enough for me that this convention over config Maven implementation is worth it’s salt. The project in question consisted of 23 separate modules or sub-projects.
It’s difficult to talk about Maven without mentioning the POM (Project Object Model), the heart of Maven. The POM is the near-equivalent of an Ant build.xml, but it’s layout is not:
<project xmlns= http://maven.apache.org/POM/4.0.0
Each project has it’s own POM. From the simple and succinct pom.xml above, Maven has enough information to compile source files, run unit tests, and package the project output into a jar. Maven assumes that your source files are in srcmain and your unit tests are in srctest (although this can be changed).
Maven has a different approach to Savant when it comes to handling multiple projects that are linked through dependency (e.g. web -> business -> data tier projects). A ‘master’ POM is located one directory level above where the projects are stored, listing the projects or ‘modules’ within a modules node. Each module must be made aware that it has a master POM, and once everyone’s happy Maven is able to work out the dependencies between the projects automatically.
The configuration data defined in POMs is used to produce and deploy project artifacts, but configuration data alone is not enough.
Rather nicely, Maven uses plugins to perform all of the work it does. For example, Java compilation is performed using the compile goal of the compiler plugin (a goal is an individual atomic command similar to an Ant task). Likewise jar creation is handled by the jar plugin. As well as compiler, jar and other core plugins, more are available here for additional functionality. These plugin goals can be run directly, but more commonly they are run as part of a lifecycle command.
A lifecycle command (like Ant targets) groups a series of plugin commands together. Built-in lifecycle commands include compile, which compiles the source code of the project, and package, which builds a jar/war file.
Maven really shines in this area. Dependencies are, shockingly, defined in the dependencies node of a POM (see JUnit dependency definition in sample POM above).
Like Savant, Maven utilises a remote shared repository, along with a local repository to cache previously retrieved artifacts. However, whereas Savant only has a .deps file for each artifact, listing it’s dependencies, Maven includes the full POM for each artifact, containing, as well as dependency information, license information and everything else the original developers have specified.
A quick note on remote repo’s – Maven’s default remote repo is held on Ibiblio, a huge repository of OSS software. Artifacts are downloaded as needed automatically via the internet to the local repo. This is a lovely feature, but some form of license checking will need to be performed to ensure the artifact’s license type/version is allowed (this check is already performed in the latest release of DSI-Savant), and there could be problems working offline (having to rely on the local cache could cause problems).
Maven and Continuous Integration
I’ve worked on a project that used Maven with Bamboo, and my lowly developer’s impression was that they worked well together without any problems. Bamboo has native support for Maven (as does Luntbuild). Seeing as Maven can be run from the command line, it can be made to work with most (all?) CI systems.
What About Flavoured Builds?
Flavoured builds are an integral part of the existing build system in DSI. The build flavour is set by an Ant property, and there’s little hassle involved. Surely Maven has something just as good, if not better? Well no, not really. Maven uses profiles, which to be honest are overkill when it comes to what flavoured builds are used for here. Savant wins this one.
The ease of reuse of build functionality (stored in Maven plugins), as well as a cleaner and more complete dependency management mechanism gives Maven a clear advantage over Ant, even with the added niceties of Savant and the custom DSI-specific functionality that has been lovingly incorporated (yes, Maven has the edge even with all the nice work put in to DSI-Savant, consider my pride swallowed).
However, not everyone thinks of Maven in positive terms, especially when switching over existing projects, particularly large ones with multiple modules and large Ant scripts. This might prove more trouble than it’s worth. But for new Java projects, Maven is the way, for sure.