On the misuse of the Singleton pattern




The Singleton pattern is known as the most overused and misused pattern among those of the GoF. Thus, I thought it appropriate to devote a whole post to convince those of you who, unknowingly, abuse this pattern to lazily couple your modules/classes and to compromise the flexibility and testability of your code. If you already know the consequences of using a Singleton and have decided to use it anyway, it's up to you.

But, what is a Singleton?

In Design Patterns, it is described as:

Ensure a class only has one instance, and provide a global point of access to it.

Let's cover quickly the first part of the description, because I want to focus in that global thing.

If you need or can do with more than one instance, then don't use a Singleton

The first thing we have to ask ourselves is: do we need to enforce this class to have only one instance? This looks simple, but more often than not people use the Singleton pattern for classes which they'd rather have one instance, but it's not an inherent property of this class.

Let's look at an example: I have a connection to a database in a single-threaded application. We don't get any advantage in opening and closing multiple connections, so let's make this resource a Singleton. To be really efficient, we are going to wrap this connection in a handler object, which will be our Singleton. We could even turn it into a container of an abstract class attribute, so we can subclass this data handler and be flexible about the data source (this is one of the main uses of the Singleton, if any client of the Singleton can do with any of its subclasses). Now anywhere in our code we can retrieve this handler instance and get our data (global property).

But what if suddenly I am going to have two data sources? I can have my configuration in a file and my application data in a database. We could have then two different classes, both Singleton, one for configuration and one for app data, so we could eventually switch to configuration in database, or data in files. But, what is the point? We would have two instances of something, two database connections, or two file handlers. If we won't, our Singleton are still unique, but we don't get the flexibility of being able to change our data source. This is out of control, because we are trying to solve a design problem with implementation.

Another option is to keep our Singleton, but label our data, have flags so different data go to different destinations (file or database), have different methods for different data... Again, our design is flawed, not scalable.

Before seeing a better design for this, we are going to see why this second property of the Singleton is getting you a shot in the foot.

Global considered harmful

First of all, let's state what global stands for in this context: anything invading our scope in a non-explicit way. So, a parameter is not global state because we declare in our function that we are receiving it. Global variables are a hidden way to affect our code. Static functions are also global by definition, but they can be harmless if they do not hold, modify or access state .

Global state hides dependencies in our modules and methods, and makes as unable to leverage dynamic polymorphism and interfaces from the client of the method. This compromises two important properties of our code: reusability and testability.

Your instance is belong to all of us

What would be a better design? Dependency Injection. Let's have an example in Java:

public class DataHandler {

    protected static DataHandler instance = null;

    protected static void createInstance() {
        DataHandler.instance = new DataHandler();
    }

    public static DataHandler getInstance() {
        if(DataHandler.instance == null) createInstance();

        return DataHandler.instance;
    }

    private DataHandler() {}
}

That's the Singleton code, then you need the data handling code of course, the connection/descriptor, etc. Here we detect the first code smell: violation of the SRP. Our class is responsible of both managing its own creation and handling data.

Let's suppose that the class ShowUsersWindow has a method void populateTable(OurGraphicTable table). How can we test that this method populates correctly the table when there are no users in the database? Well, with this design, we are going to need to manipulate the data source (and have a running database server, or existing files), and access it for each test. That, or force a given order of execution in our tests, and this is bad because all our tests should be independent from each other. For our tests we would mock the OurGraphicTable object and pass it as a parameter, and it would check that the correct methods are called, or that the final state of the table is appropriate for the expected input. No need to say that accessing and changing the database for each test is slow as hell, and makes your tests of the populateTable method dependent on all the methods required of the DataHandler class. Not good.

public class ShowUsersWindowTestCase {

    @Test
    public testPopulateTableWithEmptyDatabase() {
        // Arrange
        DataHandler.getInstance().emptyUserDatabase(); // Let's hope this method is thoroughly tested, otherwise this test is not reliable
        OurGraphicTable mockTable = new OurGraphicTableMock();
        ShowUsersWindow window = new ShowUsersWindow();

        // Act
        window.populateTable(mockTable);

        // Assert
        mockTable.assertListEmpty();
    }
}

How would this be with Dependency Injection? Well, the method would be void populateTable(OurGraphicTable table, IDataHandler handler), and we would just mock both dependencies, the OurGraphicTable mock would be exactly the same as before, and the DataHandler mock would just return the test data. Fast, clean, flexible and allows us to test populateTable() independently of the behavior of our real DataHandler implementation. DataHandler would not be a Singleton in this last design, it would just implement IDataHandler, and if we only needed one, we would make sure to just instantiate it once and pass it around as a parameter for the methods that depend on it (making it a explicit dependency). One even better solution would be to receive a List object as a parameter, also an implementation of the Dependency Injection pattern.

public class ShowUsersWindowTestCase {

    @Test
    public testPopulateTableWithEmptyDatabase() {
        // Arrange
        IDataHandler mockHandler = new DataHandlerMock(); // No effect in the database, maybe it doesn't exist at all
        OurGraphicTable mockTable = new OurGraphicTableMock();
        ShowUsersWindow window = new ShowUsersWindow();

        // Act
        window.populateTable(mockTable, mockHandler);

        // Assert
        mockTable.assertListEmpty();
    }
}

Very similar right? Well, if you get the chance to have both designs, do a benchmark and see if the performance difference is significative. Remember that Unit Tests must be fast, and must be run often.

Singleton instances can be passed as parameters as well, but then, what is the purpose of making it globally-accessible?

This rant is way longer than I thought it would be, but I hope I have made myself clear regarding my opinion about the Singleton design pattern.

The good Singleton

Just to finish, I will talk about one of the few use cases where Singleton is considered to be a good fit: The Logger. A logging service is usually implemented as a Singleton, so every method of the application can use it without the cumbersome task of having a parameter in each and every method for it. How is this different of the first example about the database connection?

Simple: the logging service does not hold a state which will affect the execution of our application. The information flows only to the outside of our system. This service can be considered more as a language feature than as a service of our application used by other methods, it has to be alive as long as the program runs, we don't need its behavior to change according to our program state. Sure, we lose the ability to subclass the Logger, to have different log files for different data (unless we use one of the approaches already presented, which are not very OO, but would work wonders in this case), or for different states of the application... but, if you need any of these features, your logging service is far more complex than the one we are speaking about, and as you may have already realized, you should not implement it as a Singleton.