-
Notifications
You must be signed in to change notification settings - Fork 1
refactor(ui): remove ports dependency from UI layer #138
Description
Summary
The messages.go file in the UI layer imports from internal/ports, which violates the architectural principle stated in ARCHITECTURE.md: "CLI and UI only depend on Services - never on Ports or Adapters directly".
Problem
Location: internal/ui/messages.go:3
import "github.com/renato0307/rocha/internal/ports"
type AttachSessionMsg struct {
Session *ports.TmuxSession
}
type AttachShellSessionMsg struct {
Session *ports.TmuxSession
}Architectural diagram:
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ UI/CLI │ ──▶ │ Services │ ──▶ │ Ports │
└─────────────┘ └─────────────┘ └─────────────┘
│
▼
┌─────────────┐
│ Adapters │
└─────────────┘
- Ports define interfaces and types for infrastructure concerns (tmux, git, storage)
- Services orchestrate business logic using those ports
- UI should only know about domain concepts, not infrastructure details
Why It Matters
When UI imports from ports:
- UI becomes coupled to infrastructure layer
- Changes to
ports.TmuxSessionripple into UI - Harder to test UI in isolation
- Blurs architectural boundaries
Nuance
This is a borderline case because:
TmuxSessionis a simple data struct, not an interface- UI isn't calling tmux methods, just passing data
- The struct conceptually represents a domain entity (a session)
Proposed Solutions
Option 1: Move TmuxSession to domain package (recommended)
// internal/domain/tmux_session.go
type TmuxSession struct {
Name string
Attached bool
// ...
}
// internal/ports/tmux.go
type TmuxClient interface {
ListSessions() ([]domain.TmuxSession, error)
// ...
}
// internal/ui/messages.go
import "github.com/renato0307/rocha/internal/domain"
type AttachSessionMsg struct {
Session *domain.TmuxSession
}Option 2: Use session name only
Similar to other messages like KillSessionMsg, ArchiveSessionMsg:
type AttachSessionMsg struct {
SessionName string
}
type AttachShellSessionMsg struct {
SessionName string
}Then the handler looks up the full session object. This is more consistent with other action messages.
Option 3: Document as acceptable exception
If the team decides the pragmatic tradeoff is worth it, add a comment in ARCHITECTURE.md explaining why this specific case is allowed.
Recommendation
Option 1 is the cleanest architectural solution. Option 2 is simpler and more consistent with existing patterns in the same file. Option 3 should be last resort.
Labels
- enhancement
- architecture