Cuándo cada uno: el criterio es el coste de la perdedora
Elegir entre última escritura y multivalor no depende del tipo del campo sino de cuánto cuesta perder el valor descartado y de si quien lo escribió podría reconstruirlo sin ayuda.
Un color de fondo y el cuerpo de un documento son los dos cadenas de texto guardadas en un campo, editadas por las mismas personas, sincronizadas por el mismo motor y sujetas a la misma concurrencia. Y sin embargo casi nadie duda de que el primero puede resolverse quedándose con el último y de que el segundo no. La intuición es correcta, pero el motivo que se suele dar —que uno es importante y el otro no— es demasiado vago para decidir los cuarenta campos intermedios de un modelo real, que es donde se pierde el trabajo de verdad. El criterio que sí decide es económico y se enuncia en una frase: lo que importa no es el valor que gana, sino cuánto cuesta el valor que se descarta. Esta lección convierte esa frase en cuatro preguntas que se responden en minutos, en un esquema ejecutable que reparte políticas campo a campo y en una advertencia sobre por qué el valor por defecto tiene que ser el conservador.
- Formular el criterio de elección como coste de la escritura perdedora y no como importancia del campo.
- Aplicar cuatro preguntas operativas que separan los campos sin necesidad de conocer el dominio a fondo.
- Implementar una fusión dirigida por esquema que asigne política campo a campo dentro del mismo documento.
- Entender la asimetría entre los dos costes: un impuesto constante frente a una catástrofe rara.
El criterio: cuánto cuesta la perdedora
Formalicémoslo antes de aplicarlo, porque la forma explícita ya resuelve la mitad de las discusiones. El daño esperado de una política que descarta es el producto de dos factores: la probabilidad de que dos escrituras al mismo campo sean concurrentes, y el coste de reconstruir el valor descartado. El primer factor lo mide tu telemetría —es literalmente la anchura que instrumentaste en la lección anterior—; el segundo lo estima cualquiera del equipo mirando el campo durante diez segundos.
El color de fondo puntúa bajísimo en el segundo factor. Si tu elección se pierde, lo notas al instante porque estás mirando el campo, y volver a elegirlo cuesta dos clics y ninguna memoria: el valor no era información que existiera solo en tu cabeza, era una opción de una lista finita que sigue ahí. El cuerpo de un documento puntúa altísimo por las tres razones opuestas: puede que no notes la pérdida hasta días después, reconstruirlo exige recordar lo que escribiste, y esa información no está en ningún otro sitio del universo.
Los dos ejemplos anteriores son cadenas de texto, y la conclusión es opuesta. Un booleano puede necesitar multivalor —terminado contra cancelado son dos afirmaciones incompatibles que alguien tiene que arbitrar— y un texto largo puede admitir perfectamente la última escritura si es una descripción generada automáticamente a partir de otros campos. El tipo del dato no aparece en el criterio en ningún momento; lo que aparece es qué le pasa a la persona cuyo valor se descarta.
Las cuatro preguntas
En la práctica no hace falta estimar números: basta responder cuatro preguntas cerradas por campo, y con tres de ellas suele bastar para decidir. La primera es la más discriminante de todas. ¿Quien perdió puede reconstruir el valor en segundos y sin ayuda? Si la respuesta es que sí, la última escritura es adecuada y cualquier maquinaria adicional está gastando metadatos y pantallas en proteger algo que se recompone solo.
La segunda: ¿el valor es una observación del mundo o una afirmación de una persona? Una lectura de sensor, una posición de cursor, una última ubicación conocida o un estado de presencia son muestras de algo externo que evoluciona por su cuenta, y para ellas el valor más reciente es genuinamente el más válido. Un título, una decisión, una prioridad asignada a mano son afirmaciones, y dos afirmaciones concurrentes no se resuelven por antigüedad porque ninguna era más verdadera que la otra.
La tercera: ¿la escritura fue atómica o incremental sobre un estado que el escritor había leído? Si alguien leyó el valor, lo modificó y lo escribió de vuelta, descartar su escritura no destruye un dato sino una transformación, y esa transformación era precisamente la intención que el sistema debía preservar. Este es el caso donde con más frecuencia la respuesta correcta no es ninguna de las dos políticas sino una tercera estructura.
Y la cuarta, que es de detectabilidad y decide los empates: ¿se daría cuenta alguien de que perdió? Un campo que el usuario tiene delante mientras edita produce pérdidas ruidosas y autocorregibles. Un campo que se escribe una vez y se lee meses después produce pérdidas que nadie atribuirá jamás a la sincronización, y ese silencio es el que convierte un daño pequeño en un daño acumulado durante años.
flowchart TB Q1[se reconstruye en segundos sin ayuda] -->|si| L[ultima escritura] Q1 -->|no| Q2[observacion del mundo o afirmacion de alguien] Q2 -->|observacion| L Q2 -->|afirmacion| Q3[la escritura fue atomica o incremental] Q3 -->|atomica| M[multivalor] Q3 -->|incremental| O[otra estructura conjunto contador o secuencia] style L fill:#a6e3a1,color:#11111b style M fill:#f9e2af,color:#11111b style O fill:#89b4fa,color:#11111b
El mismo documento, campo por campo
La conclusión operativa es que la política no es una propiedad del producto ni de la librería, sino del campo, y por tanto pertenece al esquema. Una fusión dirigida por esquema cuesta muy poco y convierte una decisión implícita heredada de una dependencia en una tabla que se puede revisar, discutir y probar.
const ESQUEMA = {
colorFondo: { politica: "lww" }, // se rehace en dos clics
posicionRaton: { politica: "lww" }, // muestra del mundo, sin residuo
ordenColumnas: { politica: "lww" }, // preferencia de vista, no contenido
titulo: { politica: "mv" }, // afirmacion de una persona
estado: { politica: "mv" }, // terminado contra cancelado se arbitra
etiquetas: { politica: "conjunto" }, // dos personas anaden, nadie sustituye
vistas: { politica: "contador" }, // incrementos que deben sumarse
cuerpo: { politica: "secuencia" },// edicion incremental sobre lo leido
};
const FUSIONES = {
lww: fusionarLWW,
mv: fusionarMV,
conjunto: fusionarConjuntoOR,
contador: fusionarContador,
secuencia: fusionarSecuencia,
};
// El defecto es el conservador: un campo sin politica declarada no se descarta
const POR_DEFECTO = "mv";
function fusionarDocumento(a, b, esquema = ESQUEMA) {
const salida = {};
for (const clave of new Set([...Object.keys(a), ...Object.keys(b)])) {
if (!(clave in a)) { salida[clave] = b[clave]; continue; }
if (!(clave in b)) { salida[clave] = a[clave]; continue; }
const politica = esquema[clave]?.politica ?? POR_DEFECTO;
salida[clave] = FUSIONES[politica](a[clave], b[clave]);
}
return salida;
}
La línea que de verdad importa de ese fragmento es la del valor por defecto, y va contra lo que hace todo el sector. Un campo nuevo que alguien añade el martes sin pensar en concurrencia entra automáticamente en la política que no destruye; si resulta que era un color de fondo, alguien lo verá en la primera pantalla de conflicto y lo bajará a última escritura con una línea. El defecto contrario —el que traen las librerías— hace que ese mismo campo entre en la política que destruye y que nadie se entere nunca, porque su modo de fallo no genera ninguna pantalla.
// Instrumentacion que convierte el criterio en un dato en vez de una opinion
function medirRiesgo(traza) {
const porCampo = new Map();
for (const ev of traza) {
const c = porCampo.get(ev.campo) ?? { escrituras: 0, concurrentes: 0 };
c.escrituras += 1;
if (ev.concurrente) c.concurrentes += 1;
porCampo.set(ev.campo, c);
}
return [...porCampo].map(([campo, c]) => ({
campo,
tasa: c.concurrentes / c.escrituras,
politica: ESQUEMA[campo]?.politica ?? POR_DEFECTO,
}));
}
La conversación sobre políticas de fusión tiende a volverse teórica y a durar horas. Sale mucho mejor si se hace con la tabla de tasas delante y solo sobre los campos que de verdad tienen concurrencia medida. Casi siempre son menos de diez, casi siempre son los mismos que el equipo ya sospechaba, y casi siempre hay uno o dos sorprendentes que nadie habría mirado. Los cuarenta campos restantes no merecen ni un minuto: su tasa es cero y cualquier política funciona.
Cuando el criterio dice que ninguno de los dos
Las dos políticas de este nivel son respuestas a la pregunta de a quién se le da el valor cuando hay dos. La tercera pregunta de la lista anterior sirve justamente para detectar los campos donde esa pregunta está mal planteada, porque la escritura no era una sustitución sino una transformación. Ahí no hay que elegir entre última escritura y multivalor: hay que salir del registro.
Los síntomas son reconocibles sin conocer el dominio. Un campo cuyo valor es una lista a la que la gente añade y quita elementos es un conjunto, y modelarlo como registro pierde las adiciones ajenas aunque nadie disputara nada. Un campo cuyo valor es un número que solo se incrementa es un contador, y modelarlo como registro pierde incrementos que eran acumulativos por naturaleza. Un campo cuyo valor es texto que la gente edita por partes es una secuencia, y ahí la unidad de conflicto no es el campo sino la posición.
Última escritura, sin dudarlo
Color, zoom, orden de columnas, panel plegado, posición de cursor, presencia, última lectura de un sensor. Se rehacen solos y nadie los echa de menos.
Multivalor, y enséñalo
Título, estado, responsable, fecha límite, precio. Son afirmaciones de personas, se escriben enteras y perderlas cuesta una conversación.
Ni uno ni otro
Listas de etiquetas, totales acumulados, texto redactado. La operación real no era asignar, y elegir política es responder a la pregunta equivocada.
Los peligrosos de verdad
Campos con alto coste de reconstrucción y baja detectabilidad: notas largas escritas sin conexión, configuraciones que se leen meses después.
La razón por la que esta decisión se toma sistemáticamente mal, incluso por equipos que conocen a la perfección ambas estructuras, es que los dos costes que hay que comparar tienen formas completamente distintas y el instinto los mide con la misma vara. El coste del multivalor es un impuesto: constante, previsible, pagado por el equipo, visible en cada revisión de diseño, porque cada campo con esa política obliga a inventar una experiencia de resolución, a probarla y a mantenerla. Se siente todo el rato y por eso pesa mucho en la decisión. El coste de la última escritura es lo contrario en las cuatro dimensiones: es cero la inmensa mayoría de las veces, no lo paga el equipo sino un usuario concreto en un momento concreto, no aparece en ninguna revisión porque no genera artefactos, y cuando por fin ocurre puede ser arbitrariamente grande. Comparar un impuesto que duele siempre con una catástrofe que no duele nunca hasta que ocurre tiene un resultado predecible, y es que el impuesto pierde todas las votaciones. Cuando alguien defiende la última escritura diciendo que la probabilidad de concurrencia en ese campo es del uno por ciento, está usando el valor esperado como criterio, y el valor esperado es exactamente el estadístico equivocado para riesgos de cola: nadie asegura una casa porque el incendio tenga alta probabilidad, sino porque su coste no está acotado. La formulación correcta del criterio no pregunta cuánto se pierde en promedio, sino cuál es el peor caso individual y si el sistema puede sobrevivirlo. Para un color de fondo el peor caso es que alguien vuelva a hacer dos clics, y una probabilidad del cien por cien seguiría siendo aceptable. Para una nota que alguien redactó durante una hora en un avión, el peor caso es que ese trabajo no exista, y una probabilidad del uno por mil sigue siendo inaceptable, porque cuando le toque a esa persona no le habrá pasado el uno por mil: le habrá pasado el cien por cien de su hora. De ahí se sigue la única disciplina que hace que esta decisión salga bien de forma sostenida, y es procedimental antes que técnica. La política tiene que estar declarada por campo en el esquema, no heredada de la configuración de una dependencia; el valor por defecto para un campo no declarado tiene que ser el que conserva, porque los defectos gobiernan la mayoría del modelo y un defecto destructivo produce pérdidas en todos los campos sobre los que nadie pensó; y la tabla de tasas medidas tiene que existir, porque sin ella la discusión se resuelve por intuición y la intuición sobre concurrencia es notoriamente mala en ambas direcciones. Con esas tres piezas la elección deja de ser una decisión de arquitectura tomada una vez al principio del proyecto, que es como se toma mal, y pasa a ser una línea de esquema revisable campo a campo, que es como se toma bien.
- Escribe la tabla de todos los campos de tu modelo y responde las cuatro preguntas para cada uno, sin consultar qué política tiene hoy.
- Compara tu tabla con la política real vigente y anota cada discrepancia: esa lista es el trabajo pendiente ordenado por riesgo.
- Implementa la fusión dirigida por esquema con el valor por defecto conservador y comprueba que un campo nuevo no declarado no destruye nada.
- Instrumenta la tasa de concurrencia por campo durante dos semanas y ordena la tabla; discute solo las cinco primeras filas.
- Busca al menos un campo que la tercera pregunta saque del registro y reescríbelo como conjunto, contador o secuencia.
- Para el campo con mayor coste de reconstrucción, escribe en una frase cuál sería el peor caso individual y decide si el sistema puede sobrevivirlo.