I found this post interesting for two reasons -
- It encapsulates (at least for me) the difference between a fresh out of University programmer and a more experienced programmer.
- I don't think it goes far enough - it can be extended further by introducing an abstraction with the added benefit of making it much easier to unit test.
As an inexperienced programmer just starting out it is all to easy (and I have done it myself) to start littering code with lines like this -
string emailTo = ConfigurationManager.AppSettings["emailTo"];
There are a few things wrong with doing this but the most important is what happens if for some reason it is decided to remove the application settings from the config file and use a database table instead? The only real option open to you in this case is an error prone find and replace routine - not ideal!
The answer is to not directly reference the ConfigurationManager but as the article suggests create a wrapper around it - so you would create an AppConfig class with methods for getting settings (see the referenced post for implementation details).
If this class is used correctly and consistently throughout the application then you now have only one class in your application where ConfigurationManager is referenced so now if a change is required to store in a database you only have to update the code in a single class.
This is where the post finishes and a year or so ago I probably would have as well but there is still a problem with it - what if after changing the code to read from a database your (indecisive) boss decides he wants to change back? You can start to see why this is not a particularly good way to go about things - it breaks the Open/Closed principal - once a class is built it should not be modified (except in the case of bugs which is a source of debate).
There is a much more elegant way to do this - simply create an abstraction. Couple this with Dependancy Injection and it becomes a very flexible solution to the problem. The way I would do it is to create the following interface -
public interface IConfigurationManager
{
public string GetSetting(string key, string defaultValue);
//Other methods for different types
}
Then you can refactor the AppConfig class to implement the interface - you can then refactor your calling code to use the interface rather than a concrete class and use Dependency Injection to supply an implementation at runtime.
Now if you need to change to a database storage system all you need to do is create a new class that implements the IConfigurationManager interface such as -
Now if you need to change to a database storage system all you need to do is create a new class that implements the IConfigurationManager interface such as -
public class DatabaseSettings : IConfigurationManager
{
public string GetSetting(string key, string defaultValue)
{
//pull setting from DB
}
}
Now the only place where you will need to alter any code is the code that wires up the Dependancy Injection configurations (which could be none at all if you have configured through XML/config file) - now the Open/Closed principal is not being violated and swapping back to the old method is simply a matter of changing the dependency injection configuration! A far better way to do things I'm sure you will agree.
Of course there is still more than can be done with this although I think that is good enough for now but for a more comprehensive example see this post
Of course there is still more than can be done with this although I think that is good enough for now but for a more comprehensive example see this post