HackerTrans
TopNewTrendsCommentsPastAskShowJobs

GermanJablo

no profile record

Submissions

Show HN: DocNode, A TypeScript OT library for local-first apps

github.com
3 points·by GermanJablo·قبل 7 أشهر·0 comments

DocNode: A TypeScript OT library for local-first apps

github.com
12 points·by GermanJablo·قبل 7 أشهر·10 comments

Now We Know What Local-First Means (and It's Not What You Think)

docnode.dev
18 points·by GermanJablo·قبل سنتين·4 comments

comments

GermanJablo
·قبل 4 أشهر·discuss
Interesting. I'm the author of DocNode, a library that does exactly what you're describing; it might be useful. https://docukit.dev

Cheers!
GermanJablo
·قبل 4 أشهر·discuss
> A central server doesn't remove the need for this data though!

Yes, it's possible. The problem is that we're using different definitions of what OT means. This conversation has converged on the same point we started in another thread; I suggest we continue it there:

https://news.ycombinator.com/item?id=47436249
GermanJablo
·قبل 4 أشهر·discuss
The root of our misunderstanding or debate is clear: although CRDT is fairly well defined, I don’t think the same is true for OT.

What I have in mind is what I mentioned earlier:

> OT can be id-based, in which case operations are transformed directly on the document, not on other operations.

This is exactly what I do in my library DocNode[1], which I describe as “id-based OT”.

With this model, it’s not even necessary to satisfy TP1. In fact, the concept T(o1, o2) doesn’t exist, because operations aren’t “transformed” against other operations, but against the document. Maybe the word “transform” is a bit misleading, and “apply” would be more appropriate. The problem is that there is still a slight transformation. For example, if a client inserts a node between nodes A and B, but by the time it reaches the server B has been deleted, the effective operation might become “insert between A and C”.

The server is append-only. The client has several options to synchronize with the server: rebasing, undo-do-redo, or overwriting the document.

Maybe I’m the one who shouldn’t describe DocNode as “[id-based] OT” and should instead coin a new term. Operational Application (OA)? Operations Without Transformation (OWT)? Operations Directly Transformed (ODT)? Operational Rebasing (OR)? Not sure. What would you recommend?

[1] https://www.docukit.dev/docnode
GermanJablo
·قبل 4 أشهر·discuss
> Citation needed

It seems to me the burden of proof is on you. You were the one who claimed that “CRDTs perform better than OT-based systems.” I’m simply denying it. My reasoning is that CRDTs require idempotence and commutativity, while OTs do not. What requirement does OT have that CRDT does not? Because if there isn’t one, then by definition your claim can’t be correct. And if there is one, that would be new to me, although I suspect you might be using a very particular definition of OT.
GermanJablo
·قبل 4 أشهر·discuss
Ok, replace "P2P restriction" with "idempotent, commutative restriction".

> For example, OT has a tradeoff where you can discard old operations. The cost of doing so is that you can no longer merge old changes.

Why wouldn’t you be able to? My server receives operations, applies them to the document, and discards them. It can receive operations as old as it wants.

___

> Can you give some examples of this metadata?

Yes, it depends on the CRDT, but if we're talking about lists or tree structures with insert and delete operations, these can come in the form of thombstones, or operation logs, or originRight or originLeft, or DAG. Even with a garbage collector, the CRDT needs to retain some of this metadata.

Yes, you can optimize by not bringing it into memory when it’s not needed. But they’re still there, even though they could be avoided entirely if you assume a central server that guarantees a deterministic ordering of operations.
GermanJablo
·قبل 4 أشهر·discuss
Nowhere does it say it's multiple CRDTs. It says "isn't a single CRDT" and that "it's inspired by multiple separate CRDTs." A bit confusing, I agree.

By the way, I work at Figma.
GermanJablo
·قبل 4 أشهر·discuss
> But with some optimisation work, CRDTs perform better than OT based systems.

I read your paper and I think this is a mistake. You assume that OT has quadratic complexity because you're considering classic operation-based OT. But OT can be id-based, in which case operations are transformed directly on the document, not on other operations. This is essentially CRDT without the problems of supporting P2P, and therefore the best CRDT will never perform better than the best OT.

> CRDTs let you scale your backend. OT (usually) requires server affinity. CRDT based systems are way more flexible. Personally I'd rather complex code and simpler networking than the other way around.

All productivity apps that use these tools in any way shard by workspace or user, so OT can scale very well.

If you don't scale CRDT that way, by the way, you'd be relying too much on "eventual consistency" instead of "consistency as quickly as possible."

> (For anyone who's read the papers, I'm conflating OT == the old Jupiter-based OT algorithm that's popular in Google Docs and others.)

Similar to what I said before. I think limiting OT to an implementation that’s over three decades old doesn’t do OT justice.
GermanJablo
·قبل 4 أشهر·discuss
The biggest evidence for collaborative editing is the immense popularity of Google Docs, Notion and Figma.

Just because programming code isn't a good use case for automated conflict resolution doesn't mean everything else isn't.

Just imagine non-technical people using git to collaborate on a report, essay, or blog post. It's never going to happen.
GermanJablo
·قبل 4 أشهر·discuss
> (1) we found (contrary to popular belief) that OT actually does not require a centralized server

In theory, yes, but in practice, any OT that operates without a central server (or master peer) essentially ends up being a CRDT. A CRDT is a subset of OT, specifically one that adds the requirement of P2P support.

> (2) we found it to be harder to implement OT exactly right vs CRDTs

I would say that each has its own complexity in different areas. CRDT's complexity lies in its data structure and algorithm, while OT's lies in its sync engine (since it must handle race conditions and guarantee deterministic ordering). In my opinion, OT is simpler overall. Hopefully DocNode and DocSync will make OT even easier.

> (3) we found many (though not all) of the problems that CRDTs have, are also problems in practice for OT

Oh, definitely not! OT has many benefits[1]. I think the misconception stems from the common belief that OT should be positional, rather than id-based. In the first case, operations are transformed on other operations. In the second case, operations can also be transformed on the current document (O(1)), eliminating the problems commonly associated with OT. This is the approach I use in DocNode.

> the problems CRDTs have in general are vastly worse to the end-user experience.

This is 100% correct.

____

https://www.docukit.dev/docnode#how-does-it-compare-to-yjs
GermanJablo
·قبل 4 أشهر·discuss
> You don't think Figma is a serious application?

I don't know where this popular belief came from. The Figma blog literally says "Figma isn't using true CRDTs"[1].

> The only real benefit of OT is that its simpler to reason about.

That's incorrect. When you free yourself from the P2P restriction that CRDTs are subject to, there's a huge amount of metadata you can get rid of, just to mention one benefit.

[1] https://www.figma.com/blog/how-figmas-multiplayer-technology...
GermanJablo
·قبل 4 أشهر·discuss
Thanks! I've recently made some improvements to the documentation. I agree the synchronization section could be improved more. I'll keep your feedback in mind. If you'd like to try the library, feel free to ask me anything on Discord and I'll help you.
GermanJablo
·قبل 4 أشهر·discuss
Author of DocNode here. Yes, it’s still early days. But it’s a very robust library that I don’t expect will go through many breaking changes. It has been developed privately for over 2 years and has 100% test coverage. Additionally, each test uses a wrapper to validate things like operation reversibility, consistency across different replicas, etc.

DocSync, which is the sync engine mainly designed with DocNode in mind, I would say is a bit less mature.

I’d love it if you could take a look and see if there’s anything that doesn’t convince you. I’ll be happy to answer any questions.
GermanJablo
·قبل 4 أشهر·discuss
Yes, the undo issue is a known bug in the website demo because it's messing with Lexical's undo functionality. It's not actually a DocNode bug. I'll fix it soon.

The feedback about the delay/pause button is also good, thanks!
GermanJablo
·قبل 4 أشهر·discuss
I remember reading Part 1 back in the day, and this is also an excellent article.

I’ve spent 3+ years fighting the same problems while building DocNode and DocSync, two libraries that do exactly what you describe.

DocSync is a client-server library that synchronizes documents of any type (Yjs, Loro, Automerge, DocNode) while guaranteeing that all clients apply operations in the same order. It’s a lot more than 40 lines because it handles many things beyond what’s described here. For example:

It’s local-first, which means you have to handle race conditions.

Multi-tab synchronization works via BroadcastChannel even offline, which is another source of race conditions that needs to be controlled.

DocNode is an alternative to Yjs, but with all the simplicity that comes from assuming a central server. No tombstones, no metadata, no vector clock diffing, supports move operations, etc.

I think you might find them interesting. Take a look at https://docukit.dev and let me know what you think.
GermanJablo
·قبل 4 أشهر·discuss
The tombstone problem is exactly why I built DocNode. You're right that you can't compact them without consensus, so DocNode just doesn't create them. It assumes a server decides the order, which is already the case in 99% of collaborative apps. The result: a doc stays the same size whether it was edited once or a thousand times. Yjs for the same doc grows every time someone types, pastes, or undoes. Check it out: https://docukit.dev
GermanJablo
·قبل 6 أشهر·discuss
Interesting! I'm the author of https://docnode.dev and I see some similar concepts
GermanJablo
·قبل 7 أشهر·discuss
Thank you so much for your help! I followed your advice:

https://news.ycombinator.com/item?id=46211551
GermanJablo
·قبل 7 أشهر·discuss
I think it's debatable what constitutes an "operation". In a CvRDT, a delta or diff can be considered an operation. In an ID-based OT, it can be considered that there is a transformation of operations, only instead of transforming with respect to other operations, they are transformed with respect to the current document (if there were conflicts, they cannot always be applied in their original form).
GermanJablo
·قبل 7 أشهر·discuss
Thanks for the advice. I'll try it when the post is a week old. I hope it doesn't get rejected.
GermanJablo
·قبل 7 أشهر·discuss
I think there's a misunderstanding here.

People often associate CRDTs with IDs and tombstones, while associating OTs with positions.

This is incorrect. What makes them different is that CRDTs must work in P2P environments *by definition*. That's all.

Other true statements:

- All CRDTs are OTs, but not all OTs are CRDTs.

- If an OT supports P2P, then it's also a CRDT.

- If it doesn't support P2P, it's not a CRDT.

- A CRDT can have no IDs and be operation-based.

- An OT can have no positions and be ID-based.

In fact, I just released an ID-based OT framework yesterday: https://docnode.dev.

I hope that clarifies things a bit more!