Appearance
Refactoring Guide
Code debt. Snarly, ad-hoc, organically fussed with, did i say temperamental? Man crawling across the desert, barely able to say "refactor, need refactor."
Aren't people saying, how perfect AI is at doing such a mundane, hair-pulling chore? Sure, but kinda know not to trust AI refactoring my baby. So, I asked it to compile these guidelines. Then, I asked it to use it on an easy, simple refactoring: Centralize timing of user clicks. The result? Nice, almost painless. Needed mild manual intervention, and go!
I plan to use this to do some harder refactoring, making a backup, first.
Table of Contents
- General Principles
- Refactoring Process
- Performance Optimization Principles
- Simplification Principles
- Migration Strategy
- Example: Mouse Timing Centralization
- Applying to Layout Algorithms
General Principles
1. Centralization Over Distribution
Move from scattered logic to single source of truth.
Pattern:
- Before: Logic duplicated across multiple components
- After: One manager owns the responsibility
- Benefit: Consistency, easier debugging, single point of change
2. Declaration Over Management
Components declare intent, manager handles execution.
Pattern:
- Component sets properties:
needs_X = true,X_callback = fn - Manager reads properties and handles lifecycle automatically
- Component receives callbacks at appropriate times
3. State Persistence
State lives on persistent objects, not ephemeral components.
Why: Components can be destroyed/recreated. Shared state objects persist.
Pattern:
- Move state from component-local variables to shared state objects
- State survives component recreation
- Enables cross-component coordination
4. Enum-Based Configuration
Single enum replaces multiple boolean flags.
Benefits:
- Enforces mutual exclusivity or valid combinations
- Type-safe, self-documenting
- Easier to extend with new options
5. Automatic Lifecycle
Manager handles all lifecycle automatically.
Events:
- Start conditions → Manager detects and starts
- Stop conditions → Manager detects and stops
- Edge cases → Manager handles cleanup
6. Single Source of Truth
One manager, one timer/cache/state per concern.
Benefits:
- No conflicts between multiple instances
- Easier to reason about
- Better performance (shared resources)
Refactoring Process
Phase 1: Analysis
- Identify scattered logic - Where is the same pattern repeated?
- Find the manager - What should own this responsibility?
- Map state flow - Where does state live? Where should it live?
- Identify lifecycle - What are start/stop/cleanup conditions?
Phase 2: Design
- Define the abstraction - What properties/components are needed?
- Design the interface - How do components declare intent?
- Plan state migration - How to move from old to new?
- Design lifecycle - When does manager start/stop/cleanup?
Phase 3: Implementation
- Build manager infrastructure - Core timing/state management
- Add target properties - State and callbacks on shared objects
- Migrate components - One by one, remove old logic
- Test edge cases - Re-renders, hover-leave, rapid interactions
Phase 4: Cleanup
- Remove deprecated patterns - Old code, unused properties
- Update documentation - Reflect new architecture
- Verify performance - Ensure improvements realized
Performance Optimization Principles
1. Batch Operations
Group related work to minimize overhead.
Pattern:
- Collect all changes first
- Apply in single batch
- Use spatial indexes for efficient queries
2. Lazy Evaluation
Compute only when needed, cache when possible.
Pattern:
- Don't precompute everything
- Compute on-demand
- Cache results until invalidated
3. Incremental Updates
Update only what changed, not everything.
Pattern:
- Track what changed
- Update only affected parts
- Skip unchanged work
4. Efficient Data Structures
Choose structures optimized for access patterns.
Pattern:
- Spatial queries → R-tree (RBush)
- Fast lookups → Maps/Dictionaries
- Sequential access → Arrays
5. Minimize Re-renders
Reduce component recreation and style recomputation.
Pattern:
- State on persistent objects (not components)
- Batch style updates
- Use reactive statements efficiently
Simplification Principles
1. Remove Duplication
Extract common patterns into shared logic.
Pattern:
- Find repeated code blocks
- Extract to manager or utility
- Components call shared logic
2. Reduce Nesting
Flatten conditional logic and state checks.
Pattern:
- Early returns
- Guard clauses
- Extract complex conditions to named methods
3. Single Responsibility
Each class/function does one thing well.
Pattern:
- Manager: Owns timing/state
- Component: Declares needs, handles callbacks
- Target: Holds state and configuration
4. Clear Abstractions
Names and structure reveal intent.
Pattern:
- Enum values are self-documenting
- Method names describe what, not how
- Properties clearly indicate purpose
5. Eliminate Workarounds
Replace hacks with proper solutions.
Pattern:
- Identify workarounds (e.g.,
s_mouse_forNamefor state persistence) - Design proper solution (state on target)
- Migrate away from workaround
Migration Strategy
Incremental Migration
Migrate one component/feature at a time.
Benefits:
- Lower risk
- Easier to test
- Can rollback individual changes
Backward Compatibility
Support both old and new patterns during transition.
Pattern:
- Add new properties alongside old
- Manager supports both
- Remove old after migration complete
Testing Strategy
Test each migrated component thoroughly.
Focus:
- Normal operation
- Edge cases (re-renders, rapid interactions)
- Regression (existing behavior preserved)
Example: Mouse Timing Centralization
Before: Distributed Timing
Component → Own Timer → Manual Start/Stop → Component State- Each component manages its own timer lifecycle
- State lives in component (lost on re-render)
- Duplicated logic across components
- Manual hover-leave handling per component
After: Centralized Timing
Component → Declares Intent → Central Manager → Automatic Lifecycle- Single manager owns all timers
- State persists on shared target (survives re-render)
- Logic centralized in one place
- Automatic hover-leave cleanup
Key Abstractions
- Timing Types: Autorepeat, long-click, double-click
- State Transitions: Down → Timer → Callback → Up
- Configuration: Enum-based (
T_Mouse_Detection) - Lifecycle: Automatic start/stop/cancel
Migration Pattern
- Remove component timer
- Declare on target (
mouse_detection,*_callback) - Remove manual lifecycle code
- Test thoroughly
Applying to Layout Algorithms
Analysis Questions
- What is scattered? - Layout logic in multiple places?
- What is the manager? - Should there be a
Layoutmanager? - What is the state? - Positions, sizes, constraints?
- What is the lifecycle? - When to compute? When to update?
Design Questions
- What do components declare? - Size constraints? Position preferences?
- How does manager compute? - Single pass? Incremental? Cached?
- What triggers updates? - Size changes? Content changes? User actions?
- How to optimize? - Spatial index? Dirty tracking? Batch updates?
Simplification Opportunities
- Remove duplication - Common layout patterns?
- Reduce complexity - Nested calculations? Circular dependencies?
- Clear abstractions - What are the core concepts?
- Eliminate workarounds - Hacks for edge cases?
Performance Opportunities
- Batch operations - Compute all layouts together?
- Lazy evaluation - Only compute visible/needed?
- Incremental updates - Only update what changed?
- Efficient structures - Spatial index for layout queries?
- Minimize re-renders - Cache layout results?