Asking for advice: I do not have a multiplayer app, but I have some large, interconnected, denormalized trees on my frontend as user profiles. Think like a tiled layout, where a user can add/remove/resize tiles, and then add a number of components into each tiled slot, each of those having their own profiles too. Multiple "layouts" can exist with different arrangements of tiles, and theres some other complexity with individual tiles referencing and sharing other pieces of state globally.
Making safe updates via regular REST is difficult, as you have to make sure someone with two tabs open isn't going to make an update on tab 1, then another on tab 2 which puts the overall profile into an invalid state. And in general, ordering matters. Skipping an update serverside that was properly applied clientside could break things.
The dumb-as-rocks solution I came up with is to just send the minimal amount of data over that can completely overwrite a particular chunk of state, and place it behind a queue. Usually thats fine, but sometimes thats a lot of wasted data, 50KB when the actual change was only a couple bytes.
I don't need CRDTs for any of the regular reasons, but it seems like it would make state management a million times easier, even for a single user. For one, I'd get syncing between a user's browser tabs, which is good. But moreover, I can just make simple changes to frontend state, and trust that the CRDT is going to negotiate it properly with the server. I no longer have to deal with it myself.
Does this make sense? Or is the overhead required to make something like Yjs work not worth it when I don't even need multiplayer and local-first.
If your application makes active use of multiple tabs, it might make sense to use YJS or something, because it's very effective in resolving those types of problems.
However, if your profile edits are single-user only, it's probably overkill to introduce a CRDT. At first glance, it seems the two-tabs-open scenario is your highest source of bugs, so what you could do is use a BroadcastChannel to signal update events to all other tabs.
How is YJS different from introducing CRDT? Doesn't it basically just do that for you anyways?
If CRDT is complications and difficult to manage, either YJS resolves that completely, or more likely that complexity will leak out of the abstraction layer no matter what.
To me it seems more like that OP should compare and contrast concurrency solutions, one of which is CDRT via YJS or another could be something like concurrency based on Go routines.
Edit: Should obviously mention Loro, the literal thread we're in now lol
I wrote that comment as a stream-of-consciousness, so it could have been written much clearer. What I meant was that you probably don't want to reach for a CRDT of any kind unless either multi-tab or multi-user editing is an inherent part of your app's experience. Else you can get the same benefits with less complexity.
Maintaining the shared state with REST calls that overwrite parts of server state is indeed brittle, and really only suitable for overwriting fields on flat data records. It also requires that you consider server-client state coordination with care at all times, and things can easily get out of sync in non-happy paths.
Like you said, building out a CRDT which specifies how updates are coalesced will significantly reduce cognitive burden.
Making safe updates via regular REST is difficult, as you have to make sure someone with two tabs open isn't going to make an update on tab 1, then another on tab 2 which puts the overall profile into an invalid state. And in general, ordering matters. Skipping an update serverside that was properly applied clientside could break things.
The dumb-as-rocks solution I came up with is to just send the minimal amount of data over that can completely overwrite a particular chunk of state, and place it behind a queue. Usually thats fine, but sometimes thats a lot of wasted data, 50KB when the actual change was only a couple bytes.
I don't need CRDTs for any of the regular reasons, but it seems like it would make state management a million times easier, even for a single user. For one, I'd get syncing between a user's browser tabs, which is good. But moreover, I can just make simple changes to frontend state, and trust that the CRDT is going to negotiate it properly with the server. I no longer have to deal with it myself.
Does this make sense? Or is the overhead required to make something like Yjs work not worth it when I don't even need multiplayer and local-first.