"Cero rotura" casi nunca es cero
La migración de perfiles de LoverCast no rompió nada visible, y aun así no fue gratis. Sobre la diferencia entre no romper y no medir lo que rompes.
Cuando desplegamos la migración de perfiles de LoverCast, la frase que salió sola fue "esto no rompe nada". Y en el sentido que la gente suele darle a esa frase —nadie llama furioso porque se le ha borrado algo— era verdad.
Pero no era cero. Era que decidimos qué se perdía, cuánto tiempo, y para quién, antes de apretar el botón. Eso es otra cosa, y la diferencia importa más de lo que parece.
Lo que de verdad pasó
En Migrar el esquema sin romper las apps instaladas conté el mecanismo: una vista de compatibilidad para que las apps viejas siguieran leyendo user_preferences como si nada. Funcionó para lecturas. Para escrituras, los clientes Android/TV sin actualizar se quedaron en read-only hasta que instalaran la versión nueva, y perdieron el realtime entre dispositivos mientras tanto.
Eso está escrito, con fechas y alcance, en docs/MULTI_PROFILE_DEPLOY.md. No como nota a pie de página: como una sección del plan de rollout, tan legítima como el paso de aplicar las migraciones.
La rotura existe. Es pequeña, está acotada a un subconjunto de clientes, y desaparece sola en cuanto la gente actualiza. Pero llamarla "cero" habría sido la primera mentira del proyecto, y las mentiras de proyecto tienen la costumbre de creérselas antes que nadie el que las escribe.
Por qué "cero rotura" es casi siempre la frase equivocada
El problema no es la palabra "cero". Es lo que hace esa palabra en la cabeza de quien decide: si algo es cero rotura, no hay nada que sopesar, nada que medir, nada que decidir. Es gratis. Y las migraciones de esquema con clientes que no controlas casi nunca son gratis — lo único que puedes elegir es dónde cae el coste y cuánto dura.
Expand-contract, que es la técnica de fondo de la migración de LoverCast, no elimina ese coste: lo hace negociable. Añades sin romper (expand), convives con las dos formas el tiempo que haga falta, y solo entonces recoges lo viejo (contract). Eso te compra tiempo y opciones. No te compra gratuidad.
La vista de compatibilidad es el ejemplo perfecto: en el papel, "los clientes viejos ni se enteran". En la práctica, se enteran a medias — leen bien, escriben mal, y punto. Descubrir eso antes de desplegar, probando escrituras y no solo lecturas, es lo que separa un rollout consciente de uno que se entera por los logs de producción.
El mismo patrón en el cliente que no controlas
Esta no es una lección solo de bases de datos. Aparece en cualquier sitio donde hay un cliente publicado que no puedes forzar a actualizar: una API pública con integraciones de terceros, un formato de fichero que exportas, una app móvil con usuarios en versiones de hace ocho meses.
En todos esos sitios, el instinto es el mismo que tuvimos al principio con los perfiles: cambiar la forma de los datos y asumir que, si el cliente viejo no explota, es que no ha pasado nada. Pero "no explota" no es lo mismo que "no pierde nada". A veces pierde algo silencioso — sincronización en tiempo real, un campo que ahora llega vacío, una funcionalidad que se degrada sin avisar— y ese silencio es peor que un error visible, porque nadie lo investiga.
Qué hacer con esto
No es "no migres nunca sin cero rotura", porque esa migración no existe casi nunca cuando hay clientes que no actualizas tú. Es más simple y más incómodo:
- Mide, no asumas. Prueba el camino de escritura del cliente viejo, no solo el de lectura. La rotura de LoverCast estaba exactamente ahí, tres capas por debajo de donde mirábamos primero (un detalle de cómo PostgREST implementa el upsert).
- Escríbelo. Si la rotura te da vergüenza ponerla en el documento de despliegue, es una señal de que la decisión no estaba tan bien pensada como creías. Escribirla te obliga a mirarla de frente antes de que la vea otra persona.
- Acótala a propósito. No es lo mismo "un subconjunto de usuarios pierde una función menor durante dos semanas" que "algo se rompe en algún sitio, para alguien, sin que sepamos ni cuánto ni cuándo se arregla". La primera es una decisión. La segunda es una apuesta.
"Cero rotura" casi nunca es cero. Es "rotura pequeña, conocida y asumida a propósito" — y esa frase, aunque suene peor, es la que de verdad se sostiene cuando alguien pregunta qué pasó.
Si estás en medio de una migración con clientes que no controlas y quieres comparar notas, escríbeme.