Módulo 5 · Arquitectura y código mantenible

Lección 28 — Refactorizar sin romper nada

Refactor apoyado en pruebas: cambiar el interior sin mover el contrato.

Publicada
En esta lección
  1. Ejercicio 1 — La auditoría de la red
  2. Ejercicio 2 — La extracción guiada
  3. Ejercicio 3 — El bug de pasada (el experimento prohibido)
  4. Ejercicio 4 — Feigning del contrato
  5. Ejercicio 5 — La extracción del job (prep de la 29)
  6. Entrega

Refactor real sobre TicketFlow con red completa. Sin solutions.md hasta entregar.

Ejercicio 1 — La auditoría de la red

  1. Antes de tocar nada: ¿qué cubre tu suite para reservar()? Lista por nivel (unitaria/integración/contrato/E2E) qué prueba existe HOY y qué hueco ves (¿la transacción con lock? ¿el outbox tras commit? ¿el problem+json del 409?).
  2. Escribe los 2 tests de caracterización que faltan para poder refactorizar con red (si crees que no falta ninguno: escribe uno que falle si alguien mueve el outbox antes del commit).

Ejercicio 2 — La extracción guiada

  1. Ejecuta el refactor del servicio de reserva en 4 commits (validar_asientos / cobrar / ReservacionService / deprecación de la función vieja). Suite verde tras cada commit — pega los 4 hashes y el output de git log --oneline.
  2. En cada paso anota: ¿cuántos tests se tocaron? La meta es que los de caracterización NO se toquen en ninguno.
  3. El paso 4 (deprecación): la función vieja delega en el servicio y DeprecationWarning. ¿Quién todavía la llama y por cuánto tiempo muere?

Ejercicio 3 — El bug de pasada (el experimento prohibido)

  1. PROPÓSITO didáctico: hazlo UNA vez para verlo romperse. En el branch del refactor, arregla de pasada el bug del redondeo del total (la 08) y añade un campo nuevo a la respuesta. Ejecuta la suite: ¿cuántos tests rojos? ¿Cuáles de contrato?
  2. Ahora hazlo bien: git revert del commit mezclado, bug en commit separado con test de regresión primero, campo nuevo con su test y nota de versión (14). La suite entera en verde en ambos commits por separado.

Ejercicio 4 — Feigning del contrato

  1. Enumera las 5 no-rompibles de TU front (status, tipos de problem, campos JSON, IDs, mensajes parseados). Escribe el test "contract guard": una batería que falla si cualquiera cambia (puedes reutilizar assert_problem de la 26).
  2. Rompe UNO a propósito (renombra seat_refs → seats en la respuesta): ¿qué test lo caza y en cuántos segundos lo supiste?

Ejercicio 5 — La extracción del job (prep de la 29)

  1. Extrae expirar_reservas(clock) -> list[str] (refs expiradas) al servicio, dejando el management command como puro disparador. Test con FakeClock: 3 reservas, una vencida, dos vigentes → devuelve 1 ref y las marcas EXPIRED con expires_at correcto.
  2. Escribe el test del disparador: el comando llama al servicio una vez y devuelve el conteo. La lógica NO está en el comando — verifica con un mock que si el servicio lanza, el comando propaga.

Entrega

Pega los hashes del refactor, el experimento del bug de pasada (rojo), el contract guard y la extracción del job. Después: Lección 29 — Colas y jobs en segundo plano (módulo 6).