Singleton Patterns23 July 2019
Photo: Jantine Doornbos- Unsplash
Design patterns are a key element of any developers toolkit. Even if you do not realise that you are using them as you start your career, you are. They have two major benefits:
- They have developed as proven ways to solve common patterns in software engineering. They are not the work of a single developer or company but rather are an evolving set of best practises.
- They define a common way to imply intent. Developers will understand code that follows or is based on common patterns. Patterns have become a shared language amongst developers.
Patterns are the basis of a solution. Even if you find you have to add to them for your problem they still provide a useful starting point. Since first being defined by the Gang of Four book in 1994 many more patterns have been identified. In parallel, many antipatterns have been developed. These guarantee that a solution is a wrong way to solve a given problem. Some patterns fall into both camps for some developers. For me, the one pattern I never use in an object-oriented program is the Singleton pattern.
A Singleton defines a class which can only have one possible instance created. It defines a constructorless class that controls how it is instigated and accessed. It offers no public, instance-specific state. Instead, it can introduce global state into Object-oriented programme. They are also always defined as static objects.
I have seen Singletons used in many projects and I have always found there to be better ways to solve the problem. I usually refer to them as a code smell. In a recent project, I was looking at a Singleton class was defined to interact with Cloud provider storage. The class defined a common set of methods for uploading and downloading of files. The implementation for each cloud provider was implemented using a pluggable backend set of classes. The provider to consume was set in configuration during application startup. In theory quite a flexible piece of functionality.
The issue with the code in this project was that it had been implemented in a non-thread-safe manner. This meant that the problem I was investigating was easy to find. A slow method that was looping through a list of objects. It was using the Singleton based instance to create a URL to assign to the object for the location of a file. The solution was to revamp the Singleton based class using option 4 on Jon Skeet’s excellent article on the topic. I then moved the foreach loop to a Parralleel.Foreach and reduced the execution time for the method by 83%. I didn’t refactor the Singleton to a better solution as the class was consumed over 400 times throughout the project. I didn’t have the luxury of time.
This leads me to something else that is problematic using Singletons. You can not easily unit test a singleton. It is a static object which means that if you include it in your tests you will not be able to fake or mock it. Hardly ideal for such a core piece of functionality for this program.
A key aim in object-oriented applications is to remove the use of global state. The Singleton pattern provides a mechanism to use global state. Singleton instances also violate the key aims of the SOLID principles. There are many performance issues to be aware of and refactoring Singletons out of an established code base is very hard. Experience has shown that their use, especially in an early-stage project, is not worth the cost later on.