The Root of All Evil

January 23, 2010

Okay, it’s 2010, and my New Year resolution is to fill this blog with life. Luckily for me, I have the perfect candidate desperately deserving some spotlight – the singleton pattern.

“The singleton, seriously?” you might ask. After all, it’s probably the most widely known pattern out there. For instance, let’s take a question right out of the classic job interview for a developer position. “What patterns do you know?” Care to make a guess which pattern gets picked the most? Yep, you’re right, it’s the singleton. And you know what else? It’s even a valid answer. The singleton pattern is listed by the GoF.

So, why did I choose it to get picked on? Easy enough to answer – it’s also the pattern that’s causing the most trouble when it comes to application design. Don’t get me wrong, there are tons of anti-patterns that can cause even greater harm in an application, but programs suffering from really bad code typically don’t employ too many of the patterns described by Gamma et al.

But enough of that. Let’s start chipping away at our global variables instead. Oops, I meant singletons! After all, there are no global variables in our nice, clean, object oriented world. Or are there?

Okay, I guess, that’s what you could call a loaded question. But why is a global variable a bad thing? It’s accessible from every scope. It’s perfect when different parts of the application need to access the same shared state. And I could list so many scenarios where a singleton makes the code really simple. All it takes is a reference to the instance and I’m golden.

Or not.

To illustrate my point, I’ll take one of the most common use cases for the singleton pattern – aside from the System.Web.HttpContext and the application configuration – the current User. That’s information I need all the time when I’m building an application that requires authentication, enforces security, logs changes to the business objects, etc.

A quick disclaimer in between: Yes, I’m aware that ‘singleton’ refers to there being just a single instance of a specific type, and there’s hardly just one User or HttpContext in a web application. That’s why I’m using the term ‘well-known instance’ most of the time. But for the sake of this blog-post, they aren’t all that different and ‘singleton’ is so much easier to type and read.

So, here I am, happily building a little booking application. One requirement is that each Order must be associated with the User who created the Order. Easy enough to do; I just assign the value from User.Current to the Order.CreatedBy field inside the Order’s constructor, and I’m done. Next, I launch the application, log in, create a new Order, and save it. I can easily verify the correct behavior through the application’s UI, via the debugger, or by checking the database.

Hmm… I know that I’m missing something. Oh, yes, the unit tests. Stupid me! I have to write a test first, and then the code that’s doing the heavy lifting. Let’s see… I get a new Order from the OrderFactory, assert that it is correctly initialized and that CreatedBy is set. Wait, that’s strange… The assertion fails; CreatedBy is still null. Oh, right, I forgot about User.Current. I set it, and the test is green.

Now that the Order class is done, I can start using it all over the place. After all, it’s one of the core types of my business domain. For instance, I want to check that each User can only select his own Orders. So, I’m creating two Users, Alice and Bob, and create a couple of orders for each, remembering to change the value of User.Current halfway through the test setup…

Anyone starting to feel the pain? Don’t be shy, raise your hand. I’ll even go first. And before I start sketching a scenario where each and every one of my domain tests requires a correctly set current User – and potentially triggering all sorts of nasty flashbacks of uprooting such evil – I’ll head on to the message-part of this post:

Don’t use a singleton just because you need a specific instance all over the place. And if you really do have a use case for it, think about it one more time and then don’t use a singleton.

Why? Because it flat out ruins your code’s testability. For each and every singleton your system under test depends on, you need to add setup and teardown logic, always making sure that your tests don’t have side effects. You don’t want to do that. It’s painstaking. It usually makes your test-runtime skyrocket. It is an external dependency. And it can drive the next guy working on this code nuts. Btw, chances are that’s going to be the you from a couple of weeks in the future.

Does this mean I don’t use singletons? No, not really. Especially when I’m working on re-motion, it’s usually the way to go. And by ‘usually’, I mean about a dozen config classes, holding the deserialized configuration or reflection-based metadata. Neither tends to change at runtime in applications built on top of re-motion, but forcing the users of re-motion to pass those instances around when creating objects, well, that would make the API really hard to use.

If that sounds like it’s okay to use singletons in a framework but not in an application, well, that’s because it is. Or at least, that’s what I’m telling myself to stop from obsessing over designs I chose before I saw the havoc a misused singleton could wreck out there in the wild.

But what about applications? How can you get rid of your configuration singletons? Well, you can’t. You still want to cache the config once it’s deserialized, but you can pass it into the constructor, thus removing the dependency on the singleton instance. Same goes for current User and other pieces of data used far and wide in the application.

Of course, as soon as you start passing this data around via constructor arguments, you find yourself thinking about object composition, inversion of control, factories and strategies, and generally structuring your code in such a way that you only have a few, carefully selected entry points. But that’s stuff for another blog post.

Michael

2 Responses to “The Root of All Evil”

  1. You’ve already hinted to it at the end of that blog post, but of course one of the ways to get rid of singletons _in your code_ is to move the responsibility of their life-time management to some place else – for example, an inversion-of-control container. You’ll still have objects with singleton semantics – for your application, the configuration will always stay the same, for example -, but that will only be a property assigned to your object by the IoC container.

    I’m really looking forward to re-motion’s current singletons (mixin configuration, mapping configuration, and so on) becoming managed by an IoC container…

  2. Hi Fabian!

    Actually, the lifetime-management of an IoC container can be just as problematic in unit tests as getting the respective object from a regular singleton instance. You might still have to reset the IoC during the test setup, thus incurring the time-penalty of doing some expensive operation such as reflecting or deserializing.

    Michael

Leave a Reply