El software local-first vuelve, y los motores de sincronización hacen el trabajo pesado

La mayoría del software que usamos sigue tratando al servidor como la única copia real de nuestros datos. El teléfono y el portátil son ventanas finas hacia una base de datos en otro lugar, y cuando se cae la conexión, la ventana se queda en blanco. El movimiento local-first sostiene que esto está al revés. El dispositivo debería guardar la copia de trabajo, la red debería ser un medio para sincronizarla y la app debería seguir funcionando cuando desaparece la red.
La idea no es nueva, pero por fin es práctica. Lo que ha cambiado no es un giro filosófico entre los desarrolladores. Es que los motores de sincronización y los tipos de datos replicados libres de conflictos (CRDT) han madurado lo suficiente para resolver la parte más difícil: fusionar dos ediciones hechas en dos dispositivos sin perder ninguna. Si hoy construyes software colaborativo, la sincronización ya no es un detalle de infraestructura que se entrega al equipo de backend. Es una decisión de producto con consecuencias en tu modelo de datos, tus permisos y tus costes de soporte.
El manifiesto de 2019 y por qué tardó siete años
En 2019, el grupo de investigación Ink & Switch publicó un ensayo titulado Local-first software: you own your data, in spite of the cloud. Enumeraba siete ideales: respuesta rápida sin spinners, trabajo que sobrevive a la pérdida de red, colaboración entre dispositivos y personas, datos que sobreviven a la empresa que creó la app, seguridad y privacidad por defecto, y usuarios que controlan sus propios archivos. Casi nadie discrepaba de la lista. El problema era el coste de implementación.
Construir una app local-first solía significar escribir tu propia lógica de fusión, tu capa de almacenamiento y tu protocolo de replicación. La mayoría de los equipos eligieron la vía solo en la nube porque era más simple, y los usuarios toleraban los spinners. Ese cálculo ha cambiado porque bibliotecas como Automerge y Yjs hicieron los CRDT utilizables en JavaScript, y los motores de sincronización asumieron la fontanería que los rodea.
Qué hace realmente un motor de sincronización
Un CRDT es una estructura de datos diseñada para que las réplicas puedan fusionarse en cualquier orden y aun así converger al mismo resultado, sin un árbitro central. Textos, listas y mapas pueden modelarse así. Un motor de sincronización se sitúa encima y gestiona el trabajo poco vistoso: mover cambios entre cliente y servidor, replicar solo el subconjunto de datos que cada usuario puede ver, persistir el estado tras reinicios y reconciliar con una base de datos autoritativa.
Varios productos en producción funcionan con este patrón. Linear ha escrito públicamente sobre su almacén del lado del cliente, que permite que su gestor de incidencias responda al instante mientras los cambios se sincronizan en segundo plano. La edición multijugador de Figma es otro caso conocido de muchos clientes editando el mismo documento a la vez. La lección es que la copia local es con la que interactúa el usuario, y el servidor pasa a ser coordinador en lugar de cuello de botella.
Dónde se rompe el modelo
Los CRDT son excelentes para fusionar ediciones de texto y conjuntos de elementos. Son mucho menos útiles cuando tus reglas de negocio dependen de invariantes globales. Si dos personas reservan el último asiento de un vuelo estando sin conexión, una función de fusión no puede decidir quién lo obtiene sin información que solo tiene el servidor. Lo mismo ocurre con los pagos, con los recuentos de inventario que no pueden ser negativos y con cualquier cosa que implique dinero o compromisos legales.
La migración de esquemas es el segundo problema que los equipos subestiman. Cuando un cliente que va tres meses por detrás se reconecta, debe entender datos escritos por una versión más nueva, y la versión nueva debe tolerar datos escritos por una antigua. Eso exige puertas de versión en el cliente, deprecación cuidadosa de campos y un plan para clientes que nunca se actualizan. El almacenamiento es el tercero. Un teléfono tiene espacio y batería finitos, así que necesitas políticas de desalojo, replicación parcial y una respuesta clara a qué pasa cuando la base de datos local supera lo que el dispositivo puede contener.
Un marco de decisión sencillo
Antes de elegir una arquitectura local-first, haz tres preguntas sobre cada tipo de dato de tu producto. Primero, ¿necesita funcionar sin conexión o responder en menos de unos 100 milisegundos? Segundo, ¿varias personas editan el mismo objeto a la vez? Tercero, si el usuario perdiera el acceso al proveedor, ¿el dato le sería inútil?
Si la respuesta a las tres es sí, tienes un caso sólido para local-first, como notas, gestores de tareas y herramientas de diseño. Si las dos primeras son no, un modelo convencional con servidor suele ser más barato y más fácil de razonar. La mayoría de los productos terminan siendo mixtos. Los borradores y el contenido colaborativo se sincronizan localmente, mientras que los pagos, los roles y la facturación siguen siendo autoritativos en el servidor.
Conclusiones prácticas
- Clasifica cada entidad de tu modelo de datos como fusionada con CRDT, autoritativa en servidor o solo lectura, y anótalo antes de escribir código.
- Versiona el esquema desde el primer día y añade comprobaciones de versión del cliente para que los clientes antiguos fallen de forma controlada en lugar de corromper datos.
- Prueba en Android de gama baja con almacenamiento limitado, no solo en el iPhone más reciente.
- Haz una prueba interna de una semana sin conexión. Usa el modo avión para el trabajo normal y registra cada punto donde la app te bloquea. Esos son tus requisitos reales.
Local-first no sustituye a la nube. Es un reequilibrio: el dispositivo hace más del trabajo que le importa al usuario, y el servidor hace la coordinación en la que es bueno. Los equipos que lo hagan bien lanzarán apps que se sienten más rápidas y sobreviven a redes malas. Los que traten la sincronización como un añadido seguirán mostrando spinners.