# Go Patterns Used in This Project This directory contains documentation on the Go design patterns and idioms used throughout the CV website project. ## Pattern Catalog 1. **[Middleware Pattern](./01-middleware-pattern.md)** - HTTP middleware chain for cross-cutting concerns 2. **[Handler Pattern](./02-handler-pattern.md)** - Organized HTTP handler structure 3. **[Context Pattern](./03-context-pattern.md)** - Request-scoped values using context 4. **[Error Wrapping](./04-error-wrapping.md)** - Structured error handling with wrapping 5. **[Dependency Injection](./05-dependency-injection.md)** - Constructor-based dependency injection 6. **[Template Pattern](./06-template-pattern.md)** - Cached template management 7. **[Singleton Pattern](./07-singleton-pattern.md)** - Single instance managers (template, config) 8. **[Factory Pattern](./08-factory-pattern.md)** - Error and response constructors ## Pattern Categories ### Structural Patterns - **Middleware Pattern** - Composable request processing - **Singleton Pattern** - Single instance coordination - **Dependency Injection** - Decoupled component initialization ### Behavioral Patterns - **Handler Pattern** - Request routing and handling - **Context Pattern** - Request-scoped data propagation - **Template Pattern** - Flexible rendering engine ### Error Handling Patterns - **Error Wrapping** - Context-rich error chains - **Typed Errors** - Domain-specific error types - **Factory Pattern** - Consistent error creation ## Pattern Usage Map ``` ┌────────────────────────────────────────────────────────────┐ │ Pattern Usage Map │ └────────────────────────────────────────────────────────────┘ main.go ├─→ Singleton Pattern (config, template manager) ├─→ Dependency Injection (handler construction) └─→ Middleware Pattern (chain setup) internal/handlers/ ├─→ Handler Pattern (method organization) ├─→ Error Wrapping (error handling) ├─→ Factory Pattern (error/response creation) └─→ Context Pattern (preference access) internal/middleware/ ├─→ Middleware Pattern (http.Handler wrapping) ├─→ Context Pattern (value storage) └─→ Error Wrapping (panic recovery) internal/templates/ ├─→ Singleton Pattern (manager instance) ├─→ Template Pattern (rendering strategy) └─→ Dependency Injection (config injection) internal/models/ ├─→ Factory Pattern (model loading) └─→ Error Wrapping (validation errors) ``` ## When to Use Each Pattern ### Middleware Pattern ✓ Cross-cutting concerns (logging, auth, CORS) ✓ Request/response modification ✓ Chain-of-responsibility needs ✗ Business logic (use handlers instead) ### Handler Pattern ✓ HTTP request handling ✓ Route-specific logic ✓ Organizing endpoints by resource ✗ Generic utilities (use packages instead) ### Context Pattern ✓ Request-scoped values (user, preferences) ✓ Cancellation signals ✓ Deadlines and timeouts ✗ Function parameters (use explicit params) ### Error Wrapping ✓ Adding context to errors ✓ Preserving error chains ✓ Debug information ✗ Simple errors (use errors.New) ### Dependency Injection ✓ Decoupling components ✓ Testing with mocks ✓ Configuration flexibility ✗ Simple functions (use direct calls) ### Template Pattern ✓ Flexible rendering ✓ HTML generation ✓ Hot reload in development ✗ JSON APIs (use direct encoding) ### Singleton Pattern ✓ Shared resources (DB, cache) ✓ Configuration managers ✓ Template engines ✗ Stateless utilities (use packages) ### Factory Pattern ✓ Complex object creation ✓ Consistent initialization ✓ Error construction ✗ Simple structs (use literals) ## Anti-Patterns to Avoid ### ❌ Global State ```go // BAD: Mutable global variable var globalConfig Config // GOOD: Pass as dependency func NewHandler(config *Config) *Handler ``` ### ❌ Panic for Flow Control ```go // BAD: Using panic for expected errors if err != nil { panic(err) } // GOOD: Return errors if err != nil { return fmt.Errorf("operation failed: %w", err) } ``` ### ❌ Ignoring Errors ```go // BAD: Ignoring error _ = json.Unmarshal(data, &result) // GOOD: Handle error if err := json.Unmarshal(data, &result); err != nil { return fmt.Errorf("unmarshal: %w", err) } ``` ### ❌ Context in Structs ```go // BAD: Storing context in struct type Handler struct { ctx context.Context } // GOOD: Pass context as first parameter func (h *Handler) Handle(ctx context.Context, w, r) ``` ### ❌ Naked Returns ```go // BAD: Naked return with named results func process() (result string, err error) { result = "foo" return // Confusing! } // GOOD: Explicit return func process() (string, error) { result := "foo" return result, nil } ``` ## Learning Path For developers new to these patterns: 1. **Start with**: Handler Pattern, Error Wrapping 2. **Then learn**: Middleware Pattern, Context Pattern 3. **Advanced**: Dependency Injection, Template Pattern 4. **Master**: Singleton Pattern, Factory Pattern ## Resources - [Effective Go](https://golang.org/doc/effective_go) - Official Go style guide - [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments) - Common mistakes - [Practical Go](https://dave.cheney.net/practical-go) - Best practices ## Pattern Evolution This project evolved through these pattern adoptions: ### Phase 1: Basic Structure - Simple handlers - No middleware - Manual cookie reading ### Phase 2: Middleware Introduction - PreferencesMiddleware added - Cookie handling centralized - Context pattern adopted ### Phase 3: Type Safety - Request/response types - Validation tags - Typed errors ### Phase 4: Error Handling - Error wrapping throughout - Domain error types - Centralized error handler ### Phase 5: Testing - Dependency injection for testability - Mock-friendly interfaces - Benchmark tests