Best Practices for Loading Application Settings

cdesign-patternsjavaobject-oriented

A simple way to keep the settings of a Java application is represented by a text file with ".properties" extension containing the identifier of each setting associated with a specific value (this value may be a number, string, date, etc..). C# uses a similar approach, but the text file must be named "App.config". In both cases, in source code you must initialize a specific class for reading settings: this class has a method that returns the value (as string) associated with the specified setting identifier.

// Java example
Properties config = new Properties();
config.load(...);
String valueStr = config.getProperty("listening-port");
// ...

// C# example
NameValueCollection setting = ConfigurationManager.AppSettings;
string valueStr = setting["listening-port"];
// ...

In both cases we should parse strings loaded from the configuration file and assign the ​​converted values to the related typed objects (parsing errors could occur during this phase). After the parsing step, we must check that the setting values ​​belong to a specific domain of validity: for example, the maximum size of a queue should be a positive value, some values ​​may be related (example: min < max), and so on.

Suppose that the application should load the settings as soon as it starts: in other words, the first operation performed by the application is to load the settings. Any invalid values for the settings ​​must be replaced automatically with default values​​: if this happens to a group of related settings, those settings are all set with default values.

The easiest way to perform these operations is to create a method that first parses all the settings, then checks the loaded values ​​and finally sets any default values​​. However maintenance is difficult if you use this approach: as the number of settings increases while developing the application, it becomes increasingly difficult to update the code.

In order to solve this problem, I had thought of using the Template Method pattern, as follows.

public abstract class Setting
{
    protected abstract bool TryParseValues();

    protected abstract bool CheckValues();

    public abstract void SetDefaultValues();

    /// <summary>
    /// Template Method
    /// </summary>
    public bool TrySetValuesOrDefault()
    {
        if (!TryParseValues() || !CheckValues())
        {
            // parsing error or domain error
            SetDefaultValues();
            return false;
        }
        return true;
    }
}

public class RangeSetting : Setting
{
    private string minStr, maxStr;
    private byte min, max;

    public RangeSetting(string minStr, maxStr)
    {
        this.minStr = minStr;
        this.maxStr = maxStr;
    }

    protected override bool TryParseValues()
    {
        return (byte.TryParse(minStr, out min)
            && byte.TryParse(maxStr, out max));
    }

    protected override bool CheckValues()
    {
        return (0 < min && min < max);
    }

    public override void SetDefaultValues()
    {
        min = 5;
        max = 10;
    }
}

The problem is that in this way we need to create a new class for each setting, even for a single value.
Are there other solutions to this kind of problem?

In summary:

  1. Easy maintenance: for example, the addition of one or more parameters.
  2. Extensibility: a first version of the application could read a single configuration file, but later versions may give the possibility of a multi-user setup (admin sets up a basic configuration, users can set only certain settings, etc..).
  3. Object oriented design.

Best Answer

Essentially the external configuration file is encoded as a YAML document. This is then parsed during application start up and mapped to a configuration object.

The final result is robust and above all simple to manage.