1

Simple question: What is the best/common practice regarding to throwing errors for application configuration providers?

Given is a simple key/value-based configuration source:

class Configuration
    string GetValue(key);
    void SetValue(key, value);

Or more extended, with the ability to add/remove key/value elements

class Configuration
    string GetValue(key);
    void SetValue(key, value);
    void AddKeyValuePair(string key, string value);
    void RemoveKeyValuePair(string key);

Not throwing exceptions on methods like GetValue() has the benefit of not interrupting the application flow and making code easier to read because of a lack of exception handling etc. It also allows to use null-conditional operators (maybe monads) or null-coalescing operators for e.g. setting defaults:

var value = configuration.GetValue("myKey") ?? "Hello World";

Return null simply tells the user: 'Whoops, got nothing to return since nothing is set/there'.

However..

If I'd avoid throwing exceptions, what would happen if I try to add a key/value pair which is already available? Or set the value with a key that isn't there in the underlying storage? Or removing a key/value pair that isn't available? Would it be obvious for the user that simply nothing happens when we tries to remove a none-existing key pair?

What is the prefered approach for application configuration?

1

It sounds like you are on the verge of Railway Oriented Programming.

As with most things there is no Right Way To Do It, only trade-offs. Exceptions are costly when thrown, but they are fairly standard practice in C#. Conversely, returning a pass/fail means you have to check the return value (if you care about it failing).

Using Exceptions, they will have to wrap calls to your code in try/catch blocks (which I never find fun). If you were going to avoid using exceptions for expected failures (key not found), I would change the API to make the return value explicit as to whether or not the configuration was changed. And make the methods clear as to expected preconditions (key present or not). That way, the caller can pick a method which allows them to ignore the return value. Or else they can explicitly handle the case where their requested change could not be performed.

Here is an example class with more explicit methods and return values.

class Configuration
    string GetValue(string key); // presence expected, null means not there
    bool ChangeExistingValue(string key, string value); // only change if present
    bool AddNewKeyValuePair(string key, string value); // add only if not present
    void AddOrUpdateValue(string key, string value); // obvious use
    bool RemoveKeyValuePair(string key); // obviously presence is expected

When called, I can choose the method I need (C#):

// don't want to add the value if it's not already there
// return value of false is ignored
config.ChangeExistingValue("asdf", "fdsa");

// -- vs --

// there is a problem if this value is not there
if (!config.ChangeExistingValue("asdf", "fdsa"))
    throw new SomeException(...);

// -- vs --

// I don't care about before, just put it in there now
config.AddOrUpdateValue("asdf", "fdsa");
1

First and foremost: What is a configuration for?

A configuration allows the user to change the behaviour of our application to influence the behavior of your application in some way or the other. Your application behaves in a certain, sane way but the user wants to customize the behaviour.

That said the perspective for your answers is the following:

If I'd avoid throwing exceptions, what would happen if I try to add a key/value pair which is already available?

Your application has a sane default behaviour. If the user decides to overwrite it, this is okay. If the user changes his mind, he should be able to do so without hassle as long as your application is in a sane state.

Or set the value with a key that isn't there in the underlying storage?

If your configutation should only accept certain values, and you should let your users know that.

Or removing a key/value pair that isn't available?

The purose of this action is, that you do not want a customized behaviour and instead want to rely on the defaults. You should handle this case gracefully and accept it in case of you would allow the set-operation in other cases let your user know that this configuration value isn't allowed.

Would it be obvious for the user that simply nothing happens when we tries to remove a none-existing key pair?

No. But would he care?

In case the user wants to get a value, which isn't explicitely set, return the (sane) default.

Regarding exceptions:

Exceptions are just that: exceptional behavior in case you could not handle the situation. Think of a Samurai - accomplish your mission or die trying.

Setting not allowed options is exceptional so it would be okay to throw an exception.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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