Perhaps the most important difference is that software — even after being purchased and used — remains relatively easy to patch, unlike a physical lock.
Tbf that's a new-ish principle. 2003 was Windows XP era and the early days of Metasploit. I.e. Microsoft and all the other companies were still figuring out this internet thing, while most computers were riddled with unpatched vulnerabilities. There was no such thing as zero day back then, because you could use many exploits years later.
> But Windows Update was definitely already a thing back then, so I don’t think this “Microsoft was still figuring out this Internet thing” holds.
They had update mechanisms sure. But it was very much upto you to run. When XP came out most people used dial-up (at least in the UK), after 2002 ADSL internet started to become ubiquitous and computers were on the internet for longer periods.
They had to start baking security into every aspect of the OS. It was one of the reasons Vista came out several years later than planned. They had to pull people from Vista development and move them onto Windows XP SP2.
One of the reasons Vista was such a reviled OS is because the UAC controls broke lots of piece of software which ran under XP, 2000 and 98.
> Software was updated all the time, and it’s much more difficult to do that with locks.
YIt wasn't unusual to run un-patched software that come from a disc for years. You had to manually download patches and run them yourself. A software update / next version could take like 30 minutes or so on 56k dialup to download. If you didn't need to download a patch, you probably didn't.
It was a thing, but it was also a thing to have it disabled or simply not working. XP was famous for its hackability. And web frameworks were also far from what you see today with auto updates. It's hard to describe to people who were not involved how crazy ITsec was back then. It felt like the wild west compared to today. Literally every other DB had a critical unpatched vulnerability. Thankfully Shodan did not exist yet, so the barrier to entry was high for people without a particular skillset (which was also much harder to learn back then). But MSF pushed security awareness pretty hard once people realized how easy it can be if you just collect a bunch of scripts for common exploits in a simple framework that everyone can learn.
Totally true. Also consider that although software can theoretically or technically be patched, sometimes patches just don't exist... the amount of unmaintained but yet useful software is just huge.
I believe that in the right contexts—specifically where eventual consistency is acceptable—the local-first paradigm is highly valuable and will gradually become mainstream. A major factor limiting adoption today is that existing local-first solutions are incomplete: when building such applications, developers must handle many problems that are trivial under strong-consistency or traditional models. This raises the learning cost and creates significant friction for paradigm shifts.
Our recent work on Loro CRDTs aims to bridge this gap by combining them with common UI state patterns. In React, developers can keep using `setState` as usual, while we automatically compute diffs and apply them to CRDTs; updates from CRDTs are then incrementally synced back into UI state [1]. This lets developers follow their existing habits without worrying about consistency between UI state and CRDT state. Paired with the synchronization protocol and hosted sync service, collaboration can feel as smooth as working with a purely local app. We’ve built a simple, account-free collaborative example app[2]. It only has a small amount of code related to synchronization; the rest looks almost the same as a purely local React app.
Loro is very cool. I'm currently testing out building with it. Hadn't seen loro-mirror before, looks very nice too. Is loro-mirror supposed to be used with rich text editors like prosemirror, etc.?
loro-prosemirror[1] offers much better support for integrating Loro with ProseMirror/Tiptap.
In theory, loro-mirror could also be used to integrate Loro with other rich-text editors, but that wasn’t its original design goal and it may need further refinement to work well.
Definitely! If it's open-source, it's public-sync. Two important clarifications:
- An app like Telegram that makes the client open-source while the server code is unavailable is not public-sync. The software required for multi-device sync must be public.
- The opposite is not necessarily true. That is, not all public-sync software is open source, as explained at the end of the article.
The implementation can indeed combine multiple different CRDTs. Within Loro's internal implementation, each op does need to store a parent ID. However, as Seph mentioned, consecutive operations under the same parent can be effectively compressed, so the amortized overhead of these parent IDs is often not significant.
We are carefully stabilizing our encoding format and will have a clear storage format documentation introduced in version 1.0. I agree that a more transparent format can provide users with a better sense of control, and we will try to create a human-readable format for exporting CRDT data (the kind that includes operation history). As for the application state, Loro already supports direct export in json format.
Similar to OT, in certain scenarios, it's sufficient to ensure that only a subset of peers have the complete data, while others don't need the full history. For instance, in real-time collaboration scenarios with a central server, we can, just like OT, allow clients to hold only a shallow clone instead of the complete history. This approach results in minimal overhead for the clients.
I guess it all depends on how you define "client" and "shallow history", and the guarantees you provide around propagation of that history.
But if you have a central server that is considered to be the authoritative source of state, and assuming clients interact with that central server directly, then I'm not sure what is accomplished by modeling your data with CRDTs in the first place?
> If you remove these ops from history, does that remove the ability to time travel (per the home page "An antidote to regret, enabling historical edits traversal") or merge branches?
Yes. But squash can be supported.
> How can we be sure an operation is synchronized?
In Loro, we not only record the real-world timestamp efficiently, similar to Git, but also capture the DAG information. This approach ensures that if an operation (op) is particularly old, it will have many other ops depending on it. By utilizing both pieces of information, we can determine the operations that are likely synced across all peers. For peers like servers, it's feasible to preserve all operations. However, we can remove some operations in scenarios such as opening the document online for the first time.
> If dropping these ops is necessary for speed/storage optimization but disables time-travel, is it possible to put the removed historical/tombstone ops into a "cold storage" that's optional and only loaded for time-travel use?
Yes. This is not supported at the moment, but we hope to implement it before version 1.0.
We are addressing the CRDT downsides mentioned in the article at Loro:
- Ever-growing state. This is no longer an issue. With OT-like CRDTs, you can discard unnecessary historical data at any time. This is theoretically feasible, and we are moving towards this goal.
- Complex implementation. The complexity is internal within the package, and it's written in Rust, making it universally applicable.
- Opaque state. We aim to expose these internal states through improved DevTools, making them easier to control and observe. This is one of the essential steps in enhancing our DX.
The code in the blog is from Vue Pinia, a state management library, and not from Loro. It serves as an example demonstrating that CRDTs can be modeled similarly. Thus, you might expect to use Loro in a similar way.
Indeed, schema migration is challenging. There is a lot to explore, both in reducing the need for migration and in ensuring a smooth transition when it's required. We plan to tackle this issue in the future.