Package names: short, lowercase, no underscores. Plural only for utility packages (bytes, strings).
Standard Go Project Layout:
cmd/ — entry points (one subdirectory per binary)
internal/ — non-exported code
pkg/ — exportable libraries (use sparingly)
One file per logical unit; filename in snake_case (e.g., order_repository.go).
Test files: *_test.go for unit tests, *_ct_test.go for component tests, *_it_test.go with
the build constraint integrative for integrative tests (see testing.md).
Always handle errors — using _ for errors is forbidden.
Wrap errors with context: fmt.Errorf("open config file: %w", err).
Check sentinel errors with errors.Is; typed errors with errors.As.
Define a custom error as a struct with exported fields for its data (e.g. an id, a Code) and an
Error() string method that formats them for display — the fields stay directly accessible via
errors.As, not only inside the formatted string (see internal/domain/errors.go's
ValidationError in the car-rental-orchestrator demo for the pattern).
panic only for unrecoverable startup failures (e.g., MustNew... constructors).
Table-driven tests are the default for multiple input cases.
Call t.Parallel() in independent tests.
No time.Sleep — use channels or sync.WaitGroup.
Mock only at package boundaries; test internal logic directly.
Use testify/require for preconditions, testify/assert for assertions.
Structure test bodies with // GIVEN, // WHEN, // THEN.
BDD scenarios with Godog; include a sample .feature file and step definitions.
make coverage counts every test and scenario for every package of the module, by passing the
module's packages to -coverpkg. A Godog scenario in test/bdd that reaches internal/usecase
counts for internal/usecase. A scenario that starts the built executable starts one built with
-cover, which writes into the same GOCOVERDIR.
The debug executable is build/<artifact>-debug, the release executable build/<artifact>.
Define interfaces in the consuming package; verify at compile time: var _ MyInterface = (*myImpl)(nil)
Constructors return interfaces, not concrete types (unless package is internal)
Always handle errors — using _ for errors is forbidden; wrap with context: fmt.Errorf("op: %w", err)
Define custom errors as structs with exported data fields plus an Error() string method — keep
fields directly accessible via errors.As, not only inside the formatted string
Pass logger as *zap.SugaredLogger — never as a global variable
Table-driven tests are the default; call t.Parallel() in independent tests; no time.Sleep
Use testify/require for preconditions, testify/assert for assertions; BDD scenarios with Godog
Project layout: cmd/ for entry points, internal/ for non-exported, pkg/ for exportable
Use any instead of interface{}; use slices/maps packages (1.21+) over manual loops