Docs Hintergrund: Gezielte Kollaboration

Docs

Das neue Docs ist schon eine Weile da. Doch wie funktioniert das eigentlich mit der Kollaboration? Und wie kann man Bandbreiten-sparend so viele Daten übertragen? Dafür gibt es ein spezielles „Operational Transformation„, welches Kollisionen vorbeugt und für ein reibungslosen Version-Verlauf unter mehreren Benutzern sorgt. 

Damit stehts ein reger Austausch garantiert ist – und damit auch immer das Dokument gegenüber aktuell ist – muss eine professionelle Lösung her. Man kann nicht einfach das ganze Dokument zum anderen Nutzer übertragen – viel zu lange würde es dauern, geschweige von dem Traffic, was das bei jeder Abfrage erzeugt. Deshalb hat sich Google das Operational Transformation-System (OT) zu nutze gemacht: Es werden nur Veränderungen übertragen.

Dabei unterscheidet Google Docs in drei verschiedene Arten von Veränderungen: InsertText (Text einfügen), DeleteText (Text löschen) sowie ApplyStyle (Formatierung anpassen). Nun wird nacheinander jede Veränderung im Revision-Log gespeichert. Klinkt sich ein neuer Client hinzu (Dokument wird geöffnet), dann lädt er sich den kompletten Log herunter und spielt das quasi Live ab. Ansonsten wird nur die Veränderung abgefragt, die sich seit dem letzten Nachfragen geändert hat.

Im Beispiel von Google gibt es John und Luiz. Beide arbeiten gemeinsam an einem Dokument in Google Docs. Ausgehend vom Text „EASY AS 123“ sollen nun Updates durchgeführt werden und diese sollen zum Gegenüber synchronisiert werden. Die Zahlen im roten Feld entsprechen je einem Zeichen. Ein Unterstrich stellt das Leerzeichen dar. John’s Aktionen werden in hellgrün und Luiz‘ Aktionen in gelben Boxen dargestellt.

Erstes Beispiel: „EASY AS 123“ soll zu „EASY AS ABC“ geändert werden. 

Beispiel 1 

Erklärung: Vom Ausgang her haben wir „EASY AS 123“. Nun markiert John „123“ und schreibt stattdessen „ABC“. Dennoch bleibt das ein komplexer Prozess: Zeichen 9 bis 11 werden gelöscht und es werden A B und C stattdessen eingesetzt. Die Kurzform in diesen Fall wäre „InsertText ‚ABC‘ @9“, was bedeutet: Ab Stelle 9 „ABC“ eintragen. Diese Kurzform wird in dem Revision-Log zusammengefasst, ansonsten kommen Veränderungen direkt so an, wie so oben stehen (Buchstabe für Buchstabe Live).

Aber nicht immer ist es so einfach. Beispiel 2: Angenommen, John arbeitet gerade an „ABC“, Luiz will aber gleichzeitig „IT“ vor „EASY“ schreiben. Blöd nur, wenn dann das Zeichenindex (1 bis 11, siehe oben) von John und Luiz völlig verschieden ist.

Beispiel 2

Jetzt ist es aber so, dass Luiz noch nicht die Änderung von Beispiel 1 mitbekommen hat, ganz einfach weil es in der selben Sekunde geschehen ist. Auf der folgenden Grafik kann man das schön verfolgen – was kommt nun wohl bei Luiz an, wenn er nicht Fuchs sondern Hund will? 

Kollision bei Google Docs

Das ist aber nicht wirklich die Frage, denn bei Luiz steht am Ende wirklich „The quick [FETT]brown dog[/FETT]. Und bei John kurze Zeit später ebenso. Nun erkläre ich euch, wie das im Detail mit den o. g. Veränderungen funktioniert. Also weiter im Beispiel.

Nun wäre der logische Schritt, dass zuerst die Delete-Anweisung von Beispiel 1 durchgesetzt wird:

Beispiel 2: Konflikt mit Beispiel 1 

Damit so etwas nicht passiert, gibt es ein ausgeklügeltes System, welches solche Kollisionen ausgleicht. Das JavaScript von Google Docs muss nun John’s Änderungen auf Luiz‘ Dokument relativ umsetzten, das heißt: Das Zeichen-Index muss jetzt angeglichen werden: Zu den 11 Zeichen müssen nun 2 Zeichen hinzugerechnet werden („IT“-Eingabe) und diese müssen global umgesetzt werden. Also wird jetzt nicht Zeichen 9-11, sondern 11-13 gelöscht:

Beispiel 2: Eine Konfliktlösung - Zeichen-Index lokal aktualisieren 

Das sieht doch schon viel logischer aus. Also hier noch einmal eine Zusammenfassung:

  • Es gibt 3 Veränderungsarten: Delete(Text), Insert(Text) und ApplyStyle
  • Weiterhin gibt es ein Zeichen-Index, welches jeden Buchstaben eine eindeutige Zahl zuweißt
  • Veränderungen werden erst lokal durchgesetzt (Zeichen-Index aktualisieren)
  • dann werden sie synchronisiert, in einem Revision-Log abgespeichert
  • der Revision-Log wird von Clients inkrementell geladen
  • Veränderungen werden mit den lokalen Zeichen-Index relativiert
  • Veränderungen werden ausgegeben
Nun noch ein anderes Beispiel aus der Praxis, damit man sieht, wie ApplyStyle mit DeleteText und InsertText zusammen funktioniert:

Wenn John in sein Dokument „I AM HAPPY“ schreibt, dann hat sein lokaler Index 10 Zeichen. Natürlich wird jeder Buchstabe via InsertText an Luiz übertragen (InsertText ‚I‘ @1, InsertText ‚_‘ @2, usw…).
Jetzt markiert John im Text das „AM“. Das bedeutet im Quelltext „ApplyStyle ‚mark‘ @2-3“ wird an den Revision-Log übergeben. Luiz denkt sich, dass er auch mal etwas macht und schreibt vor dem „HAPPY“ einfach „REALLY“ und hinter „HAPPY“ ein Fragezeichen. Sein Index beträgt jetzt 1-18; John löscht das „AM“ (DeleteText @2-3). Bei Luiz rechnet das JavaScript jetzt um, bleibt in dem Fall aber bei Zeichen 2-3. Synchronisierung.

Wie im letzten Artikel bereits erklärt, geht das alles über einen ziemlich flotten Server irgendwo da in der Wolke. Also Client -> Server -> Client und umgedreht. Also ist es ziemlich schwer nachzuvollziehen, ob auch überall das selbe angekommen ist. Daher muss das JavaScript 100% zuverlässig arbeiten und den Zeichen-Index ständig aktuell halten. Eine wirkliche Meisterleistung, die ein kleines Webtool namens Google Docs da vollbringt.

Teile diesen Artikel: