| name | go-guide |
| description | Go language guardrails, patterns, and best practices for AI-assisted development.
Use when working with Go files (.go), go.mod, or when the user mentions Go/Golang.
Provides project structure conventions, error handling patterns, testing standards,
and concurrency guidelines specific to this project's coding standards.
|
| license | MIT |
| metadata | {"author":"samuel","version":"1.0","category":"language","language":"go","extensions":".go"} |
Go Guide
Applies to: Go 1.21+, Microservices, APIs, CLIs
Core Principles
- Simplicity: Prefer simple, readable code over clever solutions
- Concurrency: Use goroutines and channels for concurrent operations
- Errors Are Values: Explicit error handling, no exceptions
- Composition Over Inheritance: Interfaces and struct embedding
- Standard Library First: Rich stdlib, minimize dependencies
Guardrails
Version & Dependencies
- Use Go 1.21+ with Go modules (
go.mod)
- Run
go mod tidy before committing
- Pin major versions in
go.mod
Code Style
- Run
gofmt / goimports before every commit
- Run
go vet and golangci-lint before committing
- Package names: lowercase, no underscores (
userservice not user_service)
- Exported:
PascalCase | Unexported: camelCase
- Follow Effective Go guidelines
Error Handling
- Always check errors:
if err != nil { return err }
- Return errors, don't panic (panic only for unrecoverable)
- Wrap errors with context:
fmt.Errorf("fetch user: %w", err)
- Use custom error types for domain errors
- Don't ignore errors with
_ unless justified with comment
Concurrency
- Use
context.Context for cancellation and timeouts
- Always set timeout for HTTP requests
- Use
sync.WaitGroup for goroutine coordination
- Close channels from sender side only
- Use
select with default to avoid blocking
Interfaces
- Accept interfaces, return structs
- Define interfaces where they're used (not where implemented)
- Keep interfaces small (1-3 methods ideal)
- Use
io.Reader, io.Writer from stdlib when applicable
Project Structure
myproject/
├── cmd/ # Main applications
│ └── api/
│ └── main.go # Entry point
├── internal/ # Private application code
│ ├── domain/ # Business logic
│ ├── service/ # Application services
│ ├── repository/ # Data access
│ └── http/ # HTTP handlers
├── pkg/ # Public libraries (reusable)
├── api/ # OpenAPI/Protobuf specs
├── go.mod
├── go.sum
└── README.md
internal/ for private code (not importable by other projects)
pkg/ only for truly reusable libraries
cmd/ for executables (one per subdirectory)
- No global variables (use dependency injection)
Error Handling Patterns
Basic Pattern
func GetUser(id string) (*User, error) {
user, err := db.FindUserByID(id)
if err != nil {
return nil, fmt.Errorf("get user %s: %w", id, err)
}
return user, nil
}
Custom Errors
type NotFoundError struct {
Resource string
ID string
}
func (e *NotFoundError) Error() string {
return fmt.Sprintf("%s with ID %s not found", e.Resource, e.ID)
}
var notFound *NotFoundError
if errors.As(err, ¬Found) {
}
Testing
Standards
- Test files:
*_test.go (same package)
- Test functions:
func TestFunctionName(t *testing.T)
- Table-driven tests for multiple cases
- Use
t.Helper() in test helpers
- Use subtests:
t.Run("name", func(t *testing.T) {...})
- Coverage target: >80% for business logic
- Benchmark critical paths:
func BenchmarkFunction(b *testing.B)
Table-Driven Tests
func TestCalculate(t *testing.T) {
tests := []struct {
name string
a, b int
expected int
wantErr bool
}{
{"positive numbers", 2, 3, 5, false},
{"negative numbers", -2, -3, -5, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := Calculate(tt.a, tt.b)
if tt.wantErr {
if err == nil {
t.Error("expected error, got nil")
}
return
}
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if result != tt.expected {
t.Errorf("got %d, want %d", result, tt.expected)
}
})
}
}
Tooling
Essential Commands
go fmt ./...
go vet ./...
go test ./...
go test -cover ./...
go test -race ./...
go build ./cmd/api
go mod tidy
golangci-lint run
Linter Configuration
linters:
enable:
- gofmt
- govet
- staticcheck
- ineffassign
- misspell
- gosec
- errcheck
- gocyclo
- dupl
linters-settings:
gocyclo:
min-complexity: 10
dupl:
threshold: 100
Advanced Topics
For detailed patterns and examples, see:
External References