Google DocsのようなCollaborationを実現するGoogle Realtime API
Video
とりあえずこれを観る

Google Docs Style instant collaboration
全部JS, サーバ不要
コンフリクト全自動解消!!
バックエンドはGoogle Drive
Realtime cube
システム構築
ユーザが作るもの
Realtime data model
(only) your application!
Working with the data model
gaip.drive.realtime.load(fileId, onFileLoaded, initModel)
onFileLoadedでevent listenerを仕掛ける
作例
ダイアグラム、フローチャート作成アプリ
裏側に迫る
リアルタイム編集
大量の編集差分リクエストを受け付けて、全てのクライアント上のドキュメントで整合性を保たなければいけない
とにかくすべてのmutaionsを保存しておく
append only
insert
指定位置 (index) に文字列を挿入する
delete
指定位置から何文字かを消す
サーバにすべてのmutationをstoreしておく
ドキュメントが読み込まれたら、これらのmutationからビルドされる
snapshotを送信する
複数人での同期を図る仕組み
mutationを文字通りそのまま受け入れていたら自分や他人の編集が衝突しまくり、ドキュメントが壊れる
思考実験
Aさんが index=4 の位置に5文字 insert
NG: Aさんのmutationを受け入れ前に、Bさんが index=14 の位置に文字列を追加
OK: Aさんのmutationを受け入れ前に、Bさんが index=20 の位置に文字列を追加
直前までの変化を汲んで適用するmutationを読み替えていかないといけない
Story1. サーバでの変換処理 Transformation
1. A -> Google: insert
@4 rainy
2. B (locally changed): insert
@14 brightly
3. B -> Google: insert
@14 brightly
4. Google -> B (locally merged) : insert
@4 rainy (... A's mutation)
5. Google -> A (locally merged) : insert
@20 brightly (... modified B's mutation)
Story2. サーバはすべてのchangesは変換できない
The server might not know about A's mutation after it send B's to A.
1. B -> Google: *insert @14 6-char
: 一番乗りのcommitなので、serverがmodifyする必要ない
2. A (locally changed): **insert @4 5-char
この変更はまだserverは知らない
3. Google -> A: *
(... B's commit)
衝突するので、Aが見ているドキュメントが壊れる
4. A -> Google: **
(... A's commit)
サーバでは整合性がとれている (変換の必要なし)
5. Google -> B: **
(... A's commit)
Bが見ているドキュメントは整合性が取れている
Story2の解決策
サーバでだけでなく、Clientでもtransformする
Keep a client-side queue of sent mutations and transform incoming mutations against the queue
送信済みのcommitsのキューを持っておく
受信しているcommitsをキューの内容に対して変換する
各々のクライアントでTransform Managerというやつを用意する
Pending Mutation Queue 送信待ちキュー
Story2での Step2 の **insert @4 5-char
がここに居る
サーバーからcommitを受け取る
もちろん、このcommitは、クライアントのPending Mutaion Queueとの衝突は考慮していない (できるはずがないので当然の状態)
Transform Manager内で自身に適用するmodified commitを作成する
サーバから ACK
を返されたら、Pending Queueの中からcommitを消去できる
Undoの仕組み
自分がやったmutationを取り消して元に戻す仕組み
あるmutationを確定した際に、Undo Stackに inverse mutation (真逆のcommit) を積んでいく
insertを確定したならば、指定位置から指定文字数分消去する delete commit を積む
これだと、他人に編集されると打ち消し位置が壊れる
inverse mutationの他に、すべての共同編集者から受信したmutationsを積んでいく
なるほど


これでさっきと同じTransform Functionを使えそう
共同編集者の編集情報を考慮した上で、自分の操作を取り消せる
取り消し開始位置をshiftして対処できる
例
Event planning system を作りながら、data model の構築を学ぶ
意味のある複数のプロパティをひとかたまりに定義できる
各々のプロパティを到着順に解決していると、サーバへの到着順によっては、days, 20 のような組み合わせになる可能性がある
トランザクション定義のようなものか
一つのtaskを誰かに割り当てるための操作は2ステップ
taskを古い所属から消す、新しい所属にtaskを追加する
うまいことやらないと、新しい所属先が2個同時に設定されたりする
Export data model as
JSON逆に、JSONをアップロードすると、Model Diff を抽出して更新してくれる
? [共同編集]機能の実装の[入門]として最初に観た動画