The Maven Way™

Stephen Connolly's picture

If you follow the Apache Maven mailing lists, there is an oft-invoked but never defined term that crops up:

The Maven Way™

(Ok, so it’s not really a trademark. Apache, Apache Maven and Maven are all trademarks of the Apache Software Foundation though)

Well as part of a conversation on the mailing list, it seems I may have hit upon a definition by example of what exactly The Maven Way is:

<project>
  <groupId>…</groupId>
  <artifactId>…</artifactId>
  <version>…</version>
  <packaging>…</packaging>
  <dependencies>
  </dependencies>
</project>

The more lines you add to the above project template, the further from The Maven Way you are.

It’s not wrong to be far from The Maven Way… it’s just a difficult and uncomfortable place to be.

To quote another subscriber to the mailing list

The above describes what the project is. The more you have to tinker with plugins and the like, the more likely you are describing how the project should be built.

Maven exists to figure out how after you have told it what.

- Mark Wood

When building new types of things it’s ok, perhaps even expected, to venture far from The Maven Way… but once you figure out how that new type of thing should be built, the idea is to codify that best practice into plugins and if necessary a packaging type so that others need only say <packaging>new-type-of-thing</packaging> (See note below) and they are right there on The Maven Way for building that new type of thing.

Note: of course when referencing a packaging type that is not in the default list (i.e. jar,war,ear,rar,pom) you will need to add the lines defining the <extension> that defines the packaging type, but that is far far closer to The Maven Way than adding 15 plugin definitions with configuration to hijack an existing packaging type and subvert it for the purpose of building a new type of thing.  

—Stephen Connolly
CloudBees
www.cloudbees.com

Stephen Connolly has over 20 years experience in software development. He is involved in a number of open source projects, including Jenkins. Stephen was one of the first non-Sun committers to the Jenkins project and developed the weather icons. Stephen lives in Dublin, Ireland - where the weather icons are particularly useful. Follow Stephen on Twitter and on his blog.

Comments

I completely agree with you here, and you say it much better that I could. There's just one annoying thing: you cannot define a custom packaging and use it from the same reactor build. While this is totally understandable, this is still an annoying limitation as it makes it unnecessarily hard to <i>eat your own dogfood</i>.<br /><br />In my specific case, I have a plugin that depends on some modules of the reactor (gwt-maven-plugin depends on gwt-compiler which itself depends on a few other modules such as gwt-core-client) and I'd like other modules to use the custom packaging defined by the plugin. I thus have to call the plugin without its extensions (i.e. custom packaging), and because the custom packaging has a custom lifecycle that replaces a few other plugins from the JAR packaging, I have to disable them (and because this only applies to some of the modules, I have to repeat the configuration in each one of these modules or introduce a "parent POM" just for that).
Stephen Connolly's picture

The problem you describe is a side-effect of a release cadence mismatch. Maven plugins and extensions are supposed to be shared across projects. Consuming them from the same reactor that produces them is a sign of sub-optimal project structure or sub-optimal plugin design. For example, your custom packaging should not be changing with every release of gwt-compiler. Thus you either rely on the bootstrap solution (where the 2.4.3-SNAPSHOT build uses the 2.4.2 release of the custom packaging) or you decouple the two so that the packaging is a separate release root. Similarly, the Maven plugin itself should not be radically changing with every release, in fact ideally you should be able to do something like this... my.group-id my-compiler-maven-plugin 2.4.2 my.group-id my-compiler-core 2.4.3-SNAPSHOT So that you are using the previously released Maven plugin (which should be just a simple shell on your core workhorse) but attaching the current core. If your Maven plugin won't work that way, then that is a sign of sub-optimal plugin design. Now when it comes to testing the 2.4.3-SNAPSHOT version of the plugin with the latest core, that's where maven-invoker-plugin comes in for integration testing. So for your specific case, your building of the gwt toolchain is further from the Maven way because you are beating out the path that is The Maven Way™ for GWT projects (at least until somebody else finds a nicer path, if there is one ;-) ) It would be great if we could find ways to make it easier for you to beat that path, but Maven wants to construct the build plan before it starts building to ensure that: when in parallel mode it knows what can be run concurrently; and that it can build dependencies before the projects that depend on them... thus building maven plugins and/or build extensions will always have to be a bit special

Damn you html tag stripping...<br /><br />using []'s instead of <><br /><br />[plugin]<br /> [groupId]my.group-id[/groupId]<br /> [artifactId]my-compiler-maven-plugin[/artifactId]<br /> [version]2.4.2[/version]<br /> [dependencies]<br /> [dependency]<br /> [groupId]my.group-id[/groupId]<br /> [artifactId]my-compiler-core[/artifactId]<br /> [version]2.4.3-SNAPSHOT[/version]<br /> [/dependency]<br /> [/dependencies]<br />[/plugin]

Add new comment