Search code examples
c#configurationrefactoringdependency-injectionseparation-of-concerns

Taking baby-steps in applying a better design


In wanting to get some hands-on experience of good OO design I've decided to try to apply separation of concerns on a legacy app.

I decided that I wasn't comfortable with these calls being scattered all over the code base.

ConfigurationManager.AppSettings["key"]

While I've already tackled this before by writing a helper class to encapsulate those calls into static methods I thought it could be an opportunity to go a bit further.

I realise that ultimately I should be aiming to use dependency injection and always be 'coding to interfaces'. But I don't want to take what seems like too big a step. In the meantime I'd like to take smaller steps towards that ultimate goal.

Can anyone enumerate the steps they would recommend?

Here are some that come to mind:

  • Have client code depend on an interface not a concrete implementation

  • Manually inject dependencies into an interface via constructor or property?

  • Before going to the effort of choosing and applying an IoC container how do I keep the code running?

  • In order to fulfil a dependency the default constructor of any class that needs a configuration value could use a Factory (with a static CreateObject() method)?

Surely I'll still have a concrete dependency on the Factory?...

I've dipped into Michael Feathers' book so I know that I need to introduce seams but I'm struggling to know when I've introduced enough or too many!

Update

Imagine that Client calls methods on WidgetLoader passing it the required dependencies (such as an IConfigReader)

WidgetLoader reads config to find out what Widgets to load and asks WidgetFactory to create each in turn

WidgetFactory reads config to know what state to put the Widgets into by default

WidgetFactory delegates to WidgetRepository to do the data access, which reads config to decide what diagnostics it should log

In each case above should the IConfigReader be passed like a hot potato between each member in the call chain?

Is a Factory the answer?

To clarify following some comments:

My primary aim is to gradually migrate some app settings out of the config file and into some other form of persistence. While I realise that with an injected dependency I can Extract and Override to get some unit testing goodness, my primary concern is not testing so much as to encapsulate enough to begin being ignorant of where the settings actually get persisted.


Solution

  • When refactoring a legacy code-base you want to iteratively make small changes over time. Here is one approach:

    • Create a new static class (i.e. MyConfigManager) with a method to get the app setting (i.e. GetAppSettingString( string key )

    • Do a global search and replace of "ConfigurationManager.AppSettings["key"] and replace instances with "MyConfigManager.GetAppSettingsString("key")"

    • Test and check-in

    Now your dependency on the ConfigurationManager is in one place. You can store your settings in a database or wherever, without having to change tons of code. Down side is that you still have a static dependency.

    Next step would be to change MyConfigManager into a regular instance class and inject it into classes where it is used. Best approach here is to do it incrementally.

    • Create an instance class (and an interface) alongside the static class.

    • Now that you have both, you can refactor the using classes slowly until they are all using the instance class. Inject the instance into the constructor (using the interface). Don't try for the big bang check-in if there are lots of usages. Just do it slowly and carefully over time.

    • Then just delete the static class.