docs: Add comprehensive system architecture diagrams
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
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user