In lesson 2.14.1, the Kladde’s booking endpoint was at the top of the refactoring list: 68 lines in one method, nine parameters, a cyclomatic complexity of 12, and a version of its own of the rule for when the office accepts bookings. In this lesson you rebuild it. At the end, a unit test checks the booking in a few milliseconds, without a database and without a web server, and management gets its Saturday mornings with a single change.
What “one responsibility” means
The S in SOLID stands for the single-responsibility principle: a class has one responsibility. That sounds like “a class does one thing”, and understood that way it’s misleading. Even a method with five lines does, strictly speaking, five things.
A more useful question is who asks for a change. A responsibility is a reason to change, and behind every reason stands somebody. Go through the endpoint from lesson 2.14.1 like this:
| Part of the endpoint | Who asks for a change? | Example |
|---|---|---|
// check: opening hours, lead time |
the office | “Saturday mornings too.” |
// book: save, double booking |
the Kladde’s domain | “Two appointments must not overlap.” (already exists in the core) |
// notify: mail, webhook, live display |
customers, partners, the office | “A fourth channel: the activity log.” |
// log |
operations | “The line needs the duration.” |
| Status codes, ProblemDetails, route | whoever calls the API | “A 409 should have a type of its own.” (lesson 2.12.1) |
Five groups of people, five reasons. Every change one of them asks for touches the same method, and each time something can break in the other four places. That’s the pain.
The refactoring separates the parts so that each reason lands in one place:
- The rule already lives in the core:
BookingRulesandFreeSlotsfrom lesson 2.5.6. The endpoint only has to use them instead of rebuilding them. - The use case “book an appointment” becomes a class of its own in the core. It asks the rule, books, and tells whoever needs to know. It knows neither HTTP nor mail.
- The notification gets a port in the core,
IBookingNotifier, and an implementation at the edge that knows the outbox, webhook and hub. - The endpoint keeps HTTP: the request coming in, the use case’s result going out as a status code.