wandres.dev
ACTUALIZACIONES OPTIMISTAS · sincronizar con el servidor

Qué es una actualización optimista

Una actualización optimista muestra el resultado esperado de una mutación antes de que el servidor lo confirme, cerrando el abismo de latencia que separa la acción del usuario de la respuesta de la red. Esta lección define la técnica como una predicción provisional promovida a verdad temporal, explica por qué la estrategia pesimista de esperar con un spinner resulta insuficiente cuando cada interacción cuesta cientos de milisegundos, y fija la condición que la hace posible: que el resultado sea calculable en el cliente sin consultar al servidor. Sitúa el optimismo en su linaje conceptual —el control de concurrencia optimista de las bases de datos y la compensación de latencia de los primeros frameworks reactivos— y traza la frontera entre responsividad y correctitud que las cuatro lecciones siguientes exploran en detalle.

⏱ 16 min

Entre el instante en que un usuario pulsa un botón y el instante en que el servidor confirma que la operación tuvo éxito hay un abismo de tiempo: la latencia de la red. Cien, doscientos, quinientos milisegundos en los que, si la interfaz espera de brazos cruzados con un spinner, la aplicación se siente lenta y torpe. Una actualización optimista rellena ese abismo con una predicción: en lugar de aguardar la confirmación, la interfaz pinta de inmediato el resultado que espera obtener, apostando a que la operación tendrá éxito. El corazón de “me gusta” se enciende antes de que el servidor lo sepa; el mensaje aparece en el chat antes de salir del dispositivo. Es una mentira controlada y casi siempre cierta, y es exactamente lo que separa las interfaces que responden a la velocidad del pensamiento de las que responden a la velocidad de la red.

🎯 Al terminar esta lección sabrás
  • Definir la actualización optimista como la predicción del resultado mostrada antes de la confirmación del servidor.
  • Entender por qué la estrategia pesimista de esperar con un spinner resulta insuficiente frente a la latencia.
  • Reconocer la condición que la hace posible: que el resultado sea calculable en el cliente sin preguntar al servidor.
  • Situar la técnica en su origen conceptual: el control de concurrencia optimista y la compensación de latencia.

El abismo de la latencia

El modelo pesimista es el instinto por defecto: el usuario actúa, disparas la petición, muestras un spinner, y solo cuando la respuesta llega actualizas la interfaz. Es correcto por construcción —nunca enseñas algo que el servidor no ha confirmado— pero paga ese rigor con tiempo. La investigación clásica sobre percepción humana marca una frontera dura alrededor de los cien milisegundos: por debajo, una respuesta se siente instantánea; por encima, el usuario percibe una demora y su atención empieza a fugarse. Un viaje de ida y vuelta a un servidor rara vez baja de esa cifra, y bajo una red móvil mediocre la supera con holgura. La estrategia pesimista, por tanto, condena cada interacción a sentirse más lenta que el pensamiento que la originó.

La actualización optimista invierte el orden. En lugar de actuar al final —cuando el servidor responde— actúa al principio: pinta el resultado esperado de inmediato y lanza la petición en segundo plano.

// Pesimista: la UI espera a la red
async function darMeGustaPesimista() {
  setCargando(true);
  const real = await api.darMeGusta(postId); // el usuario espera aqui
  setMeGusta(real.meGusta);
  setCargando(false);
}

// Optimista: la UI se adelanta a la red
async function darMeGustaOptimista() {
  setMeGusta(true);            // 1. predice y pinta ya
  await api.darMeGusta(postId); // 2. confirma despues, en segundo plano
}

La diferencia no es de rendimiento medido en el servidor —ambas peticiones tardan lo mismo— sino de rendimiento percibido, que es el único que el usuario siente.

📝
La regla de los cien milisegundos

La frontera no es un capricho de diseñadores. Desde el trabajo de Miller en 1968 sobre tiempos de respuesta hasta las síntesis posteriores de Nielsen, la literatura coincide: por debajo de una décima de segundo el usuario percibe el sistema como una prolongación de su propia voluntad, sin intermediación consciente; por encima de un segundo, el hilo de pensamiento se rompe. El optimismo existe para meter el feedback dentro de esa décima de segundo aunque la red tarde diez o cincuenta veces más en responder.

La apuesta: predecir sin preguntar

El optimismo no es gratis ni universal: descansa sobre una condición estricta. Para mostrar el resultado antes de que el servidor lo confirme, tienes que ser capaz de calcularlo en el cliente sin consultarlo. Alternar un “me gusta” cumple la condición de sobra: sabes que el nuevo estado es true y que el contador sube en uno. Añadir una tarea a una lista también: conoces su texto y su posición. Pero hay resultados que el cliente no puede predecir —el identificador real que asignará la base de datos, una marca de tiempo del servidor, un total recalculado a partir de datos que no tienes— y ahí el optimismo es parcial o directamente imposible.

La frontera se ve mejor en código. Cuando el resultado depende solo de datos que el cliente ya posee, la predicción es una función pura del estado actual; cuando depende de algo que vive únicamente en el servidor, no existe función que la produzca.

// Predecible: funcion pura del estado que ya tienes
function trasAlternar(post: Post): Post {
  return {
    ...post,
    meGusta: !post.meGusta,
    likes: post.likes + (post.meGusta ? -1 : 1),
  };
}

// Impredecible: el id real y la fecha de creacion los pone el servidor.
// No hay forma de calcularlos en el cliente, solo esperarlos.
// const creada = await api.crear(texto);
ℹ️
Optimista sobre lo predecible, honesto sobre lo demas

La regla operativa es sencilla: sé optimista con la parte del resultado que puedes calcular, y espera al servidor para la parte que no. Puedes pintar de inmediato la tarea nueva con un identificador temporal y su texto, pero deja como pendiente el campo que el servidor rellena. El optimismo no obliga a fingir el resultado entero: obliga a fingir solo aquello de lo que estás razonablemente seguro.

Y esa seguridad es, en el fondo, estadística. El optimismo apuesta a la tasa base: la inmensa mayoría de las mutaciones tienen éxito. Pulsar “me gusta” casi nunca falla; guardar un borrador casi siempre funciona. Optimizas para ese noventa y nueve por ciento y tratas el uno por ciento restante —el fallo— como una excepción que hay que manejar con cuidado, no como el caso común que dicta el diseño. Las tres lecciones siguientes son, precisamente, el manejo disciplinado de ese uno por ciento.

flowchart TD
U[usuario pulsa] --> P[camino pesimista]
U --> O[camino optimista]
P --> PS[spinner y espera de red]
PS --> PR[respuesta llega y se pinta]
O --> OR[render inmediato de la prediccion]
OR --> OB[peticion viaja en segundo plano]
style PS fill:#f38ba8,color:#11111b
style OR fill:#a6e3a1,color:#11111b

La ventana de incertidumbre

Entre la predicción y la confirmación se abre una ventana de tiempo en la que un dato vive en un limbo: se muestra al usuario, pero no está garantizado. Modelar ese limbo de forma explícita, en lugar de fingir que no existe, es lo que separa un optimismo robusto de uno frágil. Un dato optimista no tiene dos estados sino tres, y nombrarlos como un tipo revela de golpe todo el trabajo que queda por hacer en el resto del nivel.

// El ciclo de vida de un dato optimista, hecho tipo
type Optimista<T> =
  | { estado: "confirmado"; valor: T }             // el servidor dijo si
  | { estado: "pendiente"; valor: T; previo: T }   // prediccion + snapshot
  | { estado: "fallido"; valor: T };               // hay que revertir a previo

Ese previo que aparece en el estado pendiente no es decorativo: es la memoria del pasado que hará posible la reversión, y le dedicamos una lección entera. El paso de pendiente a confirmado es la reconciliación; el paso a fallido es el rollback; y qué ocurre cuando dos clientes escriben a la vez sobre el mismo dato es el problema de los conflictos. Las cuatro lecciones restantes no son más que las transiciones de esta pequeña máquina de estados, estudiadas una a una.

Optimista frente a pesimista

Conviene ver las dos estrategias como los extremos de un mismo eje, no como opciones enemigas. El pesimismo prioriza la correctitud: no muestra nada que no esté confirmado, al precio de la demora. El optimismo prioriza la responsividad: muestra la verdad probable ahora y la reconcilia después, al precio de una divergencia temporal entre lo que ve el usuario y lo que sabe el servidor. Entre ambos hay matices —deshabilitar el control mientras se guarda, mostrar el resultado pero con una señal discreta de “guardando”— y elegir el punto correcto del eje es una decisión de diseño, no un dogma.

🐢

Pesimista

Prioriza la correctitud: no muestra nada sin confirmar. A salvo de mentiras, pero cada interacción arrastra la latencia entera de la red antes de responder.

🐇

Optimista

Prioriza la responsividad: muestra la verdad probable ya y la reconcilia después. Veloz, al precio de una divergencia temporal que hay que reparar con cuidado.

La elección entre uno y otro no es de temperamento del programador, sino de la naturaleza de la operación: cuánto tarda, cuán predecible es su resultado, cuán reversible es su fracaso y cuánto le importa al usuario que sea inmediata. Guardar la posición de un cursor pide optimismo sin dudarlo; transferir dinero pide lo contrario.

El punto medio más habitual combina ambas actitudes: pinta el resultado de inmediato pero bloquea el control mientras la confirmación viaja, para impedir un segundo envío antes de conocer el desenlace del primero.

// Punto intermedio: optimista pero con el control bloqueado hasta confirmar
async function guardar(nuevo: Valor) {
  setGuardando(true); // bloquea el boton: evita el doble envio
  setValor(nuevo);    // pinta ya, sin esperar a la red
  try {
    await api.guardar(nuevo);
  } finally {
    setGuardando(false); // libera al confirmar o al fallar
  }
}
💡
El optimismo no es siempre la respuesta correcta

Hay operaciones donde adelantarse es un error. Un pago, un borrado con consecuencias en cascada, cualquier acción irreversible o de alto coste si la predicción resulta falsa: en esos casos, la ansiedad de un spinner honesto es preferible a la falsa calma de un optimismo que luego hay que desmentir. La última lección del nivel dedica su cierre a delimitar cuándo NO ser optimista; por ahora basta con retener que el optimismo es una herramienta afilada, no un ajuste que se activa en todas partes.

El optimismo redefine donde vive la verdad, aunque sea por un instante

Lo que hace profunda a esta técnica no es el truco visual de pintar antes de tiempo, sino lo que implica sobre la naturaleza de la verdad en una aplicación distribuida. En el modelo pesimista la verdad vive siempre en un solo sitio —el servidor— y el cliente es un espejo pasivo que solo refleja lo ya confirmado. La actualización optimista rompe esa jerarquía: promueve la predicción del cliente a la categoría de verdad provisional, una verdad con fecha de caducidad que gobierna la interfaz durante los milisegundos que tarda el servidor en pronunciarse. Durante esa ventana coexisten dos verdades —la provisional del cliente y la canónica que aún viaja— y la aplicación apuesta a que coincidirán. Esta idea no nació en el frontend: es la misma que en 1981 Kung y Robinson formularon como control de concurrencia optimista, donde una transacción procede como si nadie más tocara los datos y solo valida el conflicto al final; es la misma que la replicación optimista de los sistemas distribuidos, donde las réplicas divergen a sabiendas y convergen después. La interfaz optimista es la traducción de ese principio al terreno de la percepción humana: en vez de proteger la consistencia haciendo esperar al usuario, la sacrifica temporalmente a cambio de responsividad, y confía en repararla cuando llegue la verdad de verdad. Entender esto reordena el resto del nivel, porque cada técnica que sigue —reconciliar, revertir, resolver conflictos— no es más que la maquinaria que hace segura y honesta esa promoción temporal de la predicción a verdad. Sin esa maquinaria, el optimismo es una mentira; con ella, es la forma más avanzada de respeto por el tiempo del usuario.

⚔️ Distingue lo predecible de lo que no lo es
  1. Toma tres mutaciones de tu aplicación —un “me gusta”, una tarea nueva, un pago— y clasifícalas por cuán predecible es su resultado en el cliente.
  2. Para cada una, escribe qué parte del resultado podrías pintar de inmediato y qué parte tendrías que esperar del servidor.
  3. Reimplementa el “me gusta” en su versión pesimista con spinner y en su versión optimista, y mídete a ti mismo la diferencia de sensación con la red artificialmente lenta.
  4. Identifica una operación de tu aplicación donde el optimismo sería un error y argumenta por qué la espera honesta es preferible allí.
  5. Estima la tasa de fallo real de una de tus mutaciones y decide si el uno por ciento excepcional justifica la maquinaria de reconciliación y reversión que viene a continuación.
  6. Modela una de tus mutaciones con el tipo Optimista de tres estados y comprueba qué campo hace de snapshot; ese campo será el protagonista de la lección sobre rollback.