Skip to content

Proposal: Migrate to uber-go/fx for Dependency Injection #253

Open
@diyor28

Description

@diyor28

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

  1. Improved Modularity: Modules like finance, crm, and warehouse can be cleanly registered and initialized independently.
  2. Less Boilerplate: Reduce the amount of manual constructor wiring in main() and other root packages.
  3. Easier Testing: Dependencies can be mocked and injected easily via fx.Provide.
  4. Better Lifecycle Control: fx.Lifecycle provides clear entry/exit points for services like PostgreSQL, WebSocket brokers, etc.
  5. Built-in Observability: Useful for future integrations like metrics, logging, and tracing.
  6. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesthelp wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions