So Singletons are bad, then what?

  • There has been a lot of discussion lately about the problems with using (and overusing) Singletons. I've been one of those people earlier in my career too. I can see what the problem is now, and yet, there are still many cases where I can't see a nice alternative - and not many of the anti-Singleton discussions really provide one.

    Here is a real example from a major recent project I was involved in:

    The application was a thick client with many separate screens and components which uses huge amounts of data from a server state which isn't updated too often. This data was basically cached in a Singleton "manager" object - the dreaded "global state". The idea was to have this one place in the app which keeps the data stored and synced, and then any new screens that are opened can just query most of what they need from there, without making repetitive requests for various supporting data from the server. Constantly requesting to the server would take too much bandwidth - and I'm talking thousands of dollars extra Internet bills per week, so that was unacceptable.

    Is there any other approach that could be appropriate here than basically having this kind of global data manager cache object? This object doesn't officially have to be a "Singleton" of course, but it does conceptually make sense to be one. What is a nice clean alternative here?

    I personally am yet to understand the who singleton issue, however ... what if the app grows much bigger? What if you suddenly want to go the multi-tiered route? If you have 1000 clients, then they will still send a whole bunch of requests before their caches fill up. Would it maybe make sense then to have a secondary tier, or a proxy? What if it goes down? I do not know what exactly you are building, but is sounds to me that you can get away with a singleton only for as long as the requirements do not change to the point that it does not help anymore. I suppose this applies to any design ...

    What problem is the use of a Singleton supposed to solve? How is it better at solving that problem than the alternatives (such as a static class)?

    @Anon: How does using a static class make the situation better. There is still tight coupling?

    @Martin: I'm not suggesting it makes it "better". I'm suggesting that in most cases, a singleton is a solution in search of a problem.

    The book says it's useful to have a singleton if it would be detrimental to have multiple instances of the class. If you can imagine a situation in which it isn't for your case, then you're probably doing it wrong. What if you suddenly handle more than one database connection?

    @Anon: Static classes can't have state. Given that we're talking about a cache, where exactly would a static class store its data?

    @Bobby: one remark, why make it a singleton when you could simply pass a reference to the screen (via its base class) and store a single object in the main application core ?

    @Aaronaught: Wait, since when can we not have static fields in a class?

    I suppose you're right, @Anon, but the thought of an entire cache based on static fields makes my skin crawl. Seems that no matter how hard the language designers try to steer programmers away, the programmers always end up re-inventing global variables.

    @Aaronaught: Using a Singleton is using global state, it is no better than a static class in that regard.

    @Anon: Not true. Static classes give you (almost) no control over instantiation and make multi-threading even more difficult than Singletons do (since you have to serialize access to every individual method instead of just the instance). Singletons can also at least implement an interface, which static classes cannot. Static classes certainly have their advantages, but in this case the Singleton is definitely the lesser of two considerable evils. A static class that implements *any* mutable state whatsoever is like a big flashing neon "WARNING: BAD DESIGN AHEAD!" sign.

    @Aaronaught: If you're just synchronizing access to the singleton, *then your concurrency is broken*. Your thread could be interrupted just after fetching the singleton object, another thread comes on, and blam, race condition. Using a Singleton instead of a static class, in most cases, is *just taking the warning signs away and thinking that solves the problem*.

    @Anon: We are talking about *instance lifetimes* here. The methods of a Singleton class all have an implicit guarantee that all necessary state has been initialized; a static class has no such guarantee. *Every public method* of a static class (with state) must make this check explicit and must also therefore use synchronization in the case of concurrency. Singletons are *usually* a poor design choice, but static classes with state are *almost always* a disaster waiting to happen.

    @Aaronaught: What, are we not allowed to use static constructors now?

    Oh for god's sake @Anon, please don't tell me you actually write programs like this. Static constructors are supposed to be used for unmanaged resources and the like. You have absolutely no control over when they execute, can't guarantee that any base class initializers have executed, and using one suppresses any `beforefieldinit` optimizations. None of these are terrible things *if you know what you're doing*, but if you're using them for a purpose like this then I'd say it places you pretty far outside that camp. You do not want critical initialization code running at totally random times.

    @Aaronaught: I don't write (production) code like this. I also don't write code using Singletons. It's largely irrelevant to a discussion on their merits. In Java, static code blocks are guaranteed to execute at class load time, which happens on first access. C# static constructors are executed the first time a member is accessed or the class is instantiated. Does not happen at a "random time" any more than `getInstance()` is called at a random time.

    @Anon: That is *not* correct. Static constructors are guaranteed to execute *before* any members are accessed; there are no constraints on *how soon* before. At least for C#, it's right there in the documentation. I wouldn't use a Singleton *or* a static class with state, but if I had to choose one then at least Singleton maintains a very *limited* degree of OO and lifetime management; the static class version is effectively writing procedural code.

    @Aaronaught: Check here, or section 10.12 of the actual language spec (the wording is the same). With regards to terrible design, I'm in the camp of making the terrible design obvious rather than sweeping it under the rug.

    @Anon: I'm not sure what it is that you want me to look at in there, but you do realize that you are quoting an obsolete section of the documentation that has been superseded by the one I *just* linked to? And by your own admission, your position is that if you had to choose between two less-than-ideal options, you would choose the *worse* one because the flaws would be more *obvious*; great, that is some fine engineering sense right there.

    @Aaronaught: I realize that the link I provided was out-of-date, which is why I asked you to look at *the actual current language specification* (which is a pain to link to), rather than the Visual Studio documentation. And no, that's not my position. My position is that the Singleton anti-pattern is generally used in a way that provides *no* benefits over the alternatives, and in that case, it's better to make the terrible design obvious rather than hiding it.

    @Anon: It *does* provide benefits over the alternatives if your alternative is a static class. You can control access, instantiation, you can even write a conditional in the initializer to choose from a derived type if your app needs to change its behaviour based on configuration or environment. It's not the *best* design, but it is miles better than a static class. Singletons *have* a purpose, they're just largely an obsolete design. Global static classes with mutable state were *never* a solution, they served only to prove the old programming adage, *"You can write FORTRAN in any language."*

    @Aaronaught: It *can* provide benefits, you mean. See my point about generally being used in a way that doesn't provide those benefits.

    Singletons are effectively global variables. If you would be wary of using mutable global variables, you should be wary of using mutable global state of other kinds, such as the Singleton pattern.

    doesn't the Initialization On Demand Idiom solve some of the concurrency problems mentioned previously (due to lack of static members)?

  • Aaronaught

    Aaronaught Correct answer

    10 years ago

    It's important to distinguish here between single instances and the Singleton design pattern.

    Single instances are simply a reality. Most apps are only designed to work with one configuration at a time, one UI at a time, one file system at a time, and so on. If there's a lot of state or data to be maintained, then certainly you would want to have just one instance and keep it alive as long as possible.

    The Singleton design pattern is a very specific type of single instance, specifically one that is:

    • Accessible via a global, static instance field;
    • Created either on program initialization or upon first access;
    • No public constructor (cannot instantiate directly);
    • Never explicitly freed (implicitly freed on program termination).

    It is because of this specific design choice that the pattern introduces several potential long-term problems:

    • Inability to use abstract or interface classes;
    • Inability to subclass;
    • High coupling across the application (difficult to modify);
    • Difficult to test (can't fake/mock in unit tests);
    • Difficult to parallelize in the case of mutable state (requires extensive locking);
    • and so on.

    None of these symptoms are actually endemic to single instances, just the Singleton pattern.

    What can you do instead? Simply don't use the Singleton pattern.

    Quoting from the question:

    The idea was to have this one place in the app which keeps the data stored and synced, and then any new screens that are opened can just query most of what they need from there, without making repetitive requests for various supporting data from the server. Constantly requesting to the server would take too much bandwidth - and I'm talking thousands of dollars extra Internet bills per week, so that was unacceptable.

    This concept has a name, as you sort of hint at but sound uncertain of. It's called a cache. If you want to get fancy you can call it an "offline cache" or just an offline copy of remote data.

    A cache does not need to be a singleton. It may need to be a single instance if you want to avoid fetching the same data for multiple cache instances; but that does not mean you actually have to expose everything to everyone.

    The first thing I'd do is separate out the different functional areas of the cache into separate interfaces. For example, let's say you were making the world's worst YouTube clone based on Microsoft Access:

                  |                 |                 |
             IMediaCache      IProfileCache      IPageCache
                  |                 |                 |
                  |                 |                 |
              VideoPage       MyAccountPage     MostPopularPage

    Here you have several interfaces describing the specific types of data a particular class might need access to - media, user profiles, and static pages (like the front page). All of that is implemented by one mega-cache, but you design your individual classes to accept the interfaces instead, so they don't care what kind of an instance they have. You initialize the physical instance once, when your program starts, and then just start passing around the instances (cast to a particular interface type) via constructors and public properties.

    This is called Dependency Injection, by the way; you don't need to use Spring or any special IoC container, just so long as your general class design accepts its dependencies from the caller instead of instantiating them on its own or referencing global state.

    Why should you use the interface-based design? Three reasons:

    1. It makes the code easier to read; you can clearly understand from the interfaces exactly what data the dependent classes depend on.

    2. If and when you realize that Microsoft Access wasn't the best choice for a data back-end, you can replace it with something better - let's say SQL Server.

    3. If and when you realize that SQL Server isn't the best choice for media specifically, you can break up your implementation without affecting any other part of the system. That is where the real power of abstraction comes in.

    If you want to take it one step further then you can use an IoC container (DI framework) like Spring (Java) or Unity (.NET). Almost every DI framework will do its own lifetime management and specifically allow you to define a particular service as a single instance (often calling it "singleton", but that's only for familiarity). Basically these frameworks save you most of the monkey work of manually passing around instances, but they are not strictly necessary. You do not need any special tools in order to implement this design.

    For the sake of completeness, I should point out that the design above is really not ideal either. When you are dealing with a cache (as you are), you should actually have an entirely separate layer. In other words, a design like this one:

                              Cache (Generic)---------------+--IProfileRepository
                                    ▲                       |
                                    |                       +--IPageRepository
                  |                 |                 |
             IMediaCache      IProfileCache      IPageCache
                  |                 |                 |
                  |                 |                 |
              VideoPage       MyAccountPage     MostPopularPage

    The benefit of this is that you never even need to break up your Cache instance if you decide to refactor; you can change how Media is stored simply by feeding it an alternate implementation of IMediaRepository. If you think about how this fits together, you will see that it still only ever creates one physical instance of a cache, so you never need to be fetching the same data twice.

    None of this is to say that every single piece of software in the world needs to be architected to these exacting standards of high cohesion and loose coupling; it depends on the size and scope of the project, your team, your budget, deadlines, etc. But if you're asking what the best design is (to use in place of a singleton), then this is it.

    P.S. As others have stated, it's probably not the best idea for the dependent classes to be aware that they are using a cache - that is an implementation detail they simply should never care about. That being said, the overall architecture would still look very similar to what's pictured above, you just wouldn't refer to the individual interfaces as Caches. Instead you'd name them Services or something similar.

    First post I have ever read which actually explains DI as an alternative to global state. Thanks for the time and effort put into this. We are all better off as a result of this post.

    Why can't the Cache be a singleton? Is it not a singleton if you pass it around and use dependency injection? Singleton is just about limiting ourselves to one instance, not about how it is accessed right? See my take on this:

    @AdamSmith: Did you actually read *any* of this answer? Your question is answered in the first two paragraphs. Singleton Pattern !== Single Instance.

    @Aaronaught I did, but you have a definition of singleton pattern, and I don't see a problem with any of the points. The problems you list don't follow from merely following the singleton pattern bullet list you present.

    I completely agree with @AdamSmith. You're not really giving an alternative to singleton Aaron, unless you mean we should simply use `static` instead, which is a bad advice. Static and singletons have their niche, the problem is the misusage of them. || Now that's good and simple writing on your tumblr, Mr Smith. I also advice for more complex reading on the same subject, this great article, more than 10 years old and still much useful:

    Or you could say singletons are actually good and use Toolbox (i.e. check my answer in this very question)!

    @Cawas and Adam Smith - Reading your links I get the feeling you didn't really read this answer - everything is already in there.

    @Wilbert Reading your comment I feel you didn't really read my links (there are many links, dude, with many big reads). You're being too much pretentious thinking it's all in this answer. From the "question quote" and beyond all *Aaron* do is address the problem in the question about caching. And that has nothing to do with singletons being good or bad, as he just proposes one good architecture solution for a singular problem. So, the only part addressing singleton issues is the bullet list. Big deal.

    @Cawas I feel that the meat of this answer is the distinction between single-instance and singleton. Singleton is bad, single-instance is not. Dependency Injection is a nice, general way to use single-instances without having to use singletons.

    @Wilbert I hear you. I read the bullet list part again. I see what you mean. And now I do agree. That is indeed the meat of the answer... But I still think there's something missing there. It's like you and Aaron are both first assuming Singleton are bad, then drawing this conclusion. Singleton is indeed a subsection of single instance. But it's also a subsection of a "kind of global var". As such, a single instance can't really replace a singleton just as much as it can't be global. So, that's cherry picking.

    There is one more condition to be the bad singleton pattern: Mutability or access to external mutable state. For example making something like `AsciiEncoding` a singleton with a static accessor would be fine since any possible instance of it would be equivalent.

    @CodesInChaos: That's an interesting point, and actually demonstrates another way of implementing single instances without the problem-ridden Singleton pattern. Certain thread-safe classes like `AsciiEncoding` are single instance but are also constructable and inheritable. It's a fairly specialized implementation of a more general class of *pools*, like the ADO.NET connection pool. What's interesting about these is that the singleton-ness is an *implementation detail* and never exposed to the consumer. `Encoding.ASCII` is just a utility method, you could still subclass and create your own.

    Great explanation of DI, and I've been using DI extensively in the last few years. But I'd like to point out that occasionally, doing DI manually is unreasonably cumbersome, and some languages don't support automatic DI well, e.g. C++. I've found service locators (implemented as singletons, yes) to be a good alternative in those cases, they've got only a few of the weaknesses of singletons you identified above.

    I'm not sure if I understand this last picture or not. Why are there interfaces on the *side*? How are these interfaces different from the ones below the cache?

    @Lucas that didn't clarify. Maybe because of your typos.

    @tieTYT: He was just pointing out that a full design would have to access the data through a repository interface and that the Cache will mediate the repositories' access to the underlying data store.

    @Lucas ah, so is he saying the impl of that Cache class *uses* those interfaces on the side but *implements* the interfaces below?

    @AdamSmith if you're going to pass it around rather than access through the `getInstance()` then there's no need to add the singleton boilerplate code in the first place. conversely you just want to "ensure" one instance then that means you're setting yourself up for the (ab)use of the `getInstance()` method. if there's no `getInstance()` then people can't abuse it.

    @Dax Fohl singletons are to prevent multiple instances from being created. You use getInstance() instead of new. Just like with other objects sometimes you instantiate them and sometimes you pass them around. People create problems for themselves by ALWAYS using getInstance() instead of passing a pointer which they would have done for any other non singleton class.

    @tieTYT: No, the repositories reference the various abstract cache types; the concrete cache classes below are implementations of the abstract caches. This is one possible implementation. Another would be a decorator implementation where the cache actually implements `IMediaRepository` and wraps the real `IMediaRepository`, although you really *have* to use an IoC container in order to make effective use of that pattern. Any of these are, of course, still better than the Singleton pattern.

    There are two meanings of "single instance". 1. Your application uses only one instance, (and you want every part of the application to have access to that single instance). 2. You want to block "new Foo()" from being called more than once in the same process. A lot of trouble comes from this second idea, which imo is quite pointless. I have never seen a case where restricting the use of "new Foo()" would be a good idea.

    @Aaronaught, Why do you say that singletons are **never** explicitly freed? I do actually remember seeing singletons that *are* explicitly freed.

    @Pacerier: No, they aren't. Read the answer. The Singleton pattern is intended to have an object lifetime equivalent to the application itself. Therefore, it can't be freed. (Of course, in non-GC'ed languages it *can* be freed, but it is illegal to do so.) Please feel free to link to a Singleton implementation that permits this behaviour if you disagree.

    @Aaronaught, Do you mean that a singleton implementation that allows explicit freeing is no longer considered a "singleton" simply *by definition*?

    @Pacerier: The fundamental basis of the singleton pattern is its absolute and exclusive control over object lifetime. The instance cannot be created *or destroyed* by anyone else, lest it invalidate the guarantees made by a singleton. So yes, this is a matter of definition; an instance with a public destructor is *ipso facto* not a true singleton.

    "Dependency Injection" a.k.a. interfaces.

    @Peter: Those two concepts aren't necessarily related. In the SOLID) guidelines, they are the "D" and the "I" respectively. Both good practices, both independent of each other.

    I'm really surprised that there is no mention in any of the answers about how Singleton and Service Locator patterns create **hidden complexity**. I believe that is one of the stronger reasons to leave Singleton dead.

    Great answer! Do anyone have a link to an example where this is done? To get a even better understanding of it? I'm in the process of experimenting with switching out my singleton myself.

    As in "Difficult to parallelize in the case of mutable state (requires extensive locking)" -- isn't this a problem with every single instance as well?

    @Aaronaught I got a bit confused about the last graph. 1. Does the Cache Interfaces request data from the same instance of Cache (Generic)? 2. Does the Cache (Generic) hold references of Repository Interfaces, and use them to query data from the server? Your answer is really excellent and I'd like to learn more thoroughly from it!

    Your caches have dependencies on specific dbms syntax and drivers? :D

    +1 though because the rest of your answer is great - well written, easily understandable and a great reference to give to people you catch typing public static Whatever getInstance()

    Accessible via a global, static instance field; > This is a fact. I don't see why it is bad. Created either on program initialization or upon first access; > Nice. No public constructor (cannot instantiate directly); > So what? Never explicitly freed (implicitly freed on program termination). --> Yes but like many other mechanism and I hope if you decided to use it is because you know what you do. Of course using singleton to just do a stupid call is stupid.

    Couple of questions. Why the inability to subclass is a problem if you want a single instance? Why do you mention inability to use interfaces, when a singleton could implement an interface. Maybe I didn't get it.

    `Inability to subclass` not true for singleton class

    It seems for me that your answer is rather a guide for how to properly subclass than the usage of singletons. Unfortunately, these two things are not related.

License under CC-BY-SA with attribution

Content dated before 6/26/2020 9:53 AM