wandres.dev
NO ES OFFLINE-FIRST · la taxonomía honesta

Offline-first: una promesa de disponibilidad

Offline-first nace de la web móvil y de los service workers: es una promesa de disponibilidad que dice que la interfaz responde aunque la red falle, y no dice nada sobre quién posee los datos ni sobre dónde vive la fuente de verdad.

⏱ 17 min

El nivel anterior te dio los ideales. Este nivel te da algo menos inspirador y más urgente: el vocabulario. Porque en cuanto sales del manifiesto y entras en la conversación real del sector, cuatro palabras empiezan a usarse como si fueran intercambiables —offline-first, local-first, sync-first, app nativa— y no lo son. Confundirlas no es un desliz académico: es lo que hace que un equipo prometa soberanía del dato cuando lo que ha construido es una caché resistente, o que rechace una arquitectura por cara cuando en realidad nunca necesitó pagar ese precio. Empezamos por la más antigua y la peor entendida. Offline-first no nació en un laboratorio de investigación sino en la trinchera de la web móvil de mediados de los años diez, y significa exactamente una cosa: que la aplicación siga siendo utilizable cuando la red no coopera. Es una afirmación sobre la disponibilidad de la interfaz, no sobre la arquitectura de los datos, y esa distinción es el cimiento de todo lo que viene después.

🎯 Al terminar esta lección sabrás
  • Fijar la definición exacta de offline-first y su origen histórico en la web móvil.
  • Entender el service worker como el mecanismo que hizo la promesa técnicamente posible.
  • Separar la disponibilidad de lectura de la disponibilidad de escritura, que son problemas de dificultad radicalmente distinta.
  • Comprender por qué offline-first es una propiedad de la capa de entrega y no del modelo de datos.
  • Detectar la inferencia inválida que salta de la disponibilidad a la propiedad del dato.

De la web móvil a la red como mejora progresiva

El término se acuña alrededor de 2013, en un momento muy concreto de la historia de la web. El tráfico se estaba mudando al móvil, y el móvil trajo consigo una realidad que el escritorio había ocultado durante una década: la conexión no es un interruptor de dos posiciones. Entre estar conectado y estar desconectado vive un continuo enorme y hostil —el túnel del metro, el ascensor, el avión, el hotel con portal cautivo, la cobertura de un solo punto que responde a los tres segundos— que la web de escritorio nunca tuvo que modelar. El navegador, mientras tanto, seguía asumiendo lo contrario: una petición o se resuelve o falla, y si falla se muestra el dinosaurio.

Ese continuo tiene además una propiedad que lo hace peor que la desconexión limpia: la red intermitente miente. Una conexión caída devuelve un error rápido y permite reaccionar; una conexión de un solo punto acepta la petición, la retiene treinta segundos y luego falla, o peor, la entrega al servidor y pierde la respuesta. La aplicación no puede distinguir entre lo que no llegó y lo que llegó pero cuya confirmación se perdió, y esa ambigüedad es la raíz de una familia entera de fallos que ninguna estrategia de caché resuelve.

📝
El nombre importa más de lo que parece

El sufijo first en este vocabulario no significa preferente ni prioritario, significa primero en el orden de diseño. Mobile-first no quiere decir que el móvil importe más que el escritorio, sino que se diseña la restricción antes que la comodidad. Offline-first significa exactamente lo mismo respecto a la red, y local-first lo significará respecto a la sede del dato. Reconocer que el sufijo denota orden de construcción y no jerarquía de valor evita una parte considerable de las discusiones estériles sobre estos términos, porque revela que son afirmaciones sobre el método, no sobre la importancia.

La respuesta conceptual fue un giro de encuadre que le debe todo a la mejora progresiva. En lugar de tratar la conectividad como el suelo sobre el que se construye la aplicación, offline-first la trata como una capa que se añade encima. La aplicación se diseña primero para el caso sin red, y la red aparece después para enriquecerla: sincronizar, refrescar, traer lo que falta. El nombre lleva el orden dentro: primero lo local, después lo remoto. Es la misma inversión retórica que hizo mobile-first con las pantallas, y por la misma razón: diseñar para el caso restringido produce un sistema que degrada con elegancia, mientras que diseñar para el caso cómodo produce uno que se rompe en cuanto sale del laboratorio.

Conviene subrayar que esto era, en su origen, una postura de diseño de producto antes que una técnica. El movimiento se articuló en artículos, charlas y una comunidad pequeña que insistía en un punto casi moral: dar por hecha la red es una forma de privilegio de infraestructura, y las aplicaciones que lo hacen fallan sistemáticamente para los usuarios con peores condiciones. La primera generación de intentos técnicos fue un fracaso instructivo. El mecanismo declarativo que el navegador ofreció al principio para cachear una aplicación completa resultó tan rígido y con modos de fallo tan opacos que se ganó una reputación tóxica y acabó retirado de la plataforma. La lección quedó: la disponibilidad sin red no se puede declarar, hay que programarla.

Merece la pena detenerse en por qué aquel primer intento fracasó, porque el diagnóstico se aplica a todo lo que viene después. Aquel mecanismo pedía al desarrollador una lista de recursos y prometía encargarse del resto, pero el resto incluía decisiones que ninguna lista puede expresar: cuándo considerar obsoleto lo guardado, qué hacer con una petición que no estaba en la lista, cómo activar una versión nueva sin romper una sesión en curso. Al no poder expresarlas, el navegador las tomaba por su cuenta con una política fija, y esa política era invisible, no negociable y frecuentemente equivocada. La conclusión que la plataforma extrajo —dar código en vez de configuración— define la forma de todo el trabajo posterior en este campo.

Hay un matiz histórico que conviene retener porque explica el sesgo del término. Offline-first se formuló desde la perspectiva de quien construye la interfaz, no de quien diseña el modelo de datos, y ese origen dejó huella en su vocabulario. Habla de recursos, de peticiones, de estrategias de caché, de arranque; no habla de propiedad, de conflicto ni de autoridad. No es que lo omitiera por descuido: es que resolvía otro problema. Muchos de los malentendidos de la última década vienen de aplicar un vocabulario nacido en la capa de entrega a preguntas que pertenecen a la capa de datos.

El service worker: un proxy que tú programas

Lo que convirtió offline-first de aspiración en práctica fue el service worker: un hilo de ejecución que el navegador conserva fuera de la página, sin acceso al DOM, y que se interpone en la salida de red de la aplicación. Toda petición pasa por delante de él, y él decide qué hacer: devolver algo del almacén de respuestas, ir a la red, ir a la red con un plazo y caer a lo guardado si tarda, o inventar una respuesta sintética. No es una caché con reglas configurables; es código tuyo ejecutándose en el camino crítico. Esa es toda la diferencia, y también todo el peligro.

De ahí salen las estrategias que se han vuelto folclore del oficio. Servir primero lo guardado y no ir a la red da la latencia mínima a costa de mostrar datos viejos. Ir primero a la red y usar lo guardado solo como red de seguridad da frescura a costa de depender del peor caso de latencia. Devolver lo guardado de inmediato y revalidar en segundo plano ofrece un compromiso muy citado: respondes ya, y la próxima vez respondes mejor. Ninguna de las tres es correcta en abstracto; cada una es una posición distinta en el intercambio entre frescura y disponibilidad, y elegir es admitir cuál de las dos estás dispuesto a sacrificar.

Estrategia Qué prioriza Qué sacrifica Encaje típico
Lo guardado primero Latencia mínima Frescura Recursos versionados por nombre
La red primero Frescura Peor caso de latencia Datos que caducan rápido
Responder y revalidar Percepción de rapidez Coherencia momentánea Contenido tolerante a lo obsoleto
Solo lo guardado Independencia total Cualquier actualización Activos inmutables

La tabla se lee mejor si notas lo que ninguna fila menciona: en las cuatro, la fuente de la que se revalida sigue siendo el servidor, y lo que varía es únicamente cuándo se le pregunta. La sofisticación de la estrategia no altera esa relación de dependencia; solo la administra mejor. Es la diferencia entre gestionar con destreza una deuda y no tenerla.

Hay además un coste de complejidad que casi nunca se cuenta en las discusiones sobre este mecanismo. Al insertar código propio en el camino de red se introduce un segundo ciclo de vida de despliegue, independiente del de la aplicación, con sus propias versiones, su propia activación diferida y su propia capacidad de servir indefinidamente una versión antigua a un usuario que no cierra la pestaña. La clase de fallo más desconcertante de la web moderna —usuarios atrapados en una versión de hace semanas que ningún despliegue alcanza— nace precisamente ahí. La disponibilidad no es gratis: se paga en superficie operativa.

flowchart LR
UI[interfaz] --> SW[service worker]
SW --> CACHE[almacen local de respuestas]
SW --> NET[red]
NET --> SRV[servidor autoritativo]
CACHE --> UI
style SW fill:#94e2d5,color:#11111b
style SRV fill:#f38ba8,color:#11111b

Conviene añadir que el service worker no es el único almacén implicado, y que confundir las capas produce diagnósticos erróneos. El almacén de respuestas que él gestiona guarda documentos completos indexados por su dirección; el estado estructurado de la aplicación vive en otro sitio, en una base de datos del navegador con índices y transacciones. Una aplicación puede tener un service worker impecable y ninguna durabilidad de datos, porque cachear la interfaz y persistir el estado son problemas distintos resueltos por mecanismos distintos. Muchos productos que se anuncian como capaces de funcionar sin red han resuelto solo el primero.

Observa el diagrama con atención, porque contiene la tesis entera de la lección. El service worker se sitúa entre la interfaz y la red, y puede desconectar por completo el brazo derecho sin que la interfaz se entere. Pero fíjate en dónde sigue estando el nodo autoritativo: al final del camino de red, intocado. El service worker no ha movido la verdad de sitio; ha construido un desvío para cuando el camino hacia la verdad está cortado. Es una obra de ingeniería de tráfico, no una reforma constitucional.

ℹ️
Offline-first es una propiedad observable, no una arquitectura

La prueba de que una aplicación es offline-first se hace desde fuera, sin leer una línea de su código: cortas la red, la abres en frío y observas si arranca y responde. Es una propiedad conductual, verificable con un interruptor. La arquitectura de datos, en cambio, no se puede auditar así: dos aplicaciones que superan idénticamente esa prueba pueden tener modelos de propiedad opuestos. Que la comprobación sea tan barata explica en parte por qué el término se usa tanto y por qué se le atribuyen garantías que nunca prometió.

Leer sin red no es escribir sin red

Aquí está la fractura que casi todas las discusiones sobre offline pasan por alto. Hay dos problemas bajo la misma palabra, y su dificultad no está en la misma escala.

📖

Lectura sin red

Es un problema de caché, y la caché es tecnología madura. Guardas una copia de lo que el servidor dijo, la sirves cuando no puedes preguntar, y el peor fallo posible es mostrar algo obsoleto. Se resuelve con una política de invalidación y una etiqueta honesta en la interfaz.

✍️

Escritura sin red

Es un problema de consenso diferido, y no hay ninguna versión fácil. Aceptas una intención que nadie ha autorizado, la guardas con durabilidad, la reintentas más tarde y tienes que decidir qué haces si el servidor la rechaza, si el mundo cambió mientras esperabas o si el usuario ya cerró la sesión.

🧾

La cola como estructura de datos

Encolar no es una lista de peticiones pendientes: es un registro de intenciones que debe sobrevivir a cierres, reordenarse cuando dependen unas de otras y poder colapsarse cuando el usuario editó diez veces el mismo campo. Diseñarla mal produce duplicados o pérdidas.

🔁

La idempotencia obligatoria

Si un intento puede repetirse tras un fallo ambiguo, cada operación necesita una identidad estable que permita al receptor reconocer que ya la aplicó. Sin eso, el reintento honesto se convierte en el mecanismo que duplica pedidos, mensajes y cargos.

La distancia entre ambas columnas se aprecia mejor midiendo el peor caso. El peor desenlace de una lectura desde caché es que el usuario vea un dato de hace una hora y tome una decisión con información vieja, lo cual es molesto y casi siempre recuperable. El peor desenlace de una escritura encolada es que el usuario crea haber guardado un trabajo de dos horas que el servidor acaba rechazando, y que la aplicación lo descarte sin que él llegue a enterarse. Son fallos de órdenes de magnitud distintos, y por eso merecen presupuestos de diseño distintos.

El mecanismo que la plataforma ofrece para lo segundo —registrar una tarea que el navegador ejecutará cuando vuelva la conectividad, incluso con la pestaña cerrada— resuelve la parte fácil del problema difícil: el transporte. Garantiza que el intento llegue. No garantiza nada sobre su suerte. Entre el momento en que el usuario pulsa y el momento en que el servidor decide hay una ventana que puede durar días, y en esa ventana el estado que la interfaz muestra no es un hecho: es una intención pendiente de juicio. La aplicación puede tratarla con honestidad, marcándola como no confirmada, o puede fingir que ya ocurrió. Casi todas eligen fingir, y de ahí nacen la mitad de los malentendidos que desmontaremos en la tercera lección.

Nota además una asimetría cruel: la cola de escrituras crece cuando la red falla, que es exactamente cuando menos información tienes para validarla. El usuario acumula veinte cambios en un vuelo, y a la llegada esos veinte cambios se enfrentan de golpe a un mundo que se movió sin él. La disponibilidad de escritura, sin una decisión explícita sobre autoridad, no es una funcionalidad: es deuda que se cobra toda junta y en el peor momento.

Hay una tercera categoría que suele quedar fuera del análisis y que en la práctica decide si un producto es utilizable sin red: la lectura de lo que aún no has visto. Una caché de respuestas solo puede servir lo que alguna vez pidió, de modo que un usuario desconectado puede navegar impecablemente por su historial reciente y chocar contra un muro en cuanto abre algo que no había abierto antes. La diferencia entre cachear reactivamente lo consultado y replicar proactivamente un conjunto de trabajo completo es enorme en coste y en experiencia, y es una de las primeras cosas que separa a un producto que tolera la desconexión de uno que fue diseñado para ella.

flowchart TD
A[el usuario actua sin red] --> B[se guarda la intencion con durabilidad]
B --> C[la interfaz muestra el resultado previsto]
C --> D[vuelve la conectividad]
D --> E[se envia la intencion al servidor]
E --> F[aceptada y confirmada]
E --> G[rechazada y hay que decidir]
style G fill:#f38ba8,color:#11111b

El nodo sombreado del diagrama es el que ninguna especificación de plataforma resuelve por ti, y es también el que separa las categorías de todo este nivel. La plataforma te da mecanismos excelentes para llegar hasta el penúltimo paso: almacenamiento duradero, reintento en segundo plano, notificación al volver la red. Lo que ocurre en la última bifurcación no es un problema de infraestructura sino de gobierno del dato, y ninguna herramienta puede decidirlo en tu lugar porque depende de a quién hayas concedido la última palabra.

Disponibilidad no es propiedad

Antes de la conclusión, una precisión sobre el alcance del término que ahorra discusiones. Offline-first no exige que la aplicación sea igual de capaz sin red que con ella; exige que degrade de forma predecible y comunicada en lugar de romperse. Una aplicación que sin conexión deshabilita explícitamente lo que no puede hacer, explica por qué y conserva intacto lo que sí puede, cumple el criterio con nota. Una que finge poder hacerlo todo y falla en silencio lo incumple, aunque técnicamente arranque. El estándar no es la paridad de funciones, es la honestidad del estado degradado.

Con esto ya podemos formular la conclusión con precisión. Offline-first responde a una pregunta sobre el comportamiento de la interfaz: si la red no está, ¿la aplicación sirve para algo? Es una promesa de disponibilidad, y por tanto vive en la capa de entrega, junto a la caché, la degradación elegante y los tiempos de espera. No responde en absoluto a la otra pregunta, la que de verdad ordena este campo: cuando la copia local y la copia remota discrepan, ¿cuál de las dos es la verdad?

Que sean preguntas independientes tiene consecuencias que sorprenden. Existen aplicaciones ejemplares en su comportamiento sin red cuyos datos son inequívocamente del servidor: si el proveedor cierra, la caché local se convierte en un cementerio de respuestas que no se pueden interpretar sin la aplicación que las produjo. Y existe la combinación inversa, más rara pero real: sistemas cuya fuente de verdad es genuinamente local pero que fallan al arrancar sin red porque alguien puso una comprobación de sesión en el camino crítico de inicio. Un requisito no implica el otro en ninguna de las dos direcciones.

Hay una prueba mental sencilla para no volver a mezclarlas. Pregúntate en qué momento se manifiesta cada propiedad. La disponibilidad se manifiesta en el instante del arranque y en cada interacción posterior: es continua, visible y fácil de medir. La autoridad solo se manifiesta en dos instantes excepcionales —cuando dos versiones chocan y cuando el proveedor desaparece— y es invisible el resto del tiempo. Una propiedad que se observa constantemente y otra que se observa casi nunca no pueden ser la misma propiedad, por muy correlacionadas que estén en el catálogo de productos.

La confusión tiene además un componente económico que conviene nombrar sin cinismo. La disponibilidad se puede demostrar en un vídeo corto y produce una impresión inmediata de calidad; la propiedad del dato no se puede demostrar en absoluto, porque su prueba consiste en un acontecimiento que nadie quiere que ocurra. Cuando una propiedad es barata de exhibir y la otra es imposible, el lenguaje comercial deriva hacia la primera y toma prestado el prestigio de la segunda. No hace falta atribuir mala fe a nadie para predecir ese desplazamiento; basta con observar qué se puede filmar.

De ahí se sigue también por qué offline-first es un objetivo perfectamente respetable por sí mismo y no una etapa intermedia hacia otra cosa. Para una enorme cantidad de software —herramientas internas, aplicaciones de campo, clientes de servicios con reglas de negocio estrictas— la autoridad debe seguir estando en el servidor por razones de corrección, y lo único que hace falta añadir es que la interfaz no se rompa cuando la red falle. Presentar ese caso como una versión incompleta de local-first es un error de encuadre que empuja a equipos hacia arquitecturas cuyo coste no necesitaban asumir.

⚠️
El error de razonamiento más frecuente del sector

La inferencia inválida se enuncia así: funciona sin red, luego los datos son del usuario. Es un salto de la disponibilidad a la propiedad, y no se sostiene. Una caché sofisticada produce exactamente los mismos síntomas observables que una réplica autoritativa: apertura instantánea, escritura fluida, nada de indicadores de carga. La diferencia solo se manifiesta en dos momentos que casi nadie prueba: cuando dos versiones entran en conflicto y hay que decidir cuál sobrevive, y cuando el servidor deja de existir para siempre. Toda la taxonomía de este nivel consiste en aprender a mirar esos dos momentos en lugar del primer arranque.

Offline-first es un requisito de calidad de servicio; local-first es un requisito de soberanía

Vale la pena decirlo en el vocabulario de los sistemas distribuidos, porque ahí la distinción es vieja y está resuelta. Offline-first es una afirmación sobre disponibilidad en el sentido técnico del término: el sistema sigue aceptando operaciones aunque una partición lo separe de sus pares. Es exactamente la elección de disponibilidad frente a consistencia que el teorema clásico obliga a hacer bajo partición, tomada en la capa del cliente y a menudo sin que nadie la formule como tal. Y como toda elección de ese tipo, tiene una factura pendiente: la reconciliación posterior. Lo que offline-first no toca, ni pretende tocar, es quién ostenta la autoridad sobre el estado convergido. Puedes construir un sistema perfectamente disponible bajo partición cuya autoridad siga siendo un único servidor central que, al reunificarse la red, descarta sin apelación todo lo que no le gusta; sigue siendo offline-first y no es local-first en ningún sentido. Local-first añade una exigencia de otra naturaleza, que no es de ingeniería de disponibilidad sino de gobernanza del dato: que la réplica del usuario sea primaria, que su formato sea interpretable sin el proveedor y que su continuidad no dependa de la supervivencia de una empresa. Por eso las dos propiedades se pueden combinar en las cuatro maneras posibles, y por eso la industria las confunde con tanta facilidad: comparten síntomas y no comparten compromisos. Toda la disciplina que este nivel intenta instalarte cabe en una regla: cuando alguien describa una aplicación por lo que hace sin red, has aprendido algo sobre su calidad de servicio y absolutamente nada sobre quién manda en sus datos.

⚔️ Audita la disponibilidad de una app que uses a diario
  1. Elige una aplicación web que uses todos los días y ábrela en frío con la red desactivada. Distingue tres resultados posibles: no arranca, arranca vacía, arranca con contenido. Anota cuál es.
  2. Si arrancó con contenido, averigua cuánto contenido: ¿lo último que viste, o todo tu historial? La diferencia te dice si estás ante una caché de sesión o ante una réplica.
  3. Intenta escribir sin red. Recarga la pestaña sin reconectar y comprueba si tu escritura sigue ahí. Si desapareció, la escritura vivía en memoria y la disponibilidad era una ilusión.
  4. Reconecta y observa la interfaz durante los diez segundos siguientes. Busca cualquier señal de que algo se reconcilió, se reintentó o se descartó en silencio. Si no ves ninguna, la aplicación te está ocultando su momento más interesante.
  5. Sin red, intenta abrir algo que no hubieras abierto antes en esa sesión. El resultado distingue una caché reactiva de lo consultado de una réplica proactiva de tu conjunto de trabajo, y esa distinción vale más que cualquier etiqueta del producto.