Software development

Singletons are not your enemy

The singleton design pattern ensures that a class can be instantiated once only. It provides easy access by means of a global operation that returns this single instance.

Definition of the singleton design pattern

A large portion of the programming community has recognized the singleton design pattern as an antipattern that is best avoided. This recognition is strong enough that most developers won’t touch a singleton with a ten-foot pole, even if their lives depend on it. I have a problem with most extreme opinions, mainly because they are usually quite wrong. And this is one of those, a pseudo truth that is being repeated over and over again like a prayer without questioning. Some high deity in the form of a prominent developer once spoke it out in a general context, and it’s being applied to every single programming scenario ever since. A big issue here is that it’s all based on how a definition from the Gang of Four, published in 1994, was being implemented and used over the years, and how these implementations had their flaws. And then it’s being applied to languages like C#, which wasn’t published until eight years later and which received loads of improvements during the years. The even bigger issue is that the criticism is purely targetting the standard implementation that can be found almost anywhere on the internet. As a result, the commonly accepted lore says that singletons are to be avoided because they …

  • … can introduce global state where it is not beneficial.
  • … are tightly coupled to calling code (can’t be mocked).
  • … hide dependencies (accessible from anywhere and not immediately visible from the outside)
  • … are difficult to test (carry global state).
  • … violate the single-responsibility principle (take care of existing only once in addition to their normal task)
public sealed class Singleton {
    public static Singleton Instance { get; } = new Singleton();
    private Singleton() { }
    public void Do() { // something with files }
}

// usage in code
public void MyMethod() {
    Singleton.Instance.Do();
}

A better C# singleton

This very crude standard implementation obviously checks all the boxes that the common singleton antipathy is proclaiming. Luckily, C# and dotnet can do much better with very little effort.

Obviously, the global state character of singletons can’t be helped, and that is by design. A globally accessible object is exactly that, a globally accessible object. If this much can ruin your day at the office, then you should primarily think about introducing code reviews.

The tight coupling is a good point, and fortunately, type inheritance is the perfect way to get around this. Introducing a public contract to the singleton while also hiding the implementation does the trick and enables dependency injection and mockability at the same time. And let’s face it, calling the singleton directly was never a good idea in the first place. Code should only ever have to worry about objects, not where they come from or what dependencies they bring along. The split of contract and implementation is also splitting responsibilities to a point where the public access class is taking care of the single instance issue while the internal implementation does the actual work.

Testability is a little tougher to provide, but it’s not impossible either. There is nothing that an internal field, an InternalsVisibleToAttribute and good old dependency injection can’t handle. Just mock whatever underlying resource access or mechanism is required by the singleton, and then get cracking on those tests.

public sealed class SingletonAccess {
    public static ISingleton Instance { get; } = new Singleton();
}

public interface ISingleton {
    void Do();
}

internal sealed class Singleton : ISingleton {
    internal IFileHandler _fileHandler = new FileHandler();
    public void Do() { _fileHandler.DoSomething(); }
}

// usage in code
public void MyMethod(ISingleton singleton) {
    singleton.Do();
}

I find it hard to understand, why so many developers are still practising and preaching the rejection of singletons, especially with today’s technologies and languages like C# (or anything that supports type inheritance for that matter). Yes, a singleton does introduce global state, but that’s its sole reason for existence. If you don’t want that, don’t use it, and also make sure that others don’t through the use of code reviews. And if you do want global state, then a singleton is the perfect way of injecting it into your code properly, because there should not be a line in your code that looks like Singleton.Instance.Do() (Here is another bit of pseudo truth to wrap your head around). With that out of the way and everything else sorted out using a decent implementation, singletons …

  • … can introduce global state where it is not beneficial.
  • … are tightly coupled to calling code (can’t be mocked).
  • … hide dependencies (accessible from anywhere and not immediately visible from the outside)
  • … are difficult to test (carry global state).
  • … violate the single-responsibility principle (take care of existing only once in addition to their normal task)

At this point, it’s obviously up to you and how you go about implementing global state. But keep in mind that it’s not the fault of the hammer if you use it to drive screws. Don’t blame the singleton for an implementation that’s been flawed for over two decades.

Leave a Reply

Your email address will not be published.