Singletons Are Evil
This means that 25% of all classes in the code base are virtually impossible, or at least very hard to unit test. Testing gets difficult as the singletons' global state has to be initialised for each test. This slows down test execution and makes the tests more brittle. That's one of many reasons I just hate the singleton pattern. It's an object oriented anti-pattern. In case you do not believe me, I am sure you will believe well known people like Miško Hevery, Uncle Bob or J.B. Rainsberger to name just a few. At least read Steve Yegge's take on the singleton which is my favourite article on the topic.
Pure Evilness
Some years ago I worked on a code base which was similar both in size and the number of singletons involved. In fact it was not that bad, only 15% of all classes were depending on a singleton, still it was nasty to work with.So I took the liberty to educate my team mates on the singleton's evilness. The following list was taken from my Design Patterns reading group notes and contains all negative effects of singletons that I'm aware of. Singletons are evil because they ...
... introduce global state/global variables.
- ... hurt modularity and readability.
- ... make concurrent programming hard.
- ... encourage you to forget everything about object oriented design.
- ... are a throwback to non object oriented programming.
- ... allow anyone to access them at any time. (They ignore scope.)
- Finding the right balance of exposure and protection for an object is critical for maintaining flexibility.
- They typically show up like star networks in a coupling diagram.
- ... make assumptions about the applications that will use them.
- If nobody is going to use them they are basically just memory leaks.
- Signatures of methods (inputs) don't show their dependencies, because the method could pull a singleton out of thin air.
- All singletons have to stick in boilerplate code.
- Everyone who uses it has to stick in boilerplate code, too.
- When classes are coupled, it is possible only to test a group of classes together, making bugs more difficult to isolate.
- ... can prevent a developer from testing a class at all.
- Two tests that actually depend on each other by modifying a shared resource (the singleton) can produce blinking tests.
- Mocking would make unit tests run more quickly.
- It is simpler to simulate behaviour than to recreate behaviour.
9 comments:
Well presented blog. The diagrams make it very clear what you are discussing. Well done.
So what's the alternative, if you need access to a resource/service from several parts of a program?
After short research, I land on stackoverflow: stackoverflow.com/questions/1300655/whats-alternative-to-singleton
Ah yes, I should have added alternatives. Thanks for the link.
Singletons are only evil when they are used in conjuction with the service lookup pattern. If they are injected (ie the use of getInstance() in utterly few places) they pose no problems to testing or coupling.
@Johan
You are right. But in such a case the calling code does not see the singleton as it is, it's just using delegation. So it's not your typical singleton usage ;-)
It's not that singletons themselves are bad but the GOF design pattern is. The only really argument that is valid is that the GOF
design pattern doesn't lend itself in regards to testing, especially if tests are run in parallel.
Using a single instance of an
class is a valid construct as long as you apply the following means in code:
1. Make sure the class that will be used as a
singleton implements an interface. This allows stubs or mocks to be implemented using the same interface
2. Make sure that the
Singleton is thread-safe. That's a given.
3. The singleton should be simple in nature and not overly complicated.
4. During the
runtime of you application, where singletons need to be passed to a given object, use a class factory that builds that object and
have the class factory pass the singleton instance to the class that needs it.
5. During testing and to ensure deterministic
behavior, create the singleton class as separate instance as either the actual class itself or a stub/mock that implements its
behavior and pass it as is to the class that requires it. Don't use the class factor that creates that object under test that
needs the signleton during test as it will pass the single global instance of it, which defeats the purpose.
We've used Singletons
in our solutions with a great deal of success that are testable ensuring deterministic behavior in parallel test run streams.
codematrix
Ross,
I agree that not the fact that a class is a singleton (let's call that singleton scoped) is the problem, but the hard coded lookup using getInstance() as described in the GoF book. I argue that a class returned from the factory is not a singleton, if it does not follow the pattern described, but something else. Nevertheless, separating lookup/creation from usage is probably the best idea to fix these problems.
Hi Peter,
I agree, the classfactor is not to return the singleton. The classfactory creates an instance of a class that requires a singleton. At the point of creation, the classfactor will pass it the global instance of the singleton to the class' constructor. This is only true during the RUNTIME of the application.
On the flip-side during testing, the Unit Test will not use the classfactor to create the object under test but rather construct the object directly, whereby, the unit test will pass it a newly constructed object (copy) that was used as a singleton during RUNTIME to the depended class under test. This way each test can have their own copy of the Singleton object. This copy can be a real instance of the singleton or stub/mock.
codematrix
Post a Comment