liveBook · Manning

Dependency injection

As explained in Shipping Go: Develop, deliver, discuss, design, and go again

Dependency injection is a software design technique in which a component receives the services or objects it depends on from outside rather than constructing them itself.

Suppose a translation handler creates its own translation service. A handler test that expects a missing translation to produce HTTP 404 could break when someone adds that translation. The test is then checking the service’s changing data as well as the handler’s response logic. Dependency injection gives the handler a service from outside, so the test can choose which service it receives. section 6.4

Think of fitting different engines into a car body: the body needs an engine that meets its requirements, not one particular model. In Go, a small interface expresses the requirement. A consuming struct holds that interface, and its constructor accepts a concrete service that satisfies it. The handler calls the interface without needing to know which implementation was supplied. section 6.2 section 6.3

Listing 6.5 translate.go
// TranslateHandler will translate calls for caller.
type TranslateHandler struct {
    service Translator                                               #1
}
 
// NewTranslateHandler will create a new instance of the handler using a
// translation service.
func NewTranslateHandler(service Translator) *TranslateHandler{      #2
    return &TranslateHandler{
        service: service,
    }
}
 
...
 
// TranslateHandler will take a given request with a path value of the
// word to be translated and a query parameter of the
// language to translate to.
func (t *TranslateHandler) \
    TranslateHandler(w http.ResponseWriter, r *http.Request) {       #3
...
    translation := t.service.Translate(word, language)               #4
...
}

The handler stores a Translator, accepts it through NewTranslateHandler, and calls it when handling a request. section 6.3

To wire the translation endpoint by hand:

  • Define the narrow Translator interface around the Translate method the handler needs. section 6.2
  • Make StaticService satisfy the interface, then pass it to NewTranslateHandler when setting up the HTTP route. section 6.3
  • In handler tests, pass a stub instead of the static service to control the translation returned. section 6.4

Testing the handler without changing the service

A stubbed Translator returns "bar" for "foo" and an empty string otherwise. Injecting it lets a handler test check the expected HTTP 200 response for a found translation and HTTP 404 for a missing one. Adding Dutch translations to the real service no longer changes what that handler test receives. section 6.4

Manual wiring keeps the choice of implementation visible at setup time; Wire, Fx, and Kit are noted as alternatives for wiring dependencies. The practical payoff is a modular service whose parts can be changed and tested independently. Configuration can also work with dependency injection to hide incomplete or untested features. section 6.3 section 8.7 section 11.2

How Shipping Go: Develop, deliver, discuss, design, and go again covers it

How deep it goes
Works through interface definition, constructor injection, manual application wiring, and test stubs; leaves automated wiring to named alternatives.
Examples
Uses a translation handler, a static translation service, application route setup, and a stub returning fixed test values.
What it assumes
Builds on Go structs, HTTP handlers, and tests while explaining the interface and constructor used for injection.
What you can do after
Build it from scratch by hand-wiring a Go service into a handler and injecting a stub for isolated handler tests.
How it connects
Connects interfaces and interface segregation to modularity, coupling, testing stubs, mocking, and configuration.

Also explained in

Compare how 21 books explain dependency injection →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Shipping Go: Develop, deliver, discuss, design, and go again. The section links point to the parts of the book it draws on.