Files
myep/docs/service-simplification-plan.md
T

6.3 KiB

Service Simplification Plan

Status: draft Last updated: 2026-04-05

Purpose

This document tracks the next pass of service simplification work. The goal is to reduce orchestration density, make the booking flow easier to follow for a human reader, and keep responsibilities aligned with the actual boundaries in the code.

The emphasis is not on deleting services for its own sake. The emphasis is on:

  • keeping one clear owner for each meaningful boundary
  • removing thin wrappers and pass-through helpers
  • avoiding services that mostly shuffle data between layers
  • keeping presentation concerns out of calculation and orchestration code

Current Read

The codebase is already in a better place than it was at the start of the refactor, but a few services still carry more than one responsibility:

  • BookingService no longer owns session lifecycle, baseline snapshot handling, return URL management, or room grouping. That work now lives in BookingSessionService and BookingRoomSelectionService, which keeps the booking orchestration boundary narrower.
  • BookingService still covers hydration, booking bootstrap, service preselection, and booking status rules.
  • BookingParticipantCountService now handles only participant count shaping.
  • ParticipantPrepopulationService now owns applicant prefill plus the create-mode dummy-data shortcut.
  • BookingPriceCalculatorService is focused on pricing, but it still sits close to display-oriented behavior in adjacent code paths.
  • TravelDataService remains broad and is likely the next larger boundary after booking orchestration is reduced.

One registry stands out as a real orchestration boundary and should be left alone for now:

  • ParticipantFieldHandlerRegistry

It is not just a lookup table. It owns execution order, edit-mode mutability gating, and synchronization of submitted form data back into the DTO state.

Next Pass

1. Reduce BookingService

Primary goal: make the booking create/edit flow easier to read by splitting unrelated concerns.

Concrete next steps:

  • keep booking session lifecycle in one place
  • extract baseline room snapshot handling into a narrower helper or dedicated service
  • separate return URL handling if it stays conceptually unrelated
  • keep startFreshBooking() focused on booking bootstrap rather than general session utilities
  • keep hydration behavior obvious and local to the booking session path

Decision rule:

  • if a method only forwards to DTO/session behavior, prefer removing the wrapper
  • if a method is a genuine workflow owner, keep it and narrow the surrounding API instead of splitting it into generic helpers

2. Keep pricing calculation focused

Primary goal: keep pricing code about pricing, not rendering.

Concrete next steps:

  • keep BookingPriceCalculatorService as the pricing boundary
  • continue removing display formatting from pricing code paths
  • keep any remaining view-specific formatting in the presentation layer or a dedicated UI helper
  • avoid introducing another service that only formats values already known to the view

Decision rule:

  • if a value is only needed for display, prefer exposing the raw numeric/domain value and formatting it as close to the UI as possible

3. Leave the field-handler registry in place

Primary goal: avoid unnecessary churn in a class that is already a meaningful orchestration layer.

Concrete next steps:

  • do not refactor ParticipantFieldHandlerRegistry in this pass
  • revisit only if a later change can split ordering, mutability, and synchronization into clear collaborators without making the flow harder to trace

Decision rule:

  • if a registry owns actual workflow behavior, treat it as a boundary rather than a smell

Follow-Up Queue

After the booking service pass, the next likely candidates are:

TravelDataService

This is the largest broad service still in the codebase. It likely needs a later pass if the application should become easier to follow end to end.

Likely directions:

  • separate runtime travel loading from cache/snapshot maintenance if the public API still feels too wide
  • keep the read path explicit and avoid hiding maintenance work behind one large method surface

BookingPriceCalculatorService

This service should stay focused on pricing logic, but it may still have room for further internal cleanup if more display or transport aggregation concerns surface.

Likely directions:

  • keep calculation responsibilities together
  • avoid dragging presentation behavior back into the calculator
  • split only if a sub-boundary becomes obvious and reusable

ParticipantFieldHandlerRegistry

This stays on the list only as a future optional refactor, not as an immediate target.

Likely directions, only if justified later:

  • isolate ordering/sorting logic if it becomes independently meaningful
  • split synchronization code if a clearer DTO/form boundary emerges
  • otherwise leave it as the central orchestration point for participant field processing

Progress Tracker

Item Status Notes
Participant card DTO cleanup Done Card data now uses typed DTOs instead of nested array payloads
Room label formatting cleanup Done Pricing labels now have a dedicated presentation helper
Booking service split In progress Session lifecycle, baseline snapshot, return URL handling, room grouping, and participant count shaping moved out of BookingService; dummy prefill moved into ParticipantPrepopulationService
Pricing service review Pending Keep focused on calculation, not rendering
Travel data service review Pending Broad boundary, likely later pass
Participant field registry review Deferred Real orchestration boundary, intentionally left alone for now

Acceptance Criteria

The next booking-service pass is only worth keeping if it:

  • reduces the number of unrelated responsibilities in BookingService
  • makes the booking flow easier to trace from controller to session/DTO state
  • preserves existing booking behavior and test coverage
  • does not replace one large service with several generic “manager” classes

Working Agreement

  • Update this document as decisions are made.
  • Record rejected simplification ideas here with a short reason.
  • Keep the plan aligned with actual code, not with an abstract architecture ideal.
  • If a future simplification does not clearly reduce cognitive load, do not add it.