I was recently pointed to a list of Maven Problems maintained on the JBoss wiki. This is actually a great summary of areas to improve, and I’m not surprised that the list is very close to the list of issues that the Maven community has been working to address over the past few months. In this post, I’ll take this chance to address each of the points raised on the JBoss Wiki.
Issue: No easy way to test multiple dependency configurations
Some projects, such as Hibernate would benefit from an easy way to configure multiple dependency configurations. This is especially useful for setting up multiple test configurations.
Being able to depend upon, or import, a specific set of dependencies was introduced in Maven 2.0.9 with a new “import scope” that allows you to import the dependencyManagement section from another pom. This works in some cases, but it was essentially a hack to introduce new functionality without changing the POM format.
A little background info: Maven 2.x has always used a POM model version 4.0.0, and the parsers in 2.x are not capable of understanding newer versions. This is a pretty significant issue that the team is well aware of since moving to a new model is required for most of the powerful things we need to do going forward. For now, it’s not clear how to do this in a way that allows projects built with a new model to be consumed by users of older versions of Maven. We have many ideas and could fill a whole blog post on that topic alone. Lets just say this is an unresolved blocker for solving issues like this.
What we specifically need to do to address this problem is to create a new first class element called TargetPlatform (to steal a term from the Eclipse world). This would allow better support of groups of dependencies that represent the runtime environment. Without changing the model, it isn’t possible to define these platforms in a useful way.
Issue: Maven builds are significantly slower than Ant builds.
A full build of the App server would take about 5-6 minutes and an incremental build about 1-2 minutes. With Maven, the build takes about 10-12 minutes for a full build and 3-5 minutes for an incremental build. Having fast incremental builds is very important to facilitate development.
I don’t think this is an apples-to-apples comparison. Maven by default executes your unit tests, which naturally takes longer. It’s been a while since I significantly used Ant, but the last I knew, it was not exactly incremental either.
Maven 3.x takes a significant step forward in performance. We now have a specific suite of performance tests that enable us to measure the impact of changes on the build performance. Because of this, Maven 3.x is anywhere from 25% – 2x faster than 2.x. Most of these changes have come about as part of improving the performance of the embedder and plugins for the upcoming M2eclipse .9.9 release. Specifically, an incremental build interface has been defined and several key plugins are now updated to use it. This means that in M2e builds, we can tightly integrate with the Eclipse builder and provide a list of things (files) a given plugin depends upon, and then communicate back the files that plugin has actually touched. This is the first step in being able to support full incremental build from the CLI, as many more plugins will need to implement the new interface before builds can become truly incremental like a good make based build can be.
Issue: Building a subset of modules
I definitely missed this from my Make days and long ago wrote a proposal for it. Dan Fabulich picked this up and implemented it first as a plugin for 2.0.x and then in the 2.1.x core. You can read about these Advanced Reactor Options in Maven: The Complete Reference.
Issue: Maven is limited for of sharing configuration
For example, in a multi-module build I might want to have a set of properties that are generated before any module build. This could be something like generate a timestamp, get the current svn revision, etc. In Maven these properties must be set separately for each module. If there was better support for shared module tasks, the properties configuration could be run before any module and the properties would easily be available to all the modules.
Currently the only way to share configuration is via inheritance. For example in Apache projects, we have a pretty robust toolchain for building our releases. If you want to use this in your project, you would have to copy all the associated XML since it wouldn’t make sense to inherit from our POMs.
We are working on a concept called “mixins” which is essentially composition in the poms. This will allow you to deploy and then later depend upon snippets of POM XML to compose your build.
Issue: One artifact per project rule
Maven has a general rule that there should be only a single artifact per project. This is important to maven dependency resolution, because there is only one set of dependencies in the POM. If multiple artifacts are generated in by a single POM (this commonly done by the assembly plugin) then there is no way to list a separate set of dependencies for the non-primary artifact. Maven projects also often include a -sources jar and a -javadocs jar. There is no intuitive way to generate a source jar for a secondary project jar. For example if my project includes a “-client” jar, then I might also want something like a “-client-sources” jar.
The idea here is to encourage separation of concerns. Traditionally people lump API, client and, server code into a giant build that spits out multiple artifacts. The way this is intended to work in Maven is that each one is it’s own project. For the most part, this holds up under all kinds of scenarios.
However, I have seen some issues when tools like Axis are used to generate the client and server directly from some other definition. There isn’t currently a clean solution for this when the resulting JARs have different dependencies. We’ve kicked around a few ideas, but no solid proposal exists yet.
I’ll address the rest in part two of this post.