braden-lk 38 minutes ago

We built LegendKeeper using Yjs! (It's a mapping app as well, but fantasy). Ended up rolling our own sync server to handle large scale multiplexing, as we have D&D game-masters with 25,000+ documents to manage. (I don't know how they do it, tbh!)

We opt for the central server as a super-peer and use the Yjs differential update system to avoid loading docs in memory for too long. While there are many things about local-first that are a huge pain in the ass, the UX benefits are pretty huge. The DX can be nice too! Getting to focus on product and not on data transit (once you've got a robust sync system) is pretty sweet. The first 4 weeks of launching our Yjs-based system was rough though; lots of bugs that virally replicated between peers. It requires a really paranoid eye for defensive coding; after several years, we have multiple layers of self-healing and validation on the client.

er4hn 3 hours ago

> Architecturally, Y-Sweet acts as a bus: clients connect to the Y-Sweet server rather than directly to each other. Whenever a client connects or makes changes, it syncs its local document with the Y-Sweet server. Y-Sweet merges the client’s document into its own copy, saves it to S3 and broadcasts updates to other clients. Since CRDTs are guaranteed to eventually converge on the same state, at the end of this process all clients have the same document.

I had thought that the advantage of CRDTs was you do not need a centralized server and that if you do have a central server Operational Transforms are easier. Am I missing why CRDTs are used here?

  • jakelazaroff 3 hours ago

    Author here! A few thoughts on this:

    - First and (maybe most importantly), WebRTC in browsers requires a central server for signaling. So unless web browsers loosen that constraint, a "true" P2P web app without a central server is unfortunately infeasible.

    - My understanding is that with Operational Transforms, the server is "special" — it's responsible for re-ordering the clients' operations to prevent conflicts. I mention a little later in the article that Y-Sweet is just running plain Yjs under the hood. So it is a central server, but it's easily replaceable with any other instance of Y-Sweet; you could fork the code and run your own and it would work just as well.

    - Peers will only sync their changes if they're online at the same time. That means that the longer peers go without being online simultaneously, the more their local documents will diverge. From a user experience point of view, that means people will tend to do a lot of work in a silo and then receive a big batch of others' changes all at once — not ideal! Having a "cloud peer" that's always online mitigates that (this is true for any algorithm).

    • saurik 2 hours ago

      The ability to run your own server--or even not requiring a bespoke set of operations--isn't a special property of a CRDT; the same thing should be doable with something like ShareJS and it's generic tree/JSON structures.

      FWIW, though, the author of ShareJS had said some pretty strong things pro-CRDT in the past and even kind of lamenting his work on OT, so...

      https://news.ycombinator.com/item?id=24194091

      • josephg 30 minutes ago

        Hi, that’s me!

        OT would work fine to make this collaboratively editable. It’s just not local first. (If that matters to you.)

        With an OT based system like sharejs or google docs, the server is the hub, and clients are spokes connecting to that hub. Or to put it another way, the server acts as the central source of truth. If the server goes down, you’ve not only lost the ability to collaboratively edit. You've also usually lost your data too. (You can store a local copy, but sharejs not designed to be able to restore the server’s data from whatever is cached on the clients).

        With Yjs (and similar libraries), the entire data set is usually stored on each peer the server is just one node you happen to connect to & use to relay messages. Because they’re using Yjs, the author of this travel app could easily set up a parallel webrtc channel with his wife’s computer (in the same house). Any edits made would be broadcast through all available pipes. Then even when they’re on the road and the internet goes down, their devices could still stay in sync. And if the server was somehow wiped, you could spin up another one. The first client that connects would automatically populate the server with all of the data.

        But whether these local first characteristics matter to you is another question. They might be a hindrance - for commercial data, centralisation is often desirable. I can think of plenty of use cases where replicating your entire database to your customers’ computers (and replicating any changes they make back!) would be a disaster. It depends on your use case.

  • paulgb 3 hours ago

    (One of the authors of Y-Sweet)

    You’re right, that is one of the advantages of CRDTs, but it turns out to be hard to realize on the web — aside from RTC (which has its own dragons), you still need a server in the mix.

    The other thing an authoritative server solves is persisting the data. Because one server is the authority for a document at a time, you can use S3 or R2 for persistence without worrying about different servers with different versions of the document colliding and erasing each other’s changes.

    • er4hn 3 hours ago

      Oh, this is interesting. Can you elaborate (or link to some post) about what sort of issues you run into? I find the concept of CRDTs to be very interesting, but if you still need a centralized server I question the value of them over OTs. I'd love to understand more about if this is a connectivity issue, a CRDT issue, or what.

      • paulgb 2 hours ago

        The main issue you run into is that the web is designed around client-server communication; you can do peer-to-peer communication in theory but because of NAT and firewalls, many of those end up not being peer to peer in the end.

        Plus, if you want the data to persist so that two people can collaborate even if they are never online at the same time, you need a server anyway.

        CRDTs as data structures support peer-to-peer, it’s just that in many use cases that aspect of CRDTs is not needed.

        • er4hn an hour ago

          Okay that all makes a lot of sense thank you.

  • com 3 hours ago

    I think that using a bus decomplicates the connectivity story - having a “cloud peer” removes quite a bit of coding and testing from implementing true peer to peer discovery and communications functionality.

    Bonus points: you could potentially rip out the bus and replace it with something that involves peer to peer connectivity without changing client data structures.

tkiolp4 an hour ago

Would be perfect is somehow it could work without S3. Would be awesome if the internet could just work in p2p mode out of the box, just some JS and HTML and you have 2 computers talking to each other collaborating on a doc without the need of a server (or S3)

  • josephg 22 minutes ago

    You often still want a server somewhere to relay messages. Imagine I type something in my computer at home and turn the device off before leaving the house. Then on the road I pull up the document on my phone. I should see the latest version of the document on my phone. However, there were no moments where both devices were online at the same time.

    For this to work, my home computer needs to upload the changes somewhere my phone can access them. For example, a home server or a dumb box in the cloud.

    It’s very difficult to make this work without a server kicking around somewhere. So long as the server is fungible (it can easily be replaced for basically any other server), I don’t really see the problem with keeping a server around to relay messages.

xrd 3 hours ago

Ink & Switch is like the Medici family of the Internet era. Medici's funded the piano, and I&S is funding local-first. I love what they do.

wonger_ 3 hours ago

I love how the map automatically updates based on the places typed in the editor. A great visual aid to a text-based workflow.

I got confused by this comment though:

  > To determine when to re-render, “reactive” frameworks like Svelte and Solid track property access using Proxies, whereas “immutable” frameworks like React rely on object identity.
I thought React was just as reactive as all the other JS frameworks, and that the state/setState code would look similar.
  • jakelazaroff 2 hours ago

    Author here! Maybe I could have worded that better — basically, when you call setState in React, it compares the identities of the new state and old state to determine whether to re-render. Svelte and Solid use “signals” to automatically determine when to re-render, with the drawback that you’re no longer interacting with the “raw” value but a Proxy. But neither way would be able to detect Yjs mutating its internal state; you’re correct that even in React you would need some sort of wrapper code “tricking” it into re-rendering when appropriate.

  • IggleSniggle 2 hours ago

    I haven't worked frontend in a long time but just from reading that snippet I would assume React does a `obj===obj` (identity) comparison for state update under the hood, while Svelte/Solid are doing a Proxy trap on the accessors like `parent.obj =` would result in an intercept fn being called when you hit that 'obj' access. Proxy being a little more complicated to reason about and setup in totality but a lot more powerful and flexible.

er4hn 3 hours ago

On an unrelated note, I'm getting local-first case studies everytime I leave a wifi space since my cell phone is still suffering from the Verizon outage (Los Angeles area). My conclusion has been I can read stuff like calendar invites (Google), I can save notes on stuff to do in Trello, but I cannot queue up IMs to send in GHC.

RobCodeSlayer 2 hours ago

This is awesome! Since you’re using CRDTs, do you have any plans to make it collaborative? I would find it useful to build an itinerary with multiple people

  • jakelazaroff 2 hours ago

    It is collaborative! Start a document and send someone else the link :)

NeutralForest 3 hours ago

I've been hanging local-first circles but haven't made to switch to write anything with it yet. Is there a typical stack people recommend to get started? I'm not really sure where to start, especially in terms of backend.

xnx 3 hours ago

Is there some version of local-first that doesn't require a webserver, but does seamlessly sync state to a consumer cloud service like Google Drive? I'd love to write apps that have all the speed and portability of local apps, but the data isn't tied to a specific device. It seems like it would be feasible to have a large JSON blog background synced to a cloud file service after some threshold of accumulated change or time.

catchmeifyoucan 2 hours ago

Great write-up, I've been looking for a solution like this for adding syncing to my local-app!

I love that it's document stored in S3, and it's probably going to be way cheaper than if hosted elsewhere in a database. Can't wait to try it out soon

k__ 2 hours ago

Awesome stuff. Reminds me of the offline-first movement from ~10 years ago.

I'm currently looking into TinyBase to make working with high latency decentralised services more bearable.

Would be cool if there were a better comparison of the different solutions for storage and sync, with features, good use-cases, etc.

mentalgear 2 hours ago

The future is local-first. IF you haven't yet learned about it and how to break-out of the expensive cloud/serverless cage, this is a good start: https://localfirstweb.dev/

com 3 hours ago

This is great! I was quite excited to see Ink & Switch’s Embark and now this…

Jake makes creating a local-first multiplayer app seem so simple.