Too many times I’ve seen this anti-pattern applied. So many that I’m here writing about it with the hope some of those applying it will read this post and stop doing it.
The anti-pattern I’m referring to is the one I christened Environment Aware Artifact, also known as The Production Build. If you don’t understand what I mean it is very possible you are either working in a single environment project (very unlikely) or you are actually applying this anti-pattern. In both cases, please keep reading!
The principle is simple: ensure your deployables/builds are environment agnostic. What that means truly depends on your specific application, but usually it can be condensed into this simple statement: externalize your environment configuration so that it is NOT bundled within your deployable but deployed separately.
Let me try to explain the previous sentence by using a Java example, but please consider this anti-pattern does not apply to Java environments only.
Say that you are developing a web application (what about an eCommerce web site?) which needs to invoke some sort of external service (let’s say it is the ePayment system). Probably you have to use different URIs for the external system depending if you are in a test environment (you don’t want to use the real ePayment service for your tests, do you?) or in a production environment (you want to collect real money from your customers, right?).
If you are a supporter of this anti-pattern you will create a configuration file (if it’s a Java properties or an XML it doesn’t matter) which will end up within your WAR: by doing this you will tie your deployable (the WAR file) to a specific environment (the one the configuration file refers to).
If you are asking yourself “What’s wrong with that?” then you are one hundred percent contributing to this anti-pattern: you are the reason for this article! The problem is you will have to rebuild the deployable every time you move from one environment to another which introduces errors and issues you would never expect (you can either trust me or experience them on your own skin, your choice). On top of that you are exposing environment related, potentially security related, information (what if instead of a URI we were talking about a password?), to everybody who is involved into the build chain!
If you are asking yourself “How can I achieve that?” you are starting to understand it is indeed an anti-pattern and I’m glad you are! As you can imagine different tools, systems, platforms and languages have separate ways of achieving such goal, some being simpler others being more complex. In other words you have to investigate your own selection, but in case you are using one of the platforms I use here are some advises.
Please consider it is generally more important to have an environment agnostic deployable rather than a container agnostic one: more than often the type of environment surrounding your final artifact is either pre-determined (corporate or project decision) or highly definable (installation instructions). If you have to decide between adding a step to your installation procedure and building multiple artifacts the former is 99.99% preferable!
Starting from version 4 of this wonderful application server you can provide system environment properties through the properties service: just put your environment specific configuration in a properties file and add that file to deploy/properties-service.xml to have them exposed to your deployables. Starting with version 7 the file name changed to standalone.xml or domain.xml, depending on the application server startup mode. Properties set as such will be readable as system ones.
I believe this feature has always been there, for sure starting from version 5.5 of the web container. It is part of the context definition and documented as, guess what, environment entries. Please note these configuration mode is readable through JNDI.
Other JavaEE containers
Most of the containers out there provide the ability to specify environment properties using their management interfaces, being them JNDI bound or available as system properties. Please refer to your container documentation.
Any JVM language in general
This is applicable to every language based on the JVM and any environment: deploy into the system JRE a library containing a configuration class which provides your configuration parameters. While this solution might be sub optimal in certain environments it’s definitely applicable to a broader set of cases, including desktop applications. With the proper adjustments it is applicable to many other platforms/languages as well, including C#, .NET and so on.