Safe Refactoring Guidelines
This document provides guidelines for safely modifying runtime components, preserving game performance, and preventing breaking changes during code evolution.
Overview
Refactoring Screeps AI code carries unique risks because bugs can cause game progress loss or resource waste. These guidelines help minimize risk while improving code quality.
Refactoring Principles
The Safety Triangle
All refactoring must balance three concerns:
- Correctness: Does the code still work as intended?
- Performance: Is CPU and memory usage preserved or improved?
- Maintainability: Is the code easier to understand and modify?
Golden Rule: Never sacrifice correctness for performance or maintainability.
Risk Assessment Framework
Risk Levels
Low Risk (Safe to refactor freely):
- Code formatting and style changes
- Adding comments or documentation
- Renaming private variables
- Extracting pure utility functions
- Updating types without behavior changes
Medium Risk (Requires careful testing):
- Changing function signatures
- Modifying task state machines
- Updating memory schemas
- Changing pathfinding parameters
- Adjusting thresholds and constants
High Risk (Requires extensive validation):
- Rewriting core algorithms
- Changing spawn logic
- Modifying kernel orchestration
- Altering evaluation criteria
- Changing respawn detection
Risk Mitigation Checklist
Before refactoring:
- Identify risk level
- Document current behavior
- Create regression test
- Measure baseline performance
- Plan rollback strategy
Safe Refactoring Patterns
Pattern 1: Extract Function
Safe When:
- Logic is pure (no side effects)
- No shared state dependencies
- Function is self-contained
Example:
1 | // Before |
Validation:
- Unit test extracted function
- Verify behavior unchanged
- Check CPU impact is neutral
Pattern 2: Rename for Clarity
Safe When:
- Name change improves understanding
- Only internal usage (not exported)
- IDE refactoring tool used
Example:
1 | // Before |
Validation:
- Ensure all references updated
- Run full test suite
- Check TypeScript compilation
Pattern 3: Introduce Constant
Safe When:
- Magic numbers used multiple times
- Value may need tuning
- Improves readability
Example:
1 | // Before |
Validation:
- Verify constant value correct
- Test all usage locations
- Document constant purpose
Pattern 4: Simplify Conditional
Safe When:
- Logic is equivalent
- Edge cases preserved
- Readability improved
Example:
1 | // Before |
Validation:
- Test all branches
- Verify edge cases
- Benchmark performance
Dangerous Refactoring Patterns (Avoid)
Anti-Pattern 1: Premature Optimization
Problem: Optimizing before measuring
Example:
1 | // Don't do this without profiling first! |
Solution: Profile first, optimize second
Anti-Pattern 2: Breaking API Contracts
Problem: Changing exported interfaces
Example:
1 | // Before |
Solution: Deprecate old interface, add new version
Anti-Pattern 3: Removing Error Handling
Problem: Simplifying by removing safety
Example:
1 | // Before |
Solution: Keep error handling even when “shouldn’t happen”
Anti-Pattern 4: Untested Behavior Changes
Problem: Changing logic without tests
Example:
1 | // Before |
Solution: Write test, change code, verify test
Component-Specific Guidelines
BehaviorController Refactoring
Critical Invariants:
- Minimum role populations maintained
- Task state machines remain valid
- Spawn logic doesn’t break
- Memory initialization preserved
Safe Changes:
- Pathfinding parameters (
reusePath,range) - Task transition logic (if tested)
- Target selection algorithms (if CPU-neutral)
Risky Changes:
- Role definitions (body, minimum count)
- State machine structure
- Spawn priority ordering
Testing Requirements:
- Unit tests for role logic
- Integration tests for spawn logic
- Regression tests for task switching
MemoryManager Refactoring
Critical Invariants:
- Dead creeps always pruned
- Role counts always accurate
- Memory size doesn’t grow unbounded
Safe Changes:
- Logging improvements
- Performance optimizations (if measured)
- Additional bookkeeping (if bounded)
Risky Changes:
- Pruning algorithm
- Role counting logic
- Memory schema modifications
Testing Requirements:
- Test pruning with various creep states
- Verify role counts with edge cases
- Check memory growth over time
Kernel Refactoring
Critical Invariants:
- Components execute in correct order
- Performance tracking accurate
- Respawn detection works
- Evaluation persists correctly
Safe Changes:
- Component initialization
- Logging improvements
- Configuration options
Risky Changes:
- Execution order
- Component wiring
- Error handling flow
Testing Requirements:
- End-to-end integration tests
- Multi-tick simulation tests
- Respawn scenario tests
Memory Schema Migrations
Safe Migration Pattern
Step 1: Add New Field (Non-Breaking)
1 | // Version 1: Original |
Step 2: Populate New Field
1 | // Initialize for new creeps |
Step 3: Remove Old Field (Breaking)
1 | // Only after all creeps migrated |
Version Migration Strategy
Use Role Versions:
1 | const HARVESTER_VERSION = 2; // Increment when schema changes |
Benefits:
- Automatic migration
- No manual intervention
- Gradual rollout as old creeps die
Performance-Safe Refactoring
CPU Budget Preservation
Before Refactoring:
1 | // Measure baseline |
After Refactoring:
1 | // Measure new implementation |
Memory Size Preservation
Before Refactoring:
1 | const memoryBefore = JSON.stringify(Memory).length; |
After Refactoring:
1 | const memoryAfter = JSON.stringify(Memory).length; |
Rollback Procedures
Level 1: Quick Rollback (Same Session)
In Console:
1 | // Revert to previous code |
Limitations: Only works if previous code still in cache
Level 2: Git Rollback (Requires Deploy)
Local:
1 | git revert HEAD |
Wait: ~10-30 seconds for deployment
Level 3: Emergency Rollback (Manual)
When: Catastrophic failure, immediate action needed
Steps:
- Stop all creeps:
for (const name in Game.creeps) Game.creeps[name].suicide() - Redeploy last known good version
- Wait for respawn or rebuild
Refactoring Checklist
Pre-Refactoring
- Understand current behavior completely
- Identify all usage locations
- Create regression tests
- Measure baseline performance
- Document intended changes
- Plan rollback strategy
During Refactoring
- Make minimal changes
- Preserve existing tests
- Update documentation
- Add new tests for changes
- Run tests frequently
- Check TypeScript compilation
Post-Refactoring
- All tests pass
- Coverage maintained or improved
- Performance neutral or better
- Documentation updated
- Code review completed
- Deployed to test environment
Post-Deployment
- Monitor CPU usage (first 1000 ticks)
- Watch for error logs
- Verify behavior matches expectations
- Check memory growth
- Validate metrics vs baseline
- Rollback if regressions detected
Common Refactoring Scenarios
Scenario 1: Optimizing Pathfinding
Goal: Reduce CPU by caching paths longer
Risk: High (can cause stuck creeps)
Safe Approach:
- Test in private server first
- Increase
reusePathincrementally (5 → 7 → 10) - Monitor for stuck creeps
- Rollback if issues detected
Validation:
- Creeps reach destinations
- CPU decreases measurably
- No idle time increase
Scenario 2: Adding New Role
Goal: Introduce builder role
Risk: Medium (spawn logic changes)
Safe Approach:
- Define role with minimum: 0 initially
- Test role logic in isolation
- Increase minimum after validation
- Monitor energy balance
Validation:
- New role spawns correctly
- Existing roles unaffected
- CPU budget accommodates new role
Scenario 3: Changing Task Logic
Goal: Improve harvester delivery efficiency
Risk: High (core behavior change)
Safe Approach:
- Document current behavior
- Create comprehensive tests
- Implement change with feature flag
- A/B test in private server
- Gradually enable in production
Validation:
- Energy flow maintained or improved
- No delivery target starvation
- Task transitions remain valid
Code Review Guidelines
Reviewer Checklist
Correctness:
- Logic changes preserve behavior
- Edge cases handled
- Error handling adequate
Performance:
- CPU impact measured
- Memory usage checked
- No obvious performance regressions
Testing:
- Tests updated or added
- Coverage maintained
- Tests verify key behaviors
Documentation:
- Comments explain why, not what
- Public APIs documented
- Breaking changes noted
Related Documentation
- Strategy Testing - Testing methodologies
- Improvement Metrics - Measuring effectiveness
- Creep Roles - Expected behaviors to preserve
- Memory Management - Memory safety guidelines
- Performance Monitoring - CPU tracking