Open
Description
Background
Currently, the IOTA SDK uses hand-wired constructors and factory functions to manage dependencies between services and modules. While this is consistent with idiomatic Go and aligns with Domain-Driven Design (DDD), it becomes cumbersome as the project scales — particularly with interdependent modules like Finance, CRM, and Warehouse.
Why uber-go/fx?
fx
is a mature, production-grade dependency injection framework for Go developed by Uber. It builds on top of dig
and provides:
- Lifecycle management (start/stop hooks).
- Module-based dependency grouping.
- Automatic wiring of constructors.
- Strong type-safety and compile-time checks.
- Tracing and introspection of the dependency graph.
Benefits for IOTA SDK
- Improved Modularity: Modules like
finance
,crm
, andwarehouse
can be cleanly registered and initialized independently. - Less Boilerplate: Reduce the amount of manual constructor wiring in
main()
and other root packages. - Easier Testing: Dependencies can be mocked and injected easily via
fx.Provide
. - Better Lifecycle Control:
fx.Lifecycle
provides clear entry/exit points for services like PostgreSQL, WebSocket brokers, etc. - Built-in Observability: Useful for future integrations like metrics, logging, and tracing.
- Aligns with DDD: Module encapsulation is preserved, and fx modules map well to DDD aggregates.
Sample Migration Sketch
func main() {
app := fx.New(
fx.Provide(
NewConfig,
NewPostgresDB,
crm.NewService,
finance.NewService,
warehouse.NewService,
),
fx.Invoke(startServer),
)
app.Run()
}
Each module (e.g., crm.NewService
) defines its own dependencies and registers them cleanly without central glue code.
Migration Strategy
- Start with core infrastructure (DB, config, logger).
- Gradually migrate modules to
fx.Provide
&fx.Module
. - Keep backward-compatible
NewX()
constructors for testability. - Replace lifecycle hooks where needed (e.g.,
Start()
/Stop()
methods).
Risks & Trade-offs
- Slight learning curve for contributors not familiar with
fx
. - Errors move from compile-time to startup-time (needs better runtime checks).
- Debugging failed graphs can be challenging without proper logging.