faf3a2ca45
Created detailed ASCII diagrams documenting the entire system architecture: 1. System Architecture (_go-learning/diagrams/01-system-architecture.md) - Overall system architecture with client/server/storage layers - Layered architecture (Presentation → Application → Business → Data) - Component interaction and HTTP request flow - Data flow from app start through per-request lifecycle - Package dependencies and file organization
220 lines
6.2 KiB
Markdown
220 lines
6.2 KiB
Markdown
# 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
|