Fixing Misconfigurations With Smart Defaults

In a recent article, we considered what value a program’s configuration provider should return when a setting is missing or misconfigured. We concluded that the returned value ought to be null in such situations. 

 

As an example, assume a pagination PageSize happens to be (incorrectly) configured to ‘Broccoli’. As expected, the string ‘Broccoli’ will fail to convert to a positive whole number required for a valid pagination page size, i.e. the maximum number of records we can retrieve in one call from a data store. 

The PageSize configuration retrieval operation should return an integer when it succeeds—or a null when it doesn’t.

 

Why would we bother returning null for a misconfiguration? How can application settings even be screwed up?! Aren’t config values part of a deployment script? 

Yes, they should be. And they should be fine. However, we developers write deployment scripts. And we sometimes make mistakes. Notwithstanding our human fallibility, as conscientious software engineers, we are responsible for creating robust applications that can handle missing and invalid configurations—if possible. 

 

One of the guiding principles of programming secure applications is to code for ‘Defence in Depth’, i.e. not merely secure the application boundary—entry points exposed to the outside world—but stymie deep in the program all malicious intruders who have made it past this first line of defence. 

Similarly, with configurations: If the settings retrieval mechanism fails to read acceptable values, the ability of config consumer logic to auto-correct—or self-heal ‘in depth’—to such unusable setup values can sometimes save the day.

 

Setting up a graceful recovery mechanism for configuration problems, whether unavailable or misdefined, won’t be possible for all or even most situations. It will only work in a minority of reasonably benign cases. Even so, there is value in preferring an elegant recovery rather than unexpectedly terminating the program.

 

So, if we have a null configuration value returned to us, how do we recover from that?

 

Simple—by providing a default value.

 

A hardcoded setting appropriate for the consuming logic. Not all hardcoding is unacceptable.

 

That would work in the case of our previous PageSize example. Again, here is the configuration interface definition:

  public interface IApiClientConfiguration
  {
     int? PageSize { get; }
     string BaseUrl { get; }
  }

Recapping, this PageSize pagination property specifies the maximum number of records returned from a hypothetic ApiClient, the consumer of this configuration.

 

In the code for the consuming ApiClient, we may set a PageSize fallback value of 20 when the configuration cannot retrieve a usable value. The assumption is that 20 records per page is a value that works well in most use cases.

 

  private const int DEFAULT_PAGE_SIZE = 20;
  private int PageSize => Config.PageSize ?? DEFAULT_PAGE_SIZE;

Note: In C# the ?? is the null coalescing operator. It evaluates the expression to its left and, if it is null, returns the expression to its right. Here, if Config.PageSize is null, we’ll assign DEFAULT_PAGE_SIZE.

 

However, even though defaulting PageSize is fine, the same cannot be said for the other configuration property, BaseUrl.

Why not?

 

Unlike PageSize, we likely cannot specify a base URL value that will always be valid and usable. For example, separate deployment environments will have distinct values for BaseUrl. While a default page size of 20 records per page might not be optimal, it represents a number that will work as a pagination page size every time. However, for the BaseUrl property, there is no URL that we can specify that we know will always be correct. After all, URLs change. And the last thing we want to do is to define a wrong default value. A hardcoded fallback is our last line of defence – it must be a good, universally usable value.

 

Conclusion

We can often increase our applications’ robustness by specifying default values for settings. This simple and effective technique only works when the default value applies universally.

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply