wandres.dev
NIVEL DIOS: SÍNTESIS · el legado de Flux

Seguir aprendiendo: el código, los autores y hacia dónde va el estado

Última lección del track: convertir un curso terminado en una práctica que continúa. Propone leer el código fuente de Redux —unos pocos archivos que caben en una tarde y en los que `compose` ocupa cinco líneas y `applyMiddleware` menos de treinta— como el ejercicio de lectura de código con mejor relación entre esfuerzo y comprensión que existe en el ecosistema. Sigue con los escritos de quienes construyeron esto, que documentaron sus dudas y sus rectificaciones con una honestidad poco común, y con el mapa de hacia dónde se está moviendo el estado en la web: componentes de servidor que se llevan la mitad del problema, signals que cambian la capa de detección de cambios en todos los frameworks a la vez, y motores de sincronización con datos locales que reabren el problema entero desde otro ángulo. Cierra con un plan de estudio diseñado para no caducar.

⏱ 22 min

Un track termina; un oficio no. La diferencia entre alguien que hizo un curso sobre estado compartido y alguien que sabe de estado compartido es lo que ocurre en los dos años siguientes, y esa diferencia no la marca la cantidad de material consumido sino tres hábitos concretos: leer el código de las herramientas en lugar de solo su documentación, seguir a las personas que las construyeron en lugar de a quienes las resumen, y mirar hacia dónde se desplaza el problema en lugar de hacia dónde se desplaza el catálogo. Esta última lección no añade una técnica más al arsenal: entrega los tres hábitos con instrucciones suficientes para empezar esta misma semana, y termina con la única forma de plan de estudio que no caduca, que es la que se organiza alrededor de un problema y no alrededor de una herramienta.

🎯 Al terminar esta lección sabrás
  • Leer el código fuente de Redux y reconstruir sus mecanismos centrales a partir de unos pocos archivos.
  • Localizar los escritos de sus autores y extraer de ellos el razonamiento, no solo las conclusiones.
  • Mapear las tres corrientes que están desplazando el problema del estado en la web.
  • Montar un plan de estudio organizado por problemas, con criterios para no perseguir el catálogo.

Leer el código: una tarde bien invertida

Redux es, casi con seguridad, el mejor primer código fuente que un programador de interfaces puede leer entero. No porque sea el más importante, sino porque es pequeño, está escrito para ser leído, no depende de nada y resuelve un problema que ya entiendes por completo, que es la condición que convierte la lectura de código en aprendizaje en lugar de en desciframiento. El núcleo entero son unos pocos archivos, y la mayor parte de su volumen son comentarios y tipos.

🧱

El store

Una variable con el estado, un conjunto de oyentes y tres métodos. Fíjate en la bandera que impide despachar dentro de un reducer y en la copia de la lista de oyentes antes de notificar.

🧬

La composición de reducers

Recorre las claves, llama a cada reducer con su trozo y devuelve el objeto anterior si ninguno cambió. Esa última línea es la que hace barata la comparación por referencia.

🧅

Las capas de middleware

Menos de treinta líneas que construyen la cebolla entera. El truco está en que cada capa recibe la siguiente y devuelve una función con la misma forma.

🪄

La composición de funciones

Cinco líneas y una reducción por la derecha. Es la pieza que hace que la cebolla exista, y probablemente el mejor ejemplo de la relación entre brevedad y potencia del ecosistema.

El orden de lectura importa. Empieza por la composición de funciones, que se entiende en dos minutos y sin la cual el resto parece magia. Sigue por el ensamblado del middleware, que es el archivo más denso y más instructivo del proyecto: en él se ve por qué el dispatch que reciben las capas está deliberadamente cerrado sobre el dispatch final y qué clase de error produce llamarlo antes de tiempo. Continúa por el store, donde encontrarás decisiones defensivas que solo tienen sentido cuando ya te ha mordido el problema que evitan. Y termina por la composición de reducers, que es donde la inmutabilidad deja de ser un principio y se convierte en una comparación concreta.

// Reescribe estas dos piezas de memoria antes de leer el original.
// Si te salen, has entendido el nucleo entero.
const compose = (...fns) => fns.reduce((a, b) => (...args) => a(b(...args)))

function applyMiddleware(...middlewares) {
  return (crear) => (reducer, inicial) => {
    const store = crear(reducer, inicial)
    let dispatch = () => { throw new Error('despacho durante la construccion') }
    const api = { getState: store.getState, dispatch: (a, ...r) => dispatch(a, ...r) }
    const cadena = middlewares.map((m) => m(api))
    dispatch = compose(...cadena)(store.dispatch)
    return { ...store, dispatch }
  }
}

Cuando termines con el núcleo, el siguiente escalón natural es el enlace con React, que es donde vive la parte difícil de verdad: cómo se evita que dos componentes vean estados distintos del mismo dato durante un render concurrente. Ahí aparece el hook que el propio React acabó incorporando para resolver ese problema en general, y entender por qué existe explica una década de sutilezas sobre suscripciones externas. El tercer escalón es la librería de selectores memoizados, corta y llena de decisiones de diseño discutibles y bien discutidas, sobre todo en lo relativo al tamaño de la cache y a las claves débiles.

Los escritos de quienes lo construyeron

Una peculiaridad de este ecosistema, poco frecuente en el oficio, es que sus autores escribieron mucho, escribieron bien y escribieron sobre todo cuando se habían equivocado. Leer esos textos cambia la relación con las herramientas porque devuelve las decisiones a su contexto: casi todo lo que hoy parece arbitrario fue una respuesta razonada a una restricción concreta que se puede reconstruir.

ℹ️
Qué buscar y qué leer en cada fuente

No se trata de leerlo todo, sino de leer con una pregunta en la mano.

Fuente Qué encontrarás La pregunta que responde
Ensayos del creador de Redux Textos que desaconsejan su propia librería y explican cuándo no usarla Por qué la moderación es parte del diseño
Escritos del mantenedor actual Historia del enlace con React, criterios de rendimiento, guías idiomáticas Por qué Redux Toolkit es como es
Charla original de Flux en 2014 El problema del contador de mensajes y el rechazo del enlace bidireccional Qué dolor originó todo esto
Arquitectura de Elm Modelo, mensaje y actualización sin ninguna herencia orientada a objetos Cuál es la forma pura del patrón
Autores de las librerías ligeras Diseño de átomos, proxies y stores mínimos, con sus renuncias explícitas Qué se gana y qué se pierde al aligerar

Hay dos textos que conviene destacar por lo que enseñan sobre el oficio más que sobre la librería. El primero es el ensayo en el que el propio creador de Redux argumenta que probablemente no lo necesitas, publicado cuando su adopción estaba en el punto más alto. El segundo es la serie de artículos del mantenedor actual explicando por qué se abandonó el patrón de conexión por componentes de orden superior, por qué se adoptó Immer pese a la doctrina de la inmutabilidad manual y por qué se acabó incluyendo una capa de cache dentro de una librería que decía no ser una librería de datos. Los tres cambios contradicen posiciones defendidas antes por el mismo proyecto, y están documentados con sus motivos.

💡
Leer para reconstruir el razonamiento, no para copiar la conclusión

La forma productiva de leer estos textos es detenerse en cada recomendación y preguntarse qué restricción la produjo, porque las conclusiones caducan con la restricción y el razonamiento no. Cuando un artículo de hace ocho años dice que hay que escribir constantes de acción en un archivo aparte, la conclusión es hoy inútil, pero el razonamiento —que los identificadores repetidos a mano producen errores silenciosos que ninguna herramienta detecta— sigue vigente y hoy lo resuelve el sistema de tipos. Quien retiene la conclusión acaba escribiendo archivos de constantes en 2026; quien retiene el razonamiento reconoce el mismo problema cuando reaparece con otro disfraz, que es lo que efectivamente ocurre cada pocos años.

Hacia dónde va el estado en la web

Tres corrientes están moviendo el problema, y ninguna de las tres es una librería nueva. Conviene mirarlas por separado porque afectan a capas distintas del modelo mental y se pueden combinar entre sí.

flowchart TD
HOY[estado en el cliente en 2026] --> A[componentes y acciones de servidor]
HOY --> B[signals como capa de deteccion]
HOY --> C[motores de sincronizacion y datos locales]
A --> A1[menos cache en el cliente y mas datos en el render]
B --> B1[misma arquitectura con notificacion mas fina]
C --> C1[el cliente vuelve a ser dueno de la verdad]
C1 --> D[reaparece el problema original con otra escala]
style HOY fill:#89b4fa,color:#11111b
style D fill:#f38ba8,color:#11111b

La primera corriente es el desplazamiento del estado hacia el servidor. Los componentes de servidor y las acciones de servidor se llevan una parte del trabajo que antes exigía cache en el cliente: si los datos llegan ya resueltos en el render y la mutación se declara como una función que corre en el servidor, desaparecen muchas de las razones para tener una copia local con su ciclo de vida. Lo que queda en el cliente después de ese desplazamiento es, precisamente, lo que las lecciones anteriores llamaban estado de cliente compartido, más las actualizaciones optimistas y las transiciones pendientes que el propio framework ha empezado a modelar con hooks propios.

La segunda corriente son las signals, que se han extendido a la vez por casi todos los ecosistemas y tienen incluso una propuesta de estandarización en el lenguaje. Es importante leerlas por lo que son: un cambio en la capa de detección de cambios y de notificación, no un sustituto de la arquitectura. Una signal resuelve mejor el problema de enterarse de que algo cambió con grano fino; no dice nada sobre quién posee el dato, quién puede escribirlo ni dónde viven los efectos. Por eso siguen apareciendo stores construidos encima de signals, y por eso quien las interpretó como el fin de los gestores de estado lleva tiempo desconcertado.

La tercera es la más interesante a largo plazo y la menos comentada: los motores de sincronización y las arquitecturas con datos locales, con sus estructuras de datos que convergen sin conflicto y sus bases replicadas en el navegador. Su promesa es que la aplicación escriba siempre en local y la sincronización ocurra por debajo, lo que devuelve al cliente la propiedad de la verdad que la corriente del servidor le estaba quitando. Si esa promesa se cumple a escala, el problema del estado no desaparece: vuelve con más fuerza, porque un cliente que es dueño de datos compartidos con otros clientes necesita exactamente lo que este track ha estado enseñando —cambios como valores, transiciones puras, historial inspeccionable— y lo necesita con garantías más duras.

⚠️
Cómo distinguir una corriente de una ola

Cada dos años aparece algo que se presenta como el fin del estado en el cliente, y conviene tener un criterio para no reaccionar a todas. Una corriente cambia dónde vive el problema o quién es el dueño de la verdad; una ola cambia la sintaxis con la que se expresa la misma solución. Las tres de esta lección son corrientes: la primera mueve datos al servidor, la segunda cambia el mecanismo de notificación, la tercera devuelve la propiedad al cliente. En cambio, una librería nueva que ofrece la misma arquitectura con menos líneas es una ola: puede valer la pena adoptarla, pero no exige revisar el plano ni reaprender nada. Aplicar esa distinción antes de invertir tiempo es lo que separa mantenerse al día de perseguir novedades.

📝
Las tres corrientes no se excluyen: se apilan

Es tentador leerlas como candidatas a sustituirse entre sí, y sería un error de lectura. Una misma aplicación puede resolver sus datos de lectura con componentes de servidor, notificar sus cambios de cliente con signals y mantener un módulo con datos locales sincronizados para la parte que debe funcionar sin red. Las tres capas conviven porque atacan preguntas distintas del modelo mental: la primera decide de quién es la verdad, la segunda cómo se entera quien lee, la tercera cómo se reconcilian dos verdades que divergieron. Cuando alguien afirma que una de ellas hace innecesarias a las demás, casi siempre está confundiendo dos de esas preguntas, y comprobar cuál es la confusión resulta un ejercicio bastante rápido de diagnóstico.

Un plan de estudio que no caduca

Un plan organizado por herramientas caduca con ellas; uno organizado por problemas dura lo que dure el problema, que en este caso es indefinido. La propuesta de cierre es un plan de cuatro movimientos, pensado para repetirse en ciclo y no para completarse una vez.

📖

Leer un núcleo al año

Un código fuente pequeño y completo cada año: el de Redux, el de un store ligero, el de una librería de memoización. Leer entero enseña más que hojear diez.

🔨

Construir la pieza a mano

Escribir tu propio store con suscripciones, tu propio middleware y tu propio selector memoizado. Nada revela un malentendido tan rápido como implementarlo.

🗺️

Mapear un stack ajeno

Cada cierto tiempo, rellenar las cuatro preguntas —dueño, escritura, efectos, lectura— en un ecosistema que no usas. Mantiene el modelo portable.

✍️

Escribir la decisión

Documentar cada elección de estado con su motivo y su señal de revisión. En un año, ese registro vale más que cualquier artículo que hayas leído.

// El ejercicio del segundo movimiento, con sus dos trampas marcadas.
function memoizarUno<A extends unknown[], R>(fn: (...a: A) => R, iguales = Object.is) {
  let ultimos: A | null = null
  let salida: R
  return (...args: A): R => {
    const mismo = ultimos !== null
      && ultimos.length === args.length
      && args.every((v, i) => iguales(v, ultimos![i])) // trampa 1: comparar por posicion
    if (mismo) return salida
    ultimos = args
    salida = fn(...args)   // trampa 2: cache de tamano uno, inutil si alternas argumentos
    return salida
  }
}

El movimiento más infravalorado de los cuatro es el segundo. Implementar un store con suscripciones, un ensamblado de middleware y un selector memoizado ocupa una tarde y produce una comprensión que ninguna cantidad de lectura consigue, porque obliga a tomar todas las decisiones pequeñas que la documentación omite: qué pasa si alguien se desuscribe durante la notificación, qué se compara y con qué profundidad, cuándo se invalida la cache. Esas decisiones pequeñas son, casi siempre, el contenido real de las librerías que usamos.

El problema es más antiguo que la web y va a sobrevivirte: lo que puedes acumular es criterio, no catálogo

Conviene cerrar el track situando lo aprendido en la escala temporal correcta, porque esa escala es la que determina qué tiene sentido seguir estudiando. El problema del que se ha ocupado este material —varios agentes modificando concurrentemente un estado compartido, y alguien que después necesita entender por qué ese estado es el que es— no es un problema de las interfaces de usuario ni de la web ni de esta década: es una de las formas fundamentales del problema de la coordinación, y se lleva estudiando con distintos nombres desde que existen los sistemas concurrentes, mucho antes de que hubiera navegadores. Las bases de datos lo resolvieron con registros de transacciones, los sistemas distribuidos con registros replicados y ordenamientos parciales, los editores colaborativos con transformaciones operacionales y después con estructuras que convergen sin conflicto, los sistemas de control de versiones con grafos de cambios inmutables. Cuando en 2014 unos ingenieros se encontraron con un contador de mensajes que mentía, no descubrieron un problema nuevo: redescubrieron uno viejo en un entorno donde aún no se había planteado, y aplicaron —seguramente sin saber cuánta genealogía tenía— la misma familia de respuestas que se había ido decantando en todos los demás sitios. Esto tiene una consecuencia práctica que debería gobernar cómo empleas tu tiempo a partir de mañana: el catálogo de herramientas que hoy conoces al detalle tiene una vida media de unos tres años y la tendrá siempre, porque su renovación no es un accidente sino el funcionamiento normal de un ecosistema sano; en cambio, la capacidad de mirar un sistema desconocido y preguntar quién posee este dato, quién tiene derecho a escribirlo, dónde se aísla lo impuro y cómo se entera quien lee, no ha caducado en cincuenta años y no va a caducar durante tu carrera. Así que el consejo con el que se cierran estos veintitrés niveles no es que sigas la evolución de ninguna librería, sino que cada vez que aparezca una nueva la uses como lo que realmente es: una ocasión más de ver el mismo problema antiguo desde un ángulo distinto, y por tanto de entenderlo un poco mejor de lo que lo entendías antes. Quien acumula catálogo empieza de cero en cada ola y siempre va tarde; quien acumula criterio llega a cada ola sabiendo ya casi todo lo que importa, y solo tiene que aprender los nombres.

⚔️ Convierte el final del track en el principio de una práctica
  1. Lee entero el núcleo de Redux en el orden propuesto: composición, middleware, store y composición de reducers. Anota tres decisiones que no habrías tomado y por qué.
  2. Antes de mirar el original, reescribe de memoria el ensamblado del middleware y compáralo. Las diferencias son tu mapa de lagunas.
  3. Implementa a mano un store con suscripciones, un middleware de registro y un selector memoizado con cache de tamaño uno. Documenta las decisiones pequeñas que tuviste que tomar.
  4. Elige tres textos de los autores, uno de ellos anterior a 2018, y extrae de cada uno la restricción que produjo su recomendación. Marca cuáles siguen vigentes.
  5. Investiga una de las tres corrientes hasta poder explicar qué parte del modelo mental cambia y qué parte deja intacta. Clasifícala como corriente o como ola con el criterio de la lección.
  6. Escribe la primera entrada de tu registro de decisiones de estado: qué elegiste, por qué, qué señal te haría cambiar y en qué fecha lo revisarás.