ADR: Refactor Core Class Static State Management¶
Status¶
Implemented (Date: 2025-06-26)
Pull Request: #1463
Context¶
Our current Core class implementation uses static fields to store application state, which has created significant challenges for testing and maintainability over the past three years. The development team has experienced a 3:1 ratio of test code to feature code, with much of this overhead attributed to difficulties working with the static state architecture.
Current Problems¶
Test Isolation Issues: Tests interfere with each other due to shared static state
Difficult Test Setup: Creating isolated test scenarios requires complex workarounds
Mocking Limitations: Static dependencies make it nearly impossible to inject test doubles
Maintenance Overhead: High ratio of test maintenance code to actual feature development
Technical Debt Impact¶
The static state pattern has resulted in:
Brittle test suites where test order affects outcomes
Increased development time for writing reliable tests
Reduced confidence in test results due to intermittent failures
Difficulty in implementing proper unit testing practices
Decision¶
We will refactor the Core class to use dependency injection and extract state management into a separate CoreState class.
Proposed Architecture¶
Current: Core (static fields + logic)
Proposed: Core (logic) → CoreState (state management)
Implementation Strategy¶
Create CoreState Class: Extract all static state into a dedicated state management class
Implement Singleton Pattern: Ensure single instance behavior is maintained for production use
Add Dependency Injection: Allow Core to accept CoreState instance via constructor or setter
Maintain API Compatibility: Preserve existing public interface to avoid breaking changes
Gradual Migration: Implement changes incrementally to minimize risk
Consequences¶
Positive (Achieved)¶
Improved Testability: TestCoreState enables isolated testing with custom state configurations
Better Thread Safety: Synchronized blocks and proper SaveThread lifecycle management prevent race conditions
Enhanced Maintainability: Clear separation between state management and business logic
Test Infrastructure: Dedicated testing utilities reduce test complexity and improve reliability
Future Flexibility: CoreState architecture enables easier feature development and testing
Additional Benefits Delivered¶
Auto-save Reliability: Improved thread lifecycle management reduces potential memory leaks
Code Quality: Cleaner deprecation handling with explicit removal indicators
Developer Experience: Easier test writing with customizable state handling
Implementation Considerations¶
Learning Curve: Team successfully adapted to new CoreState pattern
Code Review: Comprehensive review completed through PR process
Backward Compatibility: Maintained while improving internal architecture
Implementation Results¶
The refactoring has been successfully implemented with the following changes:
Core Refactoring Delivered¶
CoreState Class: Successfully extracted state management (IProject, IMainWindow, IEditor) from Core class
State Centralization: All static state now managed through centralized CoreState instance
API Compatibility: Maintained backward compatibility while improving internal architecture
Additional Improvements Implemented¶
Auto-save Enhancement: Improved SaveThread with proper lifecycle management through
fin()methodThread Safety: Added synchronized blocks and better thread management to prevent race conditions
Test Infrastructure: Created TestCoreState class for customizable state handling in unit tests
Deprecation Cleanup: Updated deprecated methods with
forRemoval = truefor clearer migration path
Testing Benefits Realized¶
Test Isolation: Unit tests can now use TestCoreState for isolated testing scenarios
Improved Reliability: Better thread lifecycle management reduces test flakiness
Maintainability: Cleaner separation of concerns between state and business logic
Alternatives Considered¶
Alternative 1: Keep Current Architecture¶
Pros: No development effort required
Cons: Continues current testing problems, technical debt accumulates
Alternative 2: Complete Rewrite¶
Pros: Clean slate approach
Cons: High risk, significant development time, potential for introducing bugs
Alternative 3: Partial Static Cleanup¶
Pros: Lower effort than full refactor
Cons: Only addresses some issues, doesn’t solve core testing problems
Decision Makers¶
Proposed by: Hiroshi Miura
Review Required: Development Team
Success Metrics - Results¶
Testing Improvements¶
Test Isolation: ✅ Achieved through TestCoreState implementation
Test Reliability: ✅ Improved with better thread safety and lifecycle management
Test Infrastructure: ✅ Dedicated testing utilities implemented
Maintainability: ✅ Cleaner state management architecture delivered
Technical Improvements¶
Thread Safety: ✅ Enhanced with synchronized blocks and proper SaveThread management
Code Quality: ✅ Improved with cleaner deprecation handling
Architecture: ✅ Successfully separated state management from business logic
Next Steps¶
Monitor test suite performance and reliability improvements
Gather developer feedback on new testing patterns
Document best practices for using TestCoreState in future tests
Consider extending CoreState pattern to other components if beneficial
References¶
Relevant Mail Thread: SourceForge Mailing List Discussion
“Head First Design Patterns” - Singleton and Dependency Injection patterns
“Working Effectively with Legacy Code” by Michael Feathers - Techniques for making legacy code testable
Team testing pain points documented over 3-year period
This ADR documents the completed implementation of Core class refactoring. The solution successfully addresses the original testing and maintainability concerns while providing additional improvements in thread safety and code quality.