My colleague here at ThoughtWorks, Jez Humble, contends that the SNAPSHOT model that Maven uses is prohibitive to many of the principles espoused in his book. And I have to say, I largely agree with him.
Before diving into why I agree with him, it's worthwhile to add a bit of context. I'm one of a minority of people in ThoughtWorks that prefer Maven to Ant. That's not to say that we don't deliver projects using Maven, but if given a choice, most ThoughtWorkers prefer Ant. Personally, I have had a long history of using Maven, starting with my work with Spring Batch. That's not to say that Maven doesn't have it's problems, but if given a choice, I'll start a project with Maven. (Why that's the case would certainly be worthy of another blog post) I mention all of this because I am not bringing up issues with the release model of Maven to bash it because I hate the tool. I bring it up because I think there can be improvements in how Maven thinks about and deals with releases.
I remember the first time I had to cut a release with Maven oh so many years ago. I had my project working, everything was in exactly the state I wanted it to be into for release. All I needed to do was create the final cut. Like a good Maven user, I went to check out the documentation for how Maven approached releases. I quickly found the section on the release plugin and thought 'Aha, I just need to use this plugin, and my release will be painless, thanks Maven!' Of course, reality is never that simple. The maven release project has two 'phases' prepare, and then the actual release. Below is a list of what Maven does during the prepare phase, shamelessly pulled from the official plugin site:
- Check that there are no uncommitted changes in the sources
- Check that there are no SNAPSHOT dependencies
- Change the version in the POMs from x-SNAPSHOT to a new version (you will be prompted for the versions to use)
- Transform the SCM information in the POM to include the final destination of the tag
- Run the project tests against the modified POMs to confirm everything is in working order
- Commit the modified POMs
- Tag the code in the SCM with a version name (this will be prompted for)
- Bump the version in the POMs to a new value y-SNAPSHOT (these values will also be prompted for)
- Commit the modified POMs
I didn't understand that process years ago, and I still don't understand it today. I have my codebase, I've tested it thoroughly, both with unit, integration, automated, and manually testing. I just want to take the 'binary' that I've been using, and promote it to production while also taging the SCM revision that created it. Why does a snapshot state even matter? I suppose with external dependencies there are some concerns about APIs changing underneath you. However, what does it matter, you have working code, right now, surely the changing API is a problem for tomorrow, not the release of today?
In my time at ThoughtWorks, and other consulting experience, I have always prognosticated that the same build that a developer makes on his machine, and ultimately what will come out of CI (because he or she commits that revision) should look as identical as possible to what will be in production. Why add an extra step to change anything at all?
In short, I agree with Jez, why can't every artifact created from mvn deploy be potentially a release into production? The only value I've seen the snapshot concept add is away to describe a dependency as 'whatever the latest CI has produced is'. It seems to me its just as easy to say: 'any release greater than x.y' and call it a day, which is something Maven supports now as well, at least from a dependency declaration perspective.