liveBook · Manning

Dependency injection

As explained in Learn Go with Pocket-Sized Projects

Dependency injection is a technique in which an object or component receives its required dependencies from outside rather than constructing them internally.

Dependency injection gives a function or component its dependencies from outside instead of constructing them internally. A money converter can receive an exchange-rate provider while remaining unaware of the bank, API, or data source behind it. This separates fetching from conversion, reduces assumptions, and makes replacement and testing easier. section 6.5 section 10.8

Go supports two common dependency-injection forms:

  • Interface dependency: pass an object implementing a small interface, such as a ratesFetcher with FetchRates(from, to). section 6.5.1
  • Function dependency: pass a function with the required signature, optionally naming that signature as a type. section 6.5.1
  • Local functions can provide configuration-specific behavior, while separate fetchers can support free or authenticated rates. section 6.5.1
  • Small interfaces close to their use restrict what a dependency can do and let tests substitute mocks instead of hardcoded implementations. section 10.3.3 section 10.8

Injecting a repository

A habits service can receive a Repository through its constructor, while its Create function accepts a smaller habitCreator interface. The main function supplies the real repository; tests supply a mock that implements only Add. The service therefore validates and saves habits without constructing or depending directly on the repository implementation. section 10.3.3

Listing 6.34 Dependency injection via an interface
type ratesFetcher interface {
    FetchRates(from, to Currency) (ExchangeRate, error) #1
}

func Convert(..., rates ratesFetcher) { #2
    ...
    rate, err := rates.FetchRates(from, to) #2
    ...
}

...

func main() {
    ratesRepo := newRatesRepository() #3
    money.Convert(..., ratesRepo)
}

Use the interface-based listing to see the contract, injected parameter, and caller-created implementation in one compact Go example. section 6.5.1

Listing 6.35 Dependency injection via a function
func Convert(...,
    rates func(from Currency,  #1
        to Currency) (ExchangeRate, error),  #1
) (Amount, error) {
    ...
    rate, err := rates(from, to) #2
    ...
}

func main() {
    ratesRepo := newRatesRepository() #3
    money.Convert(..., ratesRepo.FetchRates) #4
}

Compare the function-based form, where Convert receives ratesRepo.FetchRates directly rather than an object implementing an interface. section 6.5.1

How Learn Go with Pocket-Sized Projects covers it

How deep it goes
Defines the pattern and demonstrates interface, function, local-function, and repository forms, stopping short of broader framework machinery.
Examples
Uses exchange-rate providers, configurable fetcher functions, and a habits repository injected into a gRPC server and domain function.
What you can do after
Apply it via Go interfaces or function parameters to replace external services, constrain dependencies, and mock behavior during tests.
How it connects
Connects inversion of control, interfaces, mocking, testing, repositories, and context-aware service calls.

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 Learn Go with Pocket-Sized Projects. The section links point to the parts of the book it draws on.