# 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 1. **[Code Organization](./01-code-organization.md)** - Package structure, file naming, project layout 2. **[Error Handling](./02-error-handling.md)** - Error wrapping, custom errors, error patterns 3. **[Testing](./03-testing.md)** - Unit tests, integration tests, benchmarks, test organization 4. **[Performance](./04-performance.md)** - Optimization strategies, profiling, benchmarking 5. **[Security](./05-security.md)** - Input validation, XSS prevention, CSRF protection 6. **[HTTP & Handlers](./06-http-handlers.md)** - Handler patterns, middleware, request/response 7. **[HTMX Integration](./07-htmx-go-integration.md)** - 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 ```go // 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 ```go // 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 ```go // 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 ```go // 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 ```go // 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 ```go // 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 ```bash # Format code go fmt ./... gofmt -s -w . # Lint code golangci-lint run staticcheck ./... # Vet code go vet ./... ``` ### Testing ```bash # 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 ```bash # 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 ```bash # 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.go` - `handler_pages.go` → `cv_pages.go` - `handler_htmx.go` → `cv_htmx.go` - `handler_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 ```go // Use custom type for context keys type contextKey string const PreferencesKey contextKey = "preferences" ``` ## References ### Official Resources - [Effective Go](https://golang.org/doc/effective_go) - [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments) - [Go Blog](https://blog.golang.org/) ### Community Resources - [Practical Go](https://dave.cheney.net/practical-go) - [Go Proverbs](https://go-proverbs.github.io/) - [Idiomatic Go](https://dmitri.shuralyov.com/idiomatic-go) ### Tools - [golangci-lint](https://golangci-lint.run/) - Linter aggregator - [staticcheck](https://staticcheck.io/) - Static analysis - [gopls](https://github.com/golang/tools/tree/master/gopls) - Language server ## Learning Path 1. **Start with**: Code Organization, HTTP Handlers 2. **Then learn**: Error Handling, Testing 3. **Advanced**: Performance, Security 4. **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!)