Thursday, January 20, 2011

The Artifact per Environment Anti-Pattern

The Problem

How to handle environment specific properties is a topic that seems to generate much discussion.

While initially this may seem a trivial problem as requirements grow the complexity of the solutions will also. Here are some of the requirements you might have to tackle:
  • Overriding default properties
  • Dealing with properties that need to kept secret to the development team e.g. production passwords 
  • Properties that need to be changed dynamically (tuned) while the app is running e.g. cache configuration
  • The addition of new environments after the original artifact has been built
I've seen countless approaches to the problem - properties in the jndi tree, in the database, good old property files, pojo's etc. Each has its own pro's and con's and can range from simple implementations to hugely complex frameworks.

Not the Solution

One solution that is often suggested is rebuilding the artifact per environment and "baking" in the environment specific properties. This pattern very standard in Grails (http://www.grails.org/Environments) and often recommended for Maven (http://www.sonatype.com/books/maven-book/reference/profiles-sect-tips-tricks.html)

Now I'm sure there are many situations where this works perfectly well - a blunt axe can still chop a tree down!  But, I believe that for many reasons its sub-optimal.. 

The Downsides an Artifact per Environment:
  • Inefficient - the simple fact that do you have to rebuild the artifact for each environment is time consuming and involves repetition of effort
  • Risky - After testing your artifact in your test environment you are then going to deploy a different artefact that was never tested to production
  • Unnecessary Builds - If the properties change after you build the artifact - you need to build it again! 
  • Hard to diagnose problems - did some deploy the test war to production by accident? Get used to having to crack open jar's and war's to check the config.
  • Not compatible with Maven repositories - Maven repositories work best with one version of an artifact per version number - e.g. there's only one Apache commons-collections 3.2.1. An artefact per environment breaks this.
The Alternatives:

So what to do instead? Generally the best way to go is to externalise your properties from the artefact and then have it choose the correct properties at runtime. This is too general an area for one prescriptive approach but hopefully this article has ruled out building an artifact per environment.

Links:

Some ways to load properties from locations dependent on system variables in Spring 

Externalising Grails config

1 comment:

  1. I think it works nicely having properties loaded from JNDI and thus configured per environment in the app server (or tomcat for local development)

    ReplyDelete