Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
Ben Nadel at CFinNC 2009 (Raleigh, North Carolina) with: Jason Dean
Ben Nadel at CFinNC 2009 (Raleigh, North Carolina) with: Jason Dean@JasonPDean )

Singleton vs. Single Instance And A Decade Of Unnecessary Guilt

By Ben Nadel on

When I write a web application, the bootstrapping of said application typically involves instantiating a bunch of objects, injecting some of them into others, and then caching all of them in memory. And, for years, I felt very guilty about this because I thought that this approach was the incarnation of the "Singleton" anti-pattern. And, for years, I just accepted that I wasn't "good enough" to find a better approach. A while back, however, Corey Haines said something in a presentation that completely lifted this guilt off my shoulders. He drew a hard distinction between the Singleton anti-pattern and the use of a "single instance" in an application life-cycle. And my life was forever changed.

NOTE: Unfortunately, I cannot find the Corey Haines presentation in which this was mentioned. If I remember correctly, it wasn't even the point of the presentation - he just mentioned it in response to a comment in the Q&A portion.

The root of my problem was two fold: first, I never truly understood what the Singleton design pattern was. And second, in the ColdFusion community where I grew up, I believe that the use of the term "Singleton" was often used in lieu of "single instance." Together, these two conditions created a context in which I was writing code every day that felt like it was based heavily on anti-patterns.

It turns out, however, that Singletons and "single instances" are not the same thing. The Singleton design pattern refers to the mode of creation and access of a class instance. With a Singleton, the class has a non-public constructor and manages a static instance of itself, thereby preventing multiple instances of itself from being created. The Singleton class is also accessed as part of the shared, global state.

In a Node.js application, the Singleton anti-pattern often manifests itself as a module that controls its own instantiation:

  • var myServiceInstance = require( "../services/MyService" );

Notice that the MyService module isn't returning a service Constructor; instead, it's returning an already-instantiated instance of the service. The module is restricting access to the constructor, allowing for only a single global instance in the entire application.

The "single instance" pattern (if you can even call it a pattern), on the other hand, is a class that is only coincidentally created once during the application life-cycle. There is nothing about the class definition that explicitly restricts its usage. And, the class is generally injected into other classes instead of being accessed as part of the shared, global state.

In a Node.js application, the "single instance" pattern often manifests itself as constructor injection:

  • module.exports = class MyController {
  • constructor( myServiceInstance ) {
  • this.myServiceInstance = myServiceInstance;
  • }
  • };

Notice that this code isn't "requiring" the global instance of MyService; instead, it is receiving an instance of MyService through its constructor (and the Inversion of Control). It just so happens that the instance it receives is the only instance created during the application life-cycle; but, this is just a coincidence that the receiving class knows nothing about.

In both cases, only a single instance of MyService ever exists within the bounds of the application. But, the two approaches are wildly different and incur different costs, even if the difference feels quite subtle at first.

There's plenty of stuff that's wrong with the code that I write. And, every day, I'm trying to find ways to make my code better. But, it's been very freeing - even if only emotionally - to finally understand that creating a single instance of a class in an application is not the same as using a Singleton class. It's also a wonderful lesson in how not understanding a concept well can lead you to very incorrect conclusions.



Looking For A New Job?

Ooops, there are no jobs. Post one now for only $29 and own this real estate!

100% of job board revenue is donated to Kiva. Loans that change livesFind out more »

Reader Comments

Here's the thing. ColdFusion, at least at the time I stopped using it, couldn't have a Singleton, or an Interface for that matter. But that's a different matter. Point is, since you couldn't have a static class, there was nothing to prevent a second instantiation of that class.

However, all that is just splitting hairs. Which, admittedly, is the favorite pass time of OO theorists. The Gang of Four saw things through the lens of C++, which colored their work somewhat. If a scripted language only instantiated one instance of a class then that is functionally performing the intent of the Singleton pattern. Note- NOT "anti-pattern". The possible misuse of a pattern doesn't invalidate the pattern itself any more than using a hammer to pound in a drywall screw invalidates hammers as tools.

Point is, a dynamic typed language is often called "Duck Typed". If it looks like a duck and quacks like a duck, call it a duck. Same with patterns. If it looks like a Singleton and acts like a Singleton, call it a Singleton. Or not, as long as you're using the concept of the pattern the way it's best to use it.

Now, just to make this comment EVEN LONGER, this might be a better question. If a language doesn't natively support a pattern, shouldn't your architectural approach reflect that? If your language can't support a Singleton (capital denoting the pattern and not an implementation of the pattern) then should you even try to mimic its effects? Same with an Interface. If you aren't using a strongly typed language that doesn't allow multiple inheritance, should you even bother trying to mimic an Interface?

Reply to this Comment

@Matt,

I think maybe I touched a nerve by calling it an "Anti-pattern"? The primary point of the post was not to bash on the Singleton pattern - the primary goald of the post was simply to call out that for the last 10-years, I have misunderstood what a Singleton even was. So, whenever anyone called it a bad pattern, I was harboring guilt about the way that I code. Guilt that - regardless of whether or not you like the Singleton pattern - was unnecessary.

I am certainly in no position to argue for or against Singletons with authority. I can't be too theoretical about this stuff, because, frankly, I'm not all that good at OO. But, I've definitely run into situations where a singleton works well ... until it doesn't. Take the singleton method, Date.now(). I use this in JavaScript all the time. And in 99% of cases it's exactly the right tool for the job.

Until, you need to write a unit test that depends on a time-delta. Then, you realize that what you really need was to inject some sort of "Clock" class that has two implements, "WallClock" and "StopClock", one of which uses Date.now() internally and one of which returns an arbitrarily-set value (primarily for testing purposes).

One of the reasons I love TypeScript so much is because it feels like such a nice blend of strongly and loosely typed languages. I get both the "looks like a duck" behavior of JavaScript, with all of the type-assurance of a more "robust" language.

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
NEW: Some basic markdown formatting is now supported: bold, italic, blockquotes, lists, fenced code-blocks. Read more about markdown syntax »
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.