Use Singleton Pattern Or Not?

Kiarash Vosough
Divar Mobile Engineering
5 min readJul 19, 2022

In this article, I will go through the cons and pros of the singleton pattern, and in much more detail, I will answer the question above.

Where are Singletons Supposed To Be Used?

Let’s start with a definition of this pattern by referring to refactoring.Guru.

Singleton is a creational design pattern that lets you ensure that a class has only one instance while providing a global access point to this instance.

It is also mentioned that this pattern addresses two problems:

  1. Ensure that a class has just a single instance.
  2. Provide a global access point to that instance.

Issue With Global Instances

Wait, what, global access? So everyone can access it?

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

The question arises: Do you sacrifice for a bit of convenience, Not to pass around instances to avoid some boilerplate code!?

By using global instances, you hide your application's dependencies in your code instead of exposing them through the interfaces and injecting them wherever is needed. Besides this is a CodeSmell, considered a bad design practice that causes trouble in the future and increases the risk of bugs.

Even when I started computer science in university, our mentor told us to avoid global variables or instances; maybe he knew I would reach this stage someday :)))

Violation Of Solid Principles

The nature of singleton violates three principles, and I am going to talk in much more detail about these horrible violations.

Singletons vs. Single Responsibility Principle

Singleton generally comes from the fact that it breaks the SRP. A singleton has two responsibilities:

  1. Manage the creation of the instance of the class
  2. Do something that is the original responsibility of the class

Singleton should also manage the access to the instance, more precisely when several threads request access to one instance; singleton should take responsibility for dispatching data to each request in threads by using locks to prevent Race-Condition or handling read and write to deliver valid data instead of an invalidated data.

This is just the beginning. As time goes by, new responsibilities will be added to the singleton. You end up with a class that nearly does anything. This will cause other problems which are going to be covered.

Singletons vs. Open/Close

Singletons break the Open/Closed Principle because the singleton class is in control over the creation of its instance, while consumers will typically have a hard dependency on its concrete instance. This disallows the implementation to be changed without having to make sweeping changes throughout the application.

For a class to be “open” it must be possible to inherit from it. Inheritance is an “is-a” relationship. If you inherit from a singleton-class then instances of the child-class are also instances of the parent class due to the “is-a” relationship, meaning you can suddenly have multiple instances of the singleton class.

If the singleton class inhibits inheritance, it’s no longer “open” on the other hand, If a singleton class allows inheritance then it is “open” for extension, then it can no longer enforce the singleton pattern.

This also led us to a new issue, which makes refactoring harder. It is also known as a brittle assumption. The assumption that there will ever be only one instance or some method inside it is often broken during a project’s lifetime, and this pattern structures the code in a way that requires a very significant effort to refactor when this assumption is inevitably wrong.

For those who are IOS developers. Just imagine that apple removed the NotificationCenter or UserDefault or even deprecated their methods. If you’ve used the Singleton of these classes all over your project, who will take the responsibility of removing deprecated API all over an app at scale?

Answer to a question: Couldn’t a singleton implement an interface to solve this problem?

Answer: If it had the interface, the instance would be replaceable; this wouldn't follow the Singleton pattern, while there should be only one instance of a singleton class.

Singletons vs. Dependency Inversion Principles

The biggest problem is here, violating DIP. Because consumers will always depend directly on the concrete class to get the instance, while the DIP prescribes the use of abstractions, this causes the Singleton implementation to be dragged along and disallows adding cross-cutting concerns by wrapping the implementation in a decorator or distributing the client without that singleton implementation.

Again, answer the last question: Couldn’t a singleton implement an interface to solve this problem?

No, instance property would still be defined on the static class, which causes the DIP to be violated again.

How does Singleton Affect Testing?

This increased coupling due to the Singleton design pattern makes creating Mocks and Stubs during unit tests tricky. In other words, using the Singleton design pattern makes your life painful when writing unit tests since it becomes tough to identify the dependency chains so that the components in your application can be unit tested adequately. Most importantly, you must use static methods when implementing the Singleton design pattern. Static methods make unit testing difficult since you cannot mock or stub. In essence, the types in your application that have a dependency on a singleton class are relatively difficult to unit test. In unit testing, each unit test should be independent of one another. Another reason the Singleton design pattern makes your life difficult in unit testing is that they remain alive in the application. Hence they persist in the state as long as the application remains in the memory.

Another hit to testing since you can end up with a situation where tests need to be ordered which is a big no for unit tests. Because each unit test should be independent of the other. So how will you solve the dependency between these states in each unit?

Conclusion

Care about programming principles since they help you write good code and avoid using patterns that violate these principles. On the other hand, if you feel that some of the principles restrict you and your code would be better without it, do not hesitate to consider writing a code that breaks the principles. Discuss it with your peers and conclude. The conclusion will be that you were wrong, considering breaking Solid Principles in 90% of the cases. In 10%, however, you may come up with brilliant ideas😁. But always keep thinking of the future of the software you are developing, do not tie up everything for the next developers, and do not increase the maintenance cost.

--

--

Kiarash Vosough
Divar Mobile Engineering

iOS Developer and Swift Lover with over 5 years of experience on Apple platforms. Find me on Any Social Media by searching Kiarash Vosough:)