Devil’s Advocate — Singleton Pattern
Singleton is considered an anti pattern. How do I know? Wikipedia tells me that.
But why do we still use it than? We gave up on GoTo statement, why can’t we give up on singleton?
First of all let’s discuss what does the singleton pattern achieve. We define singletons, when we want to share something. We want to use it in multiple places.
The simplest example of a singleton is a named function.
We defined a function that encapsulates a simple computation and we gave it a name. Now if we need this computation, we just have to remember the name. The function is globally accessible.
However what happens if I use this name in another function? I couple those two functions. In the example above monthlyIncomeWithTaxes is strongly coupled to addTaxes function.
If I want to use monthlyIncomeWithTaxes I implicitly use addTaxes. Testing the first one, implies testing the other one.
Also if I would think about reusing monthlyIncomeWithTaxes in another project, I have to take addTaxes with me as well.
Sharing means coupling. And coupling is …inconvenient.
Could we avoid coupling?
Yes! We could use protocols, or other ways of abstract definitions, where we say: this function is coupled to a function which receives int and returns int. And we can wire those functions at runtime (dependency injection). This moves the problem of coupling up to the application initialising code. The problem is still there, but at least it is in one place.
So that’s it? We can dump Singletons now?
Sadly not quite. We “solved” the strong coupling situation, but we still might run into the sharing problem, when it comes to shared state.
Why would I like to share things in the first place?
We could embrace share nothing architecture, but as you can read from the wikipedia article, in this case everything has to be self-sufficient. This is impossible, if our application has to use shared resources like memory, display or network.
Singletons are almost unavoidable, if we want to interact with such shared resource. It doesn’t help if I impose that I have multiple network connections, when I have only one backend endpoint and it insists on preserving the message order. Same applies to file system, display link and even memory access.
Don’t get me wrong, there are plenty places where we can break down the problem into a multiple self-sufficient parts, which should not be shared through the whole application, but there are also the other parts. Parts that has to be share because of physical limitations.