Jump to content
  • Advertisement
Sign in to follow this  
TheMac

Why are singletons bad?

This topic is 3409 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Everywhere you look you will find intelligent people saying singletons are bad. For one they are hard to test (I don't understand why), the user (other programmers) don't know the dependancy of the methods using the singletons (I would think that is good, make the code as simple as possible). I am going through this in my head and I can't understand why for one, singletons are hard to test in your unit tests. Why would they be hard to test? Evenyone says they are, but doesn't give an example of why they are hard. The fact that they are persistant should not effect the design of your code just so you have pretty unit tests. If you need a new class that is a singleton, why not make a new unit test? And if its the classes the singleton contains you want to test, then why not call them directly? Are we redesigning our code for the convenance of easily making unit tests? Can someone shed some light on this for me? By the way I'm a C++ developer, so .NET, Java and the fact they have private classes don't matter to me. Thanks.

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by TheMac
Are we redesigning our code for the convenance of easily making unit tests? Can someone shed some light on this for me?


Easily testable classes ~ easily usable classes.

Personally, I think Singletons are very useful for some things, for example configuration data, Resource Factories and so called "global objects" like the "application object".

Share this post


Link to post
Share on other sites
That doesn't explain why singletons are hard to test, and why the development community hates them for some reason.

Share this post


Link to post
Share on other sites
I guess the thing that's bad about about singletons is they let you get away with sloppy design because you don't really have to think much about why in the world Module A should be passed a reference to Module B. You just call A::GetInstance().doSomething() and are done with it. Whereas if you'd have to pass a reference to get the job done maybe you'd stop to think, hmmm ... I'm passing references to Module A to all kinds of things in my program, even some of the modules that shouldn't really need it ... maybe I should rethink my design?

[Edited by - Red Ant on March 17, 2009 3:40:16 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by TheMac
That doesn't explain why singletons are hard to test, and why the development community hates them for some reason.
I haven't heard the "singletons are hard to test" argument, and it's certainly not the most important reason to avoid singletons. Singletons are essentially rebadged globals, and have exactly the same problems in an OO context as global variables. If you are an OO purist, globals and singletons both violate various pure OO principles. If you are not an OO purist, singletons are more complicated than globals, yet provide extremely little extra benefit.

Share this post


Link to post
Share on other sites
Quote:
Original post by TheMac
That doesn't explain why singletons are hard to test, and why the development community hates them for some reason.


Hmmkay.

I don't know why singletons are hard to test, as I had never problems with that. oO

Many despise them because they are a pattern that's often used to make globals (aka spaghetti code) look nicer. Using singletons is often an excuse for lazy code designers, and it can create badly encapsulated/tightly coupled designs.

Share this post


Link to post
Share on other sites
People hate them because they're essentially global variables, and people have drilled into their head from the day they start programming that globals are bad.

Share this post


Link to post
Share on other sites
The main thing I have against singletons is that, although they might make it easier to share "global" data, they also create dependencies upon the objects that use them. If you remove that singleton, the objects that depend on it will cease to function.

I do believe singletons have their place, but the trick is not to over-use them or create them out of laziness.

Share this post


Link to post
Share on other sites
Proper unit testing of any nontrivial system invariably requires mock objects and other types of injectable dependencies (ie, replacing real components while testing so you can isolate each system you want to test). This is difficult or impossible with the canonical singleton.

See also here.

And the book by Gerard Meszaros, which is superb even if you don't do strict TDD.

Share this post


Link to post
Share on other sites
Quote:
Original post by Konfusius

Personally, I think Singletons are very useful for some things, for example configuration data, Resource Factories and so called "global objects" like the "application object".


Personally, I find those objects prime candidates for non-singletons.

Configuration data allows me to pass specialized, modified or categorized configurations to subsystems. It also doesn't bind me to single configuration implementation.
Resource factories have either no state or immutable state, but frequently I find the need to configure them externally. I also frequently encounter situation where similar factories are used by different systems and need to be customized.
Application objects are something I use for the very reason to avoid global context, so that I can create multiple application within same process, and then run them in different threads, perhaps in a pool.

The way I prefer to bring all of that together is something like this:
class Application {
Application(Configuration & cfg)
: configuration(argc, argv)
, factory(cfg)
, subsystem(factory, cfg)
, anothersystem(cfg)
{}
};

...
int main(int argc, char **argv) {
Configuration cfg(argc, argv);
Application app(cfg);
app.run();
};
// or
int main(int argc, char **argv) {
Configuration cfg(argc, argv);
cfg["threads"] = 2;

Application app1(cfg);
// it *can* be a singleton too
// but doesn't need to be
Application app2(Configuration::get_default());
thread t1(app1, &Application::run());
thread t2(app2, &Application::run());
t2.join();
t1.join();
};





YMMV and one size does not fit all.

Quote:
Why would they be hard to test?


Ever tried unit testing a database application where you need to test DROP statement? In common design where database access is singleton or global hard-coded, accidentally running such test without changing the configuration will wipe the production system. So how do you test it automatically?

Much easier if systems are not coupled.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!