La checklist que salvó un despliegue de viernes
Un despliegue de viernes por la tarde dejó de dar miedo cuando dejamos de fiarnos de la memoria y empezamos a fiarnos de una lista. Esta es la que corre antes de cada release.
Entrada de demostración. Está publicada para ver cómo queda el blog con contenido real:
tabla, código, listas y cita. Se borra cuando ya no haga falta. Lleva noindex y no
aparece en el sitemap.
Los despliegues de viernes tienen mala fama por una razón que casi nunca se dice en voz alta: no
falla el código, falla la memoria de quien despliega. A las seis de la tarde, con prisa por cerrar,
nadie recuerda si el feature flag está apagado, si la migración es reversible o si el backup de
las cuatro es el bueno.
Así que dejamos de confiar en que alguien se acordara y escribimos la lista. No es una lista de
deseos: cada punto es una comprobación que devuelve sí o no, y un no detiene el despliegue sin
discusión.
La lista, en orden
- El cambio está detrás de un flag y el flag está apagado en producción.
- La migración tiene
downy se ha probado en el entorno de staging de esta semana, no del mes pasado. - El SLO tiene presupuesto para el error que vamos a introducir. Si el presupuesto del mes ya está gastado, no se despliega: se arregla primero la estabilidad.
- El rollback está ensayado al menos una vez, y sabemos cuánto tarda (no «debería ser rápido»).
- Alguien mira el dashboard durante los veinte minutos siguientes, con nombre y apellidos.
Por qué el punto 3 es el que más discusiones ahorra
El presupuesto de error convierte una discusión de opiniones en una resta. Antes de la lista, decidir si un despliegue «urgía» dependía de quién hablaba más alto en el canal. Ahora es un número:
| Situación | Presupuesto | Decisión |
|---|---|---|
| Mes tranquilo, sin incidentes | 100 % disponible | Se despliega |
| Un incidente Sev-2 ya consumido | ~35 % | Se despliega con vigilancia |
| Dos incidentes y un Sev-1 | 0 % | Se congela todo hasta cerrar la causa |
Nadie discute una tabla. Y cuando alguien quiere saltársela, la conversación ya no es «creo que podemos», es «¿qué vas a quitar de la tabla y por qué?», que es una pregunta mucho más incómoda de responder.
El chequeo, automatizado
La lista vive en el repositorio y corre sola antes de cada release. Lo importante no es el script: es que si falla, el despliegue no sigue.
def listo_para_desplegar(slo, flags, migracion):
"""Devuelve (bool, motivos). Un solo 'no' bloquea el release."""
motivos = []
if slo["presupuesto_restante"] <= 0:
motivos.append("sin presupuesto de error: se congela el release")
if not flags["apagados_en_produccion"]:
motivos.append("hay flags activos: el cambio no es reversible al instante")
if not migracion["tiene_down"] or not migracion["probada_esta_semana"]:
motivos.append("migración sin 'down' probado esta semana")
return (len(motivos) == 0, motivos)
Cuarenta líneas y un if. No hace falta una plataforma: hace falta que el if esté en el camino
crítico y no en un wiki que nadie abre.
Una checklist no existe para que la gente se acuerde de las cosas. Existe para que no pueda fingir que se acordó.
Lo que la lista no arregla
No arregla el código malo, ni la falta de tests, ni que el equipo vaya con prisa porque el backlog está mal priorizado. Lo que hace es que el error se cometa con los ojos abiertos y quede en el registro: quién desplegó, a qué hora y con qué comprobaciones en verde. Cuando algo se tuerce, la revisión empieza por datos y no por recuerdos.
Este texto es una demostración del formato del blog: tabla, código con resaltado, cita y lista numerada. El contenido es inventado para la prueba.
| Fase | Responsable | Detalle |
|---|---|---|
| 💡 Idea y perspectiva | 👤 100 % humano | Sale de una revisión post-incidente del equipo. |
| ✍️ Redacción y tono | 👤 100 % humano | Escrito de principio a fin por mí. |
| 🔤 Corrección | 🤖 IA | Gramática y sinónimos puntuales; ninguna frase reescrita por el modelo. |