[ENHANCEMENT] Refactor imperative shell business logic to functional core with Effect.ts
✨ [ENHANCEMENT] Refactor imperative shell business logic to functional core with Effect.ts
🎯 Enhancement Overview
Refactor pure business logic currently residing in the imperative shell to the functional core, following Effect.ts patterns and functional programming principles. This enhancement will improve testability, maintainability, and architectural consistency.
🤔 Problem Statement
The imperative shell currently contains significant pure business logic that violates architectural boundaries. Specifically:
-
http-monitoring-functional.ts
has pure functions mixed with imperative code - Authentication logic in
http-server.ts
could be pure functions - Timing and health check calculations are embedded in I/O operations
- Global mutable state is used instead of Effect Services
🔧 Technical Requirements
src/imperative-shell/http-monitoring-functional.ts
)
High Priority: HTTP Monitoring Module (Current Issues:
- Lines 60-113: Pure functions (
generateRequestId
,extractClientIp
,updateMetricsWithRequest
) in imperative shell - Lines 46-54, 133-182: Global mutable state using
let
andMap
- Lines 249-274: Pure metrics calculations mixed with imperative data access
Refactoring Targets:
- Create
src/functional-core/http/monitoring-service.ts
- Service interface with Effect - Create
src/functional-core/http/metrics-calculator.ts
- Pure metrics calculations - Create
src/functional-core/http/monitoring-service-live.ts
- Service implementation
src/imperative-shell/http-server.ts
)
Medium Priority: Authentication Logic (Current Issues:
- Lines 220-317: Authentication logic that could be pure functions
- Token validation and bearer token parsing mixed with I/O
Refactoring Targets:
- Create
src/functional-core/auth/authentication-service.ts
- Move
validateBearerToken()
as pure function - Create tagged union
AuthResult
type for auth outcomes
src/imperative-shell/health-check.ts
)
Medium Priority: Timing and Health (Current Issues:
- Lines 181-191: Timing logic using imperative approach
- Lines 63-76: Server metadata creation mixed with I/O
Refactoring Targets:
- Create
src/functional-core/utils/timing-service.ts
- Use Effect Clock for pure timing measurements
- Move health metrics calculations to functional core
🏗️ Architecture Analysis
Service Design Pattern
// Example: Monitoring Service Interface
export interface HttpMonitoringService {
readonly startRequest: (requestInfo: RequestInfo) => Effect.Effect<string, never, never>;
readonly completeRequest: (requestId: string, statusCode: number) => Effect.Effect<void, never, never>;
readonly getMetrics: Effect.Effect<HttpMetrics, never, never>;
readonly getHealthMetrics: Effect.Effect<HttpHealthMetrics, never, never>;
}
State Management Transformation
- Current: Global mutable Maps and variables
- Target: Effect Ref with immutable data structures
- Benefits: Referential transparency, easier testing, no race conditions
Error Handling Pattern
// Tagged union for authentication results
export type AuthResult =
| { readonly _tag: 'Success'; readonly token: string }
| { readonly _tag: 'MissingToken' }
| { readonly _tag: 'InvalidToken'; readonly received: string }
| { readonly _tag: 'MissingEnvToken' };
✅ Acceptance Criteria
Phase 1: HTTP Monitoring Refactor
-
All pure functions moved from http-monitoring-functional.ts
to functional core -
Monitoring Service created with Effect Services pattern -
Global mutable state replaced with Effect Ref -
All metrics calculations are pure functions -
Imperative shell only handles MCP protocol interaction -
Tests written for all pure functions (≥80% coverage) -
ESLint boundary rules pass (no functional-core → imperative-shell imports)
Phase 2: Authentication Refactor
-
Authentication validation is pure function in functional core -
Bearer token parsing moved to functional core -
AuthResult tagged union implemented -
Error responses created through pure functions -
Authentication service properly injected via Effect
Phase 3: Timing and Health Refactor
-
Timing measurements use Effect Clock primitives -
Health metrics calculations are pure functions -
Server metadata creation is pure -
Response time calculations use functional approach -
All timing logic removed from imperative shell
Code Quality Requirements
-
No ESLint errors or warnings -
TypeScript strict mode passes -
All Effect patterns properly implemented -
No class usage in functional core -
No mutations in functional core -
No void returns in functional core
🧪 Testing Strategy
Unit Tests (Functional Core)
// Pure function tests
test('updateMetricsWithRequest correctly updates metrics', async () => {
const initial = createInitialMetrics();
const updated = updateMetricsWithRequest(initial, 'GET', 200, 100);
expect(updated.requests.total).toBe(1);
expect(updated.performance.averageResponseTime).toBe(100);
});
// Service tests with mocked layers
test('HttpMonitoringService tracks requests', async () => {
const service = await Effect.runPromise(
HttpMonitoringServiceLive.pipe(Effect.provide(testLayer))
);
const requestId = await Effect.runPromise(service.startRequest(mockRequest));
expect(requestId).toMatch(/^req_/);
});
Integration Tests
- Test imperative shell correctly uses functional services
- Verify MCP protocol compliance
- Ensure proper error handling across boundaries
📊 Success Metrics
- Test Coverage: ≥80% for functional core modules
- Performance: No regression in response times
- Build Time: ESLint and TypeScript checks complete in <30s
- Code Quality: Zero ESLint violations
- Architecture: Clear separation between layers
📋 Implementation Phases
Week 1: HTTP Monitoring Service
- Create monitoring schemas in
functional-core/schemas.ts
- Implement pure metrics calculation functions
- Create Effect Service for HTTP monitoring
- Update imperative shell to use functional service
- Write comprehensive tests
Week 2: Authentication Service
- Create authentication service interface
- Move token validation logic
- Update HTTP server to use functional auth
- Add error handling with Effect channels
Week 3: Timing and Final Cleanup
- Create timing service with Effect Clock
- Refactor health check timing
- Move server metadata logic
- Clean up imperative wrappers
- Final testing and documentation
🔗 Dependencies
- Effect.ts for functional programming patterns
- No new external dependencies required
- Existing MCP SDK continues to work as-is
📚 References
- Effect.ts Documentation
- Functional Core, Imperative Shell Pattern
- Current codebase analysis from context-engineer and functional-programming-purist agents
- ESLint functional programming rules configuration
🎯 Definition of Done
- All acceptance criteria met
- Code review completed and approved
- CI/CD pipeline passes (lint, typecheck, tests)
- No performance regression
- Documentation updated if needed
- Architectural boundaries enforced by ESLint