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 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? Sample App: There is this app, with different packages that are using services like logging, creating/modifying images, sending/receiving messages from bots and the like. Those parts are already separate executables, communication via NATS. -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.