Skip to content

Singletons considered harmful

Ok, I know it’s not a new observation, but the Singleton pattern must be one of the most overused, and abused, patterns that the Gang Of Four described.

This is on my mind this week as I’m working on a body of code that has way too many Singletons. I must emphasise that ultimately it’s my problem, not the original author’s, as I dropped the ball over a year ago and did not review the design and implementation. The problem has come home to haunt me as I introduced just one change too many and all the tests began to fail.

Particularly in this case, while looking at test coverage I wondered why a pretty important piece of life cycle management wasn’t being traversed in tests. Which led me to have a close look and realise that it was buggy, and failing out right at the start of execution during tests. So I fixed that, and all the tests threw up because the Singleton in question was no longer in the expected state.

My main gripe with Singletons is that they run headlong into one of the cardinal rules of unit testing: all tests should be entirely independent of each other. The problem with a Singleton – particularly one that has some sort of lifecycle – is that suddenly tests are connected by the internal state of an object that may not even be the unit under test. Which leads to unstable tests prone to mystery failures. And unstable tests lead to a lack of confidence in the validity of the code.

Now, I’m going to need to articulate this to other coders to head off any repeat of this problem, so it’s worth my while to hand wave about when Singletons are appropriate, and when other techniques are better.

To begin with, I often see Singletons introduced to provide static pieces of code. I strongly suspect that this is because the coder does not understand how static methods and attributes work, or simply forgets. Probably the biggest single clue that these cases should not be implemented as Singletons is that they have no persistent state.

When talking it through with the team, both zoomed in to that idea from two different directions with little prompting: by thinking about the code construct (the Singleton pattern) instead of thinking about the data, it is way too easy to not see that the Singleton pattern gives the data state a different scope and different life cycle to other code.

In the space I’m mainly playing in, it’s fairly common to have a bunch of threads handling incoming requests from some external agency, all in kind of similar ways. This transactional model, if inverted to be data centric, can be summarised as: accept data, map it onto an output state, and throw away any working state in preparation for the next request. In Java terms the scope of all data is local to the thread. The data state of the Singleton, however, is at a higher level – an application or service level. Thus objection one: Singletons cause data states at different levels of abstraction or different levels of management to be promiscuously mixed.

This immediately leads to objection two: Singletons easily cause cross-thread side effects, as they bind threads together in non-obvious ways. This problem can be lessened if the Singleton provides read-only state, in which case it might be better done using static attributes, and if the potential side effects are well documented and described.

Objection three is somewhat more of an aesthetic gripe. The common ways in which Singletons are usually implemented in Java, apart from not being as thread-safe as they appear to the naive eye, beaks the doctrine of Separation of Concerns. The Singleton class has two responsibilities, not just one, which is a very bad smell: it is responsible for whatever it’s purpose in life is, and it’s responsible for making sure it’s alone in the universe.

There are a variety of ways of getting around this bad smell. A lot of runtime containers – be it simply the JVM firing up with some single instance of a class providing main(), or Spring or a web application server taking care of the “only one” behaviour behind the scenes – provide a trustable context for which you can say “if I make just one of these objects, and put it in that context, there will only be one of them”. In the case of the examples above, as well, it means that we have the instance of the object in some sort of “application” or “service” scope, with a life cycle that can be tied to the broader context.

At a bare minimum, if you cannot identify or obtain access to the application context, you should aim to separate out the two concerns – provide a class that does stuff, and a class that holds a single instance of that do-stuff class. While adding a little bit of extra boiler plate code, this simple change suddenly means you can test the two behaviours independently and that you can have thread-local instances injected in the scope of your independent unit tests.

And a final objection, primarily aesthetic. There are a bunch of different ways to build a Singleton in Java. Not all of them are thread safe, and it’s annoyingly difficult to do lazy instantiation in a thread safe manner, particularly if you want there to be exactly one run through a costly process. The ugliness arises because generally the methods to be thread safe are clunky kinds of fiddles that require the coder to think about the behaviour of the JVM instead the behaviour of their code. There’s that separation of concerns biting us in they arse again.

I do not think the pattern is to be universally avoided though. It’s highly probable that the application or service scope is stateful, and has a well defined life cycle. Like it or not, the life cycle state is a single piece of information that needs to exist at a different level of abstraction to the per-thread state (unless you are fortunate enough to be able to think entirely at a thread level, and there genuinely is no application level state).

As an example, I’ve fallen into the habit of using a roughly MVC architectural pattern. Sometime I will go into this in detail, but for now simply accept that it’s a handy simple framework to hang more complex behaviour of, while encouraging the decomposition of the code into easily testable parts. In my case, the ‘view’ is often provided as servlets, often with a RESTful design, and not necessarily provided by a single class. It’s pretty common for me thus to not have an accessible application level context without using Spring or similar. In these instances, I tend to use the Controller layer to hold the application-level state, and manage the application-level lifecycle. Of course, this is easily abused as well, as without paying attention you can find all sorts of pieces of code dialling home to the controller layer or object, but at least by separating the singleton aspects from the controller aspects, you can make the opportunity to not bind tests together.

Let me leave you with a thought experiment: if I have a simple web application with just a single servlet class, does that servlet class provide a single-instance application level context?

Post a Comment

Your email is never published nor shared. Required fields are marked *
*
*