12

If you add new configuration options to a program, it can often have tons of ripple effects in terms of getting the options to where they need to be acted upon. There are three basic ways to deal with this that I'm aware of:

  1. Pass all configuration settings to the parts of your program that need them explicitly as primitives. This is the most explicit way and the way that decouples things the most. The downside is that this is both verbose and brittle.

  2. Make the most frequently used configuration settings global/static. This is the simplest way but introduces action at a distance, hinders testability and assumes that the configuration truly is global (that you'd only want one configuration at any given time).

  3. Make a configuration class/struct that contains all the configuration options for the whole program or for each major concern within the program, and then pass this around explicitly. This is less explicit than (1) but more explicit than (2). If you want to change a setting just for one function call, you can clone the config object and change this one value. This is useful in both testing and in practice. However, you still end up potentially passing tons of info to a function that it doesn't need and changing a value in the config class/struct can still cause action at a distance.

Would you consider (3) a pattern or an anti-pattern? If it's an anti-pattern, what do you do instead?

2
  • 1
    How about a variation on 3 - having several configuration classes, passing the appropriate one to where it is needed?
    – Oded
    Oct 18, 2011 at 15:13
  • @Oded: I meant to emphasize that as a possibility. Edited.
    – dsimcha
    Oct 18, 2011 at 15:15

5 Answers 5

5

The best solution would be to make several configuration interfaces and implement them as you wish. This both limits accessibility and keeps things localized. However, it's far too much effort to be worth it over simply chucking all the config in a single class and moving on to a problem with a lot more gravitas. This is the configuration, not the UtterlyCrucialAlwaysChangingClass- it's pretty much going to stay the same. As long as you don't make it all global, and the implementation is consistent, I wouldn't worry about it.

3
  • 8
    +1 for saying that something isn't theoretically ideal design but might still be good in practice when simplicity and likelihood of change (or lack thereof) is considered.
    – dsimcha
    Oct 18, 2011 at 16:40
  • I just threw out four arguments and replaced it with a Settings class. It felt like the right thing. May 17, 2014 at 13:39
  • I don't understand which of the 3 options you're advocating. Could you please specify?
    – DBedrenko
    Sep 25, 2015 at 7:32
1

I prefer your option 1 because the decoupling enables easier testing, and the configuration settings the object depends on are made explicit. If an object requires a configuration setting, then explicitly provide it to the object by a constructor argument or setter method. Reduce the verbosity by using a dependency injection framework to inject those configuration settings into the object.

1
  • You've contradicted yourself: you say to use Option 1, but then say "Reduce the verbosity by using a dependency injection framework to inject those configuration settings into the object." which is Option 3: constructor injection.
    – DBedrenko
    Sep 25, 2015 at 8:31
0

Imagine if your configuration file was written in XML. You could then just pass fragments of this XML to each of your components, so they get their configuration data.

If you are using .NET, you can create classes with DataContracts that you can use the XmlSerialiser to create an object hierachy from your configuration Xml, and pass these objects around as configuration.

This then introduces you to the next problem. Your configuration data has three different parts to it. The structural application configuration that organises your code libraries to behave as this specific product. Site configuration settings that contain your installation specific settings and User preference/settings data that varies with each user on your system.

Knowing which part is which, and keeping these data settings seperate will make installing updates much simpler (without loosing customers settings)

0

I would make the class in option #3 static. So instead of

//create SomeCl
Foo f = new Foo();
f.setConfigInst(cfg);
...
...
//Inside Foo
public void setConfig(MyAppConfig c) { localCfg = c; }
...
//somewhere else:
x = localCfg.getConfigForX();

You can just have:

//Inside Foo
x = MyAppConfig.getConfigForX();

Let the details of loading/saving configuration data happen inside MyAppConfig class. And of course you could have more complex variations, such as different classes for different purposes.

The only case where this approach would be a problem would be if you for some reason needed to work on multiple instances of different configurations at the same time, although I have yet to come across such a situation.

1
  • 1
    Which is what pretty much happens when running unit tests in some testing frameworks... But even without explicitly parallel unit tests, it is going to be a pain in the ass to unit test objects which depend on global state. Oct 18, 2011 at 15:41
0

I'm working on a project where we are using the "3 layers (interface, business logic, data access)" approach. The application can be a multiuser web server or client server.

We work with 3 different configurations, the first specific for the P.C., wheter the user is working. The second specific for the current user, and a third global configuration for all users & client apps.

Each configuration is represented in each instace of the application by an object.

This approach may help your project.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.