Click here to monitor SSC

Alex Davies

Software Engineer - Red Gate Software

The "Singleton" Design Flaw

Published Wednesday, April 15, 2009 3:08 PM

In my earlier post I mentioned that there are a couple of design patterns that I think are wholly wrong. The one that I'm most convinced is an abomination is the singleton pattern.

The basic idea is that you make a class that should only ever have one instance, and you provide that instance by storing it in a static (aka global) variable once it's made, so that everyone can get it easily.

There are lots of situations that this looks like it's going to save time. For example you might have a cache that you want everything to share. Or you may know that you only want one instance of the UI. You can save the effort of passing these things around, and all you need to do is call a static method from anywhere and you'll be given the instance.

But it's not going to save effort in the long run, because static state ruins everything:

Static state ruins readability
If you have a lump of code that doesn't read from any static state, you have to pass it any instances of things that it might change (preferably in its constructor). This is great documentation, giving you an overview of what influence a class can possibly have. Of course, there's so much static state in the world, you lose a lot of this already (the file system for starters), but there's no sense in making more.

Static state ruins testability
Automated testing of any kind is much easier if you can split up which parts of your system you are testing at any one time. To do this, you need to stop the bit you do want to test from starting and using the bits you don't want to test. Of course, you could scatter compiler directives in to choose whether to do things, but I reckon it's easier to just pass mock objects in, which pretend to be the rest of the system, but in fact just give the same results for every call (or even better, check that you're making the right calls).

Static state ruins refactoring
When refactoring, you know that you can take your code, and move it somewhere else, as long as you can get hold of all the things that it depends on. If you use static state, it's really hard to see where those dependencies are, and whether they'll be still there, and mean the same, in the code's new home.

Static state ruins expanding the system
 There have been so many times that I've written some code, and then a few weeks down the line realised that I need a similar component for a different job. It happens a lot in UI programming, where making life easy for the user is more important than avoiding redundant functionality. So, rather than copying the code, I can quickly make it more generic so it can cope with both tasks, and then use a second instance of it, passing it a different set of dependencies to deal with. If it had relied on static state, I would have had to unpick the dependencies from the code, and it probably wouldn't have been worth it.

If you want to expand your system to run in parallel (for example if it is processing web requests or something) all you need to do is make more instances of your class. No worries about thread safety until you know you really have to share something between them.

How bad is all this passing around going to get? I hate methods and constructors with lists of parameters as long as your arm. They're ugly, and mean that important details get lost. Passing things around does mean that classes that depend on lots of things get loads of constructor parameters. That's great, because then I know when a class is dealing with too many concepts and I need to take a knife to it.

So, never use the singleton design pattern, or static state at all.

Comments

 

SteveSanderson said:

Alex, are you confusing the singleton pattern with static storage? All your complaints are about statics, not singletons, and yet you conclude "So, never use the singleton design pattern..."

If you have a component whereby all consumers should work with the same instance, that component is a singleton by definition. Assuming you're implementing this through a DI container, it's a regular object instance (not static), is usually supplied to those consumers as a constructor parameter, and doesn't lead to any of the problems you describe.
April 16, 2009 6:29 AM
 

RobertChipperfield said:

Steve - I'm guessing that to most people, Singleton means having a static property on the class which gives you back the same instance of the class every time:

private static Foo s_Instance;
public Foo Instance { get {
if (s_Instance == null) s_Instance = new Foo();
return s_Instance;
} }
April 16, 2009 7:15 AM
 

Alex.Davies said:

Using dependency injection is exactly what I'm arguing for. Although your dependency injection framework may look like it's making sure that there's only one instance of something, it's actually making sure there's one instance per instance of the DI framework. That's entirely different, and totally fine :)
April 16, 2009 7:29 AM
 

RobertChipperfield said:

Hmm, I always get mildly worried when people start using entire "dependency injection frameworks" when really all you need a lot of the time is, well, a single class with a few properties on it, that gets passed into your various constructors.

I've seen many projects where the amount of complexity, both visual (code clutter) and computational (performance), introduced by the use of a DI framework *vastly* outweighs the benefits gained by using it.
April 16, 2009 7:32 AM
 

Alex.Davies said:

Yes, I don't think I'd ever use a pre-packaged DI framework. You could call the little classes that do all the instantiating of stuff and putting dependencies in constructor parameters a "dependency injection framework" though, if you like like, even if they're only 100 lines long and not dynamic at all :)
April 16, 2009 7:40 AM
 

SteveSanderson said:

@Robert:
> I always get mildly worried when people start using entire "dependency injection frameworks"
It's only really meaningful to evaluate the suitability of a DI framework in the context of a specific project. Is this article written with a specific project in mind? Clearly, a DI framework is not required to print out "Hello, world!", but in larger applications it can reduce complexity significantly: it can resolve dependency chains automatically and makes decoupling easy. Also, can you honestly name a specific project where the perf overhead of a DI framework actually caused business problems in the real world? I'm not sure I'd believe it... :)

@Alex.Davies:
> I don't think I'd ever use a pre-packaged DI framework
What's your justification for that? "Not Invented Here"? I know we can all write a DI framework in 14 lines of C# which covers 80% of the use cases, but why not get a pre-debugged one that covers 100% of the use cases and takes less time to integrate than writing those 14 lines? Have you tried using Ninject or Structuremap recently?
April 16, 2009 7:55 AM
 

RobertChipperfield said:

Steve - I have to admit you've caught me out on a specific performance problem example, but partially, that's because I've never tried to debug performance problems in huge apps, and I don't generally use pre-packaged frameworks in my own projects.

As for your comment towards Alex, I think that anything that will cover 100% of all use cases will, almost necessarily, have subtleties in its use, and be sufficiently complex internally that it's almost impossible for someone to just pick it up and use it without error.

On the other hand, 14 lines of your own code that covers 100% of *your* use cases on that project will be much easier to read and debug - and here I mean debug including your mistakes in using it (probably much more likely!), not just mistakes in the coding of the DI framework itself.
April 16, 2009 8:01 AM
 

SteveSanderson said:

OK, apologies for taking this thread way off-topic from the original post!

I don't mean to come across as a DI fanatic - I'm merely suggesting that using a tried-and-tested DI framework can sometimes add value to certain projects. Certainly in medium to large line-of-business apps these days it's becoming a fairly standard part of the infrastructure. But of course there will be other projects where it's less obviously useful, and you may have a good reason for choosing not to use one.
April 16, 2009 8:15 AM
 

RobertChipperfield said:

On the contrary, I think it's the sign of a good blog post when it provokes a nice bit of heated discussion :-)
April 16, 2009 9:45 AM
 

RossPatterson said:

Singletons are FORTRAN's NAMED COMMON in sheep's clothing.  I thought our forefathers in computing had done a good job of explaining why global variables were a bad idea, but things like this keep coming back.
April 21, 2009 9:41 AM
 

RossPatterson said:

@SteveSanderson: I don't think Alex is arguing against static storage, although that's often part of the Singleton anti-pattern too.  I think his point is that globally-shared state is almost never a good idea, no matter how many crufty parameters it removes from constructors and method calls.  I have mixed feelings about that, but in general I think it takes a very disciplined and professional development team to use global state wisely.
April 21, 2009 9:42 AM
 

BuggyFunBunny said:

@Ross:
Singletons are FORTRAN's NAMED COMMON in sheep's clothing.  I thought our forefathers in computing had done a good job of explaining why global variables were a bad idea, but things like this keep coming back.

It is easy to explain.  In enterprise development, whether C# or java or any OO language, there exists the overhang of existing file storage (VSAM for those with mainframe exposure) and file programmers and file programs.  Since management never wants to get rid of the cruft, even knowledgeable developers get seduced by the 1960's paradigms.  Since Dr. Codd is no longer with us, Date is shilling, Pascal has left for another planet, and Stonebraker is pushing column stores; MySql is now the rage with KiddieKoders.  Thus leading to client-centric paradigms, and global variables.  At least we had Woodstock back then.  Easy to explain, but depressing.
April 21, 2009 10:28 AM
You need to sign in to comment on this blog
<April 2009>
SuMoTuWeThFrSa
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789
Migrating from OCS 2007 R2 to Lync: Part 4
 Having migrated the rest of our users and legacy resources across, and start getting ready to... Read more...

Automated Script-generation with Powershell and SMO
 In the first of a series of articles on automating the process of building, modifying and copying SQL... Read more...

Seth Godin: Big in the IT Business
 Seth Godin has transformed our understanding of marketing in IT. He invented the concept of 'permission... Read more...

Using SQL Test Database Unit Testing with TeamCity Continuous Integration
 With database applications, the process of test and integration can be frustratingly slow because so... Read more...

Converting String Data to XML and XML to String Data
 We all appreciate that, in general, XML documents or fragments are held in strings as text markup. In... Read more...