Sometime ago I helped a client create an internal .net web application. One of the decisions that we had to make was on having a different web.config file for different environments. On a previous project, I had used xml poke nant tasks to do it. It had worked for us then, so I solved the problem in the same way here. This project was greenfield and we decided to go with Powershell and Psake (nant is xml and xml isn’t the best language for a deployment script). So we rolled out our own configuration manager. It took us some time to write, but we somehow managed to do it in Powershell. Each environment had its own config.xml file which contained environment specific properties. Our deployment script would just poke the web.config (which was dev config by default) with environment specific values. It kinda worked on the QA and UAT environment. However when we were supposed to deploy it to production, the ops guys had a policy where a sensitive thing such as a database password could not stay in the app folder and would be kept in the default .net config folder (which was locked down). Fair requirement, but our configuration management script would just break because even if the database password would be in the default .net directory, it would get overridden by the password in the app folder (because it was packaged with the code). This meant that for production, we had to delete the web.config file in the app directory and then the ops guys had to put in their version of the web.config in the default config folder. This approach had certain problems; for one the app structure and the deployment script were different in production and other environments. Another issue was that we had to manually give a new version of the web.config to the ops guys when we added or removed a section in the web.config.
This was before I had read the Continuous Delivery book which describes the same problem and suggests that you keep the code and configuration separate. I also worked on a project where we used Puppet extensively to manage configuration. That is when it struck me, that a lot (even all ?) of configuration belongs to the environment and not to the application. Keeping it tied to the application just makes it a maintenance nightmare. The other lesson I learnt was that we reinvented the wheel by writing our own configuration manager. Tools like Puppet and Chef already have solved the problem. You don’t need xml poke anymore, just a template with variables that vary across environment. You can have the passwords and other data stored in key value pairs or hierarchically (environment wise) in an external repository and just pull them when required. Production can have a different secure repository. There is a learning curve with the tools however, but it is definitely worth the time.
As developers we spend most of our time on dev and test environments, therefore we don’t see requirements that are very obvious to the ops guys. We design ‘elegant’ solutions where each ‘app owns it’s configuration’. From an automated deployment and continuous delivery perspective, this approach becomes a pain when the requirements of your environment change. A good approach is to have your dev configuration separately managed in exactly the same way as it would be in production by the same configuration management tool. I will never do xml poke ever again; after working with a configuration management tool it just feels like a hack.