To avoid passing payment adapters and similar collaborators through the call stack, create a global config container in an initializer, register real implementations for development/production and stubs for test, and resolve at the call site. Tests no longer need to swap implementations manually, and replacement logic is concentrated in one place. Ivan acknowledges the global is a dirty trick but argues the purpose — keeping other layers simpler — justifies it, and it is categorically different from current-user-in-model globals.