Migraciones de esquema en producción sin caídas: cómo dominar blue/green, feature flags y compatibilidad hacia atrás

Cambiar la estructura de una base de datos viva es una de las operaciones más temidas de cualquier equipo de plataforma. Esta es la hoja de ruta para hacerlo con red de seguridad: despliegues sin downtime, reversibilidad real y contratos de datos que no rompen a quien consume al otro lado.

Resumen ejecutivo

La gestión de esquemas y migraciones es el punto donde la arquitectura de datos se encuentra con la realidad operativa: el momento en que un cambio aparentemente trivial —añadir una columna, renombrar un campo, dividir una tabla— puede tumbar un servicio que factura miles de transacciones por minuto. La diferencia entre un equipo maduro y uno frágil no está en si migran, sino en cómo lo hacen.

Tres disciplinas sostienen el cambio seguro en producción. La compatibilidad hacia atrás (backward compatibility) garantiza que el código antiguo siga funcionando contra el esquema nuevo durante la transición. Las migraciones expand/contract descomponen un cambio destructivo en pasos aditivos y reversibles. Y las feature flags desacoplan el despliegue del código de la activación de la funcionalidad, convirtiendo un rollback de horas en un interruptor de segundos.

Para el CIO, el mensaje es claro: la velocidad de entrega y la estabilidad no son objetivos opuestos. Una organización que invierte en migraciones versionadas, automatizadas y observables despliega más rápido y con menos incidentes. El coste de no hacerlo se paga en ventanas de mantenimiento nocturnas, en pánico ante cada release y en una deuda técnica que termina paralizando la innovación.

Hay una clase de incidente que casi todo ingeniero de datos veterano recuerda con un escalofrío. No es la caída espectacular del centro de datos ni el ciberataque de portada. Es algo mucho más banal y, precisamente por eso, más insidioso: una migración de esquema que parecía inofensiva y que, a las 9:14 de un martes cualquiera, dejó la aplicación principal devolviendo errores 500 a media plantilla y a todos los clientes. El commit decía «rename column». La retro duró tres horas.

El problema de las migraciones es que ocurren en la frontera más delicada de un sistema: el lugar donde el estado persistente —que no se puede simplemente reiniciar ni desplegar en azul y verde como si fuera un binario sin memoria— se encuentra con un código que sí cambia constantemente. Una aplicación stateless se puede reemplazar entera en segundos. Una base de datos con doscientos millones de filas y veinte servicios leyendo de ella, no. Ese desajuste de naturalezas es el corazón de toda la disciplina que vamos a recorrer.

Durante años, la respuesta del sector fue la ventana de mantenimiento: avisar a los usuarios, apagar el sistema un domingo de madrugada, ejecutar el ALTER TABLE con los dedos cruzados y volver a encender. Funcionaba cuando el negocio tenía horario de oficina y un puñado de usuarios. No funciona cuando el negocio es una plataforma global que no duerme, cuando el SLA promete cuatro o cinco nueves de disponibilidad y cuando los equipos despliegan decenas de veces al día. La pregunta dejó de ser «¿cuándo paramos para migrar?» y pasa a ser «¿cómo migramos sin parar nunca?».

Este capítulo responde a esa pregunta. Y lo hace conectando con el hilo conductor de toda la Parte II: igual que la resiliencia y la recuperación ante desastres del capítulo anterior nos enseñaron a sobrevivir a lo inesperado, las migraciones seguras nos enseñan a controlar el cambio que sí provocamos nosotros mismos, que estadísticamente es responsable de muchas más caídas que cualquier catástrofe externa.

1. El problema fundamental: por qué un esquema no se despliega como el código

Para entender la solución conviene interiorizar primero la asimetría. El código de una aplicación es efímero y replicable: si tengo diez instancias de un microservicio, puedo levantar diez instancias nuevas con la versión actualizada, dirigir el tráfico hacia ellas y apagar las viejas. Si algo va mal, redirijo el tráfico de vuelta. El estado anterior no se ha tocado.

El esquema de datos es lo contrario: es único, compartido y persistente. Solo hay una tabla pedidos, no diez copias intercambiables. Sobre ella escriben simultáneamente versiones distintas de varios servicios. Y cualquier cambio que se le haga es, por defecto, irreversible sin pérdida: si se elimina una columna y resulta que hacía falta, los datos que contenía ya no están.

De esta asimetría se deriva una verdad incómoda pero liberadora: durante toda migración no trivial existe inevitablemente una ventana de transición en la que conviven el esquema viejo y el nuevo, o el código viejo y el nuevo, o ambas cosas a la vez. La pregunta de diseño no es cómo evitar esa convivencia —es inevitable—, sino cómo orquestarla para que sea segura. Toda la ingeniería de migraciones modernas consiste, en el fondo, en gestionar con elegancia ese periodo de coexistencia.

Cambios aditivos frente a cambios destructivos

La primera distinción operativa que todo equipo debe grabar a fuego es la que separa los cambios aditivos de los destructivos. Un cambio aditivo añade algo nuevo sin tocar lo existente: crear una tabla, añadir una columna que admite nulos, crear un índice de forma concurrente. Estos cambios son intrínsecamente seguros y compatibles hacia atrás, porque el código antiguo ni siquiera sabe que existen y, por tanto, no se ve afectado.

Un cambio destructivo, en cambio, modifica o elimina algo de lo que el código vigente depende: borrar una columna, renombrar un campo, cambiar un tipo de dato, añadir una restricción NOT NULL sobre una columna que tenía valores nulos. Estos cambios rompen el contrato con quien lo consume y son la fuente principal de incidentes. El gran truco de la disciplina, como veremos, consiste en transformar todo cambio destructivo en una secuencia de cambios aditivos.

⚠ Matiz técnico que cuesta caro: no todos los ALTER son iguales según el motor. En versiones modernas de PostgreSQL, añadir una columna con valor por defecto es instantáneo, pero crear un índice sin CONCURRENTLY bloquea la tabla entera. En MySQL/InnoDB, ciertos ALTER reconstruyen la tabla completa y bloquean escrituras durante minutos u horas. Conocer el comportamiento exacto de bloqueo de cada operación en tu motor concreto no es opcional: es el conocimiento que separa una migración invisible de una caída de producción.

El problema fundamental: por qué un esquema no se despliega como el código

Figura 17.1 — El código se despliega en azul/verde sin tocar el pasado; el estado obliga a orquestar una ventana de convivencia.

2. Compatibilidad hacia atrás: el contrato invisible que sostiene todo

Si solo hubiera que recordar una idea de este capítulo, sería esta: el esquema de datos es una API, y como toda API tiene consumidores que dependen de su forma. Cada tabla, cada columna, cada tipo de dato es una promesa implícita hecha a los servicios, a los jobs de ETL, a los cuadros de mando de BI y a los modelos de Data Science que leen de ella. Romper esa promesa de golpe es romper a todos ellos a la vez.

La compatibilidad hacia atrás consiste en garantizar que, durante la transición, el código que aún no se ha actualizado siga funcionando contra el esquema modificado. Esto se consigue con una regla operativa engañosamente simple: el esquema y el código se despliegan en pasos separados, y el esquema cambia siempre antes que el código que lo aprovecha, de forma aditiva. Nunca se elimina nada hasta estar absolutamente seguro de que nadie lo usa.

Aquí entra en juego un concepto que conviene tomar prestado del mundo del streaming de eventos pero que aplica a toda la capa de datos: el contrato de datos (data contract). Un contrato de datos es un acuerdo explícito y versionado entre quien produce un dato y quien lo consume. Formaliza qué campos existen, qué tipos tienen, qué garantías de presencia ofrecen y bajo qué reglas pueden evolucionar. Cuando este contrato es explícito —y no una suposición tácita en la cabeza de tres ingenieros— las migraciones dejan de ser una apuesta y se convierten en una negociación gobernada.

Compatibilidad hacia atrás, hacia delante y total

Conviene afinar el vocabulario porque la consultoría seria distingue tres garantías. La compatibilidad hacia atrás (backward) significa que un consumidor nuevo puede leer datos producidos con el esquema antiguo. La compatibilidad hacia delante (forward) significa que un consumidor antiguo puede leer datos producidos con el esquema nuevo —ignorando, por ejemplo, los campos que no conoce—. Y la compatibilidad total (full) combina ambas. En sistemas con despliegues escalonados, donde durante minutos u horas conviven productores y consumidores de distintas versiones, perseguir la compatibilidad total es lo que permite que el orden de despliegue deje de ser un campo de minas.

Compatibilidad hacia atrás — el esquema como API con consumidores conectados y los tres tipos de compatibilidad.

3. El patrón expand/contract: cómo desarmar una bomba en cámara lenta

El patrón expand/contract —también llamado parallel change o expand-migrate-contract— es la técnica central para ejecutar cambios destructivos sin downtime. Su elegancia reside en una idea: en lugar de transformar el esquema en un solo paso brusco, lo hacemos en tres fases sucesivas, cada una de ellas individualmente segura y reversible. El ejemplo canónico, el que todo equipo acaba viviendo, es el de renombrar una columna; usémoslo para que el patrón sea tangible.

Fase 1 · Expand (expandir)

Supongamos que la columna nombre_completo debe pasar a llamarse nombre_cliente. Hacer un RENAME directo rompería todo el código que aún lee la columna vieja. En su lugar, en la fase de expansión añadimos la columna nueva sin tocar la vieja. Ambas coexisten. Es un cambio puramente aditivo: el código existente sigue trabajando contra nombre_completo y no se entera de nada.

Fase 2 · Migrate (migrar y duplicar la escritura)

Ahora viene el periodo de convivencia gestionada. Se despliega una versión del código que practica doble escritura (dual write): cada vez que se actualiza un registro, se escribe tanto en la columna vieja como en la nueva. En paralelo, un proceso de backfill recorre los registros históricos copiando los valores de la columna antigua a la nueva. Cuando el backfill termina y todas las escrituras nuevas van a ambos sitios, las dos columnas contienen exactamente los mismos datos. A partir de ese punto, se va migrando la lectura del código de la columna vieja a la nueva, servicio por servicio, sin prisa.

Fase 3 · Contract (contraer)

Solo cuando se ha verificado —con métricas, no con fe— que ningún consumidor lee ya la columna vieja, se ejecuta la contracción: se detiene la doble escritura y, finalmente, se elimina la columna obsoleta. Este es el único paso destructivo de toda la secuencia, y para cuando llega es completamente inofensivo, porque hemos demostrado empíricamente que nadie depende ya de lo que vamos a borrar.

✔ La clave de consultoría: entre la fase de expansión y la de contracción puede pasar una hora o pueden pasar tres meses. El tiempo no es el enemigo, la prisa sí. Un equipo maduro deja columnas «zombi» conviviendo el tiempo que haga falta hasta tener certeza absoluta de que el último consumidor migró. El coste de unos días de duplicidad de datos es ridículo comparado con el de una caída.

Expand/contract — las tres fases (expand / migrate / contract) con la columna vieja y nueva.

Figura 17.2 — Un cambio destructivo se descompone en tres pasos aditivos. La destrucción real solo ocurre cuando ya es inofensiva.

4. Blue/green y migraciones: el matiz que casi todos pasan por alto

El despliegue blue/green es una estrategia bien conocida en la capa de aplicación: se mantienen dos entornos productivos idénticos —el «azul», que sirve el tráfico actual, y el «verde», con la versión nueva— y se conmuta el tráfico de uno a otro de golpe. Si algo falla en verde, se vuelve a azul instantáneamente. Es elegante, rápido y reversible. El problema es que esa elegancia se rompe en cuanto entra en juego la base de datos compartida.

Aquí está el matiz que provoca incidentes incluso en equipos avanzados: en un blue/green clásico de aplicación, ambos entornos —azul y verde— suelen compartir la misma base de datos. No se duplica el estado, porque duplicar una base de datos transaccional viva y mantenerla sincronizada es enormemente costoso. Esto significa que el esquema debe ser simultáneamente compatible con la versión azul y con la verde durante la conmutación. Si el despliegue verde requiere un esquema que rompe a la versión azul, el supuesto rollback instantáneo a azul ya no es posible: azul ya no funciona contra el esquema migrado.

La conclusión operativa es contundente: blue/green no sustituye al patrón expand/contract, lo necesita. La migración de esquema debe ser siempre compatible hacia atrás antes de la conmutación de tráfico, precisamente para preservar la capacidad de rollback que es la razón de ser del blue/green. Quien despliega verde con un cambio destructivo de esquema ha convertido su red de seguridad en un decorado.

¿Y cuando sí conviene una base de datos por entorno?

Existe una variante en la que cada entorno tiene su propia base de datos, habitual en migraciones de gran calado —cambiar de motor, reestructurar profundamente el modelo— donde se monta la base verde nueva y se sincroniza con la azul mediante replicación o captura de cambios (CDC, que vimos en el contexto de la integración casi en tiempo real). Es más caro y complejo, pero permite ensayar la versión nueva contra datos reales sin tocar producción, y es la opción que eligen organizaciones que afrontan re-plataformados completos. La regla de oro sigue siendo la misma: hasta que el corte sea irreversible, ambos lados deben poder servir tráfico.

Blue/green — el router de tráfico, los entornos azul/verde y la base de datos compartida que obliga a expand/contract.

5. Feature flags: separar el despliegue del riesgo

Las feature flags (interruptores de funcionalidad) son la tercera pata del trípode, y posiblemente la que más transforma la cultura de un equipo. Su premisa es desacoplar dos cosas que tradicionalmente iban unidas: desplegar código (poner el binario nuevo en producción) y activar la funcionalidad (que ese código nuevo empiece realmente a ejecutarse para los usuarios). Con una feature flag, se puede desplegar el código que usa el esquema nuevo dejándolo apagado, y encenderlo después con un simple cambio de configuración, sin redesplegar nada.

El impacto sobre las migraciones es enorme. La lógica que pasa a leer de la columna nueva, la que activa el nuevo modelo de datos, la que cambia el comportamiento del servicio: todo ello puede ir protegido tras un flag. Si al activarlo aparecen errores o degradación, el rollback no es un redespliegue de minutos ni un revertido de migración, sino un interruptor que se apaga en segundos. El código problemático ya estaba en producción, pero inerte; apagarlo lo devuelve al estado anterior al instante.

Esto habilita además dos prácticas valiosísimas. La primera es el despliegue canario: encender el flag solo para un 1 % del tráfico, observar las métricas, y si todo va bien escalar progresivamente al 5%, 25%, 100%. La segunda es la separación limpia entre el trabajo de los equipos: los ingenieros de plataforma pueden ejecutar las migraciones de esquema en su propio calendario, y los equipos de producto encender las funcionalidades en el suyo, sin coordinaciones frágiles de tipo «desplegad exactamente a las 3:00 y no antes».

Feature flags — el interruptor y la escalera de despliegue canario (1% → 5% → 25% → 100%)

⚠ La trampa de los feature flags: son deuda técnica con fecha de caducidad. Una flag que se queda encendido y olvidado durante un año se convierte en una rama de código muerta, en una bifurcación de comportamiento imposible de razonar y en una fuente de bugs sutiles. La disciplina exige retirar el flag en cuanto la funcionalidad esté consolidada al 100 %. Las organizaciones serias tratan los flags obsoletos como un tipo de incidente de higiene técnica, con su propio backlog de limpieza.

6. Migraciones versionadas: el esquema como código

Toda esta orquestación se desmorona si las migraciones se ejecutan a mano. El principio rector es tratar el esquema como código: cada cambio se expresa como un script de migración versionado, almacenado en el repositorio junto al código de la aplicación, revisado en un pull request y ejecutado de forma automática y determinista por el pipeline de CI/CD. El estado del esquema deja de vivir en la memoria de quien lo modificó por última vez y pasa a ser un artefacto auditable, reproducible y aplicable de forma idéntica en desarrollo, preproducción y producción.

Una migración bien escrita tiene dos direcciones: el up que aplica el cambio y el down que lo revierte. Aunque, como hemos visto, la reversibilidad real de un cambio destructivo es limitada —no se puede «desborrar» una columna con sus datos—, disponer de un down bien pensado para los cambios aditivos es una red de seguridad valiosa. Los equipos más avanzados, sin embargo, prefieren confiar en la reversibilidad estructural del patrón expand/contract antes que en un down destructivo, precisamente porque el primero no pierde datos y el segundo sí.

Dos filosofías: imperativa frente a declarativa

El ecosistema de herramientas se divide en dos grandes familias filosóficas. El enfoque imperativo —representado por herramientas como Flyway o Liquibase— consiste en escribir explícitamente la secuencia de cambios: «crea esta tabla, luego añade esta columna, luego este índice». Cada migración es un paso numerado e inmutable. El enfoque declarativo —encarnado por herramientas como Atlas o por las migraciones automáticas de muchos ORM— consiste en describir el estado final deseado del esquema y dejar que la herramienta calcule el diff y genere los pasos necesarios para llegar a él.

Ninguno es universalmente superior. El imperativo da control absoluto y predecibilidad sobre cómo se ejecuta cada cambio —crítico cuando se necesita un índice concurrente o un backfill por lotes—, a costa de más trabajo manual. El declarativo reduce la fricción y elimina errores de transcripción, pero puede generar planes de migración peligrosos si no se revisan, porque la herramienta no siempre conoce el comportamiento de bloqueo de cada operación en producción. El criterio de consultoría es claro: cuanto más crítico y de mayor volumen sea el sistema, más se inclina la balanza hacia el control imperativo, al menos para las operaciones delicadas.

Migraciones versionadas — el flujo del esquema como código por el pipeline y las dos filosofías (imperativa/declarativa)

7. Criterios para seleccionar herramientas de migración y feature flags

Dado que en Dataprix se mantiene un inventario de las mejores herramientas de cada categoría, conviene cerrar la parte técnica con criterios de selección accionables. A la hora de elegir una herramienta de migración de esquemas, hay seis preguntas que separan una decisión sólida de una corazonada:

Primero, ¿soporta de forma nativa el motor de base de datos concreto y sus operaciones específicas sin bloqueo, como los índices concurrentes de PostgreSQL? Una herramienta agnóstica que no conoce los matices de tu motor te dará una falsa sensación de seguridad.

Segundo, ¿se integra limpiamente en el pipeline de CI/CD y permite ejecución no interactiva, idempotente y auditable?

Tercero, ¿gestiona el estado de las migraciones de forma fiable, con bloqueo para evitar que dos despliegues simultáneos corrompan el historial?

Cuarto, ¿ofrece un mecanismo de revisión y de dry-run que muestre el plan antes de ejecutarlo en producción?

Quinto, ¿qué madurez tiene su comunidad y su documentación, factor decisivo para la operación a largo plazo?

Y sexto, ¿encaja con la filosofía del equipo —imperativa o declarativa— en lugar de imponerle una contraria a su cultura?

Para las plataformas de feature flags —ya sea una solución gestionada como LaunchDarkly o Unleash, o una implementación propia ligera— los criterios diferenciadores son la latencia de evaluación del flag (debe ser despreciable en el camino crítico de la petición), la capacidad de segmentación (por porcentaje, por usuario, por región, para habilitar canarios reales), la observabilidad de qué flags están activos y para quién, y muy especialmente las herramientas de gobierno del ciclo de vida que ayuden a detectar y retirar flags obsoletos antes de que se conviertan en deuda. Una plataforma que facilita crear flags pero no limpiarlos es una fábrica de deuda técnica disfrazada de agilidad.

Selección de software — los seis criterios en tarjetas con check

8. Cómo se vive esto en distintos sectores

La teoría se entiende mejor cuando aterriza en contextos reales. Las restricciones de negocio cambian radicalmente la forma de aplicar estos patrones según el sector, y conviene ilustrarlo con varios escenarios representativos del tipo de situaciones que enfrentan los equipos de datos.

Fintech: el coste de la inconsistencia transaccional

En una plataforma de pagos, una migración mal ejecutada no degrada la experiencia: puede duplicar un cargo o perder una transacción, con consecuencias legales y de reputación severas. El reto típico aparece al evolucionar la tabla de movimientos para soportar una nueva divisa o un nuevo método de pago. Aquí la doble escritura del patrón expand/contract debe garantizar consistencia transaccional estricta: la escritura en la columna vieja y en la nueva tiene que ocurrir dentro de la misma transacción, nunca en dos pasos que puedan quedar a medias. Un equipo de pagos competente acompaña además cada migración de un proceso de reconciliación que verifica, registro a registro, que ambas representaciones cuadran antes de autorizar la contracción. La velocidad se subordina por completo a la corrección.

E-commerce: migrar bajo el fuego del Black Friday

Para un retailer online, la restricción dominante es el calendario comercial. Ninguna migración de esquema sobre el catálogo o el carrito se ejecuta en las semanas previas a las grandes campañas; existen periodos de code freeze sagrados. El patrón habitual es completar la fase de expansión y el backfill con mucha antelación, dejar la doble escritura corriendo silenciosamente durante semanas, y reservar la contracción —el único paso de riesgo— para la calma posterior a la campaña. Los feature flags brillan aquí: permiten desplegar el código de una nueva funcionalidad de catálogo durante el freeze, manteniéndolo apagado, y encenderlo de forma canaria una vez pasada la tormenta, sin tocar el sistema en el momento de máxima carga.

Salud: migrar sobre datos que no admiten pérdida

En el sector sanitario, donde un registro clínico es a la vez crítico y regulado, la prioridad es la trazabilidad y la no pérdida absoluta. Las migraciones que afectan a historiales se diseñan con la premisa de que ningún dato histórico puede desaparecer ni alterarse silenciosamente. Esto empuja hacia patrones casi exclusivamente aditivos —columnas nuevas, tablas de versiones— y hacia una contracción extremadamente conservadora, que a menudo no llega a borrar nada, sino que se limita a marcar campos como obsoletos y a archivarlos. La auditoría completa de cada cambio de esquema, con quién, cuándo y por qué, no es una buena práctica opcional, sino un requisito de cumplimiento.

Logística: el reto del volumen y la tabla gigante

En una plataforma logística con tablas de eventos de seguimiento de cientos de millones de filas, el enemigo no es la consistencia ni el calendario, sino el volumen puro. Aquí un backfill ingenuo que intente actualizar todos los registros de golpe satura la base de datos, dispara la replicación lag y tumba el rendimiento. La técnica imprescindible es el backfill por lotes (batched backfill): procesar los registros en bloques pequeños, con pausas controladas entre lotes, monitorizando la carga del sistema y aplicando backpressure si la base de datos empieza a sufrir. Una migración sobre una tabla de mil millones de filas no es un script que se lanza y se olvida: es una operación gobernada que puede durar días y que se vigila como se vigila un proceso de producción crítico.

Casos sectoriales — fintech, e-commerce, salud y logística, cada uno con su restricción dominante.

9. Anti-patrones: los errores que se repiten una y otra vez

Los incidentes de migración son sorprendentemente repetitivos. Conocer los anti-patrones más frecuentes es la forma más barata de evitarlos, porque casi todos nacen de las mismas tentaciones.

El primero y más letal es el cambio destructivo en un solo paso: el DROP COLUMN o el RENAME directo, ejecutado con el código antiguo todavía en producción. Es el origen del incidente con el que abríamos el capítulo. La regla que lo previene es absoluta: nunca un cambio destructivo en el mismo despliegue que el cambio de código que lo necesita.

El segundo es la migración acoplada al despliegue de aplicación, donde el mismo paso del pipeline aplica el esquema y arranca el código nuevo, sin posibilidad de desacoplarlos. Esto elimina la flexibilidad de orden que es la esencia de la compatibilidad hacia atrás. El tercero es el backfill no controlado sobre tablas grandes, que ya hemos visto cómo tumba sistemas por volumen. El cuarto es la migración sin probar contra datos realistas: un ALTER que tarda 50 milisegundos sobre la tabla vacía de desarrollo puede tardar 40 minutos y bloquear escrituras sobre la tabla real de producción.

El quinto, más sutil, es la migración irreversible sin plan de contingencia: lanzarse a un cambio que no se puede deshacer sin haber pensado qué se hará si algo sale mal a mitad de camino. Y el sexto es el cementerio de feature flags: la acumulación de interruptores olvidados que nadie se atreve a tocar porque ya nadie recuerda qué hacían. Todos estos anti-patrones comparten una raíz común: la confusión entre parecer rápido y ser seguro. La velocidad sostenible nace, paradójicamente, de la disciplina.

Anti-patrones — los seis errores frecuentes con código de color rojo de aviso.

10. Caso ilustrativo: partir una tabla monolítica sin que nadie lo note

Vale la pena recorrer un escenario completo y representativo —del tipo que afrontan habitualmente los equipos de plataforma de empresas de tamaño medio— para ver cómo encajan todas las piezas. Imaginemos una empresa SaaS cuya tabla usuarios ha crecido sin control: con el tiempo ha acumulado treinta y cuatro columnas que mezclan datos de autenticación, de perfil, de facturación y de preferencias. La consulta más caliente del sistema golpea esa tabla millones de veces al día, y la mezcla de responsabilidades se ha vuelto un cuello de botella. La decisión arquitectónica es separar las columnas de facturación a una tabla propia facturacion_usuario. Es, en esencia, un cambio destructivo masivo. Así se ejecuta sin downtime.

Se arranca con la expansión: se crea la nueva tabla facturacion_usuario, vacía, vinculada por clave foránea. No se toca la tabla original. Cero impacto. A continuación se despliega, protegida tras un feature flag apagado, la versión del código que escribe los datos de facturación tanto en las columnas viejas de usuarios como en la nueva tabla. El flag se enciende primero en el entorno interno, luego para un 1 % de cuentas reales, observando latencia y errores. Mientras tanto, un proceso de backfill por lotes recorre los millones de usuarios existentes copiando sus datos de facturación a la tabla nueva, en bloques de unos pocos miles de registros, con pausas que se ajustan dinámicamente según la carga del sistema.

Días después, con el backfill completo y la doble escritura estable, llega el momento de migrar las lecturas. Servicio por servicio, protegido por su propio flag, el código deja de leer las columnas de facturación de usuarios y empieza a leer de facturacion_usuario. Aquí la observabilidad es decisiva: se instrumenta el acceso a las columnas viejas para confirmar, con datos reales, que el tráfico de lectura hacia ellas cae literalmente a cero. No se avanza por intuición, se avanza por métrica.

Solo cuando el panel de observabilidad muestra cero lecturas sobre las columnas de facturación durante un periodo prudencial —días, no minutos— se autoriza la contracción: se detiene la doble escritura y, en una última migración, se eliminan las columnas obsoletas de usuarios. El cambio destructivo masivo se ha completado sin una sola ventana de mantenimiento, sin un solo error visible para el usuario y con la posibilidad de haber dado marcha atrás en cualquier punto del camino hasta el último instante. Finalmente, se programa la retirada de las feature flags ya consolidadas, cerrando el ciclo y evitando que se conviertan en deuda. Esto, y no el ALTER TABLE heroico de domingo de madrugada, es lo que distingue a una organización de datos madura.

Caso ilustrativo — partir la tabla monolítica usuarios en cuatro pasos, del

11. Checklist operativo de migraciones en producción

Antes de escribir la migración

  • ¿El cambio es aditivo o destructivo? Si es destructivo, ¿está descompuesto en una secuencia expand/contract?
  • ¿Se conoce el comportamiento de bloqueo exacto de cada operación en el motor concreto de producción?
  • ¿Existe un contrato de datos explícito y se ha verificado qué consumidores se verán afectados?

Antes de aplicarla en producción

  • ¿La migración está versionada en el repositorio, revisada en un PR y es ejecutable de forma automática e idempotente?
  • ¿Se ha probado contra un volumen de datos realista, no contra la base de datos vacía de desarrollo?
  • ¿El esquema migrado es compatible hacia atrás con la versión de código actualmente en producción?
  • Si hay backfill, ¿se ejecuta por lotes con backpressure y monitorización de carga?

Durante la transición

  • ¿La nueva funcionalidad está protegida por un feature flag que permite rollback en segundos?
  • ¿Se está activando de forma canaria (1 % → 5 % → 25 % → 100 %) observando métricas en cada escalón?
  • ¿Hay observabilidad instrumentada que confirme con datos cuándo el acceso al esquema viejo cae a cero?

Después de consolidar

  • ¿Se ejecuta la contracción solo tras verificar empíricamente que nadie depende del esquema viejo?
  • ¿Se han retirado los feature flags ya consolidados para no acumular deuda técnica?
  • ¿Queda registrado y auditado el cambio completo, especialmente en sectores regulados?

12. Conclusión: la disciplina como ventaja competitiva

La gestión de esquemas y migraciones es, en el fondo, una historia sobre cómo una organización se relaciona con el cambio. Los equipos frágiles viven cada migración como un acontecimiento traumático que requiere ventanas nocturnas, oraciones y planes de contingencia improvisados. Los equipos maduros han convertido el cambio de esquema en una operación rutinaria, automatizada y aburrida —y «aburrida», en producción, es el mayor de los elogios—.

El trípode que sostiene esa madurez es coherente y se refuerza mutuamente: la compatibilidad hacia atrás garantiza que el código viejo no se rompa, el patrón expand/contract descompone lo destructivo en aditivo y reversible, y las feature flags convierten el rollback en un interruptor instantáneo. Sobre ellos, el versionado del esquema como código y una observabilidad que sustituye la intuición por la evidencia. Ninguna de estas técnicas es exótica ni cara; lo caro es no tenerlas.

Para el CIO, la lección estratégica conecta con el hilo de toda esta Parte II y anticipa el siguiente capítulo, donde veremos cómo todas estas decisiones —motores, almacenamiento, resiliencia, migraciones— se integran en el diseño completo de la plataforma de datos de una fintech. La capacidad de cambiar el esquema de producción sin miedo no es un detalle de ingeniería: es lo que permite que la arquitectura de datos siga siendo un activo vivo y adaptable en lugar de un monumento congelado al que nadie se atreve a tocar. La velocidad sostenible y la estabilidad no compiten. Nacen, ambas, de la misma disciplina.

Recursos y lecturas recomendadas

Documentación oficial y referencias técnicas

Patrones y artículos de referencia

Libros

Formación recomendada

Los conceptos de este capítulo se asientan mejor con práctica guiada sobre las herramientas y los motores concretos. Estos itinerarios están directamente relacionados con la operación de bases de datos en producción y el versionado de esquemas:

Udemy · Versionado de esquemas

Managing database versions with Liquibase and Spring Boot

El curso más alineado con este capítulo: cómo aplicar cambios de esquema, gestionar versiones y actualizar distintos entornos con Liquibase, la herramienta de migración declarativa que vimos en la sección de selección de software. Práctica directa de changelogs, rollbacks y despliegue automatizado.

Ver el curso en Udemy →

DataCamp · Administración de bases de datos

SQL para Administradores de Bases de datos

Itinerario para administrar y operar PostgreSQL con solvencia: relaciones, diseño de bases de datos, creación de esquemas y optimización de consultas. El terreno sobre el que se ejecutan las migraciones que describe este capítulo.

Ver el track en DataCamp →

DataCamp · Rendimiento en producción

Mejorar el rendimiento de consultas en PostgreSQL

Conocer el comportamiento del motor bajo carga es lo que distingue una migración invisible de una caída. Este curso enseña a estructurar PostgreSQL para que rinda, conocimiento imprescindible para anticipar el coste real de un ALTER o un backfill sobre tablas grandes.

Ver el curso en DataCamp →

Guía de Arquitectura de Datos · Dataprix · Knowledge Is The Goal