d95c62bad4
Remove 557-line server-design.md from _go-learning/architecture - content is now covered in updated architecture documentation with real implementation examples and test coverage.
Go Best Practices for This Project
This directory contains best practices and guidelines used in the CV website project, demonstrating real-world Go development standards.
Best Practices Catalog
- Code Organization - Package structure, file naming, project layout
- Error Handling - Error wrapping, custom errors, error patterns
- Testing - Unit tests, integration tests, benchmarks, test organization
- Performance - Optimization strategies, profiling, benchmarking
- Security - Input validation, XSS prevention, CSRF protection
- HTTP & Handlers - Handler patterns, middleware, request/response
- HTMX Integration - Server-side rendering, partial updates, Go + HTMX patterns
Quick Reference
Code Organization
project/
├── cmd/ Main applications
├── internal/ Private application code
│ ├── handlers/ HTTP handlers
│ ├── middleware/ HTTP middleware
│ ├── models/ Data models
│ ├── templates/ Template management
│ └── routes/ Route definitions
├── data/ Static data files
├── templates/ HTML templates
├── static/ Static assets
└── tests/ Test files
Error Handling
// Wrap errors with context
if err != nil {
return fmt.Errorf("operation failed: %w", err)
}
// Use typed errors
func InvalidLanguageError(lang string) *DomainError {
return NewDomainError(
ErrCodeInvalidLanguage,
fmt.Sprintf("Unsupported language: %s", lang),
http.StatusBadRequest,
)
}
Testing
// Table-driven tests
func TestFunction(t *testing.T) {
tests := []struct {
name string
input string
want string
}{
{"case1", "input1", "expected1"},
{"case2", "input2", "expected2"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := Function(tt.input)
if got != tt.want {
t.Errorf("got %v, want %v", got, tt.want)
}
})
}
}
HTTP Handlers
// Use method receivers for related handlers
type CVHandler struct {
tmpl *templates.Manager
host string
}
func (h *CVHandler) Home(w http.ResponseWriter, r *http.Request) {
// Handler logic
}
Middleware
// Standard middleware pattern
func MyMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Pre-processing
next.ServeHTTP(w, r)
// Post-processing
})
}
Core Principles
1. Simplicity
- Clear is better than clever
- Explicit is better than implicit
- Simple solutions over complex ones
2. Readability
- Code is read more often than written
- Use descriptive names
- Comment why, not what
3. Consistency
- Follow established patterns
- Consistent formatting (gofmt)
- Consistent error handling
4. Performance
- Measure before optimizing
- Use profiling tools
- Optimize hot paths only
5. Security
- Validate all input
- Use context for timeouts
- Sanitize output
Common Pitfalls to Avoid
❌ DON'T
// DON'T ignore errors
data, _ := readFile(path)
// DON'T use panic for flow control
if invalid {
panic("invalid input")
}
// DON'T store context in structs
type Handler struct {
ctx context.Context // Wrong!
}
// DON'T use global mutable state
var globalConfig Config
globalConfig.Timeout = 30
// DON'T return naked values with named returns
func foo() (result string, err error) {
result = "value"
return // Confusing!
}
✅ DO
// DO handle errors explicitly
data, err := readFile(path)
if err != nil {
return fmt.Errorf("read file: %w", err)
}
// DO return errors for exceptional cases
if invalid {
return errors.New("invalid input")
}
// DO pass context as first parameter
func (h *Handler) Process(ctx context.Context, data Data) error {
// Use ctx
}
// DO use dependency injection
func NewHandler(config *Config) *Handler {
return &Handler{config: config}
}
// DO use explicit returns
func foo() (string, error) {
result := "value"
return result, nil
}
Tools & Commands
Formatting & Linting
# Format code
go fmt ./...
gofmt -s -w .
# Lint code
golangci-lint run
staticcheck ./...
# Vet code
go vet ./...
Testing
# Run tests
go test ./...
# Run with coverage
go test -cover ./...
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out
# Run benchmarks
go test -bench=. ./...
go test -bench=. -benchmem ./...
# Run specific test
go test -run TestFunctionName
Profiling
# CPU profiling
go test -cpuprofile=cpu.prof -bench=.
go tool pprof cpu.prof
# Memory profiling
go test -memprofile=mem.prof -bench=.
go tool pprof mem.prof
# Live profiling
go tool pprof http://localhost:8080/debug/pprof/profile
Build & Run
# Build
go build -o app ./cmd/server
# Run
go run ./cmd/server
# Build with optimizations
go build -ldflags="-s -w" -o app ./cmd/server
# Cross-compile
GOOS=linux GOARCH=amd64 go build -o app-linux ./cmd/server
Project-Specific Guidelines
File Naming
handler.go→cv.go,health.gohandler_pages.go→cv_pages.gohandler_htmx.go→cv_htmx.gohandler_test.go→cv_pages_test.go
Handler Organization
internal/handlers/
├── cv.go # Constructor
├── cv_pages.go # Page handlers
├── cv_htmx.go # HTMX handlers
├── cv_pdf.go # PDF handler
├── cv_helpers.go # Helper functions
├── types.go # Request/response types
├── errors.go # Error handling
└── *_test.go # Tests mirror source files
Middleware Chain Order
Recovery → Logger → SecurityHeaders → Preferences → Router
(outer) (inner)
Context Keys
// Use custom type for context keys
type contextKey string
const PreferencesKey contextKey = "preferences"
References
Official Resources
Community Resources
Tools
- golangci-lint - Linter aggregator
- staticcheck - Static analysis
- gopls - Language server
Learning Path
- Start with: Code Organization, HTTP Handlers
- Then learn: Error Handling, Testing
- Advanced: Performance, Security
- Mastery: HTMX Integration, Full Stack Patterns
Evolution of This Project
Phase 1: Basic Structure
- Simple handlers
- No middleware
- Manual cookie handling
Phase 2: Refactoring
- Handler split by responsibility
- Middleware introduction
- Context pattern adoption
Phase 3: Type Safety
- Request/response types
- Validation tags
- Typed errors
Phase 4: Testing & Performance
- Comprehensive test coverage
- Benchmark tests
- Performance profiling
Phase 5: Documentation
- Architecture diagrams
- Pattern documentation
- Best practices guide (this!)