-
Notifications
You must be signed in to change notification settings - Fork 241
Description
Privileged issue
- I've been directed through Discussions to create an issue here.
Issue Content
Problem Statement
Pet currently faces two major architectural challenges:
1. Testing is Extremely Difficult
- The application is CUI-first with tightly coupled I/O operations
- Features chain together in a pipeline requiring user interaction (load -> filter -> fzf/peco -> gocui -> substitute)
- The monolithic
filter()function incmd/util.gois nearly impossible to unit test - Global state in
dialog/params.gomakes testing even harder
2. CLI Potential is Wasted
- Pet is designed CUI-first, requiring interactive selection for everything
- No way to execute commands directly:
pet exec "docker ps"doesn't exist - Can't pass parameters via flags for scripting/automation
- Users want one-line commands but are forced through interactive prompts
Proposed Solution
Refactor Pet to use Hexagonal Architecture (Ports & Adapters) where:
- Core business logic is pure, testable, with zero I/O dependencies
- Adapters handle all I/O (gocui, fzf/peco, files, etc.)
- Interfaces allow swapping implementations (interactive vs direct, real vs mock)
- CLI commands become thin composition layers
Architecture Overview
┌─────────────────────────────────────────────┐
│ Adapters (UI Layer) │
│ ┌──────────┐ ┌──────────┐ ┌───────────┐ │
│ │CLI Direct│ │CUI Inter.│ │Future:API │ │
│ └────┬─────┘ └────┬─────┘ └─────┬─────┘ │
└───────┼─────────────┼──────────────┼───────┘
│ │ │
┌───────▼─────────────▼──────────────▼───────┐
│ Application Ports (Interfaces) │
│ - SnippetRepository │
│ - ParameterInput │
│ - Selector │
└──────────────────┬─────────────────────────┘
│
┌──────────────────▼─────────────────────────┐
│ Core Business Logic (Pure, No I/O) │
│ - Snippet CRUD │
│ - Parameter extraction/substitution │
│ - Tag filtering, validation │
└──────────────────┬─────────────────────────┘
│
┌──────────────────▼─────────────────────────┐
│ Repository Implementations │
│ - FileRepository (TOML) │
│ - GistRepository, GitLabRepository │
└────────────────────────────────────────────┘
Dealing with Gocui
Gocui integration caused a lot of our business logic to be mingled with the main event loop.
Even though it has a blocking event loop, we can then hide it behind a simple interface:
// Interface
type ParameterInput interface {
GetParameters(params []Parameter, command string) (map[string]string, error)
}
// Implementations
- GocuiParameterInput (interactive, current behavior)
- FlagParameterInput (CLI flags, new feature)
- MockParameterInput (testing, new capability)Callers don't know about the event loop - they just call GetParameters() and get values back.
Benefits
Testability
- Core logic is pure functions - trivial to unit test
- Mock adapters eliminate need for actual gocui/fzf in tests
- Test coverage can be much higher than it is now
CLI-First Capability
# Interactive (current, backward compatible)
pet exec
# Direct execution (NEW)
pet exec -d "docker ps"
pet exec -d "docker run" --param container=nginx --param port=8080
pet exec -i "abc123" --use-defaultsMaintainability
- Clear separation of concerns
- Easy to add new adapters (REST API, HTTP server, whatever you can dream of!)
- Business logic changes don't affect UI and vice versa
Implementation Roadmap
We'll do a gradual migration (not a big-bang rewrite) to keep changes reviewable and maintain backward compatibility.
Phase 1: Foundation (v1.1.0)
Create domain/ package with core types and interfaces. No breaking changes.
Phase 2: Repository Pattern (v1.2.0)
Abstract storage behind SnippetRepository interface. Add tests.
Phase 3: Parameter Input Abstraction (v1.3.0)
Refactor gocui into GocuiParameterInput adapter. Remove global state. Add FlagParameterInput and MockParameterInput.
Phase 4: Selector Abstraction (v1.4.0)
Abstract fzf/peco behind Selector interface. Add DirectSelector for CLI mode.
Phase 5: Refactor Commands (v1.5.0)
Update all commands to use new architecture. Remove monolithic filter(). Add integration tests.
Phase 6: CLI-First Features (v1.6.0)
Add new flags: -d/--description, -i/--id, --param, --use-defaults, --json. Enable scripting!
Phase 7: Documentation & Polish (v2.0.0)
Complete ARCHITECTURE.md, update README, add examples, prepare release.
Timeline: 2-3 months for gradual migration
Breaking Changes: None until 2.0 (if needed)
Success Metrics
- Add coverage metrics (lol)
- Test coverage increases to ??%
- All commands testable without mocking I/O
- CLI-first usage works:
pet exec -d "name" --param x=1or whatever syntax - No breaking changes to existing CUI workflows