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

123 lines
6.6 KiB
Markdown

# Service Simplification Plan
Status: active
Last updated: 2026-04-13
## 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` now mostly covers booking bootstrap, service preselection, and booking status rules.
- `BookingParticipantCountService` was removed — its logic lives as a private method in the one controller that needed it (`Step2Controller`).
- `BookingRoomSelectionService` was removed — its logic lives as a private method in `BookingCreateContextFactory`.
- `BookingSummaryParticipantCountService` was removed — its logic lives as a private method in `BookingSummaryDataService`.
- `ParticipantPrepopulationService` now owns applicant prefill plus the create-mode dummy-data shortcut.
- `BookingEditParticipantContextFactory` now prepares the edit participant page context directly, replacing the older pass-through participant form service.
- `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. 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
### 2. 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
## Current Notes
- `templates/booking/_summary_travel_info.html.twig` already renders the summary participant count directly, so the remaining work here is naming and contract clarity rather than Twig branching.
- The summary count still needs a clear name if the code should distinguish the display-oriented count from the canonical participant total in the DTO/service layer.
- `ParticipantFormSupportService` was reviewed and kept: it is shared between two controllers (`Step2ParticipantController` and `Edit/ParticipantController`) with real shared logic, not just delegation.
## 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 | Done | Session lifecycle, hydration, baseline snapshot, return URL handling, room grouping, and participant count shaping moved out of `BookingService` |
| Dummy prefill extraction | Done | Moved into `ParticipantPrepopulationService` |
| Micro-service consolidation | Done | `BookingRoomSelectionService`, `BookingParticipantCountService`, `BookingSummaryParticipantCountService` inlined into their single callers |
| 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.