Continuous Mindset
When I first set out on my quest to integrate Maven into a Continuous Delivery deployment pipeline, I was pretty used to working with Maven SNAPSHOTs. Back then I wouldn’t have dreamed of getting rid of them because I couldn’t see how or why I should do so. That’s all changed for me now though because as I read and re-read the excellent Continuous Delivery book, it finally sunk in that you can live without SNAPSHOTs – if you think a bit differently.
One of the overarching goals of the Continuous Delivery deployment pipeline is to make releases into production so common and so frequent that we can live up to the first principle of the Agile Manifesto:
Our highest priority is to satisfy the customer through early and continuous delivery of valuable software.
After working with Maven for years, all the time using SNAPSHOTs, how could I possibly come to believe that they aren’t needed anymore? Isn’t that Maven heresy (or some techno-crime variant)?
There was a change in my thinking along the way. Here’s how I used to think about it:
It sure does seem like SNAPSHOTs make it easy to develop because I can pick up other developer’s changes via their SNAPSHOT versioned artifacts just by updating my dependencies. We’ll get around to releasing when we’re ready, but hey right now I just need to get some coding done! Come back later when I have that done and then we’ll talk about the release!
Did that last bit sound like procrastination to you? Upon reflection I realized that while us developers really like the SNAPSHOT, it does little to move our software into production. In fact, the SNAPSHOT is a bit of a crutch because it has temporary written all over it. While we can’t release a temporary artifact, we sure can develop around it with the latest changes magically arriving via SNAPSHOT updates. But how are we going to reconcile that with Continuous Delivery?
Here’s how I think about SNAPSHOTs now with a Continuous Delivery mindset:
I’ll work in one source codebase that has no SNAPSHOT dependencies and every time I commit to Subversion, the Jenkins continuous integration server deploys a releasable artifact into the Nexus Maven repository. If I need the latest changes from other developers, I will update my local source codebase from the Subversion repository. This means that I’ll need to build the whole project, but it also means that when I test my code I’ll be in sync with the other developers.
However I won’t need to build all of the modules every time I make a coding change, but if I really expect this business application to ship with everything working (say tomorrow, or perhaps next week) it would be wise for me to stay on top of those other developer’s changes as I work.
Maven includes a command option that will let you perform a build on a subset of the modules in a multimodule project. You just need to let it know you want to do so. For instance, the following Maven command builds just the demo-domain module in our sample multimodule project:
mvn --projects demo-domain clean install
The Enforcer
The Maven enforcer plugin comes with rules that can enforce no SNAPSHOT versions. When a rule is violated the enforcer plugin will fail the build. That way we’ll know immediately when either the project version or a dependency is using a SNAPSHOT version.
The LOCAL suffix on the version supports builds on a developer workstation. The developer can build and install artifacts into the local Maven repository (~/.m2/repository) that include the LOCAL suffix. However, when Jenkins builds the project, the version will include the Subversion revision number instead of LOCAL as was described in a previous article.
The following plugin configuration illustrates how to enforce a no SNAPSHOT versions project:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.0.1</version>
<executions>
<execution>
<id>enforce-no-snapshots-and-version-format</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireProperty>
<property>project.version</property>
<message>"Project version must comply with standard."</message>
<regex>^\d+\.\d+\.\d+-(LOCAL|\d+)$</regex>
<regexMessage>"Project version must include major.minor.patch
number parts and end in svn revision number or LOCAL (e.g.,
1.2.0-LOCAL)."
</regexMessage>
</requireProperty>
<requireReleaseVersion>
<message>current project must not be a snapshot</message>
</requireReleaseVersion>
<requireReleaseDeps>
<message>no snapshot dependencies allowed</message>
</requireReleaseDeps>
</rules>
<fail>true</fail>
</configuration>
</execution>
</executions>
</plugin>
Living without SNAPSHOTs
So now that we’ve rigged up a POM that enforces no SNAPSHOTs, can we live with it? Does it still let developers develop and also work with Continuous Delivery? Well my short answer is that I think it can work. The longer answer is that this needs to be battle-tested on real projects for a while before making any grand claims for success. As with all technical endeavors, this sort of thing is always a moving target. For example, the recently released Thoughtworks Technology Radar report has put Maven on hold and recommends considering a move to Gradle.
For those of us that are going to stick with Maven for some time, there’s more to this story regarding the deployment pipeline. And I’ll be writing about some of these other topics in future articles. So for now, let’s just say that while SNAPSHOTs are a thing of the past in some circles, there are plenty of other challenges when it comes to fulfilling the goals around delivering software that we can ponder.
