wandres.dev
MIGRAR DE REDUX · a Zustand o RTK

Cuándo NO migrar

El nivel cierra con la decisión que las cuatro lecciones anteriores hacen posible y que casi nunca se toma con rigor: no migrar. Esta lección contabiliza el coste de oportunidad que ninguna estimación incluye —lo que el equipo no construye mientras reescribe estado—, describe el perfil de riesgo particular de una migración de gestión de estado, que rompe de forma silenciosa y difusa en lugar de fallar de golpe, enumera las señales que deberían detener el proyecto antes de empezarlo y presenta la alternativa que casi nadie considera: contener el problema donde está, sin trasladarlo, y dedicar el presupuesto liberado a lo que sí mueve la aguja.

⏱ 17 min

Un nivel dedicado a migrar tiene la obligación de terminar explicando cuándo no hacerlo, porque las cuatro lecciones anteriores enseñan a ejecutar bien un proyecto cuya principal fuente de desperdicio no es la mala ejecución sino la mala elección de emprenderlo. Migrar el estado de una aplicación en producción no es una mejora incremental: es consumir semanas de la capacidad del equipo para llegar a un sitio donde el usuario no percibe absolutamente nada distinto. Eso puede estar plenamente justificado —cuando el modelo actual bloquea el desarrollo, multiplica los bugs o hace inviable incorporar gente— y puede ser también la forma más elegante de desperdiciar un trimestre. La diferencia entre ambos casos no la marca la calidad de la herramienta destino, sino un cálculo que casi nadie hace por escrito y que esta lección obliga a hacer antes de escribir la primera línea.

🎯 Al terminar esta lección sabrás
  • Contabilizar el coste de oportunidad completo, incluida la capacidad del equipo que la migración consume.
  • Entender por qué una migración de estado tiene un perfil de riesgo peor que el de otras migraciones técnicas.
  • Reconocer las cinco señales que deberían detener el proyecto antes de empezarlo.
  • Aplicar la alternativa de contención: aislar el problema donde está en vez de trasladarlo.

El coste que ninguna estimación incluye

Las estimaciones de migración se hacen casi siempre en unidades equivocadas: se cuentan los slices a convertir y se multiplican por un tiempo medio optimista. Ese cálculo omite tres partidas que en la práctica suman más que la propia conversión. La primera es la revisión y el aprendizaje: cada cambio lo lee alguien más, y cada persona del equipo paga una curva con el modelo nuevo. La segunda es el arrastre sobre el trabajo en curso, porque durante meses toda funcionalidad nueva se escribe dos veces o se escribe mal, según el slice que toque. La tercera, y la mayor, es lo que el equipo no construye mientras tanto.

// el presupuesto real de una migracion, en semanas de equipo
interface Presupuesto {
  conversion: number      // lo unico que suele estimarse
  revision: number        // leer, discutir y corregir cada cambio
  arrastre: number        // funcionalidades ralentizadas mientras conviven dos modelos
  incidencias: number     // bugs silenciosos descubiertos despues de desplegar
  oportunidad: number     // lo que no se construye: la partida mayor y la nunca escrita
}

const total = (p: Presupuesto) =>
  p.conversion + p.revision + p.arrastre + p.incidencias + p.oportunidad

La utilidad de escribir el presupuesto así no está en la precisión de los números, que será mala, sino en que obliga a nombrar partidas que de otro modo permanecen invisibles. En cuanto la línea de oportunidad tiene un valor explícito, la conversación cambia de naturaleza: ya no se discute si Zustand es mejor que Redux, sino si esta migración vale más que las tres cosas que no haremos por hacerla. Esa segunda pregunta tiene respuesta; la primera, en abstracto, no la tiene.

⚠️
El sesgo de la estimación técnica pura

Quien propone la migración suele estimarla desde el conocimiento del código y desde la parte del sistema que mejor domina, y ambas cosas sesgan a la baja de forma sistemática. Los slices que uno conoce se convierten rápido; los que escribió otra persona hace cuatro años, con lógica de negocio implícita y ningún test, consumen el triple. Además, la persona que propone suele ser la más motivada, y su velocidad no es representativa de la del equipo. Una corrección honesta consiste en estimar el slice que menos conoces y usar ese tiempo como media, no como caso extremo. Si con esa media el proyecto sigue siendo rentable, es probablemente rentable de verdad.

Hay una asimetría adicional que conviene explicitar al presentar el presupuesto: las partidas de conversión y revisión se pagan seguro, mientras que el beneficio prometido es probabilístico. Menos bugs, incorporaciones más rápidas, funcionalidades desbloqueadas: todo eso puede ocurrir, y ocurrirá en la medida en que el diagnóstico fuera correcto. Comparar un coste cierto con un beneficio esperado sin decir en voz alta que uno es cierto y el otro no es la manera silenciosa en que estos proyectos se aprueban con números que nadie habría firmado de haberlos visto etiquetados.

Por qué el riesgo aquí es peor

No todas las migraciones tienen el mismo perfil de riesgo, y la de gestión de estado está en el extremo desfavorable por una razón estructural: sus fallos no son ruidosos. Cambiar de empaquetador falla en la compilación, y el problema aparece antes de desplegar. Cambiar de gestión de estado produce fallos que compilan perfectamente, pasan la revisión y solo se manifiestan como un panel que no se actualiza en cierta secuencia de navegación, un valor que se pierde al volver atrás o un renderizado de más que degrada una pantalla concreta.

flowchart TD
M[migracion de estado] --> S[fallo silencioso]
M --> D[fallo difuso]
S --> T1[compila y pasa revision]
D --> T2[aparece semanas despues en un flujo raro]
T1 --> R[coste real muy superior al estimado]
T2 --> R
style S fill:#f38ba8,color:#11111b
style D fill:#f38ba8,color:#11111b
style R fill:#fab387,color:#11111b

A esa característica se suma otra: el estado es transversal. Un cambio de librería de gráficas afecta a las pantallas que dibujan gráficas, y su radio de explosión es acotado y conocido. El estado global lo lee media aplicación, de modo que un error de suscripción en un slice central se manifiesta en pantallas que nadie relacionó con el cambio, semanas después, cuando el contexto ya se perdió. Por eso las migraciones de estado incumplen sus plazos con una regularidad que no se explica por incompetencia: la parte que se estima es la conversión, y la parte que se paga es la cola larga de fallos difusos.

🤫

Rompe en silencio

Los errores compilan y pasan la revisión. El tipo no distingue entre leer del store correcto y del equivocado si la forma coincide.

🕸️

Radio transversal

El estado global lo lee media aplicación, así que el fallo aparece lejos del cambio que lo causó.

🐌

Cola larga

Los flujos poco frecuentes tardan semanas en ejercitarse. El proyecto parece terminado mucho antes de estarlo.

🪞

Cero valor visible

Nada de esto es perceptible para el usuario, así que el riesgo se asume sin ninguna cobertura en forma de beneficio observable.

Las señales de parada y la alternativa de contener

Ese perfil tiene una consecuencia práctica sobre las pruebas que casi nadie extrae. Si los fallos de una migración de estado son silenciosos, entonces la única defensa proporcionada al riesgo son pruebas que ejerciten los flujos de estado de extremo a extremo, y no pruebas unitarias de reductores, que seguirán pasando exactamente igual porque la lógica no cambia. Un equipo que se dispone a migrar con buena cobertura unitaria y ninguna prueba de flujo está protegido justo en la parte donde no había peligro y desnudo en la parte donde lo hay.

Cinco situaciones deberían detener el proyecto antes de empezarlo, y ninguna de ellas es una opinión sobre la calidad de las herramientas. La primera: el store funciona y no genera bugs recurrentes. Un modelo aburrido que nadie toca no es deuda técnica, es infraestructura amortizada. La segunda: el equipo no domina el destino; migrar mientras se aprende produce en la herramienta nueva los mismos errores que se querían dejar atrás, con menos experiencia para detectarlos. La tercera: no hay tests alrededor del estado, de modo que la migración se hace sin red y con fallos silenciosos, la peor combinación posible. La cuarta: la aplicación está en un momento de presión de producto, y competir por la capacidad del equipo con trabajo invisible siempre pierde y debe perder. La quinta: la motivación real es el desagrado estético con el código antiguo, sentimiento legítimo pero que no es un argumento de negocio ni de ingeniería.

ℹ️
Contener en lugar de trasladar

Existe una alternativa intermedia que casi nadie considera y que ofrece buena parte del beneficio a una fracción del coste: dejar el store donde está y contenerlo. Consiste en tres movimientos baratos. Primero, ejecutar solo el paso uno del nivel —sacar el estado del servidor a una caché—, que resuelve la mayoría del dolor sin tocar el store de cliente. Segundo, envolver el store restante en hooks de dominio, de modo que el código nuevo no dependa nunca de su forma interna y una migración futura sea barata si algún día se justifica. Tercero, congelar el store antiguo: prohibir por convención que crezca, y escribir todo estado nuevo con las herramientas actuales. El resultado es un sistema donde la parte antigua está acotada, ya no crece y puede vivir años sin molestar, mientras el presupuesto se dedica a lo que sí genera valor observable. Contener no es rendirse: es reconocer que la deuda acotada y estable es mucho más barata que la deuda saldada.

El caso legítimo, y cómo se reconoce

Una lección sobre no migrar sería deshonesta si no describiera con la misma precisión el caso contrario, porque existe y es nítido. Tres condiciones deben cumplirse a la vez, y la conjunción importa: cualquiera de ellas por separado justifica una conversación, no un proyecto.

🩸

Daño recurrente y medible

No incomodidad: incidencias que se repiten, funcionalidades que se posponen por el modelo, incorporaciones que tardan meses. Con nombres y fechas.

🎓

Destino ya dominado

Alguien del equipo ha llevado el destino a producción antes. Aprender y migrar a la vez multiplica el coste y esconde los errores.

🕸️

Red de seguridad

Pruebas alrededor del estado que fallen cuando la migración rompa algo. Sin ellas, los fallos silenciosos se descubren en producción.

🪟

Ventana de calma

Un periodo sin compromisos de producto grandes. Competir por la capacidad del equipo con trabajo invisible siempre acaba mal.

flowchart TD
A[quiero migrar el estado] --> B[hay dano recurrente y medible]
B -->|no| N1[no migrar y contener]
B -->|si| C[el equipo domina el destino]
C -->|no| N2[aprender primero en algo pequeno]
C -->|si| D[hay pruebas alrededor del estado]
D -->|no| N3[escribir la red antes de mover nada]
D -->|si| E[hay ventana sin presion de producto]
E -->|no| N4[posponer con fecha de revision]
E -->|si| S[migrar por etapas segun este nivel]
style S fill:#a6e3a1,color:#11111b
style N1 fill:#f38ba8,color:#11111b

Falta una condición implícita que el árbol no dibuja porque no es binaria: haber ejecutado antes el paso uno del nivel. Decidir sobre una migración de librería sin haber extraído el estado del servidor es decidir con el inventario equivocado, porque el daño que se atribuye al store incluye entonces todo el sufrimiento de sostener una caché a mano. Ese daño es real, pero su cura no es la que se está proponiendo, y confundirlas lleva a aprobar el proyecto caro para arreglar lo que el barato ya resolvía.

⚠️
Cuidado con el argumento del reclutamiento

Aparece con frecuencia una razón que suena a negocio y no lo es: migrar para que resulte más fácil contratar, porque los candidatos prefieren la herramienta nueva. Conviene desarmarla, porque cualquier persona capaz de trabajar en tu base de código aprende un gestor de estado en una tarde, y ninguna decisión de arquitectura que dure años debería tomarse por una preferencia que se disuelve en una semana de trabajo real. Lo que sí ahuyenta a la gente no es la librería sino un modelo de estado incomprensible, y ese se arregla auditando y clasificando, no cambiando de paquete.

El árbol tiene una propiedad deliberada: casi todas sus ramas terminan en algo que hacer, no en una negativa seca. No migrar no significa quedarse quieto, significa gastar el presupuesto en el eslabón que falta —escribir las pruebas, ganar experiencia con el destino en un proyecto menor, contener el store actual— y volver a recorrer el árbol cuando ese eslabón exista. Un proyecto pospuesto con la condición objetiva escrita al lado es una decisión de ingeniería; uno pospuesto sin condición es simplemente una discusión que se repetirá cada trimestre con los mismos argumentos y ninguna información nueva.

💡
Escribe la condición de reevaluación, no solo la decisión

La forma de que un no se sostenga sin volverse dogma es acompañarlo de un umbral verificable: si el mismo tipo de incidencia se repite tres veces más este semestre, si el tiempo de incorporación de una persona nueva supera cierto límite, si una funcionalidad concreta resulta inviable con el modelo actual, entonces se reabre la decisión. Ese umbral convierte una postura en un experimento con criterio de parada, y desactiva de paso el efecto más corrosivo de estas discusiones: que quien quería migrar interprete la negativa como desprecio por el problema técnico en lugar de como una priorización explícita y revisable.

No migrar es una decisión de ingeniería, no una renuncia

El cierre de este nivel exige desmontar una asimetría que gobierna la cultura técnica sin que nadie la haya argumentado nunca: la de que migrar es una decisión y no migrar es la ausencia de una decisión. Es exactamente al revés. Mantener un sistema que funciona mientras existe una alternativa más moderna es una postura activa, y sostenerla exige más argumento y más carácter que emprender la reescritura, porque quien no migra tiene que defender su elección cada vez que alguien menciona la herramienta nueva, mientras que quien migra recibe el beneficio de la duda por adelantado y solo rinde cuentas si el proyecto descarrila de forma espectacular. Esa asimetría de reputación explica más migraciones de las que ninguna razón técnica explicaría, y su coste no aparece en ningún registro, porque lo que se pierde son las funcionalidades que nunca existieron y los problemas de usuario que nadie llegó a resolver. La forma madura de decidir invierte la carga de la prueba: la migración debe justificarse frente al statu quo con un daño concreto, medible y recurrente —bugs que se repiten, funcionalidades que se bloquean, incorporaciones que tardan meses— y no con la promesa genérica de un código más limpio, porque el código más limpio es un medio para esos fines y no un fin que se pueda cobrar. Las cuatro lecciones anteriores enseñan a ejecutar una migración con el riesgo mínimo, y esta última recuerda que la habilidad de ejecutarla no es razón para hacerlo, igual que saber operar no es indicación de operar. El ingeniero que audita su store, saca el estado del servidor, mide lo que queda y concluye por escrito que ese resto no justifica reescribir nada ha hecho un trabajo técnico completo y ha tomado la decisión más difícil del nivel; el que migra por reflejo ha ejecutado un proyecto impecable cuya premisa nadie examinó. La competencia no está en saber migrar: está en saber cuándo el mejor uso de esa competencia es no usarla.

⚔️ Escribe el caso de no migrar y defiéndelo
  1. Escribe el presupuesto completo de tu migración en semanas de equipo, con las cinco partidas, y estima la conversión usando el slice que menos conoces como caso medio.
  2. Enumera las tres cosas concretas que el equipo no construirá durante ese tiempo y ponles nombre de funcionalidad, no de categoría.
  3. Lista los daños reales y recurrentes que el store actual causa hoy: bugs repetidos, funcionalidades bloqueadas, tiempo de incorporación. Si la lista está vacía, tienes tu respuesta.
  4. Revisa las cinco señales de parada y marca cuáles se cumplen en tu situación. Basta con dos para posponer el proyecto de forma razonable.
  5. Diseña la alternativa de contención para tu caso: qué extraes a una caché, qué envuelves en hooks de dominio y qué congelas por convención.
  6. Escribe la recomendación final en un párrafo, defendible ante alguien que quiere migrar, y fija la condición objetiva que te haría cambiar de opinión dentro de seis meses.