El problema fundamental que aborda la edición colaborativa es la consistencia de estado en sistemas distribuidos, donde múltiples clientes modifican concurrentemente un mismo recurso. Tradicionalmente, esto se ha resuelto con algoritmos de Operational Transformation (OT) o, más recientemente, con Conflict-free Replicated Data Types (CRDTs). La tesis central de este artículo es que, si bien las CRDTs prometen una convergencia automática y una alta disponibilidad en entornos peer-to-peer sin maestro, su complejidad inherente y sus implicaciones de rendimiento las hacen subóptimas para la mayoría de las aplicaciones de edición colaborativa que operan con una autoridad central (incluso si es efímera o distribuida). Se propone que un enfoque más simple, basado en un servidor que gestiona el rebase de transacciones, puede lograr los mismos objetivos de resiliencia y experiencia de usuario con una fracción de la complejidad y un rendimiento superior.
La necesidad de una solución eficiente y predecible para la edición colaborativa ha crecido exponencialmente con la adopción de aplicaciones web en tiempo real. Sin embargo, la elección de la tecnología subyacente a menudo se basa en suposiciones sobre la necesidad de una arquitectura 'masterless' que no siempre se alinea con los requisitos reales del producto. Este artículo desafía la noción de que las CRDTs son una solución universalmente superior, especialmente cuando se consideran factores como la latencia, la gestión de esquemas, los permisos y la depuración en sistemas de producción a gran escala.
Arquitectura del Sistema
El enfoque alternativo propuesto se basa en una arquitectura cliente-servidor con un modelo de 'autoridad única' por documento. El servidor mantiene la fuente de verdad del documento, los pasos aplicados y la versión actual. Los clientes envían transacciones (steps) junto con la última versión conocida del documento. Si la versión del cliente no coincide con la del servidor, el cliente debe obtener los cambios recientes del servidor (fetch recent changes), rebasar sus propias modificaciones sobre ellos y volver a enviar la transacción. Este proceso garantiza la consistencia y permite la edición optimista y la tolerancia a desconexiones de red.
En contraste, Yjs, una implementación popular de CRDT, utiliza un modelo de datos basado en XML para representar documentos de ProseMirror, ya que las CRDTs no pueden representar directamente la edición de texto enriquecido. Esto implica una conversión bidireccional entre los objetos ProseMirror Transaction y las actualizaciones XML de Yjs. Un punto crítico de diseño en Yjs es que, históricamente, ha reconstruido y recreado el documento completo en cada pulsación de tecla colaborativa, lo que tiene implicaciones significativas en el rendimiento y la estabilidad de los plugins. Además, las CRDTs requieren 'tombstones' para gestionar elementos eliminados, lo que puede llevar a un consumo excesivo de memoria o a la pérdida de datos si no se gestiona cuidadosamente el garbage collection, un problema que el enfoque de rebase resuelve simplemente almacenando los pasos en una base de datos duradera y permitiendo a los clientes solicitar cambios desde una lastSeenVersion específica.
Flujo de Aplicación de Transacciones Remotas (Enfoque Simple)
- 1 Servidor Acumula transacciones de clientes en lotes (ej. 20 pasos)
- 2 Servidor Envía lote de Steps a clientes
- 3 Cliente Recibe lote de Steps
- 4 Cliente Aplica Steps a EditorState local
- 5 Cliente Actualiza DOM incrementalmente
- 6 Cliente Renderiza cambios (ej. cursores remotos)
Flujo de Sincronización de Cliente (Enfoque Simple)
- 1 Cliente Envía `transactionalSteps` y `lastSeenVersion` al servidor
- 2 Servidor Compara `lastSeenVersion` con `currentVersion`
- 3 Servidor Si no coinciden, envía `recentChanges(lastSeenVersion)` al cliente
- 4 Cliente Si hay cambios, rebasea sus `transactionalSteps` sobre ellos
- 5 Cliente Vuelve a enviar `transactionalSteps` (rebasados) al servidor
- 6 Servidor Aplica `transactionalSteps` y actualiza `currentVersion`
| Capa | Tecnología | Justificación |
|---|---|---|
| data-processing | ProseMirror Transaction | Representación de cambios atómicos en el documento. Permite rebase y aplicación eficiente de modificaciones. vs Yjs XML updates |
| data-processing | prosemirror-collab | Librería para la gestión de la colaboración basada en rebase de transacciones. Simplifica la lógica de sincronización cliente-servidor. vs Yjs, Operational Transformation (OT) frameworks |
| storage | Database (genérico) | Almacenamiento duradero de los 'steps' (transacciones) del documento. Permite a los clientes ponerse al día con los cambios desde una versión específica. vs Tombstones en CRDTs (para gestión de eliminaciones) |
| compute | React | Framework de UI para la renderización del editor. La eficiencia de las actualizaciones del DOM es crítica para el rendimiento. |
Trade-offs
Ganancias
- ▲ Simplicidad de implementación
- ▲ Rendimiento (latencia de UI)
- ▲ Facilidad de depuración
- ▲ Gestión de esquemas de documento
- ▲ Gestión de permisos
- ▲ Eficiencia de memoria (sin tombstones)
Costes
- ▲ Topología peer-to-peer verdaderamente sin maestro
function submitChanges(steps, lastSeenVersion) {
const response = server.apply(steps, lastSeenVersion);
if (response.status === 'VERSION_MISMATCH') {
const recentChanges = server.getChanges(lastSeenVersion);
const rebasedSteps = rebase(steps, recentChanges);
submitChanges(rebasedSteps, server.currentVersion);
} else if (response.status === 'OK') {
// Update local state
}
}Fundamentos Teóricos
El problema de la consistencia en sistemas distribuidos ha sido un pilar de la investigación en ciencias de la computación durante décadas. Los algoritmos de Operational Transformation (OT), como los utilizados en Google Docs, surgieron de la necesidad de reconciliar ediciones concurrentes en tiempo real, con trabajos seminales como el de Ellis y Gibbs (1989). Las CRDTs, por otro lado, representan una evolución más reciente, formalizadas por Marc Shapiro et al. (2011), que buscan garantizar la convergencia de estado sin necesidad de un servidor central para la ordenación de operaciones, basándose en propiedades matemáticas como la conmutatividad, asociatividad e idempotencia. Este artículo, al comparar Yjs con un enfoque de rebase, esencialmente contrasta la complejidad de implementar un sistema que garantiza la convergencia fuerte (CRDTs) con la simplicidad de un modelo de consistencia eventual gestionado por una autoridad, que se alinea más con los principios de un Write-Ahead Log (WAL) y la aplicación secuencial de transacciones, un concepto fundamental en sistemas de bases de datos desde los años 70 y 80.