Modules & Tooling#
Go ships with a comprehensive toolchain — dependency management, testing, linting, profiling, and cross-compilation are all built in or a single go install away.
Modules#
go.mod#
module github.com/yourname/myproject
go 1.22
require (
github.com/gorilla/mux v1.8.1
github.com/lib/pq v1.10.9
)
require (
// indirect dependencies
golang.org/x/text v0.14.0 // indirect
)Common Module Commands#
go mod init github.com/you/project # create go.mod
go mod tidy # add missing, remove unused
go mod download # download dependencies
go mod verify # verify checksums
go mod vendor # copy deps into ./vendor
go mod graph # show dependency graph
go get github.com/pkg@v1.2.3 # add/update specific version
go get -u ./... # update all direct depsVersion Selection#
Go uses Minimum Version Selection (MVS): if A requires lib@v1.2 and B requires lib@v1.3, Go picks v1.3 (the minimum version that satisfies all requirements). No SAT solver, deterministic, reproducible.
Replace and Exclude#
// go.mod
// Use a local copy during development
replace github.com/myorg/lib => ../lib
// Use a fork
replace github.com/original/lib => github.com/myfork/lib v1.0.0
// Exclude a broken version
exclude github.com/pkg/lib v1.2.3Private Modules#
# Tell Go to fetch from private Git (not proxy)
export GONOSUMCHECK=github.com/myorg/*
export GOPRIVATE=github.com/myorg/*
export GONOSUMDB=github.com/myorg/*Testing#
Test File Conventions#
user.go → user_test.go (same package)
user.go → user_test.go (package user_test — black-box testing)Running Tests#
go test ./... # all packages
go test -v ./... # verbose
go test -run TestCreate # pattern match
go test -short ./... # skip long tests
go test -count=1 ./... # disable caching
go test -parallel 4 ./... # parallel test limitTest Helpers#
func TestSomething(t *testing.T) {
t.Helper() // marks this as a helper — errors show caller's line
// ...
}Subtests#
func TestMath(t *testing.T) {
t.Run("addition", func(t *testing.T) {
if add(1, 2) != 3 {
t.Error("1+2 should be 3")
}
})
t.Run("subtraction", func(t *testing.T) {
if sub(5, 3) != 2 {
t.Error("5-3 should be 2")
}
})
}Test Coverage#
go test -cover ./...
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out # open in browser
go tool cover -func=coverage.out # per-function breakdownBenchmarks#
func BenchmarkSort(b *testing.B) {
data := generateData(1000)
b.ResetTimer()
for i := 0; i < b.N; i++ {
sort.Ints(data)
}
}go test -bench=. -benchmem ./...
# BenchmarkSort-10 50000 24350 ns/op 8192 B/op 1 allocs/opFuzzing (Go 1.18+)#
func FuzzReverse(f *testing.F) {
f.Add("hello")
f.Add("世界")
f.Fuzz(func(t *testing.T, s string) {
rev := Reverse(s)
doubleRev := Reverse(rev)
if s != doubleRev {
t.Errorf("double reverse of %q got %q", s, doubleRev)
}
})
}go test -fuzz=FuzzReverse -fuzztime=30sLinting and Static Analysis#
go vet (Built-in)#
go vet ./...Catches: printf format mismatches, unreachable code, suspicious constructs, incorrect struct tags.
golangci-lint (Community Standard)#
# Install
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
# Run
golangci-lint run ./...Runs 100+ linters including: errcheck (unchecked errors), staticcheck (advanced checks), gosimple (simplifications), govet, revive, ineffassign.
Configuration (.golangci.yml)#
linters:
enable:
- errcheck
- govet
- staticcheck
- revive
- gosec
- ineffassign
- gocritic
disable:
- depguard
linters-settings:
revive:
rules:
- name: exported
severity: warning
run:
timeout: 5mProfiling#
CPU Profile#
import "runtime/pprof"
f, _ := os.Create("cpu.prof")
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
// ... code to profile ...HTTP Profiling (Production-Ready)#
import _ "net/http/pprof"
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()# CPU profile
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
# Memory profile
go tool pprof http://localhost:6060/debug/pprof/heap
# Goroutine profile
go tool pprof http://localhost:6060/debug/pprof/goroutine
# Interactive commands
(pprof) top 20
(pprof) web # opens browser visualisation
(pprof) list funcName # source-annotated profileMemory Profiling#
func BenchmarkAllocations(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
process()
}
}Execution Tracing#
go test -trace=trace.out ./...
go tool trace trace.out # opens interactive browser viewShows goroutine scheduling, GC events, system calls, and network I/O on a timeline.
Build#
Build Tags#
//go:build linux
// +build linux
package mypackage
// This file only compiles on Linuxgo build -tags "integration,debug" ./...Embedding Files#
import "embed"
//go:embed static/*
var staticFiles embed.FS
//go:embed version.txt
var version string
//go:embed config.json
var configData []byteLinker Flags (Injecting Build Info)#
go build -ldflags "-X main.version=1.2.3 -X main.commit=$(git rev-parse --short HEAD)"var version = "dev"
var commit = "unknown"Cross-Compilation#
GOOS=linux GOARCH=amd64 go build -o app-linux
GOOS=darwin GOARCH=arm64 go build -o app-mac
GOOS=windows GOARCH=amd64 go build -o app.exe
# CGO disabled (for fully static binaries)
CGO_ENABLED=0 GOOS=linux go build -o appCode Generation#
//go:generate stringer -type=Status
//go:generate mockgen -source=repo.go -destination=mock_repo.gogo generate ./...Common generators: stringer (enum String methods), mockgen (mocks for testing), protoc-gen-go (protobuf), sqlc (type-safe SQL).
Key Takeaways#
go mod tidyis the most important module command — run it after any dependency change.- Go uses Minimum Version Selection — deterministic, no lock file ambiguity.
- Table-driven tests with
t.Runsubtests are the standard testing pattern. Always run with-race. golangci-lintis the community-standard linter — configure it once and run in CI.pprofis built in and production-ready. Use it for CPU, memory, and goroutine profiling.CGO_ENABLED=0gives fully static binaries.GOOS/GOARCHfor cross-compilation.//go:embedbundles files into binaries — no more asset loading at runtime.