Managing Dependencies (as in IoC) and Avoid Globals

  • There are Go packages that help with dependency injection, employing reflection.
  • And other practices insist on passing everything as an argument, down the pipe; employing mostly factory methods.
  • At the same time putting long-lived instances inside a context is not recommended - I like context for cancellation (and hierarchy of cancellations) and I like it for passing state when every step in a pipeline is concurrent and short lived; for other uses, using context seems a not proper choice.

Struggling with these thoughts, something like a hierarchical “service locator” (or is it?) came to my mind:

type DepRegistry struct {
	parent *DepRegistry
	deps   sync.Map
}

func (r *DepRegistry) Register(name string, dep interface{}) {
	r.deps.Store(name, dep)
}

// Load first loads from current instance, then tries
// to load from parent (panics if fails to find)
func (r *DepRegistry) Load(name string) interface{} {
	dep, ok := r.deps.Load(name)
	if !ok {
		if r.parent != nil {
			return r.parent.Load(name)
		}
		panic("unknown dep " + name)
	}
	return dep
}

func NewDepRegistry(parent ...*DepRegistry) *DepRegistry {
	res := &DepRegistry{}
	if len(parent) > 0 && parent[0] != nil {
		res.parent = parent[0]
	}
	return res
}

I would love to hear thoughts on this matter. Is it an acceptable solution? Is there anything missing?

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.