Singleton Considered Stupid 


Stevey's Drunken Blog Rants™

Design Patterns was a great book, no question. It's still in my Top Ten List of books every programmer should read. It's a beautifully crafted book, and I get a rush of nostalgia when I read through it, ten years since it was published. It was a seminal work, groundbreaking, something that revolutionized software engineering almost overnight.

Unfortunately, for the vast majority of programmers worldwide, including many of our interview candidates, it might as well have been written in Greek, or Smalltalk. Well, actually it *was* written in Smalltalk, but nobody seems to have minded; most people thought that was pseudocode.

Here's what most people got out of Design Patterns: "blah blah blah blah SINGLETON blah blah blah blah". I kid you not. I've seen this so many times that it's become a full-fledged pattern in its own right; patterns need a name, so let's call it the Simpleton Pattern.

The Simpleton Pattern unfolds like this:

Me: So! Have you ever heard of a book called Design Patterns?

Them: Oh, yeah, um, we had to, uh, study that back in my software engineering class. I use them all the time.

Me: Can you name any of the patterns they covered?

Them: I loved the Singleton pattern!

Me: OK. Were there any others?

Them: Uh, I think there was one called the Visitater.

Me: Oooh, that's right! The one that visits potatoes. I use it all the time. Next!!!

I actually use this as a weeder question now. If they claim expertise at Design Patterns, and they can ONLY name the Singleton pattern, then they will ONLY work at some other company.

As far as I'm concerned, it's as if they said they'd read Gödel, Escher, Bach, and I asked what they liked best about it, and they said they liked Achilles, but they also thought the Tortoise was pretty cool.

Not that they weren't! But if that's all that people took away from it, then no wonder Hofstadter has turned into such a grump about it.

Everyone Loves Singleton

Why is the Singleton so attractive? I'll be the first to admit: I liked it too. No, scratch that - I loved the Singleton. It felt like an old friend from the moment I laid eyes on it. It was simple and beautiful.

I'll tell you why: it's because the Singleton pattern is a throwback to non-OO programming. It's a lifeline for people who didn't understand a single word that the Gang of Four were trying to say. I don't know how it got in there in the first place -- some political OOPSLA pressure, no doubt -- but it doesn't belong in there. It's Evil.

In my Data Structures course in college, when we got to AVL trees, my prof turned and wrote on the board, in huge, clear letters:

 AVL Trees are EVIL

...and that's all we had to learn about them. He had us implement red/black trees and splay trees instead. To this day, I have no idea how threaded AVL trees work. But if that's OK with Dan Weld, it's OK with me.

But now I know how he felt.

Singleton Considered Warm and Fuzzy

Of course I loved all of Design Patterns, except for pages 243 to 256, which had the magic property of inducing a coma-like trance whenever I tried to skim through them. I could put on a black ninja suit and sneak through the building, and presuming I didn't get arrested, I could tear those pages out of every single copy of Design Patterns at Amazon, and almost nobody would notice. That's because it's the most important one, so of course nobody gets it. I sure didn't!

I don't hold it against you, of course. Nobody does a very good job of explaining that one. It takes a very, very long time before people can appreciate it, and many people never do. If YOU do, I have openings on my team.

Anyway, I liked Singleton for the same reason everyone does: it's almost exactly the way I programmed back when I didn't know jack squat about OOP. The only significant difference is that instead of having a file with a bunch of global functions in it, I have a file with a CLASS that has a bunch of global functions. No need to worry my little head about how many of them to have, since you only need one! It's OOP made easy.

The standard justification for Singleton is: "Use this pattern whenever it's clear that you will only ever need ONE instance of this class at a time." The example they use in Design Patterns is a print spooler. Obviously you'll only ever need one of those, so you should make it a Singleton, right?

Right!

Unless you need another one with different behavior, that is. But seeing as how that could never ever possibly happen, we might as well go ahead and make it a Singleton. After all, a gang of four guys can't be wrong!

A Nagging Doubt

So I went on my merry way and made a bunch of Singleton objects. At the time, I was programming in Java, so it required a bunch of boilerplate code for all these classes. I suddenly had a RegistrationManager, and a DatabaseManager, and a UserManager, and a DocumentManager, and dozens of these other ultra-cool Singleton classes. Problem was, all that boilerplate seemed unnecessary.

Why couldn't I just make the methods static?

I mean, I have this RegistrationManager class. It handles registration. (Like, duh.) It has a method called registerUser(). Obviously my system only needed one RegistrationManager object, and would only EVER need one, so it was a Singleton, like virtually every other class in my program. (This was Grade School OO Design, by the way, and I was reveling in it. It'd be kind of embarrassing if I'd called it the RegistrationMaster, now that I think about it, given that 2/3 of our services have the word "Master" in their name.)

But for every one of my beloved Singletons, all of the client code invoking the Singleton had to do this, every time:

RegistrationManagermgr = RegistrationManager.getInstance();
mgr.registerUser(...)

It was making my fingers kinda tired to type it out. I thought about this carefully, and came to the conclusion that what I really needed was some sort of syntactic shortcut. Why not do this instead:

classRegistrationManager { // BEGIN Singleton boilerplate
privateRegistrationManager_instance = newRegistrationManager();
publicRegistrationManagergetInstance() {
return_instance;
}
privateRegistrationManager() {} // prevent instantiation
// END Singleton boilerplate
// static method to delegate to instance method
publicstatic blah registerUser (...) {
return getInstance().iRegisterUser(...);
}

// instance method, as Singleton Pattern demands
private blah iRegisterUser (...) { ... }
}

(Yes, I really did this, for about 50 classes. I guess we were all young once.)

It was a little more boilerplate code per Singleton, because I had to declare a public static version of each method and delegate to a private instance method, BUT, my client code then turned into this:

 RegistrationManager.registerUser(...);

Whoo! My client code (by which I mean anyone in the same process using the Singleton instance) no longer needed to do that extra getInstance() call, which was just plain annoying and useless.

But why stop there? Why not just get rid of the delegation altogether? I resolved to figure this out, and hopped on the patterns newsgroups where Ralph Johnson lurked. Lo and behold, Ralph had answered that very question the month before. His answer: it doesn't matter; using static methods is fine - that's still a Singleton.

Great! Gosh, I was excited. I'd get rid of the Singleton instance (and the boilerplate), make everything static, and my code was now super clean.

Yep. I was using classes purely as namespaces.

Since in Java, classes are the ONLY globally available namespace mechanism built into the language, this is actually a common thing to do, Singleton or no. Unless you want to build your own reflective registry, or use JNDI or something, classes are your only option for separating your code into namespaces. So in that regard, the (very) little I was doing with classes wasn't actually so wrong.

But I'd thrown all the rest of that OO crap out the window. It was a C program with some namespace support and garbage collection.

I suppose I could tell the rest of the story, but the nutshell version is that I wound up having to (1) learn how OOP really works, the hard way, and (2) re-implement parts of my application over and over, until it started to approximate a rational OO design. I learned much later that this is called Refactoring, and I sure wish I'd read THAT book in 1999 when it came out, instead of late 2003.

Get to the Point, Already

Fine, fine. Here's the "short" summary, although clearly this should have been a book, not a blog entry:

a) I haven't covered even a tenth of the issues. But I'll name a few of them.

b) One is memory management; a Singleton is basically just a memory leak, if nobody is going to be using it for a while. But you have no idea when to deallocate it, because nobody's going to call you and say "nobody's going to be using you for a while!"

Besides, you can't tell who has kept around references to your Singleton instance, since you were pretty blase about handing it out, weren't you? (Note: Java's weak references can help with this issue).

c) Speaking of memory leaks, what if your Singleton has a handle to some limited resource, like a database or file handle? I guess you get to keep that sucker open until your program ends. Thank God C++ programs never last longer than about 10 minutes before crashing, usually from running out of resources, or from trying to access a Singleton that someone freed.

d) Another issue is that the Singleton design is syntactically noisy; most languages don't support it (well, Ruby does, sadly, but that was probably before Matz knew any better), so you have to stick in boilerplate code not only in the Singleton, but in everyone who uses it.

e) Then there's the subclassing thing. It's almost impossible to subclass a Singleton, and if you manage it, then you shouldn't have been using a Singleton in the first place. You don't *even* want to go there. I've walked roads that I dare not recount. Just pretend you can't do it, and you'll save yourself amazing amounts of pain.

f) static methods are as flexible as granite. Every time you use one, you're casting part of your program in concrete. Just make sure you don't have your foot jammed in there as you're watching it harden. Someday you will be amazed that, by gosh, you really DO need another implementation of that dang PrintSpooler class, and it should have been an interface, a factory, and a set of implementation classes. D'oh!

Don't suppose that's all. There are many other problems. For instance, try adding multithreading in and see what happens. Well, I'll tell you what happens: half the time, you get a Doubleton or a Tripleton, unless you're a synchronization expert, and having a Tripleton is about as desirable as having three Balrogs show up at your tea party. And even if you're a synchronization expert and get the double-check idiom right, you've still got one Balrog to deal with, and they're no picnic.

But these problems all fade into insignificance compared to the Big One, which is that the Singleton "pattern" encourages you to forget everything you know about OO design, since OO is hard, and procedural is easy.

Friends: don't let friends use Singletons!

What About The Other Patterns?

Yeah, what about them. Are they cool, or do they suck as much as the Singleton?

Well, as it happens, some of them DO suck -- but not for the same reasons as the Singleton sucks. Design Patterns is actually an odd book; it's part genius and part band-aid. This owes entirely to the fact that C++ swept the computing world like a wildfire around 1991 or so. Nobody expected this would happen, least of all Bjarne, because C++ was the most comical, far-fetched, unlikely programming language experiment in history.

I'm not ready to bash on C++ yet. All of this stuff I'm writing, in blogs and the ADJ, is just practice for when I start bashing C++ in earnest, and trust me: when I'm finished, one of us (me or C++) won't be here at Amazon anymore. There's only enough room for one of us in this town. But in the meantime, I'll play nice. Pretend I like C++ for now. It's better than Fortran or Pascal, so there's at least a -grain- of truth there.

Design Patterns was especially well-timed because it offered a ray of hope for people who were mired in the Woes of the New OO Programmer. You see, the OO camp was saying: "EVERYTHING IS AN OBJECT! YOU WILL THINK OF EVERYTHING AS OBJECTS FROM NOW ON! THE OO PROGRAMMING PARADIGM IS: CREATE YOUR CLASSES, ADD OPERATIONS TO THEM, AND LAUNCH THE DAMN THING!"

The last sentence (forgive the caps, sorry) is a pretty reasonable paraphrase of Stroustroup in his "The C++ Programming Language" book, where in Chapter Two he says that the programming paradigm is "Decide which types you want; provide a full set of operations for each type."

Everyone believed him, and they went and defined their types, which just stared back balefully.

Bob: "Hey Fred, how do I model a Loop?"
Fred: "Easy! Make a Loop class."
Bob: "OK. What operations should it have?"
Fred: "Um, lemme look. Prolly give it a parent, and instantiate it with a number of iterations and a stopping point."
Bob: "Wow, this OOP solves everything! What code should I put in the doLoop() method?"
Fred: "I think that's where you instantiate it"
Bob: "That's so cool, it's almost... confusing."
Fred: "Make sure you make it a Singleton. I've never seen a reason not to."

Everyone was bought into the fact that OOP was the future, and also the past, since Marketing felt it was important to make everyone forget what existed before OOP, in case they might start to have doubts. But there were a few open questions, such as how to model relationships between types, a problem Stroustroup had most conveniently overlooked in his Magnum Opus.

Stroustroup: As you can see, operator overloading has proven extremely useful, which I will demonstrate for the 16th time by once again using the Complex Number class. See how useful it is to have the + operator for this class? I sure love this example. Don't you?

Readers: Wow. He's right. It is useful.

Stroustroup did a wonderful job of marketing C++, and because you could learn it one feature at a time ("I like the double-slash comments"), it was an attractive proposition for all the bad C programmers out there.

But Stroustroup was utterly silent on the issue of how classes actually interact, and the first book to come along and package up an idea with equally good marketing was Design Patterns. It showed people some convenient and (mostly) intuitive ways for small groups of objects to collaborate to solve situations you run into all the time. Cool stuff!

The problem is, about 1/3 to 1/2 of them were basically cover-ups for deficiencies in C++ that don't exist in other languages. Although I'm not a huge Perl fan anymore, I have to admit the Perl community caught on to this first (or at least funniest). They pointed out that many of these so-called patterns were actually an implementation of Functional Programming in C++.

The Visitor, for instance, is just a class wrapper for a function with some accumulator variables, something that's achieved far more cleanly with, say, the map() function in higher-level languages. Iterator is a poor man's Visitor. The Strategy pattern is beautiful on the surface, but Strategy objects are typically stateless, which means they're really just first-order functions in disguise. (If they have state, then they're Closures in disguise.) Etc. You either get this, because you've done functional programming before, or you don't, in which case I sound like I'm a babbling idiot, so I guess I'll wrap it up.

I do think that about 2/3 of the Design Patterns in the original Gang of Four book have significant merit, and I use them occasionally. They're no longer hammers in search of a nail, but they're useful now and again, and I do appreciate them when I need them.

I'll close by saying that if you still feel the need to use Singleton objects, consider using the Factory Method pattern instead. It gives you all of the flexibility of the Singleton, with nowhere near as many problems. Using the Singleton is usually just a sign of premature optimization - I know you dread instantiating objects; you've heard it's way slow. But just relax, take a deep breath, and treat yourself to a few extra instances. You'll be amazed at how fast computers have gotten these days, and you'll be pleased at the extra flexibility using real objects gives you. Enjoy!

Tune in next time for: "Staying Up Too Late Considered Harmful."

(Note: I think there are some good uses for the Singleton pattern, but it's so incredibly overused, and serves as such a convenient crutch for people who don't understand OOP, that I figured I'd just take the stance in this article that it's basically Evil.)

(Published September 03, 2004)