Friday, December 16, 2011

Starting in Maven?

by Richard Vowles

It surprises me again and again when I meet developers who are using Maven and they don't have a local repository. For anyone using Maven, once the decision has been made to actually use it, the next thing you do is get a local Maven repository. Really, its at the top of my list for things to do.

If you are working on projects at home, open source or not, at work with a single developer, whatever, you should install a Repository Manager. If you have more than one developer using Maven, you are simply insane not to use a one. So why would you install a repository manager even if you are only a single developer? Surely its hard?

Well, no, it is incredibly simple, Sonatype's Nexus takes 10 minutes to set up for example. Here are a few if you don't already have one:

  • Sonatype's Nexus - this comes in a Pro and Free version. I use Free in three different places and it has served me very well. 
  • Apache Archiva - I used this in my last job, and I didn't like it as much as I like Nexus. It seemed a little more complex to set up. 
  • JFrog's Artifactory - I haven't used this, but they do a lot with the Gradle community and are going to do some work around Grails plugins. 
So back to why? A few reasons
  • Unfortunately, not everything is in Maven Central. This means you have to edit your settings.xml to add each repo in as you need it. Don't, put them in your Repository Manager and just point to it - let it sort them out. Add a new repo? Just add it in the Repository Manager. 
  • If you are doing Maven releases properly, you are using version ranges. Version ranges cause Maven to scan all repos in your settings.xml for updates on a regular basis - and you don't want this traffic going far if you can help it, it slows you right down.
  • If you don't have a Repository Manager, you are either (a) not releasing you artifact (a cardinal sin) or (b) only releasing to central (which is feasible for some projects, e.g. easyb). 
  • It allows you to blow away your local repository when it gets untidy from snapshot builds which people use periodically. Note if you do everything using snapshot builds, you are using Maven in a  broken fashion.
  • You can put a Repository Manager on your own machine as a proxy as well, if you want to keep as much network traffic local for example, but you have the main Repository Manager hosted elsewhere - on a slow VPN or in another country.
Releasing
I've known people working on projects who have never released - they just work with snapshots! Thats nuts! A release in maven is an individual artifact (your entire war would be one, as well as an individual api) - it is something that has been cleaned, started from scratch, compiled, verified, all tests run, tagged in the remote repository, checked out again to a different location and all  that done again and then uploaded to your Repository Manager. You should be releasing very regularly. And be fine grained about your artifacts! As soon as you have done a significant lot of work, release it. 

Version Ranges
Version ranges are important for two main areas of Maven usage. 
  • You have chosen an open source project based on its functionality, license, code quality, whatever. But you choose a specific version. For example, in a recent project we chose SOLR - 3.3.0. Our use of the 3.3.0 means we use <version>[3.3.0]</version> as our version. This means I want 3.3.0 and nothing else. Not 3.3.1, not 3.3.5, not 3.4.0. Why is that important? SOLR when it released 3.4.0 caused the meta data in (Apache) Maven Central to get corrupted - this means the only version available was 3.4.0. If I had instead specified <version>3.3.0</version> - if Maven didn't have it locally, it would go pick up 3.4.0 and happily use it. If the corruption had caused only 2.3.0 to be available, Maven would have used that - it would have been a mess! Always specify exactly what ranges you are  happy to include artifacts for - if stuff breaks, lodge JIRA tickets on Sonatype's JIRA, they are pretty quick about it and will be ensured actually using what you have chosen. 
  • Generally projects decide on how they issue a new version number - some just use two (major.minor), where the major changes on a breaking api change, some use three levels. You should specify a range when you are happy so new releases turn up - and typically you will do this of your own artifacts. You start at version 1.1 (because thats how ranges work, don't start at 1.0 or 0.x, thats just nonsense) and keep releasing until you break. Release early and often. If someone then who is using your artifact says [1,2) or say [1.7,2) (if 1.7 is the start of your api having what they want) then they will just get new releases as they come out, ensuring they keep current. These kinds of version ranges make Maven use really nice and easy to use when it comes to dependencies (along with composites, another post). 
Composites are just pom's that contain a collection of dependencies - we have composite-cxf, composite-spring, composite-jackson, composite-logging-api, composite-logging-api, etc. Composites keep your pom clean, they take out all of the stuff that isn't really specifically to do with your App, but the kind of App you are building. They become accepted building blocks - and they rev. like normal artifacts. Changing from Spring 2.5 to Spring 3.1? rev the major version of your pom - existing artifacts won't be broken, you can fix them as necessary. Composites can be great for public facing releases as well - if Wicket 1.6 was just a pom containing fine grained artifacts that were hard version ranged, then we they released bug fixes (early and often), you could override specific artifacts and bring in the new releases to get the ones you want. 

And another cardinal sin - it happens, but rarely, do not put dependencies in parent poms. Except for the plugins which often need them (and try and use composites for them), but your parent poms should not have modules or dependencies defined. Put them in the composites. 
(It sometimes happens when you are using projects that are so terribly broken you can't help it, but its rare)

Do yourself a favour, if you are using Maven, install a Repository Manager.