|
Home |
Configuration ManagementAlmost every nontrivial software system requires some sort of configuration information stored outside of the compiled code in a mutable format. An application in development is almost always running in multiple environments, i.e. development, testing, build, or production servers. We generally need the ability to “point” an application at different databases, web services, or file paths based on environment. Hard coding this type of information into the code base itself is just not feasible. I was briefly involved with a mission critical application at a Fortune 500 company that put a database connection string into a constant field in all the database access classes. Prior to promoting the code to the testing or production environment a developer would manually change the connection string to the proper database and re-compile the code. Guess what happened when new team members forgot to make the change? Configuration with StructureMapA side-effect of Dependency Injection with StructureMap is that configuration properties are pushed into objects instead of the objects pulling information from an external file. This crucial difference creates two beneficial results.
Besides being a Dependency Injection framework, StructureMap is now an improved, fully object-oriented mechanism for application configuration. New in version 0.90 is a pair of custom NAnt tasks to validate configuration at “build time” and to deploy subsets or profiles of a master StructureMap.config file (StructureMap will support MSBuild when it is released). StructureMap can also diagnose configuration problems from a command line or in the build with an error code that can be cross-referenced with the TroubleShooting guide. It is even possible to decorate methods in a class to direct StructureMap to call one or more methods during verification to test runtime functions like database connectivity and web service availability. The goal of this new function is to detect configuration problems automatically in much the same way that a compiler finds syntax problems and unit tests catch errors. StructureMap can improve a Continuous Integration infrastructure to facilitate dependable, rapid cycling between coding, testing, and deployment. The MementoSource abstract class in StructureMap provides a “plugin” pattern for external sources of configuration. This point of flexibility was intended to allow for storing configuration in central sources like Active Directory, databases, or for special encrypted configuration. Users can create new MementoSource implementations and plug them into StructureMap. Continuous IntegrationStructureMap was originally built for usage on a heavy client application backed by web services on an application server and a relational database on the backend. The development team utilized both Test Driven Development and Continous Integration to support a rapid iterative process largely based on Extreme Programming. The application ran in basically three different configurations.
ChallengesThe validation and troubleshooting improvements in StructureMap are largely a reaction to the difficulties and lessons learned from the development process described above. Application code cannot function correctly without the correct configuration, but errors in configuration cannot be found automatically by the compiler and probably will not be found by automated unit tests in the build. Runtime errors often ocurred when a configuration setting was created or changed. Multiple versions of configuration settings must be maintained and deployed correctly for different environments and possibly even different developer workstations. Problems can proliferate when a new or modified configuration key or section is not propagated to all possible configuration files. The typical “but it works on my box” situation is often a result of invalid configuration in the testing environment. A common problem on the original project was the occasional tester client trying to connect to nonexistent services on “localhost.” The development team lost time troubleshooting the testing environment. The structuremap.verification NAnt step was created specifically to validate and diagnose a testing (or any other) environment before the testing team used a new build. Using the validation step within a Continuous Integration build can help spot configuration issues early. The structuremap.deployment task was created to reduce the overhead of managing multiple configuration files. By centralizing all configuration profiles into one file it became easier to manage multiple configuration sets. If a new plugin type was added to the system, only one file needed to be changed. The build process would replicate a subset of the master configuration file each profile and deployment target ("client" or "server"). A dependency on external configuration increases “friction” in automated unit testing. Test Driven Development (TDD) and its close cousin Continuous Integration (CI) succeed when coded classes are easily instantiated and can function in relative isolation. Unit tests should also reveal the intent of the code being tested as explicitly as possible. A class that pulls information from a configuration file is harder to test because of the overhead of setting up and copying testing configuration files around in post-build steps or automated build files. In addition the unit test is less understandable because it is pulling input data from a file external to the unit test. Simply put, a dependency on configuration of any kind will make TDD more difficult. |