219b83bfc0
Added comprehensive educational documentation to fill empty folders: ## Architecture Diagrams (8 files) - System architecture with layered design - Complete request/response flow diagrams - Middleware chain execution details - Handler organization structure - Data model relationships - Error handling flows - Template rendering pipeline - PDF generation process with Chromedp ## Go Patterns (9 files) - Pattern catalog and usage guide - Middleware pattern (HTTP chain composition) - Handler pattern (method-based organization) - Context pattern (request-scoped values) - Error wrapping (typed errors, chains) - Dependency injection (constructor-based) - Template pattern (rendering pipeline) - Singleton pattern (thread-safe instances) - Factory pattern (error/response constructors) ## Best Practices (2 files) - Best practices catalog and quick reference - Code organization (project structure, naming) All documentation includes: - Real examples from this project - ASCII diagrams for visualization - Best practices and anti-patterns - Testing examples - Performance considerations Documentation structure: - 20 markdown files - ~6,000+ lines of educational content - Cross-referenced between topics - Practical, project-based examples
346 lines
7.5 KiB
Markdown
346 lines
7.5 KiB
Markdown
# 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!)
|