liveBook · Manning

Dependency

As explained in Learn Go with Pocket-Sized Projects

A dependency is an external component or service that a program component requires to perform its work.

A dependency is an external component or service a program requires to perform its work. In a money converter, a bank or exchange-rate API supplies data that conversion needs. section 6.5

Separate fetching exchange rates from using them. Keep the money package unaware of the data source, and provide the rate provider through a contract. This inversion of control reduces assumptions, isolates side effects, and makes testing and replacement easier. section 6.5

Apply the dependency pattern by:

  • Defining the smallest interface where the consumer needs it, rather than designing a shared interface in advance. section 6.5.5
  • Passing the implementation into Convert so the caller chooses the exchange-rate source. section 6.5.5
  • Replacing the real provider with a stub during tests or while an unavailable service is still being developed. section 6.5 section 6.5.5
  • Wrapping provider errors and returning them to the caller instead of hiding dependency failures. section 6.5.5

A replaceable rate provider

Convert accepts an exchangeRates implementation. Production code can call the European Central Bank client; tests can pass stubRate with a fixed rate or configured error. Passing nil instead causes a runtime nil-pointer panic when Convert calls FetchExchangeRate. section 6.5 section 6.5.5

Listing 6.50 exchangerates.go: Interface definition
type exchangeRates interface { #1
    FetchExchangeRate(source, target Currency) (ExchangeRate, error)
}

Inspect the minimal exchangeRates interface used by the consumer. section 6.5.5

Listing 6.51 convert.go: Final implementation
// Convert applies the change rate to convert an amount to a target currency.
func Convert(
    amount Amount, to Currency, rates exchangeRates) (Amount, error) {
    // fetch the change rate for the day
    r, err := rates.FetchExchangeRate(amount.currency, to) #1
    if err != nil {
        return Amount{}, fmt.Errorf(
            "cannot get change rate: %w", err) #2
    }

    convertedValue := applyExchangeRate(amount, to, r)

    if err := convertedValue.validate(); err != nil {
        return Amount{}, err
    }

    return convertedValue, nil
}

Inspect Convert receiving the dependency, fetching a rate, wrapping errors, and validating the result. section 6.5.5

How Learn Go with Pocket-Sized Projects covers it

How deep it goes
Explains external resources, inversion of control, local interfaces, stubs, error propagation, and nil-pointer failure.
Examples
Uses a European Central Bank client, a local exchangeRates interface, a stubRate test double, and a nil-pointer panic.
What it assumes
Assumes Go package and function familiarity while teaching dependency contracts, interface discovery, stubbing, and replacement.
What you can do after
Build it from scratch by defining a consumer-owned interface, injecting an implementation, stubbing it in tests, and propagating errors.
How it connects
Connects dependencies with inversion of control, interfaces, stubs, testing, error handling, APIs, and caching.

Also explained in

Compare how 27 books explain dependency →

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.