Architecture Overview
High-level architecture and design decisions for govman.
Design Philosophy
govman is built with these core principles:
- Simplicity: Easy to use, easy to understand
- Safety: No root required, safe defaults
- Speed: Fast downloads, instant switching
- Reliability: Checksum verification, atomic operations
- Cross-platform: Works on Linux, macOS, Windows
Architecture Layers
┌─────────────────────────────────────┐
│ User Interface │ (CLI, Shell Integration)
├─────────────────────────────────────┤
│ Application Logic │ (Commands, Workflows)
├─────────────────────────────────────┤
│ Core Services │ (Manager, Downloader, Config)
├─────────────────────────────────────┤
│ Utilities │ (Logger, Progress, Format)
├─────────────────────────────────────┤
│ External Dependencies │ (Cobra, Viper, stdlib)
└─────────────────────────────────────┘
Layer Descriptions
User Interface:
- CLI commands (
internal/cli/) - Shell integration code generation (
internal/shell/) - User-facing messages and help text
Application Logic:
- Command orchestration
- Input validation
- Workflow coordination
Core Services:
- Version management (
internal/manager/) - Download and extraction (
internal/downloader/) - Configuration (
internal/config/) - Go releases API (
internal/golang/)
Utilities:
- Logging (
internal/logger/) - Progress reporting (
internal/progress/) - String formatting (
internal/util/)
External Dependencies:
- Cobra (CLI framework)
- Viper (configuration)
- Go standard library
Component Diagram
┌────────────────────────────────────────────────────────┐
│ CLI Layer │
│ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ │
│ │Install│ │ Use │ │ List │ │ Info │ │ Init │ ... │
│ └───┬───┘ └───┬───┘ └───┬───┘ └───┬───┘ └───┬───┘ │
└──────┼───-─────┼────-────┼-────────┼────-────┼─────────┘
│ │ │ │ │
└──────-─-┴────-────┴─────-───┴───-─────┘
│
┌────────▼────────┐
│ │
│ Manager │
│ │
└────┬───┬───┬────┘
│ │ │
┌───────────┘ │ └──────────┐
│ │ │
┌────▼─────┐ ┌-─────▼─────┐ ┌───-─▼─-──┐
│Downloader│ │ Config │ │ Golang │
└────┬─────┘ └─-──────────┘ └────-┬────┘
│ │
┌────▼─────┐ ┌───-▼-───┐
│ Progress │ │ go.dev │
└──────────┘ │ API │
└─────────┘
Key Design Patterns
1. Facade Pattern
Manager acts as a facade for core services:
type Manager struct {
config *config.Config
downloader *downloader.Downloader
shell shell.Shell
}
CLI commands interact with Manager, which coordinates lower-level services.
2. Strategy Pattern
Different shell implementations via Shell interface:
type Shell interface {
Name() string
ConfigFile() string
PathCommand(path string) string
SetupCommands(binPath string) []string
// ...
}
// Implementations:
type BashShell struct{}
type ZshShell struct{}
type FishShell struct{}
type PowerShell struct{}
3. Singleton Pattern
Global logger instance:
var globalLogger *Logger
var once sync.Once
func Get() *Logger {
once.Do(func() {
globalLogger = New()
})
return globalLogger
}
4. Template Method
Download workflow in Downloader:
func (d *Downloader) Download(url, installDir, version string) error {
// Template method defines steps:
1. Get file info
2. Download file
3. Verify checksum
4. Extract archive
}
Data Flow Architecture
User Input
↓
CLI Parsing (Cobra)
↓
Command Validation
↓
Manager Orchestration
↓
Service Execution (Parallel where safe)
↓
Result Aggregation
↓
User Output (Formatted by Logger)
State Management
Application State
- Method: Configuration file (
~/.govman/config.yaml) - Format: YAML
- Persistence: Disk-based
- Updates: Atomic write (temp file + rename)
Runtime State
- Current version: Resolved from symlink or environment
- Session state: In-memory (not persisted)
- Progress: Ephemeral UI state
No Global Mutable State
- Configuration passed explicitly
- No global variables (except logger singleton)
- Each command execution is isolated
Error Handling Strategy
Layered Error Handling
Low-level error (e.g., HTTP 404)
↓ wrapped with context
Mid-level error (e.g., "failed to download")
↓ formatted for user
High-level error (e.g., "Go 1.25.1 not available for your platform")
↓ displayed with help
User sees actionable message
Error Types
- Validation errors: User input issues
- Network errors: Download/API failures
- Filesystem errors: Permission/space issues
- Logic errors: Invalid state
All errors include:
- Clear message
- Suggested action (via
ErrorWithHelp) - Exit code
Security Architecture
Principle of Least Privilege
- No root required: All operations in user space
- Limited file access: Only ~/.govman/ and shell configs
- No network server: Client-only architecture
Defense in Depth
- Input validation: All user inputs validated
- Path validation: Prevent directory traversal
- Checksum verification: SHA-256 for all downloads
- HTTPS only: Encrypted connections
- Safe defaults: Secure configuration out of the box
Trust Model
Trusted:
- go.dev (official Go releases)
- github.com (govman releases)
- User's local system
Not trusted: -User input (validated before use)
- Custom mirror URLs (optional, user-configured)
Concurrency Model
Single-threaded Command Execution
- One command at a time per user
- No locking needed (user-space isolation)
- Simple, predictable behavior
Safe Parallel Downloading
- HTTP connections can be parallel (configurable)
- Uses standard library's goroutines
- Progress reporting thread-safe
Atomic Operations
- File writes: temp file + rename
- Symlink updates: atomic at OS level
- Configuration updates: single write operation
Extensibility Points
Adding New Commands
- Create file in
internal/cli/ - Implement
cobra.Command - Register in
addCommands()
Adding New Shells
- Implement
Shellinterface - Add to
Detect()logic - Add to
getShellByName()
Changing Configuration
- Update
Configstruct ininternal/config/ - Set default in
setDefaults() - Configuration automatically persists
Performance Considerations
Optimization Strategies
- Caching: API responses cached for 10 minutes
- Parallel downloads: Multiple connections (configurable)
- Resume support: Incomplete downloads resume
- Minimal I/O: Only read/write when necessary
Trade-offs
- Simplicity over speed: Single-threaded for safety
- Safety over size: Self-contained binary with dependencies
- UX over efficiency: Progress bars worth the overhead
Platform Abstractions
Cross-platform Code
// Path handling
filepath.Join() // Works on all platforms
// Symlinks
os.Symlink() // Supported on all modern OSes
// Shell detection
runtime.GOOS // Conditional logic per platform
Platform-specific Code
// Shell integration
if runtime.GOOS == "windows" {
// PowerShell or cmd.exe
} else {
// Bash/Zsh/Fish
}
// Binary naming
if runtime.GOOS == "windows" {
name += ".exe"
}
Testing Architecture
Test Organization
- Unit tests:
*_test.goalongside implementation - Test package:
package_testfor public API - Test helpers: Shared fixtures and mocks
Test Coverage Goals
- Core logic: 80%+ coverage
- Critical paths: 100% coverage (install, use, download)
- Edge cases: Comprehensive error handling tests
Deployment Architecture
Distribution
GitHub Releases
↓ provides
Pre-built binaries for all platforms
↓ installed via
Installation scripts (install.sh, install.ps1, install.bat)
↓ placed in
~/.govman/bin/govman
↓ added to
User's PATH
Update Mechanism
govman selfupdate
↓ queries
GitHub API (latest release)
↓ downloads
New binary
↓ replaces
Old binary (with backup)
↓ verifies
New version works
↓ removes
Backup
Scalability
Personal Use (Design Goal)
- Manages 5-10 Go versions efficiently
- Handles daily version switching
- Fast enough for interactive use
Not Designed For
- Enterprise-wide deployment (no central management)
- Hundreds of installations (filesystem limits)
- Concurrent multi-user on same account
Future Architecture Considerations
Potential Enhancements:
- Plugin system for extensibility
- Remote version cache sharing
- Integration with IDEs
- API mode for programmatic access
Constraints:
- Must remain simple
- No breaking changes to core UX
- Maintain cross-platform support
- Keep binary size reasonable