Barry is an experienced Java developer and architect living and working in London. He has experience across a range of industries, Finance and Media in particular. Barry has posted 2 posts at DZone. View Full User Profile

The Artifact per Environment Anti-Pattern

01.21.2011
| 7646 views |
  • submit to reddit
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  http://stackoverflow.com/questions/1311360/property-placeholder-location-from-another-property/1312341#1312341

Externalising Grails config http://phatness.com/2010/03/how-to-externalize-your-grails-configuration/

From: http://decodify.blogspot.com/2011/01/artifact-per-environment-anti-pattern.html/
Published at DZone with permission of its author, Barry Fitzgerald.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Kjetil Ødegaard replied on Fri, 2011/01/21 - 10:47am

One alternative is to load the configuration files from classpath. Most application servers support configuring this per application.

Irek IrekM replied on Fri, 2011/01/21 - 11:50am

Some time ago I also came to conclusion that artifact-per-environment is bad: I've often seen stuff like somejar-windows, somejar-linux, somewar-tomcat, somewar-jboss, somejar, somejar-tests, and so on. In short, lots of hassle for both developers and end users.
My solution is to keep everything in one jar (or war), and this jar should try to configure itself automatically at runtime: eg it can try to detect web server, and 'modify' some behaviors to work on it, it can detect operating system and 'modify' behavior of application.
In case of smaller applications even database runs on the same machine, so the jar/war can configure it itself at startup or installation phase. Have you seen installation screens in webappz like Joomla! - pretty cool (although I'm not saying that perfect).

Automatize everything you can! Although writing any kind of 'installatio script' costs, it pays off: automation also reduces programmer cost, tester cost, end-admin cost and helpdesk cost.

Andrew Spencer replied on Mon, 2011/01/24 - 5:46am

I totally agree. I wrote here about it being an anti-pattern use of Maven profiles, but I didn't think to describe it as an anti-pattern, and I didn't do as good a job of explaining the downsides as you just did.

Whilst you're right that a prescriptive approach won't help, I would love to see a sort of mini-catalogue of the options. (At my current client, the approach is to read a properties file into the Spring context. This is loaded as a file rather than a classpath resource, and there's only one file per app-server...not ideal.)

cowwoc replied on Mon, 2011/01/24 - 5:04pm

Really? I'd love to know how you plan on building a single artifact containing DLL/SOs for Windows, Linux, MacOSX, IRIX, etc. You won't be able to. Each artifact needs to get build under its own operating system.

 

Maven is great for 90% of cases but it does very poorly for the remaining 10%. This case falls squarely in the "poorly handled" section. Take a look at http://stackoverflow.com/questions/4171222/maven-depending-on-inheriting-artifact-causes-build-error

Thomas Kern replied on Thu, 2012/09/06 - 10:59am

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

http://www.java-tips.org 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.