Artículos en profundidad sobre la tecnología que da forma al futuro.

La edición colaborativa es más difícil de lo que parece

CRDTs frente a OT para edición colaborativa en tiempo real: ambos tienen compromisos que nadie menciona. La realidad práctica del texto multijugador.

Dos manos fantasmales escribiendo en un mismo teclado, con flujos de luz que chocan entre ellas

Google Docs gestiona la edición colaborativa en tiempo real para millones de usuarios. Parece no costar ningún esfuerzo: escribes, tu cursor se mueve y las ediciones de tu colaborador aparecen al instante. Esta simplicidad es engañosa. Por debajo, la edición colaborativa es uno de los problemas más difíciles de los sistemas distribuidos, y los dos enfoques principales para resolverlo (Operational Transformation y CRDTs) tienen compromisos que no son evidentes hasta que intentas construir algo con ellos.

La propuesta de los CRDTs (Conflict-free Replicated Data Types) es seductora: estructuras de datos que se fusionan automáticamente sin conflictos, sin necesidad de un servidor central, con convergencia eventual garantizada por las matemáticas. Pero la realidad, como han descubierto varios equipos tras elegir CRDTs para sus editores colaborativos, es más confusa. La teoría es preciosa. La ingeniería es brutal.

El problema: ediciones concurrentes

El reto fundamental: dos usuarios editan el mismo documento al mismo tiempo, con un retraso de red entre ambos. El usuario A inserta 'Hola' en la posición 5. El usuario B, que todavía no ha visto la edición de A, borra el carácter de la posición 5. ¿Cómo debería quedar el documento final?

Es ambiguo. ¿El borrado de B debería aplicarse al carácter que estaba en la posición 5 antes de la inserción de A, o después? Si es antes, se elimina el carácter original y aparece 'Hola'. Si es después, se elimina la 'H' de 'Hola'. Ambas interpretaciones son razonables. El sistema tiene que elegir una y asegurarse de que todos los clientes converjan al mismo resultado: la divergencia significa que dos usuarios ven documentos distintos, y ese es el único fallo imperdonable.

The convergence problem:
Initial document: "The quick brown fox"
^ position 10
User A (at time T):  Insert "very " at position 10
User B (at time T):  Delete character at position 10
A sees locally: "The quick very brown fox"
B sees locally: "The quick rown fox"  (deleted 'b')
Now A receives B's operation: delete at position 10
But A already inserted 5 chars at position 10...
Should B's delete now apply at position 10? (deletes 'v' from 'very')
Or at position 15? (deletes 'b' from 'brown' — the original target)
Both A and B must arrive at the same document.
This is the problem OT and CRDTs solve differently.

Operational Transformation (OT)

OT, el enfoque más antiguo (1989), resuelve esto transformando las operaciones entre sí. Cuando A recibe la operación 'borrar en la posición 10' de B, el sistema de A comprueba qué operaciones ha aplicado A que B todavía no ha visto. Transforma la operación de B para tener en cuenta esos cambios: como A insertó 5 caracteres en la posición 10, el borrado de B ahora debe aplicarse en la posición 15 (el carácter original se desplazó a la derecha).

Funciona, y Google Docs lo usa. El problema son las funciones de transformación. Para un editor de texto con operaciones de inserción y borrado, hay que definir cómo se transforma cada par de operaciones frente a las demás. Con dos tipos de operación, son cuatro casos. Añade formato, tablas, imágenes, listas y comentarios, y el número de casos explota combinatoriamente. Cada caso debe ser correcto, y los errores sutiles provocan divergencias del documento que son casi imposibles de reproducir y depurar.

OT también requiere tradicionalmente un servidor central que establezca un orden total de las operaciones. Sin servidor, las operaciones concurrentes pueden transformarse en órdenes distintos según el cliente, produciendo resultados diferentes. Google puede permitirse un servidor central para Docs. Una aplicación peer-to-peer no puede usar OT fácilmente.

CRDTs: la promesa teórica

Los CRDTs adoptan un enfoque fundamentalmente distinto. En lugar de transformar operaciones, usan estructuras de datos en las que todos los posibles órdenes de fusión producen el mismo resultado. Es una garantía matemática: si la estructura de datos es un CRDT válido, la convergencia es automática. Sin funciones de transformación, sin servidor central, sin dependencia del orden.

En edición de texto, las variantes clave de CRDT son RGA (Replicated Growable Array) y otros CRDTs de secuencia similares. En vez de registrar posiciones (que cambian cuando se producen ediciones), asignan a cada carácter un identificador único y ordenado globalmente. Las inserciones crean nuevos identificadores entre los existentes. Los borrados marcan un identificador como tombstone (no se elimina; más sobre esto después).

CRDT sequence representation:
Document: "cat"
Internal representation (simplified):
ID: (A,1) → 'c'   (user A, logical clock 1)
ID: (A,2) → 'a'   (user A, logical clock 2)
ID: (A,3) → 't'   (user A, logical clock 3)
User B inserts 'h' between 'c' and 'a':
ID: (B,1) → 'h'   position: between (A,1) and (A,2)
Document: "chat"
User A (concurrently) inserts 'r' between 'c' and 'a':
ID: (A,4) → 'r'   position: between (A,1) and (A,2)
Both IDs go between the same characters.
The CRDT uses a deterministic tie-breaking rule
(e.g., higher user ID wins) to order them.
Final document: "chart" or "chrat"
(deterministic — all clients get the same result)

CRDTs: la realidad práctica

La promesa de los CRDTs (sin conflictos, descentralizados, con convergencia garantizada matemáticamente) es real. Pero los retos de ingeniería son considerables.

Los tombstones se acumulan. Cuando borras un carácter en un CRDT, no puede eliminarse de la estructura de datos: otras réplicas podrían no haberlo visto todavía y necesitan su identificador para posicionar correctamente sus propias ediciones. Por eso los caracteres borrados se marcan como tombstones: invisibles pero presentes. Un documento muy editado acumula miles de tombstones. Un documento de 1000 caracteres puede tener 50 000 tombstones del historial de edición. Esto infla la memoria y ralentiza las operaciones.

La sobrecarga de metadatos es enorme. Cada carácter necesita un identificador único (identificador de usuario más marca de tiempo lógica), punteros a los identificadores vecinos y una marca de tombstone. Los metadatos por carácter pueden ocupar entre 50 y 100 bytes. Para un documento de 100 KB, la representación CRDT puede ocupar entre 5 y 10 MB. Esto afecta a la sincronización, porque enviar el estado completo del CRDT por red es caro.

El rendimiento empeora con el historial. Las operaciones sobre un CRDT de secuencia no son O(1): insertar un carácter requiere encontrar la posición correcta en la secuencia ordenada por identificadores, lo que depende del número total de identificadores (incluidos los tombstones). En documentos con historiales de edición largos, esto se vuelve notablemente lento.

Preservar la intención es difícil. Los CRDTs garantizan la convergencia: todas las réplicas llegan al mismo estado. Pero ¿llegan al estado correcto? Cuando dos usuarios editan la misma palabra a la vez, el CRDT intercala sus caracteres de forma determinista. El resultado converge, pero puede no tener sentido. OT puede diseñarse para mantener intacta la edición de un usuario y aplicar la del otro alrededor. Los CRDTs fusionan de forma mecánica.

Yjs y el punto medio práctico

Yjs es la biblioteca CRDT más popular para JavaScript y da soporte a las funciones colaborativas de muchas aplicaciones web. Está bien diseñada y resuelve muchos de los problemas teóricos de los CRDTs con optimizaciones prácticas: la codificación binaria compacta reduce la sobrecarga de metadatos, y la recolección de basura de los tombstones funciona cuando todos los clientes están conectados.

Pero Yjs no es magia. Los equipos que lo adoptan descubren que una biblioteca CRDT resuelve el problema de la convergencia, pero no el problema de la colaboración. Aún necesitas: un servidor de señalización para descubrir pares, una capa de persistencia para los cambios offline, resolución de conflictos para operaciones de alto nivel (¿qué pasa si dos usuarios reestructuran la misma sección?), seguimiento de presencia (cursores, selecciones), deshacer/rehacer que respete las ediciones de otros usuarios y gestión de permisos.

Algunos equipos, tras construir un editor colaborativo sobre Yjs, han concluido que el enfoque CRDT añade complejidad que no necesitan. Si tu aplicación tiene un servidor central (y la mayoría lo tiene), OT o incluso enfoques más simples (last-write-wins con detección de conflictos) pueden ser más prácticos. Los CRDTs brillan en escenarios verdaderamente peer-to-peer: aplicaciones offline-first, software local-first y sistemas en los que no puede asumirse una autoridad central.

Qué deberían hacer la mayoría de las aplicaciones

Si vas a añadir edición colaborativa a tu aplicación, este es el marco de decisión pragmático.

  • Si tienes un servidor central y tus documentos son pequeños: usa OT. El enfoque de Google funciona. Bibliotecas como ShareDB implementan OT para Node.js. El servidor central simplifica todo: orden, persistencia, resolución de conflictos, permisos.
  • Si necesitas soporte offline o peer-to-peer: usa CRDTs (Yjs o Automerge). Los CRDTs son el único enfoque que maneja correctamente la edición offline real y la sincronización peer-to-peer. Acepta la sobrecarga de metadatos y la acumulación de tombstones como el precio de la descentralización.
  • Si tus colaboradores rara vez editan la misma sección a la vez: quizá no necesites ninguno. Un bloqueo simple (un solo editor por sección) o last-write-wins con una buena interfaz de conflictos cubre muchos patrones de colaboración reales sin la complejidad de OT o CRDTs.
  • Si estás construyendo un competidor de Google Docs: necesitas un equipo de ingenieros de sistemas distribuidos y años de desarrollo. Esto no es un proyecto de fin de semana. La simplicidad superficial de la edición colaborativa esconde una complejidad extraordinaria.

La evaluación honesta

La edición colaborativa es de esos problemas cuya dificultad no es evidente. El camino feliz (dos usuarios haciendo ediciones que no se solapan) funciona con casi cualquier enfoque. Los casos difíciles (ediciones concurrentes sobre la misma región, edición offline con sincronización posterior, estructuras de documento complejas como tablas, listas anidadas u objetos incrustados) exigen una comprensión profunda de los compromisos entre OT y CRDTs.

Ninguno de los dos enfoques es estrictamente mejor. OT es más simple con servidor y más difícil sin él. Los CRDTs funcionan sin servidor, pero cargan con sobrecarga de metadatos y acumulación de tombstones. Ambos requieren una ingeniería cuidadosa más allá del algoritmo central, y esa ingeniería (presencia, persistencia, permisos, deshacer) suele ser más difícil que el propio problema de la convergencia.

La industria avanza poco a poco hacia un híbrido pragmático: CRDTs para el modelo de datos (garantías de fusión automática), con un servidor para la coordinación (presencia, permisos, recolección de basura). Así obtienes lo mejor de ambos mundos: convergencia matemática más infraestructura práctica. Pero también heredas la complejidad de ambos, y por eso la edición colaborativa sigue siendo un problema difícil tras 35 años de investigación.