wandres.dev
CUÁNDO NO HACERLO · el criterio inverso

Cuando los datos no caben o no deben bajar

Tres fronteras distintas frenan la réplica local: el volumen físico, la ley que prohíbe exportar el dato y la licencia de un tercero que cobra por consulta y no por copia.

⏱ 20 min

El enfoque local-first descansa sobre una premisa que casi nunca se enuncia y que conviene sacar a la luz: que el conjunto de datos con el que un usuario trabaja cabe en su dispositivo y puede legalmente estar ahí. Son dos condiciones independientes y las dos fallan más a menudo de lo que sugiere la literatura, porque los ejemplos que la literatura usa —notas, tareas, un lienzo compartido, un editor de texto— son precisamente el subconjunto de aplicaciones donde ambas se cumplen sin esfuerzo. Esta lección examina las tres fronteras que impiden bajar el dato, y sostiene una tesis incómoda: la primera es de ingeniería y se puede negociar con dinero y tiempo, pero las otras dos no se negocian con ingeniería en absoluto, porque son restricciones sobre quién puede poseer los bytes y no sobre cuántos son.

🎯 Al terminar esta lección sabrás
  • Separar el tamaño total del dominio del conjunto de trabajo real de un usuario.
  • Reconocer que la cuota del navegador es una petición y no una garantía.
  • Identificar las restricciones legales que convierten una réplica local en una exportación.
  • Evaluar las salidas parciales sabiendo exactamente qué promesa rompe cada una.

El límite físico: el conjunto de trabajo y la cuota que no controlas

El primer error de estimación es medir el dominio completo cuando lo que importa es el conjunto de trabajo: la porción que un usuario concreto toca en una sesión típica. Una plataforma con doscientos millones de registros puede ser perfectamente local si cada usuario solo necesita cuatro mil de ellos, y una con dos millones puede ser imposible si la consulta natural cruza todo el conjunto. Antes de descartar nada hay que hacer esa cuenta, porque descartar por el tamaño equivocado es el modo más común de rechazar la arquitectura correcta.

flowchart TB
A[una coleccion de datos] --> B[cabe el conjunto de trabajo del usuario]
B --> C[no: dominio no particionable]
B --> D[si: sigue preguntando]
D --> E[tiene permiso legal para residir en el dispositivo]
E --> F[no: se queda en el servidor, sin excepciones]
E --> G[si: sigue preguntando]
G --> H[la licencia permite copia en bloque]
H --> I[no: consulta remota y medida]
H --> J[si: candidata real a replica local]
style C fill:#fab387,color:#11111b
style F fill:#f38ba8,color:#11111b
style I fill:#f38ba8,color:#11111b
style J fill:#a6e3a1,color:#11111b

El orden de las preguntas del diagrama no es decorativo. Se empieza por el tamaño porque es la más barata de responder, pero se continúa por las otras dos porque son las que no admiten recurso. Un equipo que valida la primera y da por buena la arquitectura ha comprobado la única condición que el tiempo iba a resolver por sí sola.

Hecha la cuenta, aparecen tres modos de fallo distintos que conviene no confundir. El primero es el dominio genuinamente no particionable por usuario: un índice de búsqueda global, un catálogo de productos con precios que cambian por minutos, un grafo social completo, la cartografía de un país. El segundo es la porción por usuario razonable con un arranque en frío inaceptable: cuatrocientos megabytes son perfectamente almacenables y perfectamente insoportables de descargar antes de la primera pantalla útil, sobre todo en una red móvil que el usuario paga. El tercero es el más sutil: el dispositivo no es tuyo. La cuota es una fracción del disco libre, varía por navegador y por plataforma, se evalúa por origen y puede reducirse cuando el usuario instala otra cosa.

// Lo que el navegador te concede no es lo que le pides.
const { quota, usage } = await navigator.storage.estimate();
// quota es una estimacion, cambia con el disco libre y no es un contrato.

const persistente = await navigator.storage.persist();
// persistente === false es una respuesta valida y frecuente.
// Sin persistencia, el desalojo bajo presion de disco es silencioso:
// no hay evento, no hay aviso, no hay forma de recuperarlo.

Hay además una asimetría de plataforma que rara vez se menciona y que decide productos enteros. Los navegadores móviles aplican políticas de limpieza más agresivas que los de escritorio, y algunos borran el almacenamiento de un origen que lleve semanas sin visitarse aunque la cuota no esté ni cerca del límite. Para una aplicación de uso diario da igual; para una que se abre una vez al trimestre —una declaración, una revisión anual, un informe estacional— significa que la réplica local estará vacía justo el día que el usuario vuelve. El patrón de uso, y no solo el volumen, determina si el almacenamiento del navegador es un lugar donde vivir o un lugar donde acampar.

La consecuencia arquitectónica de ese fragmento es más grave de lo que parece. Si el almacenamiento puede desaparecer sin aviso, la réplica local no es una copia autorizada del dato sino una caché con permisos de escritura, y toda la aplicación debe estar preparada para reconstruirse desde cero en cualquier momento. Eso es asumible cuando el servidor conserva la verdad; es catastrófico cuando el diseño prometía que el dato vivía en el cliente. La promesa de longevidad, que es uno de los ideales fundacionales del enfoque, solo se sostiene si existe un mecanismo de exportación explícito fuera del área de almacenamiento del navegador.

⚠️
El arranque en frío es una funcionalidad, no un detalle

Un producto local-first tiene dos rendimientos completamente distintos: el de la sesión número cincuenta, que es espectacular, y el de la sesión número uno, que es peor que el de una aplicación cliente-servidor equivalente porque descarga todo antes de ser útil. Ese primer minuto es el que decide la conversión de un usuario nuevo, y el que casi ninguna demostración enseña. Si tu conjunto de trabajo tarda más de unos segundos en estar listo, necesitas un modo de funcionamiento degradado contra el servidor mientras se llena la réplica, y eso es una segunda ruta de datos completa que mantener.

Aquí el argumento cambia de naturaleza. Ya no se discute si el dato cabe, sino si tiene permiso para estar ahí, y ningún avance en compresión o en cuota mueve esa frontera. Cuatro figuras jurídicas la definen y las cuatro apuntan en contra de la réplica.

La residencia y la transferencia internacional son la más rígida: hay contratos, sectores y jurisdicciones donde el dato no puede salir de un territorio o de una infraestructura concreta. Un portátil en un aeropuerto extranjero con una réplica sincronizada es, a efectos de cumplimiento, una transferencia internacional de datos que nadie autorizó y que nadie sabe describir en el registro de tratamientos. La minimización es la más contraintuitiva: el principio dice que solo debe tratarse el dato necesario para la finalidad, y la sincronización previsora hace exactamente lo contrario, descargar todo lo que quizá haga falta para que funcione sin red. Son dos principios de diseño en oposición directa, y el conflicto no se resuelve con una nota en la política de privacidad.

Hay una cuarta figura, menos citada y muy incómoda, que aparece en cuanto el producto es de empresa: la auditoría de acceso. Varios regímenes exigen registrar quién leyó qué y cuándo, no quién lo modificó. Una lectura contra un servidor deja rastro por construcción; una lectura contra una réplica local es indistinguible de no haber ocurrido, porque el dato ya estaba ahí y consultarlo no genera tráfico. No es que el registro sea difícil de implementar: es que la propiedad que hace valioso el enfoque —poder trabajar sin hablar con nadie— es exactamente la que hace imposible el registro. Ninguna de las dos se puede tener a la vez sobre el mismo dato.

El siguiente es el borrado, y es el que rompe el modelo mental de más gente. En una arquitectura centralizada, atender una solicitud de supresión es una operación con un final verificable. Con réplicas en dispositivos que pueden llevar meses sin conectarse, el borrado se convierte en un mensaje esperanzado: se marca la eliminación, se propaga cuando el dispositivo aparezca, y mientras tanto no puedes afirmar que el dato haya dejado de existir. Prometer un derecho cuyo cumplimiento no puedes verificar es un riesgo que no pertenece al equipo de ingeniería, y por eso esta decisión no debe tomarse sin quien responda del cumplimiento.

🚫

Historia clínica y datos de salud

Categorías especiales con auditoría de acceso obligatoria. Una lectura local no deja registro, y ese registro es requisito, no mejora.

🚫

Datos de pago en bruto

En cuanto el número de tarjeta toca el almacén del cliente, el cliente entra en el alcance de la auditoría. El coste no es técnico: es de certificación.

🚫

Dato sujeto a residencia

Si el contrato dice que la información no sale de una región, un dispositivo móvil es la definición misma de salir. No hay cifrado que arregle una restricción de ubicación.

🚫

Secreto comercial de otro

Precios negociados, listas de clientes, modelos de valoración. La copia local es exfiltración con pasos extra, y la disputa será contractual y no técnica.

Datos de terceros: la licencia como frontera arquitectónica

El tercer bloqueo es el que menos aparece en las discusiones técnicas y el que antes se encuentra un producto real. Buena parte de los datos valiosos no son tuyos: cotizaciones de mercado, cartografía, catálogos de referencia, bases documentales, resultados de un proveedor de enriquecimiento. Su modelo de negocio es cobrar por consulta o por asiento, y su licencia suele prohibir explícitamente el almacenamiento en bloque, la redistribución y la construcción de bases derivadas. Descargar el catálogo para que funcione offline no es un problema de ancho de banda: es un incumplimiento contractual que además destruye la medición sobre la que el proveedor factura.

Es importante entender que aquí el proveedor no está siendo obstruccionista. Su producto no es el dato en sí sino el acceso vigente y actualizado al dato, y la copia local rompe las dos mitades de esa proposición: deja de estar vigente en cuanto se descarga y deja de ser medible en cuanto se consulta sin red. Cualquier negociación que intentes irá en esa dirección, y el resultado habitual es una licencia de caché con caducidad corta y límite de volumen, que es una forma educada de decir que el modo offline no está incluido. Conviene pedir esa cláusula antes de diseñar, porque su redacción concreta —cuántos registros, cuántas horas, con qué obligación de purga— es literalmente la especificación de tu capa de almacenamiento.

Frontera Qué la impone Se resuelve con ingeniería
Volumen del conjunto de trabajo El dispositivo y la red Sí, con particionado y arranque diferido
Cuota y desalojo El navegador Parcialmente, nunca del todo
Residencia y minimización El regulador y el contrato No
Auditoría de lectura El regulador No, la lectura local es invisible
Licencia de terceros El proveedor No, es una negociación comercial

La tabla tiene una lectura que va más allá del caso concreto: solo la primera fila, y a medias la segunda, pertenecen al dominio donde un ingeniero puede intervenir. Las tres últimas se deciden en una mesa donde no hay ingenieros, y llegar a esa mesa con la arquitectura ya construida es la forma más cara de aprender esta lección. Merece la pena añadir un matiz que casi siempre se pasa por alto: incluso datos derivados que parecen inocuos pueden arrastrar la restricción de origen. Un índice local construido sobre un catálogo licenciado hereda su licencia, y un modelo entrenado sobre datos que no pueden salir tampoco puede salir.

💡
La pregunta que hay que hacer antes de escribir código

Para cada colección del sistema, responde por escrito a tres preguntas: quién es el titular del dato, qué contrato o norma regula su tratamiento y qué pasa si una copia acaba en un dispositivo que se pierde. Si alguna respuesta es no lo sé, esa colección no entra en la réplica local hasta que alguien la responda. No es burocracia defensiva: es que la respuesta cambia la arquitectura, y cambiarla después cuesta un orden de magnitud más.

Las salidas parciales y su precio

// La forma honesta de declarar la frontera: escrita, corta y comprobable.
export const capacidadesOffline = {
  documentosPropios: 'completo',      // lectura y escritura sin red
  historicoUltimoAno: 'solo lectura', // se replica, no se edita
  catalogoDeProveedor: 'no',          // licencia por consulta
  historiaClinica: 'no',              // auditoria de lectura obligatoria
} as const;
// Esta tabla es un requisito de producto: la lee soporte, la lee marketing,
// y cualquier cambio en ella es un cambio de contrato con el usuario.

Declarar las capacidades de esta forma tiene una virtud que va más allá de la documentación: convierte una decisión difusa en un artefacto que se puede revisar en cada incorporación de funcionalidad. Cada vez que alguien añade una pantalla, la pregunta pasa a ser en qué fila de esa tabla encaja, y la respuesta la da el criterio de titularidad y no la comodidad del momento. Sin ese artefacto, la frontera se erosiona colección a colección hasta que nadie sabe qué funciona sin red, incluido el equipo.

Ninguna de estas fronteras obliga a abandonar el enfoque por completo, pero todas las salidas parciales cobran algo, y la honestidad consiste en nombrar qué. La replicación por ámbito descarga solo la porción que el usuario tiene abierta, y funciona bien; a cambio devuelve al servidor la autoridad sobre qué es esa porción, y el modo offline deja de ser una propiedad del producto para convertirse en una propiedad del borde por el que el usuario se movió antes de perder la red. La caché de solo lectura sobre resultados del servidor da instantaneidad al segundo acceso sin prometer nada offline, y es probablemente la opción correcta en la mayoría de aplicaciones que se autodenominan local-first sin serlo. El índice local de metadatos con los contenidos bajo demanda funciona en gestores documentales, y su coste es que la búsqueda es instantánea y la apertura no, lo cual desconcierta al usuario hasta que se acostumbra.

Lo que estas tres opciones tienen en común es que degradan una promesa binaria en una promesa condicional, y ahí aparece el criterio que cierra la lección. Un usuario tolera bien que una aplicación no funcione sin red; tolera fatal que funcione a veces sin poder predecir cuándo. Por eso la salida parcial solo es aceptable si va acompañada de una definición explícita, escrita y visible de qué escenarios funcionan sin conexión. Esa lista es un requisito de producto, no una nota de implementación, y debe ser corta, comprobable y estable entre versiones.

Vale la pena decir en voz alta cuál es la salida parcial que más veces resulta ser la correcta, aunque sea la menos vistosa. En una fracción grande de aplicaciones de gestión, el usuario está siempre conectado, el conjunto de trabajo es enorme, los permisos cambian con frecuencia y el dato es de la empresa y no suyo. Ahí lo que aporta valor no es la réplica sino la caché reactiva con invalidación seria, que da la instantaneidad percibida sin ninguna de las cuatro fronteras de esta lección. Llamar a eso local-first sería marketing, pero implementarlo bien produce la mayor parte de la mejora sensible por una fracción del coste. Reconocer cuándo tu producto está en ese grupo es más valioso que dominar cualquier motor de sincronización.

La forma de equivocarse aquí tiene una firma reconocible. Un equipo mide correctamente el tamaño, valida que cabe, elige un motor, construye la sincronización, y meses después descubre que la colección más importante no puede replicarse por un motivo que no era técnico y que nadie había preguntado. Entonces aparece la peor arquitectura posible: un motor de sincronización a media potencia conviviendo con llamadas al servidor para los datos que de verdad importan, con dos rutas de lectura, dos modelos de consistencia y una superficie de pruebas duplicada. El error no fue elegir mal la herramienta, fue ordenar mal las preguntas.

Por eso el orden importa tanto como el contenido. Las preguntas legales y contractuales son baratas de formular, se responden con una conversación y descartan colecciones enteras en una tarde; las técnicas son caras de responder y solo tienen sentido sobre lo que ha sobrevivido a las primeras. Invertir ese orden —que es lo natural para un equipo de ingeniería, porque las preguntas técnicas son las que sabe responder— produce meses de trabajo sobre datos que nunca iban a poder bajar. Es un caso puro de optimizar la parte del problema que uno domina en lugar de la que decide el resultado.

La frontera no es el tamaño, es la titularidad

La pregunta que de verdad decide no es cabe el dato, sino de quién es el dato y quién tiene permiso para custodiarlo, y esa reformulación reordena el problema entero. El volumen es una restricción móvil: los discos crecen, las cuotas se amplían, el particionado mejora y lo que hoy no cabe cabrá en tres años, así que rechazar una arquitectura por tamaño es rechazarla por un motivo que caduca. La titularidad no se mueve: si el dato es de un tercero que cobra por consulta, si el regulador exige registrar cada lectura, si el contrato fija dónde puede residir la información, ninguna mejora técnica desplaza esa frontera ni un milímetro, porque no es una frontera sobre bytes sino sobre autoridad. De ahí sale la disciplina profesional: clasifica cada colección por titularidad antes que por tamaño, y acepta que la respuesta puede ser distinta para dos tablas de la misma base de datos. El dato del usuario sobre sí mismo —sus notas, sus documentos, sus preferencias, su trabajo— es el territorio natural del enfoque local y ahí debería aplicarse sin complejos. El dato que el usuario solo consulta porque alguien se lo presta, y el dato que la sociedad ha decidido vigilar de cerca, pertenecen al servidor por razones que no vas a arreglar con un motor de sincronización mejor. Confundir esos dos territorios no produce un sistema lento: produce un sistema que un día recibe una carta de un abogado.

⚔️ Clasifica tus colecciones por titularidad
  1. Lista las colecciones de un producto real y estima el conjunto de trabajo por usuario, no el tamaño total. Anota la diferencia entre ambas cifras.
  2. Para cada colección, identifica al titular del dato y la norma o contrato que lo regula. Marca con un signo de interrogación las que no sepas responder.
  3. Mide el arranque en frío de la porción replicable en una red móvil lenta y decide si necesitas una ruta degradada contra el servidor.
  4. Busca la cláusula de caché en la licencia de tu proveedor de datos externo. Traduce su redacción a límites concretos de volumen y caducidad.
  5. Escribe la lista visible de escenarios que funcionan sin conexión. Si no cabe en cinco líneas comprensibles para un usuario, la frontera está mal trazada.