liveBook · Manning

Dependency

As explained in Go by Example

A software dependency is an external component or runtime resource required by a program to function.

A dependency is an external component or runtime resource that a program requires. In Go, dependencies can include command-line arguments, output streams, operating-system behavior, or client integrations. section 5.2.2 section 1.3.2

Explicitly grouping dependencies makes program logic easier to change and test. An env struct can hold abstract outputs through io.Writer, arguments through []string, and flags such as dryRun. section 5.2.2 section 5.3

Dependency injection improves a command-line program by:

  • Moving core logic from main into a run function with explicit inputs and outputs. section 5.3.1
  • Replacing os.Args with injected arguments and os.Stdout with an io.Writer such as os.Stdout or strings.Builder. section 5.3.1
  • Returning errors instead of calling os.Exit inside the testable logic. section 5.3.1

Injecting command-line dependencies

main supplies real operating-system resources, while run receives an env value and remains independent of globals. Tests can substitute arguments, writers, and errors, then inspect behavior without exiting the process. section 5.3.1 section 5.6

Listing 5.1 The env type (hit/cmd/hit/hit.go)
package main

import (
    "io"
    . . .
)

type env struct {
    stdout io.Writer  #1
    stderr io.Writer  #2
    args   []string  #3
    dryRun bool  #4
}

The env type provides a compact dependency boundary for output, errors, arguments, and dry-run behavior. section 5.2.2

Listing 5.2 Refactoring the main function (hit/cmd/hit.go)
func main() {
    if err := run(&env{
        stdout: os.Stdout,  #1
        stderr: os.Stderr,   #1
        args:   os.Args,   #1
    }); err != nil {
        os.Exit(1)  #2
    }
}

func run(e *env) error {  #3
    c := config{
        n: 100,
        c: 1,
    }
    if err := parseArgs(
        &c,
        e.args[1:],  #4
        e.stderr,  #5
    ); err != nil {
        return err  #6
    }

    fmt.Fprintf(  #7
        e.stdout,   #7
        "%s\n\nSending %d requests to %q (concurrency: %d)\n",
        logo, c.n, c.url, c.c,
    )

    return nil
}

The refactored command shows how main supplies real dependencies while run consumes abstractions and returns errors. section 5.3.1

How Go by Example covers it

How deep it goes
Explains dependency grouping, abstraction, explicit injection, and testing, while stopping short of broader dependency-management tooling.
Examples
Demonstrates env, io.Writer, command-line arguments, strings.Builder, os.Exit, and a refactored run function.
What it assumes
Assumes basic Go command-line programs and functions, while teaching interfaces, injected resources, and test-oriented refactoring.
What you can do after
Apply it via dependency injection to build Go functions that accept replaceable resources and can be tested without global state.
How it connects
Connects dependencies with dependency injection, interfaces, global variables, testability, error handling, and static binaries.

Also explained in

Compare how 27 books explain dependency →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Go by Example. The section links point to the parts of the book it draws on.