By Pete Muldoon
“The worst part of this whole topic is that the people who hate singletons rarely give concrete suggestions for what to use instead.”
In this talk, we will explore just such an approach for replacing the Singleton pattern in large codebases.
It is easy to slip into the pattern of creating singletons - particularly in large legacy code bases - where low level functions need to propagate side effects like database updates, IPC etc.
Passing parameters down long function call chains can be daunting in terms of scope of change required in a large codebase.
Additionally, users calling a long established API in legacy code are frequently unwilling to change their calls to supplement the current data being passed in.
After briefly reviewing a classic singleton approach to a typical problem – sending requests to a server – and it associated drawbacks.
We will rework the example and replace the function’s internal singleton calls with calls to an explicitly passed in wrapper class. The extra information required for legacy users is injected via a custom default instance of the wrapper so that the users of the original function require no coding changes.
We will then show how the previously untestable function can now be subjected to unit testing via dependency injection.
This idea is later expanded to cover
-
keeping ABI stable
-
dealing with non-copyable types
-
dealing with delayed construction
-
dealing with Singleton dependency groupings
-
Initialization order of interdependent singletons, replacing error prone explicit intialization ordering with hard to misuse automatic initialization driven by the language.
-
Showing how the replacement pattern can be gradually introduced to a large code base instead of 'all at once'.
-
statefull grouping of dependencies.
-
Configuring long-lived Singleton replacement Objects
This alternative approach has been successfully employed in multiple areas in Bloomberg where developers believed there was no other feasible choice.