Javier apretó “Sync” y se quedó mirando la pantalla. El botón había cambiado a una sola palabra: “Syncing…”. Y después, nada. Ni un número, ni una barra, ni el más mínimo gesto de que algo estuviera ocurriendo al otro lado. Solo tres puntitos suspensivos que podían significar dos cosas exactamente opuestas: “estoy trabajando, dame un segundo” o “me caí y no te lo pienso avisar”.
Esa duda —esa grieta pequeña de incertidumbre— es la historia de hoy.
LabelLoop es el clasificador de Gmail que Javier está construyendo en público. La idea es simple de contar y difícil de hacer bien: en vez de imponerte una taxonomía prefabricada, aprende las etiquetas que tú ya usas. En la casilla del piloto conviven 33 etiquetas, 18 de ellas inventadas a mano por el propio usuario: 💼 Trabajo, 🏠 Vida Personal, 💰 Finanzas/Inversiones, 🚀 Emprendimiento, ⚖️ Legal & Trámites, 📚 Lectura & Newsletters. LabelLoop tiene que mirar esa casilla, entenderla, y ordenar lo que llega según tu cabeza, no la de un ingeniero.
El problema es que ese “mirar la casilla” es lento. Cuando aprietas Sync, la app trae la lista de correos no leídos y después hace una llamada a la API de Gmail por cada mensaje —del orden de cien, una detrás de otra— antes siquiera de empezar a generar los embeddings que le dan sentido. Eso toma minutos. Minutos en los que el botón decía “Syncing…” y se quedaba ahí, mudo.
La preocupación de Javier fue textual: “si se queda en Syncing… mucho tiempo, el usuario pensará que se ha quedado pegado.”
El síntoma engañaba
Acá viene lo interesante, y lo primero que hubo que aceptar: la app no estaba colgada. En ningún momento. El servidor respondía 200, el trabajo avanzaba, los correos se traían, los embeddings se calculaban. Técnicamente, todo funcionaba sin un solo error.
El problema no era técnico. Era de comunicación.
Y esa distinción es más incómoda de lo que suena, porque un proceso que funciona pero no informa se ve idéntico a uno que se murió. Desde la vereda del usuario no hay forma de distinguirlos: los dos muestran “Syncing…” y los dos no dicen nada más. La ansiedad de Javier no era paranoia. Era una lectura perfectamente racional de una pantalla que, sin querer, había dejado de hablar.
Así que el arreglo no fue hacer el sync más rápido. Traer cien correos de Gmail toma lo que toma; pelear contra eso era pelear contra el tiempo que se demoran cien llamadas puestas una detrás de otra. El arreglo fue hacerlo honesto sobre su avance.
Una barra que no puede mentir
La solución partió el sync en lotes cortos que el propio navegador orquesta: primero un plan (¿cuántos correos hay que traer?), después los lotes uno a uno, y al final un finalize. Cada vez que un lote vuelve confirmado por el servidor, el porcentaje sube. Nunca antes.
Ese es el punto que Javier quiso dejar clavado: la barra muestra trabajo realmente hecho, no una animación decorativa que sube sola para entretener la espera. Muchas barras de progreso en internet son mentiras piadosas —se llenan solas, se clavan en 99%, fingen. Esta no puede. El número que ves es un conjunto de lotes que el servidor ya confirmó. La barra, por diseño, no tiene permitido mentir.
Suena limpio. Y aquí es donde la cosa se puso interesante de verdad.
Construir una barra honesta está lleno de formas de mentir
Antes de escribir una línea de código, se hizo una pasada de diseño adversarial: sentarse a buscar todas las maneras en que esta barra, tan bien intencionada, terminaría mintiendo por accidente. Aparecieron varias. Tres importaron de verdad.
La primera fue la bandeja al día. Resulta que el caso más común de un sync que corres seguido no es “tengo cien correos nuevos”, sino “no tengo ninguno”. Cero correos nuevos. Y ese caso, el más frecuente, era también el más fácil de romper: con un chequeo ingenuo, la barra quedaba girando para siempre sobre un trabajo que ya estaba terminado antes de empezar. Girando sobre la nada. Hubo que enseñarle a la app a distinguir “cero conocido” —sé que no hay nada que hacer— de “total desconocido” —todavía no sé cuánto hay—, y a decirlo con todas sus letras: “Todo al día.” Nada más tranquilizador que una barra que sabe cuándo no tiene que aparecer.
La segunda fue no sumar nunca el avance a mano. Si un lote falla y se reintenta, y tú vas acumulando el progreso sumando cada vuelta, ese lote se cuenta dos veces y la barra termina mostrando “112 de 100”. Y una barra que muestra 112% es peor que no tener barra: una barra evidentemente falsa destruye de un tirón toda la confianza que la barra venía a construir. La solución fue no sumar nunca, sino derivar el número desde el conjunto de lotes confirmados. El numerador no crece: se recalcula desde la verdad.
La tercera fue el tamaño de los lotes. Lotes grandes habrían reintroducido exactamente la ansiedad que la barra venía a curar: quedaría inmóvil veinte segundos entre salto y salto, y veinte segundos quietos es otra vez “¿se murió?”. Lotes chicos, en cambio, más una etiqueta que se mueve al lanzar el lote y no al confirmarlo, dan dos señales distintas: una rápida (“mira, algo está pasando ahora mismo”) y una honesta (“y esto es lo que llevo de verdad”). Movimiento inmediato para el corazón, verdad confirmada para la cabeza.
El resultado es que hoy el sync dice cosas como: “Trayendo tus correos… 47 de 124 · 38%.” Un número que no se lo inventó nadie.
La reacción de Javier cuando lo vio andar fue corta y sin adornos: “¡La barra funciona de maravilla!”
La honestidad como principio de diseño
Lo que me quedo pensando —y por eso lo escribo— es que ninguna de estas tres decisiones era sobre velocidad. El sync sigue tomando lo que toma. Lo que cambió fue la relación entre la app y la persona que la mira esperando.
Una barra que salta, que se clava en 99%, que muestra 112%, no es solo un bug feo. Es una traición pequeña a la confianza que esa misma barra venía a construir. Y en un producto que te pide meter la mano en tu Gmail y ordenarte la vida, la confianza no es un lujo: es todo lo que tienes.
La lección es más ancha que LabelLoop. Una espera menos dolorosa no es una barra más rápida. Es una barra que no te miente sobre dónde está.