Rehabilitating the Singleton Pattern
“Design Patterns: Elements of Reusable Object-Oriented Software” came out in 1994 and it changed the software engineering landscape. What made this book unique is that it wasn’t really based on code (although it did contain a decent amount of it) but on terminology. It picked up general ideas and concepts, captured them in diagrams and, most importantly, gave them a name.
The power of names
Nobody had really thought about doing that before, and the idea was so good that even today, fifteen years later, most of these names are still in common use. You won’t come across a developer who has never heard about Singleton, a Visitor, a Factory or a Façade.
Of course, the science of software engineering has advanced quite a bit since 1994, and some of the concepts explained in the book came under attack. For example, we know a lot more about testing now, and this past decade has allowed us to identify techniques that make testing easier, and also anti-patterns that tend to get in the way of making our code testable.
Of all the design patterns from the book that have been criticized, none has taken as much of a beating as the Singleton. Not a day goes by without reading in blogs or irc that “Singletons are evil” and that you should avoid them at all costs. What’s surprising is that I read this coming from senior developers, and this statement tends to deeply puzzle more junior developers who suddenly find themselves having to rewrite a piece of code that they thought was quite natural and officially acknowledged as a good coding practice.
Here is the truth:
Singletons are fine as long as you don’t implement them with static
Scoping it out
Let’s take a closer look at this statement.
Singletons are very natural entities in a software engineering. Regardless of the kind of code you write (front end, back end, embedded in a browser, running in a container, etc…), you will most likely need to talk to certain services that only need to exist as a single instance. It’s also no surprise that popular dependency injection frameworks such as Guice and Spring explicitly support the Singleton pattern.
Don’t feel bad for feeling the need to implement a certain concept as a Singleton, it’s perfectly natural.
So what’s wrong with statics?
There is ample documentation on the problems that static variables and methods (but mostly variables) cause, but in nutshell, they make testing and concurrency more challenging, and as such, they should be avoided. The main problem is that static defines a scope that’s even bigger than the application itself. It’s a state that will only disappear once the class that contains it gets unloaded, so frameworks have very little room to control its life cycle. Another way to look at it is that the static scope is beyond the reach of Java programs and lives in the realm of the JVM.
This is really the only problem. If we can find ways to have singletons that are more narrowly scoped, then the concerns I mentioned above disappear.
The next smaller scope to the one that static provides is instance: the value will remain live as long as someone is holding on to a reference to the object, but once that is no longer the case, this value is gone.
One way to improve on the static scope would be to create all your singletons in your main method and then pass them down to your application. With this change alone, you have suddenly made your entire application much easier to test and easier to reason about from a concurrent stand point.
Once you start going down that path, you start wondering if this “main” scope isn’t too broad. If a singleton you create in your main method is not needed until way further down the stack frames, maybe there is no point in exposing that singleton to your entire application. Is there any way that you could either create (ideal case) or at least expose (second best case) that singleton only to the section of your code that needs it?
This code structure also rises another question: it’s not exactly convenient to create a bunch of singletons in your main method and then pass them “down”. How do you do that, anyway? Ideally, you pass them as parameters to the methods you are calling, but that is not going to scale very well, never mind the fact that your method signatures are going to start looking like monsters. Updating your entire call chain whenever you need access to a new singleton is an absolute disaster since you will have to add this parameter to the signature of each method.
One way to mitigate this problem is to group all your singletons in one class called, say, Configuration, and only pass that class around. If ever you need one more singleton down the road, you just add it to this class and you don’t need to change any method signature. That’s better.
We are still exposing a lot of code to all these singletons, though, and even that uber Configuration parameter looks like extra weight on these methods (most of which might just pass them around and not even use them).
Injecting for fun and profit
This is where the @Inject annotation comes in. Initially popularized by Guice, this annotation ended up being promoted to a standard by JSR 330: “Dependency injection for Java“. I’m not going to go into details on how to use this annotation (check out Guice’s excellent documentation), but I’ll just limit my comments to the topic of this post, which is how to implement singletons properly.
Using @Inject to gain access to your singletons solves the following problems:
- No static.
- The creation of the singleton is externalized. You don’t need to worry how or where that singleton is created, you just need to specify that you need it.
- Finer scope. Only the class that you declare this injected field in will have access to that singleton. A side benefit of this is that you no longer need to pollute all your method signatures in order to pass this singleton all the way down the stack frames. It’s declared as a field and the dependency injection will automatically assign it at start up time.
- Finer granularity. You no longer need to pass a monster Configuration object that contains all your singletons around: just specify which singletons you need exactly.
This post is getting a bit long already so I’ll stop for now. There is much more to cover on the subject of singletons and, more broadly, of dependency injection, which I’ll try to cover in a future post.
In the meantime, let’s all agree to acknowledge that when implemented and used properly, the Singleton is a very useful design pattern.