Formatting, Vetting, and Documentation

Overview

Go has a unique culture: there’s one blessed way to format code, a built-in static analyzer for common mistakes, and a documentation system that extracts docs from comments. This chapter covers gofmt, go vet, and godoc standards.

Code Formatting with gofmt

Why Gofmt Exists

Unlike other languages where style guides vary (tabs vs. spaces, brace placement), Go has a single canonical format enforced by gofmt. This eliminates style debates and ensures all Go code looks the same.

“Gofmt’s style is no one’s favorite, yet gofmt is everyone’s favorite.” — Rob Pike

Basic Usage

# Format a file (print to stdout)
$ gofmt main.go

# Format and overwrite file
$ gofmt -w main.go

# Format all files recursively
$ gofmt -w .

# Using go fmt (recommended)
$ go fmt ./...

Formatting Rules

gofmt enforces:

// BEFORE (your style)
func foo(x int,y string){
if x>0{
return
}
}

// AFTER (gofmt style)
func foo(x int, y string) {
    if x > 0 {
        return
    }
}
Rule Gofmt Standard
Indentation Tabs
Spacing Spaces around operators
Braces Opening brace on same line
Line length No limit (but keep reasonable)
Blank lines Strategic for readability

Code Simplification

Use -s to simplify code:

$ gofmt -s -w main.go
// Before
s[a:len(s)]
for x, _ := range v {}
[]int{1, 2, 3}[0:2]

// After -s
s[a:]
for x := range v {}
[]int{1, 2, 3}[:2]

Import Formatting with goimports

goimports does everything gofmt does, plus it manages imports:

# Install
$ go install golang.org/x/tools/cmd/goimports@latest

# Format and fix imports
$ goimports -w main.go
// Before (missing import, unused import)
package main
import (
    "unused"
)
func main() {
    fmt.Println("Hello")
}

// After goimports
package main

import "fmt"

func main() {
    fmt.Println("Hello")
}

Static Analysis with go vet

What Vet Catches

go vet detects code that compiles but is probably wrong:

$ go vet ./...

Common Issues Detected

Printf Format Errors

// go vet catches this
fmt.Printf("%d", "string")  // wrong type
fmt.Printf("%s %s", name)   // wrong number of args

Unreachable Code

func example() int {
    return 42
    fmt.Println("never runs")  // go vet: unreachable code
}

Suspicious Loop Variables

// go vet warns about this common bug
for i, v := range values {
    go func() {
        fmt.Println(i, v)  // captures loop variable
    }()
}

Useless Assignments

x := 5
x = x  // go vet: self-assignment

Invalid Struct Tags

type User struct {
    Name string `json:name`  // Missing quotes around "name"
}

Running Specific Checks

# List available analyzers
$ go tool vet help

# Run specific analyzer
$ go vet -composites=false ./...
$ go vet -printf=true ./...

Enhanced Linting with staticcheck

staticcheck provides additional checks beyond go vet:

# Install
$ go install honnef.co/go/tools/cmd/staticcheck@latest

# Run
$ staticcheck ./...

Checks include: - Unused code - Deprecated function usage - Simplification suggestions - Performance improvements - Common bugs

Documentation with godoc

Writing Documentation

Go extracts documentation from comments directly before declarations:

// Package math provides basic mathematical operations.
// It includes functions for arithmetic, trigonometry, and more.
package math

// Pi represents the mathematical constant π.
const Pi = 3.14159

// Add returns the sum of two integers.
// It handles overflow by wrapping around.
func Add(a, b int) int {
    return a + b
}

// Calculator provides stateful mathematical operations.
type Calculator struct {
    // Result holds the current calculation result.
    Result float64
}

// Add adds n to the current result.
func (c *Calculator) Add(n float64) {
    c.Result += n
}

Documentation Conventions

Rule Example
Start with name // Add returns the sum...
Complete sentences End with period
First sentence is summary Shown in package lists
Blank line for paragraphs Separate blocks

Code Examples in Docs

Create examples in *_test.go files:

// example_test.go
package math_test

import (
    "fmt"
    "myproject/math"
)

func ExampleAdd() {
    result := math.Add(2, 3)
    fmt.Println(result)
    // Output: 5
}

func ExampleCalculator_Add() {
    c := &math.Calculator{}
    c.Add(10)
    c.Add(5)
    fmt.Println(c.Result)
    // Output: 15
}

These examples: - Appear in documentation - Are tested by go test - Show real usage

Viewing Documentation

# Command line
$ go doc fmt
$ go doc fmt.Println
$ go doc -all fmt

# Local web server
$ go install golang.org/x/tools/cmd/godoc@latest
$ godoc -http=:6060
# Visit http://localhost:6060

Package Comments

For larger packages, use a doc.go file:

// doc.go

/*
Package server implements an HTTP server with middleware support.

# Getting Started

Create a new server and add routes:

    srv := server.New()
    srv.Get("/", handleHome)
    srv.Listen(":8080")

# Middleware

Add middleware to process all requests:

    srv.Use(server.Logger())
    srv.Use(server.Recovery())

# Configuration

Configure the server using options:

    srv := server.New(
        server.WithTimeout(30 * time.Second),
        server.WithMaxBodySize(1 << 20),
    )
*/
package server

Combining Tools in Workflow

Pre-commit Hook

#!/bin/bash
# .git/hooks/pre-commit

# Format
gofmt -l -w .

# Vet
go vet ./...
if [ $? -ne 0 ]; then
    echo "go vet failed"
    exit 1
fi

# Staticcheck
staticcheck ./...
if [ $? -ne 0 ]; then
    echo "staticcheck failed"
    exit 1
fi

Makefile Integration

.PHONY: check fmt vet lint

fmt:
    gofmt -w .

vet:
    go vet ./...

lint:
    staticcheck ./...

check: fmt vet lint
    @echo "All checks passed"

CI Pipeline (GitHub Actions)

- name: Check formatting
  run: |
    if [ "$(gofmt -l . | wc -l)" -gt 0 ]; then
      echo "Code is not formatted"
      gofmt -d .
      exit 1
    fi

- name: Vet
  run: go vet ./...

- name: Staticcheck
  run: |
    go install honnef.co/go/tools/cmd/staticcheck@latest
    staticcheck ./...

Summary

Tool Purpose Usage
gofmt Format code gofmt -w .
goimports Format + manage imports goimports -w .
go vet Catch common mistakes go vet ./...
staticcheck Enhanced linting staticcheck ./...
godoc Generate documentation godoc -http=:6060