Global variables are not the problem
Globals, Singletons, and Threading
- Some argue singletons are just globals with extra ceremony; they don’t fix core issues like hidden dependencies, tight coupling, or “action at a distance.”
- Others defend singletons for enforcing single initialization and (in some languages) more predictable lazy init, but still consider them “terrible” overall.
- Threading is a major fault line: critics stress that mutable globals become landmines as soon as multiple threads appear, causing races or forcing widespread mutex use and potential deadlocks.
- A counter-position: if the design clearly constrains threading and shared state, indiscriminate mutexes are worse than carefully limited globals.
Context Objects, Dependency Injection, and Testability
- Many advocate passing an explicit “context”/environment object (or DI) instead of using globals:
- Makes dependencies explicit and easier to test.
- Enables swapping implementations in tests (e.g., DB vs fake).
- Avoids thread-local or hidden state that silently breaks with coroutines or concurrency.
- Detractors see this as “god objects” or FP-style overkill, adding boilerplate and long parameter lists for marginal benefit, especially in imperative, single-threaded code.
Action at a Distance, Lifetime, and Local Reasoning
- Strong consensus that the real problem is implicit, shared mutable state—whether global, thread-local, or passed by reference—creating “spooky action at a distance.”
- Good design ties state lifetime to the entity it describes (request, object, process) rather than the whole program, and confines mutations to well-defined places.
- Globals can be acceptable for truly program-wide, mostly-read state (config, environment, metrics/loggers) if writes are rare and controlled.
Language and Concurrency Nuances
- Several comments note the article’s JavaScript-centric view: JS’s single-threaded model hides many global-state problems that are severe in other languages.
- In languages with stronger type or concurrency systems (e.g., borrow checkers, enforced locks), the compiler can prevent many of the “global gone wrong” examples.
- Static/function-local variables in C/C++ are discussed as a middle ground: useful for persistent per-function state but clearly non-thread-safe unless guarded.
Databases and Other Global-Like Systems
- SQL databases, caches, and Redis are likened to giant global variables: shared, mutable state accessed from everywhere.
- Opinion splits between seeing them as necessary, well-encapsulated infrastructure vs another form of global that must be tightly structured (e.g., event sourcing, controlled write layers).
Critiques of the Article’s Framing
- Some feel the article stretches the definition of “global” to include closures, modules, etc., and then declares globals “not the problem.”
- Others push back that mutability and implicit access patterns are the real issues; labeling globals as harmless if “encapsulated” underplays how often they cause bugs in practice.