This is nice!<p>WebODF[1] developer here. Commenting because the project is doing this sort of thing and I have decent experience writing OT. I'll give a short explanation of how Operation Transformation works.<p>"Build your own Google Docs" is a slightly brave claim - "build your own Etherpad" would be more accurate.<p>This is because their operation set is very simple; for rich text documents the operations simply do not contain enough information to transform them against other ops. At the moment, their API includes 3 operations:<p><pre><code> * Insert
* Format
* Delete
</code></pre>
What I don't see:<p>Something like MoveCursor, for a start. From the source code of the markdown editor, it appears that cursor position synchronization is handled outside of the OT realm, likely by some other signalling. This is bad because the cursor positions do not get transformed at all - you can see this if you try to collaboratively edit on the same line in the demo - your cursor jumps around unwieldily.<p>Why this happens:<p>Imagine two users A and B concurrently editing inside a paragraph (a | denotes a cursor, belonging to B):<p><pre><code> <p>abc|def</p>
</code></pre>
Now suppose A inserts "123" at position 3 (after c), and B tries to move his/her cursor to the right by 1 step.
Assume that A's operation reaches the server first.
Then server's and A's state is:<p><pre><code> <p>abc123|def</p>
</code></pre>
because B's cursor is pushed to the right by the preceding text.<p>Then B's operation "move cursor to position 4 (after the d) reaches the server. But A's operation has not reached B yet.
The state on B becomes:<p><pre><code> <p>abcd|ef</p>
</code></pre>
And the state on the server becomes:<p><pre><code> <p>abc1|23def</p>
</code></pre>
Now B's op is relayed to A, and A's to B,
and A's state becomes:<p><pre><code> <p>abc1|23def</p>,
</code></pre>
and B's state becomes:<p><pre><code> <p>abc123d|</p>.
</code></pre>
because there is no OT for "MoveCursor" against "InsertText" -- in fact "MoveCursor" is not even an op here. This is an inconsistent state, which is basically a broken editing session (should never happen). Fixing this up by passing around diffs is not allowed (in a strict sense); diffing is not controllable OT.<p>WebODF uses stateless client-side OT, so any server is just mostly a dumb operation relayer. See what the OT logic for these two operations does:
<a href="https://github.com/kogmbh/WebODF/blob/master/webodf/lib/ops/OperationTransformMatrix.js#L537" rel="nofollow">https://github.com/kogmbh/WebODF/blob/master/webodf/lib/ops/...</a><p>If the "InsertText" operation's position was lesser than the concurrent "MoveCursor" position, "MoveCursor" is <i>transformed</i> to increment it's position by the "InsertText" operation's text length. This ensures that the cursor, while moving, will end up at the <i>intended</i> position within the word you were looking at.
(you'll notice that "MoveCursor" has a 'length' parameter in WebODF because a cursor also represents a user selection, yes it has colored collaborative selections).<p>OT'd process:<p><pre><code> <p>abc<cursorB/>def</p>
</code></pre>
A inserts "123", A's state is:<p><pre><code> <p>abc123<cursorB/>def</p>
</code></pre>
B moves cursor to position 4, B's state is:<p><pre><code> <p>abcd<cursorB/>def</p>
</code></pre>
A gets B's op, <i>transforms</i> it to increment position by "123".length = 3, state becomes:<p><pre><code> <p>abc123d<cursorB/>ef</p>
</code></pre>
B gets A's op, applies it because moving a cursor doesn't affect text insertion, state becomes:<p><pre><code> <p>abc123d<cursorB/>ef</p>
</code></pre>
Hooray, Eventual Consistency!<p>Any OT implementation is full of such <i>opinionated</i> enforcements and tradeoffs. It should make some assumptions about the editing UX and make sure that this is preserved when doing realtime concurrent editing; ignoring that and <i>only</i> going for eventual consistency will result in situations where the user cannot look at where they are typing.<p>WebODF has many such operations (~23) for each kind of edit: "SplitParagraph", "InsertText", "ApplyHyperlink", "ApplyDirectStyling", etc at last count. A large number of them are supported in collaborative mode, i.e. they have OT written. And this is no small task, because <i>each operation needs to have a transform written against every other operation in the set of all operations, including itself</i>. It does help that not all operations interfere with others, so the OT matrix is somewhat sparse. :-)<p>Fact: Any complex rich text editing framework will need to have it's own customized implementation of OT. We're dealing with the Open Document Format, we have Operations that are significantly tailored to it.<p>I feel that GoInstant's API is a nice thing! But it needs:
1. More operations.
2. Purely client-side OT (not strictly required, but very very useful).<p>Shameless plug: WebODF is a FOSS project with ~3 fulltime developers (including me) working on it. We are also working with the ODF change-tracking subcommittee to standardise things. We need more contributors and/or donations. :)<p><pre><code> [1] http://webodf.org/
</code></pre>
EDIT 1: Sorry, this post became longer than I had wished. I hope it helps anyone understand how OT works. Also, 'gratulations to GoInstant for launching this. :)<p>EDIT 2: Reformatting post for readability.