The result of this work is a hybrid technique which I think combines the best features of Operational Transformation (especially the RAM-efficiency) and CRDT (ability to work in arbitrary network topologies, not requiring a central server). It also turned out to be appealingly simple, about 400 lines of JavaScript. That's with a core data structure implemented as a balanced binary tree, to make the merge algorithm O(n log n), as opposed to O(n^2) for the best operational transform algorithm I know about (n is a measure of the number of edits in flight concurrently).
For anyone spinning up a new collaborative editor, I believe these techniques are a significant advance. Of course, if people disagree, I'd be more than happy to discuss.
I agree with Raph that OT and CRDT are closer in concept than many people currently think. Each have some interesting advantages. If we find a good way to combine them, perhaps it would be possible to engineer a system that has a different combination of advantages than today's OT or CRDTs provide.
If anyone is interested in a role working on OT, I'd love to hear from you! https://jobs.lever.co/lever/517c90b8-3519-48ee-b848-33282796...
I'm not sure if your tree structure is needed to efficiently transform N operations together. Another approach is to simply compose the operations together and transform by the composed operation set, using the property that with a proper tombstone-using text ot type it holds that IT(IT(x, A), B) == IT(x, A.B). (where IT=transform, `.`=compose). Mind you, this approach is still a bit slower than your solution. (I think you can make it O(N*(log N)^3) or something like that. But still faster than O(N^2).)
I don't think this is technically a CRDT - I think its still technically just OT, but OT that holds some additional properties. My favourite differentiating characteristic is that CRDTs bundle information from the document's history with the document snapshot itself. This lets you apply an operation with an older operational context. Obviously applying an old operation would be trivial with an OT system too if you had the history and could transform the operation - its just inefficient. So in a sense, {tp2-ot+document history} is a CRDT. Just, an inefficient one. As far as I can tell what you're proposing doesn't bundle the history - and you still need that history to transform.
It has some other really nice properties though, to the point that I had a pass implementing a p2p system using something like this a few years ago, using IT and ET functions. (My researcher friend Torben Weis independently discovered that method back in 2011 but didn't publish it). But the downside is that its slow. Your tree-based approach for operations themselves might be enough to make it viable. Very cool stuff!
http://haslab.uminho.pt/ashoker/files/opbaseddais14.pdf is a good paper on this, and their idea of partially ordered logs provides theoretical support for my earlier essay about unifying operational transformation and CRDT - I'll definitely cite it in any future publications.
What about state-based CRDTs, how do they fit the big picture?
State-based CRDT involves sending the entire document model, rather than just deltas from the last state. That's fine if documents are small or deltas are big chunks, but these tend not to be good assumptions in text editing. On the flip side, they're easier to reason about because connections don't have to be stateful.
Every time I want a collaborative OT like environment for apps that I build, I end up:
1- implementing some sort of janky locking scheme, or
2- having to learn how to install and host a tightly coupled server and client environment, or
3 - Abusing some other service (like firebase or couchdb) that has pseudo-OT semantics and getting close enough
I know there a bunch of people working on this, but I've never seen it offered as a service. If one of you do, please add my to your list of potential beta testers.
The base system lets you build other CRDTs on top, check out this talk I did in Berlin for details: http://gun.js.org/distributed/matters.html .
I would add just one small tidbit of advice that might help interested people get up to speed: skim the paper, then look at the implementation.
Being able to work with actual code can make a lot of things easier.
(This article comes with working code! Try it out!)
My approach (not finished) is to use linked lists and tombstones. I found index transformations to not be provably correct in an arbitrary P2P system because it always required a document root.
Here is a (terrible terrible) demo of the linked list approach: https://www.youtube.com/watch?v=rci89p0o2wQ .
What are your thoughts on your approach handling rich text? (document nesting)
Would love to chat more, mark [AT] gundb [DOT] io
I have thought some about rich text, but haven't implemented anything yet. My general thinking is that attribute spans lend themselves well to the OT model, but trees do not. The classic example is if you have three words, user A bolds the first two, and user B italicizes the last two. With spans, they just partially overlap, which is fine, but with trees you have an ambiguity.
Representing certain kinds of document structure (like nested bullet lists) is not obvious with spans. I want to explore the combination of a marker representing "beginning of tree" and a span, and define transformations in and out of tree form that would be robust to concurrent edits. However, this is all just ideas at this point.
But just in case you haven't, it has a nice high level overview of how Google Wave implemented rich text on a tree using annotation boundaries.
Several years ago I got rich text working just fine by using a deterministic HTML sanitizer/serializer - however, the hilarious thing was, the constant switch between hard space and soft space ruined it. So everything worked... except spaces, which wasn't going to fly.
I think the graph approach you mention in the article will be the winner, though. Trees require too many transformations it doesn't seem efficient. :/