Files
gh-human-frontier-labs-inc-…/references/architecture-best-practices.md
2025-11-29 18:47:30 +08:00

169 lines
3.1 KiB
Markdown

# Bubble Tea Architecture Best Practices
## Model Design
### Keep State Flat
❌ Avoid: Deeply nested state
✅ Prefer: Flat structure with clear fields
```go
// Good
type model struct {
items []Item
cursor int
selected map[int]bool
}
// Avoid
type model struct {
state struct {
data struct {
items []Item
}
}
}
```
### Separate Concerns
- UI state in model
- Business logic in separate functions
- Network/IO in commands
### Component Ownership
Each component owns its state. Don't reach into component internals.
## Update Function
### Message Routing
Route messages to appropriate handlers:
```go
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
return m.handleKeyboard(msg)
case tea.WindowSizeMsg:
return m.handleResize(msg)
}
return m.updateComponents(msg)
}
```
### Command Batching
Batch multiple commands:
```go
var cmds []tea.Cmd
cmds = append(cmds, cmd1, cmd2, cmd3)
return m, tea.Batch(cmds...)
```
## View Function
### Cache Expensive Renders
Don't recompute on every View() call:
```go
type model struct {
cachedView string
dirty bool
}
func (m model) View() string {
if m.dirty {
m.cachedView = m.render()
m.dirty = false
}
return m.cachedView
}
```
### Responsive Layouts
Adapt to terminal size:
```go
if m.width < 80 {
// Compact layout
} else {
// Full layout
}
```
## Performance
### Minimize Allocations
Reuse slices and strings where possible
### Defer Heavy Operations
Move slow operations to commands (async)
### Debounce Rapid Updates
Don't update on every keystroke for expensive operations
## Error Handling
### User-Friendly Errors
Show actionable error messages
### Graceful Degradation
Fallback when features unavailable
### Error Recovery
Allow user to retry or cancel
## Testing
### Test Pure Functions
Extract business logic for easy testing
### Mock Commands
Test Update() without side effects
### Snapshot Views
Compare View() output for visual regression
## Accessibility
### Keyboard-First
All features accessible via keyboard
### Clear Indicators
Show current focus, selection state
### Help Text
Provide discoverable help (? key)
## Code Organization
### File Structure
```
main.go - Entry point, model definition
update.go - Update handlers
view.go - View rendering
commands.go - Command definitions
messages.go - Custom message types
```
### Component Encapsulation
One component per file for complex TUIs
## Debugging
### Log to File
```go
f, _ := os.OpenFile("debug.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
log.SetOutput(f)
log.Printf("Debug: %+v", msg)
```
### Debug Mode
Toggle debug view with key binding
## Common Pitfalls
1. **Forgetting tea.Batch**: Returns only last command
2. **Not handling WindowSizeMsg**: Fixed-size components
3. **Blocking in Update()**: Freezes UI - use commands
4. **Direct terminal writes**: Use tea.Println for above-TUI output
5. **Ignoring ready state**: Rendering before initialization complete