Nel film Interstellar, c'è una scena angosciante in cui i protagonisti scendono sul pianeta di Miller. A causa dell'estrema gravità del buco nero vicino, subiscono una brutale dilatazione temporale: un'ora passata su quel pianeta equivale a 7 anni sulla Terra.

Ogni volta che vedo quella scena, penso ai miei utenti quando cliccano "Salva" su una mia applicazione web mal ottimizzata.

La percezione del tempo non è assoluta, né in astrofisica né in UI/UX Design. Per un server backend, elaborare una richiesta al database in 800 millisecondi è un trionfo di efficienza. Ma per un essere umano che fissa uno schermo congelato aspettando che un bottone cambi colore, 800 millisecondi sono un'eternità frustrante.

Il Fango: L'Attesa Bloccante

Nel mio primo vero progetto freelance (un gestionale per un magazzino), dovevo implementare il pulsante "Metti nei Preferiti".

Seguendo alla lettera i tutorial di base, ho implementato il flusso classico: l'utente clicca, mostro un loader, aspetto la risposta del server, se va bene aggiorno l'interfaccia.

// Bad Code: Sottomettere l'utente alla dilatazione temporale
async function handleLikeRushed() {
  setLoading(true); // Blocco l'interfaccia. Inizia l'ansia.
  
  try {
    // Il server è in America, il database è lento. Passa 1 secondo.
    await api.post('/like', { itemId });
    setIsLiked(true); // Finalmente, dopo "7 anni", l'icona si colora.
  } catch (e) {
    showError();
  } finally {
    setLoading(false);
  }
}

Cosa facevano gli utenti del magazzino? Cliccavano. Vedevano la rotellina girare. Si infastidivano per la latenza, pensavano che non avesse preso il click, e cliccavano di nuovo. Inviavano cinque richieste identiche al backend prima ancora che la prima fosse risolta, mandando in tilt il database.

L'Ingegneria: Optimistic UI

L'ingegneria moderna del frontend ha inventato una soluzione per "ingannare" questa dilatazione temporale: la Optimistic UI.

Il trucco è semplice ma psicologicamente devastante: assumi (ottimisticamente) che il server dirà di sì, e aggiorni l'interfaccia immediatamente. L'azione sembra istantanea. Nel frattempo, in background (nello spazio profondo), la richiesta viaggia verso il server. Se miracolosamente dovesse fallire, farai un "rollback" annullando l'azione.

// Good Code: Aggiornamento Ottimistico
async function handleLikeEngineering() {
  // 1. Salvo lo stato precedente in caso di disastro
  const previousState = isLiked;
  
  // 2. Inganno il tempo: aggiorno IMMEDIATAMENTE la UI.
  // L'utente percepisce zero latenza. È felice.
  setIsLiked(!isLiked); 

  try {
    // 3. Comunico col buco nero (il backend) in modo silenzioso
    await api.post('/like', { itemId, like: !isLiked });
  } catch (error) {
    // 4. Rollback: se l'universo ci rema contro, ripristino il passato.
    setIsLiked(previousState);
    toast.error("Ops, salvataggio fallito.");
  }
}

Il Takeaway

Il tempo è relativo. Una latenza di mezzo secondo è invisibile nei log di sistema, ma è uno scoglio enorme per l'esperienza utente.

Quando progettate un'interfaccia, smettetela di tenere i vostri utenti in ostaggio sul pianeta di Miller. Applicate l'Optimistic UI alle azioni reversibili (come i like, le spunte, i toggle). Date l'illusione di una velocità sovrumana; lasciate che sia il codice asincrono sotto il cofano a fare i conti con i buchi neri della rete.