Go - Dependency Injection Patterns

Beginner 10/10 Teacher 10/10 Architect 10/10

Dependency Injection Patterns

Prefer simple constructor injection with interfaces over global state. Consider code generation tools (e.g., Wire) when graphs grow.

Try it: Define an interface for a clock or mailer and inject a fake in tests.

Constructor injection

type Store interface{ GetUser(ctx context.Context, id int) (User, error) }

type Service struct{ st Store }
func NewService(st Store) *Service { return &Service{st: st} }

Interfaces at package boundaries

// in consumer package: define small, focused interfaces
// in provider package: implement with concrete types

Composition root

func main(){
  db := openDB()
  st := NewDBStore(db)
  svc := NewService(st)
  startHTTP(svc)
}

Common errors

  • Huge interfaces that are hard to mock—prefer small interfaces with one or two methods.
  • Global singletons that make testing difficult.

Practice

  • Introduce a clock interface and pass a fake clock in tests to control time.

Quick quiz

  1. Where should interfaces be defined?
Show answer In the consumer package to keep them small and tailored to usage.