Are Singletons Bad

When I first started dabbling with Cocoa development, I almost immediately came into contact with the singleton pattern. Many Cocoa frameworks, including UIKit and Foundation, use the singleton pattern.

What Is the Singleton Pattern

The singleton pattern ensures only one instance of a class is instantiated for the lifetime of the routine or application.

The concept is very simple. The singleton pattern ensures only one instance of a class is instantiated for the lifetime of the routine or application. The Cocoa frameworks often refer to a shared object or a shared instance. Take a look at these examples. URLSession and UserDefaults are both defined in the Foundation framework.

// Shared Session Object
let session = URLSession.shared

// Shared Defaults Object
let userDefaults = UserDefaults.standard

With the above definition in mind, the singleton pattern appears to be a useful design pattern. Unfortunately, many developers misuse the singleton pattern and use it to conveniently access an object from anywhere in a project. Having global access to a singleton is nothing but a side effect of the singleton pattern. It's not what the singleton pattern is about.

Singletons Everywhere

Whenever I talk about singletons, I like to bring up Maslow's hammer analogy.

I suppose it is tempting, if the only tool you have is a hammer, to treat everything as if it were a nail. — Abraham Maslow

A surprising number of developers struggle with this problem. The singleton pattern appears to be solving a common problem, accessing an object in various places of a project. A singleton, nothing more than a fancy global, looks like the perfect fit for the problem. And it is the perfect fit if all you want to do is solve that problem. There's more to the story, though.

Have you ever wondered why some experienced developers consider the singleton pattern an anti-pattern? Why is it that such a useful pattern is often avoided by more senior developers?

Sacrificing Transparency for Convenience

By using singletons, you almost always sacrifice transparency for convenience. But how much are you willing to sacrifice for that little bit of convenience? Convenience should not be high on your priority list if you're working on a software project. Let me show you with an example what the problem is.

By using singletons, you almost always sacrifice transparency for convenience.

A common problem in software projects is user management. This means that a user model object needs to be created and managed. There are many solutions to this problem. If you're a fan of the singleton pattern, then you might create a singleton user object or a manager class that manages the currently signed in user. Only a single user can be signed in at a time. Right?

Problem solved? It's true that you can now access the currently signed in user from anywhere in your project. While this may seem like the best thing since sliced bread, it introduces several problems.

Consider the following question. Which object is allowed to modify the user model object? Easy. The manager object managing the user. Hmm ... but isn't the manager object accessible from anywhere in your project? This means that the user model object can be modified from anywhere in your project. If you're still with me, then I hope this is starting to sound less and less like the great idea it initially appeared to be.

How are you going to make sure that the objects that depend on the currently signed in user are notified when the user is modified? Easy. Notifications. Another popular option is to use a pattern similar to Java's observer pattern. You could use key value observing, but do you really want to observe the properties of an object that's managed by a singleton? That sounds like asking for trouble.

Losing Track of Everything

I agree that the singleton pattern seems convenient and it may occasionally be warranted to use it, but the drawbacks far outweigh the benefits. Unfortunately, the drawbacks are very subtle at first and that's what misleads many developers.

Unfortunately, the drawbacks are very subtle at first and that's what misleads many developers.

The most important drawback of the singleton pattern is sacrificing transparency for convenience. Consider the earlier example. Over time, you lose track of the objects that access the user model object and, more importantly, the objects that modify its properties.

The initial advantage of using a singleton, convenience, becomes the most important problem. Ironic. Isn't it. By using singletons in your project, you start to create technical debt. Singletons tend to spread like a virus because it's so easy to access them. It's difficult to keep track of where they're used and getting rid of a singleton can be a refactoring nightmare in large or complex projects.

Once the singleton pattern becomes an accepted practice in a project, it's difficult to move the project forward without using even more singletons. The structure of the project may seem flexible and loosely coupled, but it's anything but that.

Substituting Singletons With Dependency Injection

As I mentioned earlier, singletons have the tendency to spread like a virus. The cure to solve singleton disease is dependency injection. While a key advantage of the singleton pattern is convenience, the most important advantage of dependency injection is transparency. Transparency is good.

If an object requires a valid user model object to do its job, then that user model object should be injected as a dependency. It's easy to translate this requirement into code. Take a look at the following example.

class User {
    var firstName = ""
    var lastName = ""
}

class NetworkController {

    let user: User

    init(user: User) {
        self.user = user
    }

}

This snippet shows any developer working with the NetworkController class that it depends on a valid User instance. This is also known as passing an object by reference. It's less convenient than using a singleton, but it pays dividends in the long run. It adds clarity to the codebase, unambiguously showing which objects depend on which objects.

It's an advantage that passing an object by reference is less convenient. Huh? It forces you to consider your decision. Does the NetworkController class need access to the user model object? Would it suffice to pass the user's username and password instead? Dependency injection can be a useful tool to define the requirements of a class.

Dependency injection can be a useful tool to define the requirements of a class.

Moving Away From Singletons

A few years ago, I started working on a client project that was littered with singletons. Some singletons even referenced other singletons, adding to the problem. After several rounds of refactoring, I managed to eliminate most of the singletons from the project, which drastically increased transparency and robustness.

Have you ever worked on a project nobody in your team wanted to touch? Modifying a handful of lines in one class could cause mayhem in a distant, unrelated component of the project? This is not uncommon for projects that make heavy use of singletons.

Another benefit of ridding a project of singletons relates to testing. Writing unit tests without having to worry about singletons is fantastic. It really is. Combine this with dependency injection and you have a great combination to work with.

Are Singletons Bad

My stance on singletons varies from day to day. If I had a rough day battling singletonitis, I dislike them with a passion. The truth is that singletons aren't inherently bad if they're used correctly. The goal of the singleton pattern is to ensure only one instance of a class is alive at any one time. That, however, is not the goal many developers have in mind when using singletons.

Singletons are very much like the good things in life, they're not bad if used in moderation. The next time you're about to create a singleton, consider your motivation for creating it. Is it convenience? Then you should not create that singleton. Period. That's the simple rule I apply.

Let me know if anything’s unclear or if you have any questions about the singleton pattern. Leave them in the comments below or reach out to me on Twitter.

If you want to learn more about dependency injection, then I recommend reading or watching my tutorial about dependency injection. It shows you how you can use dependency injection in your own projects.

Stop Writing Swift That Sucks

Download the Swift Patterns I Swear By

About Bart Jacobs

About bart jacobs

My name is Bart Jacobs and I run a mobile development company, Code Foundry. I've been programming for more than fifteen years, focusing on Cocoa development soon after the introduction of the iPhone in 2007.

Stop Writing Swift That Sucks

In my free book, you learn the four patterns I use in every Swift project I work on. You learn how easy it is to integrate these patterns in any Swift project.