Refactor Global Configuration Access Toward Explicit Dependency Injection #14

Open
opened 2025-10-28 23:00:26 +00:00 by H3ALY · 0 comments
Owner

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)

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)
H3ALY added the enhancementlow-prioritybackend labels 2025-10-28 23:00:26 +00:00
Sign in to join this conversation.