Disclaimer: This isn't a total knock on singletons. Alternate title: "Why singletons can be bad".
Yesterday I had a conversation about software design with an experienced colleague and found myself reaching when discussing design patterns. Specifically, we got onto the topic of the singleton pattern.
Knowing from recent experience at Cocoa Camp that singletons are not the end all be all solution for object oriented programming (yes, I might have thought that at one point), I was careful not to sound overly enthusiastic that I used the singleton pattern. I first learned about the singleton pattern an Android dev class that I took in Winter 2011 (at BYU). It sounded pretty cool then, and it was even a semi-significant part of the midterm. I later began learning Objective-C, and after using the pattern in a few iOS apps over the past year - including collaborative projects with other developers who hadn't ever mentioned any negatives in the singleton pattern - I had gradually assumed that they were a pretty solid way to go. Last month at Cocoa Camp the pattern came up and although we didn't get into any detailed discussions on it, I got the impression that singletons weren't as favorable as I had thought...
Back to our conversation, I mentioned that I knew singletons had positives and negatives and explained a little more about why I'd used them in the past. He pried pried a little deeper, asking two questions that I want to expand on. "What are some of the downsides to the singleton pattern?" "What alternative design patterns would you suggest?" I mentioned a few things, including keeping the object in memory for the entire life of the application, rather than when specifically needed, and that an alternative method could be to pass the data between view controllers rather than via the shared singleton instance. Then we moved on. Conversation over.
Why singletons are bad
Later (okay, ten minutes after the conversation ended), I found Steve Yegge's blog post, Singleton Considered Stupid:
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.
I really hope I didn't fall into this category in the mind of my colleague, but wow was I unprepared for those two questions. Especially the second question. There are few design patterns with a name as catchy as the singleton pattern. There certainly are other ways and methodologies to accomplish a programming objective, but what's the catchy name for instance classes, interfaces, and passing data between controllers?
I've done some more reading and in hopes of getting it right the next time, here are some of my thoughts.
What do you think are some of the downsides to the singleton pattern?
There are actually a ton. The reasoning is pretty straightforward and I don't know why I didn't think of these earlier.
- A shared singleton class requires that memory be in use throughout the entire application, even when the object isn't needed.
- Singletons hide dependencies!
- As a result of these hidden dependencies you can lose track of the coupling. Instead of meticulously passing each object you need (and only the objects you need) into a function, you instead call [AppUser sharedAppUser] to access your shared instance. While it feels cleaner since it can mean less lines of code to get the access you need, you can end up with very tightly coupled code.
- You can't (really) subclass a singleton
- Singletons are hard to test! (1) With hidden coupling it's difficult to create mock objects and (2) singletons generally exist for the lifetime of the app which presents a problem for unit testing, as each unit test should run independently of other unit tests.
- Just think of it as the "global-ton" pattern. The name isn't that far off. Does it still sound as sexy?
There are some upsides too, but I'll save that for another time.
What alternative design patterns would you suggest?
- Object oriented programming. This isn't just a snarky answer. Use instance classes that are instantiated within the scope that they are needed and pass those objects between methods or controllers as necessary.
- Create the instance of your object only within the scope that is needed (be careful not to abuse the AppDelegate).
- Use dependency injection to pass a single instance of the object to the components that need it (like your unit tests).
Be smarter. Understand what is actually happening when you use the singleton pattern. As tempting as slapping in SynthesizeSingleton.h into an iOS project is (see http://www.cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html), it is NOT the solution to all your problems. You may not need it at all. Tightly coupled code can be a major problem with singletons, and chances are you probably aren't unit testing (or not properly anything) whichever objects you've transformed into singletons ...which you should fix. Most of all, if you enjoy software design but can only list of the singleton pattern when trying to have an intelligent conversation about design patterns, you have homework to do.