Approach: split the monolith into small, single‑responsibility modules with well‑defined interfaces and explicit error/retry semantics. Keep pure logic testable and side effects isolated behind adapters.Proposed components & interfaces:- Parser (pure): string -> DTO | throws ParseErrorjavascript
// parse.js
function parseInput(raw) { /* returns {customerId,...} or throws ParseError */ }
- Validator (pure): DTO -> ValidatedDTO | throws ValidationErrorjavascript
function validate(dto) { /* business rules, returns sanitized dto */ }
- Enricher (side-effect adapter): ValidatedDTO, ctx -> Promise<EnrichedDTO> - Uses external services; returns transient errors for retry; idempotent enrichment- Pricer (pure): EnrichedDTO -> PriceResultjavascript
function calculatePrice(enriched) { /* deterministic, unit-testable */ }
- DiscountApplier (pure): PriceResult, rules -> PriceResult- Repository (side-effect adapter): EnrichedDTO, PriceResult -> Promise<PersistResult> - Exposes retries, idempotency key support, and transactional semanticsOrchestrator (thin): composes above modules, maps errors to domain-level responses and handles retries only for specific adapters.Error propagation:- Use typed errors (ParseError, ValidationError, TransientError, PermanentError).- Pure modules throw synchronous typed errors; side-effect adapters return rejected Promises with typed errors.- Orchestrator: - On Validation/Parse -> return 4xx client response, no retry. - On Enricher/Repo TransientError -> retry with exponential backoff and jitter, max attempts configurable; surface failure after retries. - On PermanentError -> fail fast, log context.Retry semantics and idempotency:- Retries limited to side-effect adapters; pure functions not retried.- Repository accepts idempotencyKey to avoid double writes; use optimistic locking or upsert.- Enricher calls to flaky third‑party: wrap with retry policy + circuit breaker to avoid cascading failures.Testing strategy:- Unit tests for pure modules (parser, validator, pricer, discount) covering edge cases.- Adapter contracts mocked in orchestrator tests to assert retry and error mapping.- Integration tests with a test DB and stubbed external services verifying idempotency and transactional behavior.Operational notes:- Add structured logging with correlation ID; metrics (retry counts, error rates).- Configuration: make retry/backoff/circuit-breaker thresholds configurable per environment.