I Asked 885 Developers: Is Singleton Bad? Here’s the Answer
I Asked 885 Developers: Is Singleton Bad? Here’s the Answer

I Asked 885 Developers: Is Singleton Bad? Here’s the Answer

If you are a C# or Java developer, you’ve probably already seen the Singleton design pattern mentioned in a million blog posts and StackOverflow answers. People often say it’s an anti-pattern, and that you should avoid it at all costs.

But have you ever wondered:

Is singleton bad as people say?

The truth? It’s not.

The Singleton design pattern is not bad if you use it correctly. The primary purpose is to restrict the initialization of a class to only one instance. It is not inherently bad or good. It depends on how you use it.

If you use it correctly, it can be a powerful tool for designing your app with many benefits. In this post, you’ll discover that the singleton design pattern is not an anti-pattern. You’ll see why and how to use the new knowledge to make your life and code easier.

What is the Singleton design pattern?

Singletons. Singletons everywhere.

That is often the first thought that comes to your mind if you start working on a legacy project that has been maintained for some time.

What’s not to like about singleton?

It’s easy to implement. It makes your code easier to share access to a class.

Singleton design pattern is a creational design pattern. It is one of the most commonly used design patterns. You can use it to ensure that there is only a single instance of something, and this is often the case with a shared resource.

If you want to use the Singleton design pattern, you should ensure that you have a private constructor for your class. This will prevent any other class from creating a new singleton class instance.

Here is a quick example of how to implement the Singleton design pattern in C#:

public sealed class Singleton
{
    private static Singleton _instance;

    private Singleton() { }

    public static Singleton GetInstance()
    {
        if (_instance == null)
        {
            _instance = new Singleton();
        }
        return _instance;
    }

    public void DoSomeWork()
    {
    }
}

The Singleton instance is stored in the _instance field. The GetInstance static method checks whether or not the _instance field has been initialized. If it’s null, it creates a new instance of the Singleton class and returns it as the method result. Keep in mind that the above code is not thread-safe implementation. If you work with the multi-threaded code, google how to implement the singleton design pattern so it’s thread-safe.

The usage is straightforward.

var singleInstance = Singleton.GetInstance();

In C#, you can also store the creation logic in the property.

public static Singleton Instance
{
    get
    {
        if (_instance == null)
        {
            _instance = new Singleton();
        }
        return _instance;
    }
}

Again, the usage is straightforward.

var singleInstance = Singleton.Instance;

Is singleton bad?

Singletons have always been controversial. Some programmers believe that they are a bad design pattern. Others say they’re useful and sometimes even indispensable.

The idea behind singletons is simple. They let you create a sole instance of a class, which is available from anywhere in the application.

There are two main reasons why people use singletons:

  1. The first reason is that it lets you limit the number of objects created. If you have the singleton pattern, you don’t need to worry about object creation.
  2. The second reason is that it makes your code easy to access the class that performs some work.

The main disadvantage of the singleton design pattern is that it can become a maintenance nightmare. If you implement the singleton design pattern in the code, you have a call to the static class. That means you are coupling the code in your class with the code from the singleton class.

In that case, it’s not easy to write unit tests for the methods that use a singleton. If you try to write them, you will probably run into problems. For example, if you have a singleton that accesses the database, the only way to test that code is to provide a test database. That is not the easiest thing to do. This means that you need to write integration tests in that case.

But singleton design pattern is not bad in itself. It’s only bad when it’s abused.

I asked the community whether the Singleton pattern is bad

I wanted to run a little experiment.

I run a poll on Linkedin to ask fellow developers whether or not the design pattern is bad. The results? Out of 885 developers participating in the poll, 84% of developers think that the Singleton design pattern is not bad.

Some of the comments beneath the poll were:

“It depends…”

“No, it’s not bad. Did we misuse or overused it sometimes? Yeah, sure. Nowadays, it’s better if you let the lifecycle to be handled by the IoC container but it still isn’t always feasible and practical. For sure, you need to be careful with it and don’t compromise e.g. the testability of your code.”

“No! Any pattern used correctly is never a bad option.”

“Every design pattern is for specific needs, so use of singleton depends on purpose. Some design patterns should be used with extra caution and Singleton is one of them.”

You’re using the Singleton design pattern the wrong way

Singletons are beneficial when you need to share one instance of a class across multiple system components. The Singleton pattern solves this problem by creating a special object that will serve as a single instance for the whole system.

Here is where singleton turns bad: it can store global state. Some global states are fine, such as a database connection or providing a single point of access to the logger class. Others? The usages of the singleton design pattern that store state shared between different classes are bad.

However, the global state needs to have a reputation of being bad, not the singleton design pattern. This is because a global state can lead to many problems such as complex unit testing or debugging.

Why is that? What are the problems with a global state?

A global state is a shared global variable among all parts of the application. The state of the class can change, and you will not know about it. Therefore, it’s hard to unit test and debug. It’s also a problem if you want to reuse the same class multiple times.

One of the reasons we use global variables is that we don’t have to pass them around in every method call. However, if you don’t use it correctly, it can lead to many problems. The problems can even lead to an unstable system. To keep things organized and easy to understand, it’s a good idea to avoid the use of global states. This will help you to keep things organized and easy to understand.

Designing your code so it doesn’t need a global state

Usually, when people think about single instances, they think about static objects. But the Singleton design pattern is not the only way to provide a single instance of your class.

You see, the way Gang of Four originally designed the singleton design pattern is obsolete these days. There is a much better alternative for providing a single class instance.

Meet dependency injection.

Dependency injection (DI) is a technique where you create an object and pass all the dependencies it needs to function through the constructor. You can then create a single instance of any dependency and inject it into any other object that needs it.

DI has a few benefits over the Singleton pattern:

  1. It’s more flexible. You can easily change the dependencies of an object without breaking anything.
  2. It’s more testable. You can quickly test objects in isolation without worrying about singleton static methods/properties.
  3. It’s more scalable. You can change the dependency so that it has multiple instances of an object if you need to, without changing your code. Dependency injection is an excellent choice for designing your application.

You can learn in the separate post how to use dependency injection to make great code.

Conclusion

The Singleton pattern is widely used to allow only a single instance of a class. It prevents the application from creating more than one instance since more instances can lead to higher memory consumption and performance issues.

Singletons are often abused in software engineering. Many software engineers like to create a singleton whenever it seems appropriate. Such use of singletons creates many problems, the most common of which is a code smell called the global state.

You can’t avoid the global state at all times, but you can limit its impact by correctly applying the Singleton design pattern. Modern applications use dependency injection to prevent global state introduced with singleton design pattern.

In this blog post, I hope I have inspired you to use this pattern in your code and prevent that design pattern from hurting your project’s quality.

FAQ

What is wrong with Singletons?

The singleton design pattern can create problems when you misuse it. For example, it can lead to problems with maintaining state information, and it can be challenging to test and debug.

What can I use instead of Singletons?

Instead of a singleton design pattern, you can use dependency injection (DI). With dependency injection, you create modular classes that depend on each other. These classes are then injected as dependencies. DI allows you to quickly test your code and prevents any single class from becoming too complex.

Why is Singleton bad for testing?

A singleton is a class that only has one instance. This can be problematic for testing. In addition, singletons can often be tightly coupled to other parts of the codebase, making them difficult to test in isolation.

If Singletons are the wrong solution, what is then the correct one?

There is no single answer to this question, as there are various ways to create objects in software design. However, some alternate implementations include using factories to create objects, using composition instead of inheritance, and dependency injection.

What is the difference between Singleton and static class?

A Singleton is a class that you can only instantiate once, while you can’t instantiate a static class at all. As a result, static classes are often used for helper functions that don’t need to be instantiated.