liveBook · Manning

Package

As explained in 100 Go Mistakes and How to Avoid Them

A package is a Go unit of source organization and compilation that groups related declarations and controls dependencies between code units.

A package groups related Go declarations and gives other code a boundary to depend on. A directory can contain other package directories, but that does not create subpackages: code in net/http has no inherited access to net and can use only its exported elements. section 2.12.2

/net
    /http
        client.go
        ...
    /smtp
        auth.go
        ...
    addrselect.go
    ...

The net layout places related packages near one another without making http or smtp children of the net package. section 2.12.2

When a package layout becomes hard to follow, check the boundaries:

  • Avoid splitting code prematurely into dozens of one- or two-file packages; also avoid packages so large that their names lose meaning. A small package is reasonable when its code is cohesive and belongs nowhere else. section 2.12.2 section 2.13
  • Name a package for what it provides, using a short, expressive, conventionally lowercase word. Minimize what it exports. section 2.12.2
  • Choose grouping by application context or technical layer according to the use case, then stay consistent; do not force a final structure before the code’s relationships are clear. section 2.12.2

Replace a catch-all package with an expressive API

A caller using util.NewStringSet and util.SortStringSet learns little from the package name, while the function names repeat their subject. With a cohesive stringset package, the calls become stringset.New and stringset.Sort. A Set type can move the second operation to set.Sort(). This is a reason to replace a vague catch-all package, not a ban on every small or utility package. section 2.13 section 11.7

Package boundaries also shape tests. Files in one folder normally share a package, but a test file may use a _test package. A counter_test test must import counter and cannot reach its unexported count variable, so it tests the exported Inc behavior instead. Use that separation when a test should survive changes to implementation details. section 11.9.2

Dependencies matter at startup too: a package’s declarations are evaluated and its init functions run when it is initialized. If main depends on redis, redis initializes first. Do not make behavior depend on init ordering across files within one package; renaming files can change that order. section 2.3.1

How 100 Go Mistakes and How to Avoid Them covers it

How deep it goes
Works through directory relationships, naming and granularity trade-offs, API refactoring, and external tests; does not develop a fixed project template.
Examples
Contrasts net directory nesting, util versus stringset calls, and a counter_test file that checks an exported API.
What it assumes
Assumes familiarity with Go source files, imports, and tests while explaining directory boundaries and external test-package visibility.
What you can do after
Practice/perform package organization by grouping cohesive code, choosing expressive names, and using external tests to check exported behavior.
How it connects
Connects packages to modules, exported elements, project architecture, utility packages, external tests, and init functions.

Also explained in

Compare how 7 books explain package →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of 100 Go Mistakes and How to Avoid Them. The section links point to the parts of the book it draws on.