Refactor Global Configuration Access Toward Explicit Dependency Injection #14
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Right now, application configuration is stored in a package-level singleton via internal/platform/config using sync.Once (Init() + Get()). This design works but introduces hidden global state, makes execution order important (Get() must not happen before Init()), and is inconsistent with the cleaner dependency injection already established through the App struct (bootstrap.Load).
Configuration should ideally be accessed through the App struct reference already injected into Gin handlers (c.MustGet("app")) and passed to internal services/factories explicitly, not via hidden global state.
This change improves architectural clarity, testability, and removes the risk of nil dereferences if ordering is incorrect.
Current Behavior (as observed in code):
config.Init() called once in bootstrap
Other packages may call config.Get() without knowing lifecycle state
Config mutation after initialization is not prevented
Global state discourages per-request or per-test configuration context
Why this matters:
Aligns with architecture: Bootstrap owns config → App exposes config
Eliminates indirect coupling and enhances maintainability
Enables clean future expansion (multi-tenant, dynamic config sources)
Prevents subtle ordering bugs during startup or test setup
Scope / Expected Changes:
Prefer use of app.Config everywhere instead of config.Get()
Audit dependencies and replace global fetches with DI
Optionally add validation / fail-fast behavior on pre-init Get()
Update documentation and remove misleading references to global config source-of-truth
Non-Goals:
No change to configuration file format
No introduction of environment overrides (separate ticket if needed)
Risks / Mitigations:
Medium: Touches widely-used access pattern → will require coordinated updates
✅ Mitigation: Mechanical refactor with small PRs per subsystem
Acceptance Criteria: ✅ No consumer calls config.Get() directly
✅ Config is accessed via app.Config consistently
✅ Tests and middleware operate purely through injected dependencies
✅ Bootstrap remains the only place config is loaded/validated
✅ internal/platform/config/config.go either removed or reduced to pure struct definitions
Estimated Effort:
Small–Medium (1–2 dev days, incrementalizable)