Mercury Trading System - Comprehensive Refactoring Plan
Our Mercury trading system has grown organically over time, leading to intertwined services, duplicated code, and complex state management. This document outlines a strategic approach to refactoring key components to improve maintainability, testability, and performance.
Current Issuesβ
After analyzing PositionService, OrderService, ShadowOrderService, ShadowAccountService, and their related entities, we've identified several architectural and design issues:
- Tightly Coupled Services: Services have excessive dependencies, making changes risky
- Mixed Responsibilities: Business logic mixed with job scheduling, metrics, and notifications
- Inconsistent Data Management: Parallel transaction systems and redundant storage
- Scattered Logic: Core calculations (like PnL) repeated across multiple services
- Complex State Management: Position and order states managed across multiple services
- Verbose Error Handling: Boilerplate logging obscuring core business logic
Refactoring Strategy: Domain-Driven Designβ
We'll apply Domain-Driven Design principles to reorganize our codebase around clear domain boundaries.
Phase 1: Domain Modeling & Boundary Definitionβ
-
Identify Core Domains
- Position Management
- Order Execution
- Account Management
- Transaction Processing
- Portfolio Analytics
-
Define Domain Models
- Create clear models with well-defined relationships
- Eliminate redundant fields and duplicated data
- Standardize entity patterns
-
Establish Bounded Contexts
- Define clear service boundaries
- Document integration points between domains
- Create context maps to visualize relationships
Phase 2: Command-Query Responsibility Segregationβ
-
Define Command Services
- Create specialized write-focused services:
PositionCommandService: Position creation/updatesOrderCommandService: Order executionAccountCommandService: Balance management
- Create specialized write-focused services:
-
Define Query Services
- Create read-optimized services:
PositionQueryService: Position details/filteringOrderQueryService: Order history/filteringAccountQueryService: Performance metrics/history
- Create read-optimized services:
-
Implementation Plan
- Start with one domain (e.g., positions)
- Extract query-related methods to a new service
- Refactor command methods to remove query dependencies
- Update controllers/consumers to use appropriate service
Phase 3: Domain Service Extractionβ
-
Transaction Service Consolidation
- Create
TransactionServiceto encapsulate all transaction operations - Replace embedded transaction arrays with proper relationships
- Standardize transaction creation across all services
- Create
-
PnL Calculator Extraction
- Create dedicated
PnLCalculatorServicefor all profit/loss calculations - Extract
calculatePnL,calculateCombinedPnL,calculateFinalPnLmethods - Provide consistent methods for realized/unrealized PnL calculation
- Add comprehensive unit tests for calculator logic
- Create dedicated
-
Implementation Plan
- Extract helper methods to new services
- Use dependency injection to provide these services
- Update existing services to use the extracted functionality
- Write tests to validate calculation consistency
Phase 4: Event-Driven Architectureβ
-
Define Domain Events
- Create event types for key state changes:
PositionCreatedEventOrderStatusChangedEventAccountBalanceChangedEventTakeProfitHitEventStopLossHitEvent
- Create event types for key state changes:
-
Implement Event Publisher
- Create
DomainEventPublisherfor event distribution - Use Bull queues for event propagation
- Add retry/error handling for event processing
- Create
-
Update Services to Use Events
- Refactor services to emit events on state changes
- Replace direct service calls with event subscribers
- Decouple position updates from order processing
-
Implementation Plan
- Start with defining key events
- Create event publisher infrastructure
- Gradually replace direct service calls with events
- Test event sequencing and error handling
Phase 5: Job Scheduling Separationβ
-
Create Dedicated Scheduler Services
PositionSchedulerService: Position creation/update schedulingOrderSchedulerService: Order execution schedulingAnalyticsSchedulerService: Metrics calculation scheduling
-
Extract Queue Logic
- Move queue-related code from business services
- Standardize job parameters and retry logic
- Improve job naming and tracking
-
Implementation Plan
- Extract scheduling methods to new services
- Define clear job types and parameters
- Update modules to use scheduler services
- Add job validation and monitoring
Phase 6: Entity Relationship Redesignβ
-
Simplify Position and Order Relationship
- Clarify ownership and lifecycle dependencies
- Standardize relationship cardinality
- Improve deletion/orphaning behavior
-
Standardize Entity Design
- Apply consistent patterns for default values
- Standardize nullability across similar fields
- Document validation rules in schema
-
Implementation Plan
- Model new entity relationships
- Create migration plan for existing data
- Update repositories and services
- Verify referential integrity
Implementation Approachβ
Step 1: Create Baseline Testsβ
Before making significant changes, we need comprehensive tests:
-
Unit Tests
- Focus on core business logic
- Mock dependencies to isolate functionality
- Test edge cases and error handling
-
Integration Tests
- Test service interactions
- Verify database operations
- Validate event processing
-
End-to-End Tests
- Test complete workflows
- Validate system behavior
- Ensure backward compatibility
Step 2: Incremental Refactoringβ
We'll follow this strategy for each component:
-
Extract Domain Logic
- Identify core business rules
- Move to appropriate domain services
- Test thoroughly
-
Replace Direct Dependencies
- Inject services through constructor
- Replace tight coupling with events
- Update tests to use mocks
-
Improve Error Handling
- Standardize error patterns
- Add meaningful error contexts
- Improve logging consistency
-
Document Interfaces
- Define clear method contracts
- Document domain events
- Update API documentation
Step 3: Performance Monitoringβ
To ensure our refactoring improves the system:
-
Add Metrics
- Response times for key operations
- Resource usage before/after
- Error rates and performance degradation
-
Benchmark Critical Paths
- Position creation/update flow
- Order execution flow
- Transaction processing
-
Monitor in Staging
- Deploy changes to staging environment
- Compare metrics with production
- Validate performance under load
Prioritized Refactoring Tasksβ
-
Immediate Wins (Week 1-2)
- Remove redundant transaction storage in ShadowAccount
- Extract PnL calculation to dedicated service
- Standardize error handling patterns
-
Medium-Term Changes (Week 3-6)
- Implement command/query separation for positions
- Extract transaction service
- Create event publisher infrastructure
-
Long-Term Restructuring (Week 7-12)
- Complete event-driven architecture
- Redesign entity relationships
- Implement scheduler services
- Add performance monitoring
Progress Update (June 2025)β
We've made significant progress on our refactoring plan, with two major phases now complete:
β Phase 4: Event-Driven Architectureβ
We successfully implemented an event-driven architecture across the Mercury system:
- Domain Events: Defined clear events for positions, orders, and transactions
- Event Publishers: Implemented publisher services for each domain
- Event Listeners: Created listener services that react to events
- Decoupled Services: Replaced direct service calls with event-based communication
This has greatly reduced the tight coupling between services and improved testability. Services now communicate through well-defined events rather than direct method calls.
β Phase 2: Command-Query Responsibility Segregation (CQRS)β
We've implemented CQRS pattern for our core domains:
- Position Query Service: Separated read operations for positions
- Order Query Service: Separated read operations for orders
- Updated Controllers: Controllers now use query services for read operations
This separation improves our ability to optimize read and write operations independently and clarifies the responsibilities of each service.
π In Progress: Phase 5: Job Scheduling Separationβ
Our current focus is on extracting the job scheduling logic from business services:
- Started with identifying scheduling code in position and order services
- Planning dedicated scheduler services for each domain
Next Stepsβ
-
Complete Job Scheduling Separation:
- Create PositionSchedulerService and OrderSchedulerService
- Move queue-related code from business services
-
Move to Phase 6: Entity Relationship Redesign:
- Simplify the relationship between positions and orders
- Standardize entity design patterns across the system
-
Consolidate Transaction Services:
- Complete the implementation of TransactionService
- Remove duplicated transaction code
Conclusionβ
This refactoring plan targets the most critical issues in our Mercury trading system while minimizing risk through incremental changes. By focusing on domain boundaries, separating concerns, and improving code organization, we'll create a more maintainable and extensible system.
The event-driven approach will reduce service coupling, making the system more resilient and easier to test. Standardizing our entity design and consolidating core logic will improve consistency and reduce bugs.
Most importantly, these changes preserve the core functionality of the Mercury trading system while setting the stage for future features and improvements.
