Refactors sobre tu TicketFlow. Cada uno con tests que lo respaldan (la 28 formaliza el método). No mires solutions.md hasta entregar.
Ejercicio 1 — La vista gorda, operada
- Toma tu vista de reserva (o la más larga que tengas) y lista cada línea con su capa: HTTP (parse/status), dominio (reglas/transacciones), persistencia (ORM directo).
- Extrae
services/reservations.py::reservar()con la firmareservar(user, event_uuid, seat_refs, *, clock, gateway) -> Reservation. La vista queda: serializer + llamada + respuesta. Mide: ¿cuántas líneas tiene la vista ahora? - Verifica la prueba del algodón: llámala desde
manage.py shellsin request. ¿Funcionó?
Ejercicio 2 — Clock inyectado
- Crea el
ClockProtocol +SystemClock+FakeClock(fixed=...)y úsalo enreservar()(el default de producción intacto). - Escribe el test "una reserva con FakeClock a las 23:59 expira a las 00:09" sin sleeps ni freezegun: solo el fake.
- Bonus: el job de expiración (cuando llegue la 29) consumirá el mismo Clock — anota cómo le ayuda.
Ejercicio 3 — L de Liskov con pasarelas
- Define el Protocol
PaymentGateway.charge(amount, intent) -> ChargeResult. ImplementaFakeGateway(aprueba si el importe < 1000) ySimulatedGateway(para producción-staging). - Rompe a propósito: una implementación que devuelve
Noneen error en vez de lanzar. Escribe el test que la caza (¿qué assertion falló?). - Documenta el contrato exacto: qué devuelve, qué lanza, qué garantiza de idempotencia (14). ¿Tu docstring basta o hace falta type strict?
Ejercicio 4 — O con registro de métodos
- Implementa
PAYMENT_METHODS: dict[str, type[PaymentMethod]]con registro@register("gift_card"). Añade "cash_on_delivery" (simulado) SIN tocar el servicio de pagos: solo un nuevo módulo + registro. - ¿Qué pasa en tu código viejo si mañana añaden "crypto"? ¿Cuántas líneas cambian? (respuesta esperada: 1 archivo nuevo).
Ejercicio 5 — I en el acceso a datos
- Separa
AvailabilityReader(lo que usa el endpoint público) deReservationWriter(lo que usa el checkout). ¿Qué métodos sobraban en la interfaz única que imaginaste primero? - El
utils.py(si lo tienes): reorganicéalo por dominio (utils/time.py,utils/money.py...) o confiesa que aún no lo tienes y escribe cómo lo evitarías.
Entrega
Pega el before/after de la vista, los tests con FakeClock y el registro de métodos. Después: Lección 25 — Patrones de servicio.