Files
cv-site/doc/_go-learning/best-practices/README.md
T
juanatsap d95c62bad4 refactor: remove outdated server design documentation
Remove 557-line server-design.md from _go-learning/architecture - content is now covered in updated architecture documentation with real implementation examples and test coverage.
2025-12-02 20:25:05 +00:00

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!)