1 Go Command Toolchain
Go ships with an all-in-one toolchain. Unlike most languages, you rarely need external build tools β go handles compilation, testing, formatting, and dependency management.
| Command | Purpose | Example |
|---|---|---|
go build |
Compile packages and produce binary | go build -o myapp . |
go run |
Compile and run in one step | go run main.go |
go test |
Run tests and benchmarks | go test ./... |
go fmt |
Format source code (canonical style) | go fmt ./... |
go vet |
Static analysis for common bugs | go vet ./... |
go mod tidy |
Clean up go.mod and go.sum | go mod tidy |
go install |
Install a binary to $GOPATH/bin | go install golang.org/x/tools/...@latest |
# Initialize a new module
go mod init github.com/user/myproject
# Add a dependency (automatically updates go.mod)
go get github.com/gin-gonic/gin@latest
# Build for current platform
go build -o myapp .
# Run directly without creating a binary
go run .
# Format all files in project
go fmt ./...
# Run static analysis
go vet ./...
# Clean module cache
go clean -modcache
# List all dependencies
go list -m all
π‘ The ./... Pattern
./... is a wildcard that matches the current directory and all subdirectories. It's used with almost every go command to operate on the entire project.
2 Testing
Go has a built-in testing package and go test command. Test files end with _test.go and test functions start with Test. No external framework needed.
Basic Test
math.go
package math
func Add(a, b int) int {
return a + b
}
func Divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("division by zero")
}
return a / b, nil
}
math_test.go
package math
import "testing"
func TestAdd(t *testing.T) {
got := Add(2, 3)
want := 5
if got != want {
t.Errorf("Add(2, 3) = %d, want %d", got, want)
}
}
func TestDivide(t *testing.T) {
_, err := Divide(10, 0)
if err == nil {
t.Error("expected error for division by zero")
}
}
Table-Driven Tests
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
expected int
}{
{"positive numbers", 2, 3, 5},
{"negative numbers", -1, -2, -3},
{"zero", 0, 0, 0},
{"mixed", -1, 5, 4},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := Add(tt.a, tt.b)
if got != tt.expected {
t.Errorf("Add(%d, %d) = %d, want %d", tt.a, tt.b, got, tt.expected)
}
})
}
}
Benchmarks
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
Add(100, 200)
}
}
// Run benchmarks:
// go test -bench=. -benchmem
Running Tests
# Run all tests
go test ./...
# Run with verbose output
go test -v ./...
# Run specific test by name
go test -run TestAdd ./...
# Run with coverage report
go test -cover ./...
# Generate HTML coverage report
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out
# Run benchmarks
go test -bench=. -benchmem ./...
π Comparison: Testing Frameworks
Go (go test)
Built-in, no dependencies. Table-driven tests. Built-in benchmarking and coverage.
PHP (PHPUnit)
Third-party via Composer. Class-based with assertions. Data providers for parameterized tests.
JS (Jest)
Third-party via npm. describe/it blocks. Mocking and snapshot testing built-in.
Python (pytest)
Third-party via pip. Function-based with fixtures. parametrize decorator for test tables.
3 Code Quality
Go enforces code quality through built-in tools. gofmt eliminates style debates, while go vet and golangci-lint catch bugs and anti-patterns.
go vet β Built-in Static Analysis
# Catches common mistakes like:
# - Printf format string mismatches
# - Unreachable code
# - Incorrect struct tags
# - Copying locks by value
go vet ./...
gofmt & goimports
# gofmt β canonical code formatting (built-in)
gofmt -w .
# goimports β gofmt + auto-manage import statements
go install golang.org/x/tools/cmd/goimports@latest
goimports -w .
Go's Formatting Philosophy
Go has one canonical code style enforced by gofmt. There are no config files, no arguments about tabs vs spaces. All Go code looks the same β this is by design and considered a major productivity win.
golangci-lint β Comprehensive Linter
# Install
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
# Run all default linters
golangci-lint run
# Run specific linters
golangci-lint run --enable errcheck,govet,staticcheck
# Fix auto-fixable issues
golangci-lint run --fix
golangci-lint bundles 50+ linters. Key ones include:
errcheck
Finds unchecked errors
staticcheck
Advanced static analysis
gosimple
Suggests code simplifications
gocritic
Opinionated style checks
ineffassign
Detects ineffectual assignments
unused
Finds unused code
4 Popular Third-Party Libraries
While Go's standard library is powerful, these third-party libraries have become de facto standards in the ecosystem.
π Web Frameworks
Gin
The most popular Go web framework. Fast routing with radix tree, middleware support, JSON validation.
r := gin.Default()
r.GET("/users/:id", getUser)
r.POST("/users", createUser)
r.Run(":8080")
Echo
High-performance, minimalist framework. Built-in middleware, data binding, and automatic TLS.
e := echo.New()
e.GET("/users/:id", getUser)
e.POST("/users", createUser)
e.Start(":8080")
Fiber
Express-inspired framework built on fasthttp. Familiar API for Node.js developers.
app := fiber.New()
app.Get("/users/:id", getUser)
app.Post("/users", createUser)
app.Listen(":8080")
ποΈ ORM & Database
GORM
Full-featured ORM. Auto migrations, associations, hooks, preloading. Supports MySQL, PostgreSQL, SQLite, SQL Server.
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
db.AutoMigrate(&User{})
db.Create(&User{Name: "Alice"})
var user User
db.First(&user, 1)
db.Where("age > ?", 18).Find(&users)
sqlx
Extends database/sql with named parameters and struct scanning. Lighter alternative to GORM.
db := sqlx.MustConnect("mysql", dsn)
var users []User
db.Select(&users, "SELECT * FROM users WHERE age > ?", 18)
db.NamedExec("INSERT INTO users (name, email) VALUES (:name, :email)", user)
π§ Utilities
zap
Logging
Uber's blazing-fast structured logger. Zero-allocation in hot paths.
zerolog
Logging
Zero-allocation JSON logger. Fluent API, extremely fast.
Viper
Configuration
Supports JSON, YAML, TOML, env vars, flags. Live config reload.
Cobra
CLI Framework
Powers kubectl, Hugo, GitHub CLI. Subcommands, flags, auto-completion.
5 Build & Deployment
Go compiles to a single static binary with no runtime dependencies. This makes deployment exceptionally simple β just copy the binary to the target machine.
Cross-Compilation
# Build for Linux (from macOS/Windows)
GOOS=linux GOARCH=amd64 go build -o myapp-linux .
# Build for Windows
GOOS=windows GOARCH=amd64 go build -o myapp.exe .
# Build for macOS ARM (Apple Silicon)
GOOS=darwin GOARCH=arm64 go build -o myapp-mac .
# Common GOOS/GOARCH combinations:
# linux/amd64 β most cloud servers
# linux/arm64 β ARM servers, AWS Graviton
# darwin/arm64 β macOS Apple Silicon
# darwin/amd64 β macOS Intel
# windows/amd64 β Windows 64-bit
Static Linking & Build Flags
# Fully static binary (no CGO dependencies)
CGO_ENABLED=0 go build -o myapp .
# Strip debug info for smaller binary
go build -ldflags="-s -w" -o myapp .
# Embed version info at build time
go build -ldflags="-X main.version=1.2.3 -X main.buildTime=$(date -u +%Y-%m-%dT%H:%M:%SZ)" -o myapp .
Docker Multi-Stage Build
# Dockerfile
FROM golang:1.24-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -ldflags="-s -w" -o /app/server .
# Final image β from scratch (no OS, ~5MB total)
FROM scratch
COPY --from=builder /app/server /server
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
EXPOSE 8080
ENTRYPOINT ["/server"]
Why Go Deployment is Simple
- β’ Single binary β no runtime, no VM, no interpreter to install
- β’ Cross-compilation is a first-class feature β build Linux binaries on macOS
- β’ Docker images can be as small as 5β10MB using
FROM scratch - β’ Static linking means zero external library dependencies
6 Chapter Summary
Toolchain
build, run, test, fmt, vet, mod β all built-in
Testing
Table-driven tests, benchmarks, coverage reports
Code Quality
gofmt, go vet, golangci-lint, goimports
Ecosystem
Gin, GORM, zap, Viper, Cobra and more
Deployment
Cross-compilation, Docker multi-stage, static binaries
All-in-One
No Makefile, no external tools β just the go command