DevOps

If singletons are bad, what should you use?

If the singleton pattern is bad, what should you use when you genuinely need only one of something?

Asked on Stack Exchange,

Separate the two things the pattern conflates. Having one instance of something is ordinary and fine — one configuration, one cache, one connection pool. The pattern bundles that with global access from anywhere, and the global access is the part that causes the trouble.

Single instance is not the problem

The accepted answer opens by drawing this line, and it defuses most of the argument. Applications legitimately have one of many things, and where there is state worth maintaining you want exactly one of it. Nobody objects to that. The objection is to the mechanism usually used to reach it.

What the pattern actually bundles

  • Convenient access to an object from anywhere in the program.
  • A guarantee that only one of it can ever exist.
  • One answer's estimate is that almost all of the time you only want the first, and the second arrives as baggage — while it is the first that does the damage.
  • Global reachability is what makes the dependency invisible: nothing in a function's signature says it uses the thing, so nothing warns you when you change it.

What to do instead

  • Create the single instance once, near the top of the program, and pass it to whatever needs it.
  • That makes the dependency visible in the signature, and makes substituting a different one for a test trivial.
  • It also puts lifetime under your control rather than the runtime's, which matters when the order of construction and teardown is significant.

When the singleton is the symptom

One answer redirected the question at the design rather than the pattern, asking why screens were querying a cache object directly at all. Caching should be an implementation detail behind whatever provides the data, not something every caller reaches for by name. On that reading, wanting global access to a particular object is often evidence that a layer is missing — and adding it removes the need for the singleton rather than replacing it.