“Local-First Apps āļĒāļąāļāđāļĄāđāđāļāļīāļāļāļĢāļīāļ āđāļāļĢāļēāļ°āļāļēāļĢ Sync āđāļĄāđāļāđāļēāļĒāļāļĒāđāļēāļāļāļĩāđāļāļīāļ — āđāļāđ SQLite + HLC + CRDT āļāļēāļāđāļāđāļāļāļģāļāļāļ”
āđāļāļāļāļĨāļīāđāļāļāļąāļāđāļāļ Local-First āļŦāļĢāļ·āļ Offline-First āđāļāļĒāļāļđāļāļĄāļāļāļ§āđāļēāđāļāđāļāļāļāļēāļāļāļāļāļāļāļēāļĢāđāļāđāļāļēāļāļāļāļāļāđāđāļ§āļĢāđ āļāđāļ§āļĒāļāļļāļāļŠāļĄāļāļąāļāļīāļāļĩāđāđāļŦāļĨāļāđāļĢāđāļ§ āđāļāđāđāļāļāđāļĄāđāļāđāļāļāļāđāļāđāļāđāļ āđāļĨāļ°āđāļŦāđāļāļ§āļēāļĄāđāļāđāļāļŠāđāļ§āļāļāļąāļ§āļŠāļđāļāļŠāļļāļ āđāļāđāđāļāļāļ§āļēāļĄāđāļāđāļāļāļĢāļīāļ āđāļāļāļāļĩāđāļĢāļāļāļĢāļąāļāļāļēāļĢāļāļģāļāļēāļāđāļāļāļāļāļāđāļĨāļāđāļāļĢāļīāļ āđ āļĒāļąāļāļĄāļĩāļāđāļāļĒāļĄāļēāļ āđāļāļĢāļēāļ°āļāļēāļĢ “āļāļīāļāļāđāļāđāļāļĄāļđāļĨ” āļĢāļ°āļŦāļ§āđāļēāļāļāļļāļāļāļĢāļāđāļŦāļĨāļēāļĒāđāļāļĢāļ·āđāļāļāļāļąāđāļāļĒāļēāļāļāļ§āđāļēāļāļĩāđāļāļīāļ
Marco Bambini āļāļđāđāļāđāļāļāļąāđāļ SQLite Cloud āļāļāļīāļāļēāļĒāļ§āđāļē āļāļēāļĢāļŠāļĢāđāļēāļāđāļāļāđāļāļ Local-First āļāļ·āļāļāļēāļĢāļŠāļĢāđāļēāļāļĢāļ°āļāļāļāļĢāļ°āļāļēāļĒ (Distributed System) āļāļĩāđāļāđāļāļāđāļŦāđāļŦāļĨāļēāļĒāļāļļāļāļāļĢāļāđāļŠāļēāļĄāļēāļĢāļāđāļāđāđāļāļāđāļāļĄāļđāļĨāđāļāļāļāļāļāđāļĨāļāđ āđāļĨāļ°āļŠāļļāļāļāđāļēāļĒāļāđāļāļāļĢāļ§āļĄāļāđāļāļĄāļđāļĨāđāļŦāđāļāļĢāļāļāļąāļāđāļāļĒāđāļĄāđāļŠāļđāļāđāļŠāļĩāļĒāļāļ°āđāļĢāđāļĨāļĒ āļāļķāđāļāļĄāļĩāļŠāļāļāļāļąāļāļŦāļēāļŦāļĨāļąāļāļāļĩāđāļāđāļāļāđāļāđāļāļ·āļ:
1ïļâĢ āļĨāļģāļāļąāļāđāļŦāļāļļāļāļēāļĢāļāđāđāļĄāđāđāļāđāļāļāļ (Unreliable Ordering) āļāļļāļāļāļĢāļāđāđāļāđāļĨāļ°āđāļāļĢāļ·āđāļāļāļĄāļĩāđāļ§āļĨāļēāđāļĄāđāļāļĢāļāļāļąāļ āđāļĨāļ°āđāļŦāļāļļāļāļēāļĢāļāđāđāļāļīāļāļāļķāđāļāđāļĄāđāļāļĢāđāļāļĄāļāļąāļ āļŦāļēāļāļāļģāļāđāļāļĄāļđāļĨāļĄāļēāļĢāļ§āļĄāđāļāļĒāđāļĄāđāļāļąāļāļĨāļģāļāļąāļāđāļŦāđāļāļĩ āļāļēāļāđāļāļīāļāļāļ§āļēāļĄāļāļąāļāđāļĒāđāļ āđāļāđāļ āđāļāļĢāļ·āđāļāļ A āļāļąāđāļāļāđāļē x = 3 āļŠāđāļ§āļāđāļāļĢāļ·āđāļāļ B āļāļąāđāļ x = 5 āđāļĨāđāļ§āđāļāļĢāļāļ§āļĢ “āļāļāļ°”?
āļ§āļīāļāļĩāđāļāđāļāļ·āļ Hybrid Logical Clocks (HLC) — āļĢāļ°āļāļ timestamp āļāļĩāđāļĢāļ§āļĄāđāļ§āļĨāļēāđāļāļĢāļ·āđāļāļāļāļĢāļīāļāļāļąāļāļāļąāļ§āļāļąāļāđāļŦāļāļļāļāļēāļĢāļāđ āđāļāļ·āđāļāđāļŦāđāļŠāļēāļĄāļēāļĢāļāđāļĢāļĩāļĒāļāļĨāļģāļāļąāļāđāļŦāļāļļāļāļēāļĢāļāđāđāļāđāđāļĄāđāđāļĄāđāļĄāļĩāļāļēāļŽāļīāļāļēāļāļĨāļēāļ
2ïļâĢ āļāļ§āļēāļĄāļāļąāļāđāļĒāđāļāļāļāļāļāđāļāļĄāļđāļĨ (Conflicts) āđāļĄāđāļāļ°āļāļąāļāļĨāļģāļāļąāļāđāļāđāđāļĨāđāļ§ āđāļāđāļāđāļēāļāļļāļāļāļĢāļāđāļŠāļāļāđāļāļĢāļ·āđāļāļāđāļāđāđāļāļāđāļāļĄāļđāļĨāđāļāļĩāļĒāļ§āļāļąāļ āđāļāđāļ āļĒāļāļāđāļāļīāļāđāļāļāļąāļāļāļĩ āđāļĨāđāļ§āļāļīāļāļāđāđāļāđāļēāļĄāļē āļāļēāļāđāļāļīāļāļāļēāļĢāđāļāļĩāļĒāļāļāļąāļāđāļĨāļ°āļāđāļāļĄāļđāļĨāļŦāļēāļĒ
āļ§āļīāļāļĩāđāļāđāļāļ·āļ CRDTs (Conflict-Free Replicated Data Types) — āđāļāļĢāļāļŠāļĢāđāļēāļāļāđāļāļĄāļđāļĨāļāļĩāđāļŠāļēāļĄāļēāļĢāļāļĢāļ§āļĄāļāļąāļāđāļāđāđāļāļĒāđāļĄāđāļŠāļđāļāđāļŠāļĩāļĒāļāđāļāļĄāļđāļĨ āđāļāđāļ āđāļāđāļāļĨāļĒāļļāļāļāđ Last-Write-Wins (LWW) āļāļĩāđāđāļŦāđāļāđāļāļĄāļđāļĨāļĨāđāļēāļŠāļļāļāđāļāđāļāļāđāļēāļĒāļāļāļ°
āđāļāļ·āđāļāđāļŦāđāļĢāļ°āļāļāļāļĩāđāļāļģāļāļēāļāđāļāđāļāļĢāļīāļ SQLite āļāļđāļāđāļĨāļ·āļāļāđāļāđāļāļāļēāļāļāđāļāļĄāļđāļĨāļŦāļĨāļąāļ āđāļāļĢāļēāļ°āļĄāļĩāļāļ§āļēāļĄāđāļŠāļāļĩāļĒāļĢ āđāļāđāļāļēāļāļāđāļēāļĒ āđāļĨāļ°āļĄāļĩāļāļĒāļđāđāđāļāļāļļāļāđāļāļĨāļāļāļāļĢāđāļĄ āđāļāļĒ Bambini āđāļāđāļŠāļĢāđāļēāļ SQLite extension āļāļĩāđāđāļāđāļāļāļļāļāļāļēāļĢāđāļāļĨāļĩāđāļĒāļāđāļāļĨāļāđāļāđāļ “āļāđāļāļāļ§āļēāļĄ” āļāļĢāđāļāļĄ timestamp āļāļēāļ HLC āđāļĨāļ°āđāļāđ CRDT āđāļāļāļēāļĢāļāļąāļāļŠāļīāļāļ§āđāļēāđāļāļĨāļĩāđāļĒāļāđāļāļĨāļāđāļāļāļ§āļĢāļāļģāļĄāļēāđāļāđ
āļāļĨāļĨāļąāļāļāđāļāļ·āļāļĢāļ°āļāļāļāļĩāđāļŠāļēāļĄāļēāļĢāļāļāļģāļāļēāļāļāļāļāđāļĨāļāđāđāļāđāđāļāđāļāļŠāļąāļāļāļēāļŦāđāđāļāļĒāđāļĄāđāļŠāļđāļāđāļŠāļĩāļĒāļāđāļāļĄāļđāļĨ āđāļĨāļ°āđāļĄāļ·āđāļāļāļĨāļąāļāļĄāļēāļāļāļāđāļĨāļāđāļāđāļŠāļēāļĄāļēāļĢāļāļĢāļ§āļĄāļāđāļāļĄāļđāļĨāđāļāđāļāļĒāđāļēāļāđāļĄāđāļāļĒāļģāđāļāļĒāđāļĄāđāļāđāļāļāđāļāđāđāļāļīāļĢāđāļāđāļ§āļāļĢāđāļāļĨāļēāļ
āļāđāļāļĄāļđāļĨāļŠāļģāļāļąāļāļāļēāļāļāđāļēāļ§
Local-First Apps āļĒāļąāļāđāļĄāđāđāļāļĢāđāļŦāļĨāļēāļĒāđāļāļĢāļēāļ°āļāļēāļĢāļāļīāļāļāđāļāđāļāļĄāļđāļĨāļĢāļ°āļŦāļ§āđāļēāļāļāļļāļāļāļĢāļāđāļāļģāđāļāđāļĒāļēāļ
āļāļąāļāļŦāļēāļŦāļĨāļąāļāļāļ·āļāļāļēāļĢāļāļąāļāļĨāļģāļāļąāļāđāļŦāļāļļāļāļēāļĢāļāđāđāļĨāļ°āļāļēāļĢāđāļāđāđāļāļāļ§āļēāļĄāļāļąāļāđāļĒāđāļāļāļāļāļāđāļāļĄāļđāļĨ
āđāļāđ Hybrid Logical Clocks (HLC) āđāļāļ·āđāļāļāļąāļāļĨāļģāļāļąāļāđāļŦāļāļļāļāļēāļĢāļāđāđāļāļāļāļĢāļ°āļāļēāļĒ
āđāļāđ CRDTs āđāļāļ·āđāļāļĢāļ§āļĄāļāđāļāļĄāļđāļĨāđāļāļĒāđāļĄāđāļŠāļđāļāđāļŠāļĩāļĒāļŦāļĢāļ·āļāđāļāļĩāļĒāļāļāļąāļāļāļąāļ
āđāļāļ§āļāļēāļāļāļēāļĢāđāļāđāļāļąāļāļŦāļē
SQLite āļāļđāļāđāļāđāđāļāđāļāļāļēāļāļāđāļāļĄāļđāļĨāļŦāļĨāļąāļāđāļāļĢāļēāļ°āđāļŠāļāļĩāļĒāļĢāđāļĨāļ°āļĄāļĩāļāļĒāļđāđāļāļļāļāđāļāļĨāļāļāļāļĢāđāļĄ
āļāļļāļāļāļēāļĢāđāļāļĨāļĩāđāļĒāļāđāļāļĨāļāļāļđāļāđāļāđāļāđāļāđāļāļāđāļāļāļ§āļēāļĄāļāļĢāđāļāļĄ timestamp
āđāļāđāļāļĨāļĒāļļāļāļāđ Last-Write-Wins (LWW) āđāļāļ·āđāļāđāļĨāļ·āļāļāļāđāļāļĄāļđāļĨāļĨāđāļēāļŠāļļāļ
āļĢāļ°āļāļāļŠāļēāļĄāļēāļĢāļāļāļģāļāļēāļāļāļāļāđāļĨāļāđāđāļāđāļāļēāļāđāļāļĒāđāļĄāđāļŠāļđāļāđāļŠāļĩāļĒāļāđāļāļĄāļđāļĨ
āļāđāļāļĄāļđāļĨāđāļŠāļĢāļīāļĄāļāļēāļāļ āļēāļĒāļāļāļ
Turso āđāļĨāļ° cr-sqlite āđāļāđāļāļāļąāļ§āļāļĒāđāļēāļāļāļāļāļĢāļ°āļāļāļāļĩāđāđāļāđ SQLite āđāļāļāļēāļĢāļāļīāļāļāđāđāļāļ Local-First
CRDTs āļāļđāļāđāļāđāđāļāļĢāļ°āļāļ collaboration āđāļāđāļ Automerge āđāļĨāļ° Yjs
HLCs āļāļđāļāđāļāđāđāļāļĢāļ°āļāļāļāļēāļāļāđāļāļĄāļđāļĨāļāļĢāļ°āļāļēāļĒ āđāļāđāļ CockroachDB āđāļĨāļ° Spanner
Local-First Apps āļāđāļ§āļĒāļĨāļāļāļēāļĢāļāļķāđāļāļāļēāđāļāļīāļĢāđāļāđāļ§āļāļĢāđāļāļĨāļēāļāđāļĨāļ°āđāļāļīāđāļĄāļāļ§āļēāļĄāđāļāđāļāļŠāđāļ§āļāļāļąāļ§
https://marcobambini.substack.com/p/why-local-first-apps-havent-become
āđāļāļāļāļĨāļīāđāļāļāļąāļāđāļāļ Local-First āļŦāļĢāļ·āļ Offline-First āđāļāļĒāļāļđāļāļĄāļāļāļ§āđāļēāđāļāđāļāļāļāļēāļāļāļāļāļāļāļēāļĢāđāļāđāļāļēāļāļāļāļāļāđāđāļ§āļĢāđ āļāđāļ§āļĒāļāļļāļāļŠāļĄāļāļąāļāļīāļāļĩāđāđāļŦāļĨāļāđāļĢāđāļ§ āđāļāđāđāļāļāđāļĄāđāļāđāļāļāļāđāļāđāļāđāļ āđāļĨāļ°āđāļŦāđāļāļ§āļēāļĄāđāļāđāļāļŠāđāļ§āļāļāļąāļ§āļŠāļđāļāļŠāļļāļ āđāļāđāđāļāļāļ§āļēāļĄāđāļāđāļāļāļĢāļīāļ āđāļāļāļāļĩāđāļĢāļāļāļĢāļąāļāļāļēāļĢāļāļģāļāļēāļāđāļāļāļāļāļāđāļĨāļāđāļāļĢāļīāļ āđ āļĒāļąāļāļĄāļĩāļāđāļāļĒāļĄāļēāļ āđāļāļĢāļēāļ°āļāļēāļĢ “āļāļīāļāļāđāļāđāļāļĄāļđāļĨ” āļĢāļ°āļŦāļ§āđāļēāļāļāļļāļāļāļĢāļāđāļŦāļĨāļēāļĒāđāļāļĢāļ·āđāļāļāļāļąāđāļāļĒāļēāļāļāļ§āđāļēāļāļĩāđāļāļīāļ
Marco Bambini āļāļđāđāļāđāļāļāļąāđāļ SQLite Cloud āļāļāļīāļāļēāļĒāļ§āđāļē āļāļēāļĢāļŠāļĢāđāļēāļāđāļāļāđāļāļ Local-First āļāļ·āļāļāļēāļĢāļŠāļĢāđāļēāļāļĢāļ°āļāļāļāļĢāļ°āļāļēāļĒ (Distributed System) āļāļĩāđāļāđāļāļāđāļŦāđāļŦāļĨāļēāļĒāļāļļāļāļāļĢāļāđāļŠāļēāļĄāļēāļĢāļāđāļāđāđāļāļāđāļāļĄāļđāļĨāđāļāļāļāļāļāđāļĨāļāđ āđāļĨāļ°āļŠāļļāļāļāđāļēāļĒāļāđāļāļāļĢāļ§āļĄāļāđāļāļĄāļđāļĨāđāļŦāđāļāļĢāļāļāļąāļāđāļāļĒāđāļĄāđāļŠāļđāļāđāļŠāļĩāļĒāļāļ°āđāļĢāđāļĨāļĒ āļāļķāđāļāļĄāļĩāļŠāļāļāļāļąāļāļŦāļēāļŦāļĨāļąāļāļāļĩāđāļāđāļāļāđāļāđāļāļ·āļ:
1ïļâĢ āļĨāļģāļāļąāļāđāļŦāļāļļāļāļēāļĢāļāđāđāļĄāđāđāļāđāļāļāļ (Unreliable Ordering) āļāļļāļāļāļĢāļāđāđāļāđāļĨāļ°āđāļāļĢāļ·āđāļāļāļĄāļĩāđāļ§āļĨāļēāđāļĄāđāļāļĢāļāļāļąāļ āđāļĨāļ°āđāļŦāļāļļāļāļēāļĢāļāđāđāļāļīāļāļāļķāđāļāđāļĄāđāļāļĢāđāļāļĄāļāļąāļ āļŦāļēāļāļāļģāļāđāļāļĄāļđāļĨāļĄāļēāļĢāļ§āļĄāđāļāļĒāđāļĄāđāļāļąāļāļĨāļģāļāļąāļāđāļŦāđāļāļĩ āļāļēāļāđāļāļīāļāļāļ§āļēāļĄāļāļąāļāđāļĒāđāļ āđāļāđāļ āđāļāļĢāļ·āđāļāļ A āļāļąāđāļāļāđāļē x = 3 āļŠāđāļ§āļāđāļāļĢāļ·āđāļāļ B āļāļąāđāļ x = 5 āđāļĨāđāļ§āđāļāļĢāļāļ§āļĢ “āļāļāļ°”?
āļ§āļīāļāļĩāđāļāđāļāļ·āļ Hybrid Logical Clocks (HLC) — āļĢāļ°āļāļ timestamp āļāļĩāđāļĢāļ§āļĄāđāļ§āļĨāļēāđāļāļĢāļ·āđāļāļāļāļĢāļīāļāļāļąāļāļāļąāļ§āļāļąāļāđāļŦāļāļļāļāļēāļĢāļāđ āđāļāļ·āđāļāđāļŦāđāļŠāļēāļĄāļēāļĢāļāđāļĢāļĩāļĒāļāļĨāļģāļāļąāļāđāļŦāļāļļāļāļēāļĢāļāđāđāļāđāđāļĄāđāđāļĄāđāļĄāļĩāļāļēāļŽāļīāļāļēāļāļĨāļēāļ
2ïļâĢ āļāļ§āļēāļĄāļāļąāļāđāļĒāđāļāļāļāļāļāđāļāļĄāļđāļĨ (Conflicts) āđāļĄāđāļāļ°āļāļąāļāļĨāļģāļāļąāļāđāļāđāđāļĨāđāļ§ āđāļāđāļāđāļēāļāļļāļāļāļĢāļāđāļŠāļāļāđāļāļĢāļ·āđāļāļāđāļāđāđāļāļāđāļāļĄāļđāļĨāđāļāļĩāļĒāļ§āļāļąāļ āđāļāđāļ āļĒāļāļāđāļāļīāļāđāļāļāļąāļāļāļĩ āđāļĨāđāļ§āļāļīāļāļāđāđāļāđāļēāļĄāļē āļāļēāļāđāļāļīāļāļāļēāļĢāđāļāļĩāļĒāļāļāļąāļāđāļĨāļ°āļāđāļāļĄāļđāļĨāļŦāļēāļĒ
āļ§āļīāļāļĩāđāļāđāļāļ·āļ CRDTs (Conflict-Free Replicated Data Types) — āđāļāļĢāļāļŠāļĢāđāļēāļāļāđāļāļĄāļđāļĨāļāļĩāđāļŠāļēāļĄāļēāļĢāļāļĢāļ§āļĄāļāļąāļāđāļāđāđāļāļĒāđāļĄāđāļŠāļđāļāđāļŠāļĩāļĒāļāđāļāļĄāļđāļĨ āđāļāđāļ āđāļāđāļāļĨāļĒāļļāļāļāđ Last-Write-Wins (LWW) āļāļĩāđāđāļŦāđāļāđāļāļĄāļđāļĨāļĨāđāļēāļŠāļļāļāđāļāđāļāļāđāļēāļĒāļāļāļ°
āđāļāļ·āđāļāđāļŦāđāļĢāļ°āļāļāļāļĩāđāļāļģāļāļēāļāđāļāđāļāļĢāļīāļ SQLite āļāļđāļāđāļĨāļ·āļāļāđāļāđāļāļāļēāļāļāđāļāļĄāļđāļĨāļŦāļĨāļąāļ āđāļāļĢāļēāļ°āļĄāļĩāļāļ§āļēāļĄāđāļŠāļāļĩāļĒāļĢ āđāļāđāļāļēāļāļāđāļēāļĒ āđāļĨāļ°āļĄāļĩāļāļĒāļđāđāđāļāļāļļāļāđāļāļĨāļāļāļāļĢāđāļĄ āđāļāļĒ Bambini āđāļāđāļŠāļĢāđāļēāļ SQLite extension āļāļĩāđāđāļāđāļāļāļļāļāļāļēāļĢāđāļāļĨāļĩāđāļĒāļāđāļāļĨāļāđāļāđāļ “āļāđāļāļāļ§āļēāļĄ” āļāļĢāđāļāļĄ timestamp āļāļēāļ HLC āđāļĨāļ°āđāļāđ CRDT āđāļāļāļēāļĢāļāļąāļāļŠāļīāļāļ§āđāļēāđāļāļĨāļĩāđāļĒāļāđāļāļĨāļāđāļāļāļ§āļĢāļāļģāļĄāļēāđāļāđ
āļāļĨāļĨāļąāļāļāđāļāļ·āļāļĢāļ°āļāļāļāļĩāđāļŠāļēāļĄāļēāļĢāļāļāļģāļāļēāļāļāļāļāđāļĨāļāđāđāļāđāđāļāđāļāļŠāļąāļāļāļēāļŦāđāđāļāļĒāđāļĄāđāļŠāļđāļāđāļŠāļĩāļĒāļāđāļāļĄāļđāļĨ āđāļĨāļ°āđāļĄāļ·āđāļāļāļĨāļąāļāļĄāļēāļāļāļāđāļĨāļāđāļāđāļŠāļēāļĄāļēāļĢāļāļĢāļ§āļĄāļāđāļāļĄāļđāļĨāđāļāđāļāļĒāđāļēāļāđāļĄāđāļāļĒāļģāđāļāļĒāđāļĄāđāļāđāļāļāđāļāđāđāļāļīāļĢāđāļāđāļ§āļāļĢāđāļāļĨāļēāļ
āļāđāļāļĄāļđāļĨāļŠāļģāļāļąāļāļāļēāļāļāđāļēāļ§
Local-First Apps āļĒāļąāļāđāļĄāđāđāļāļĢāđāļŦāļĨāļēāļĒāđāļāļĢāļēāļ°āļāļēāļĢāļāļīāļāļāđāļāđāļāļĄāļđāļĨāļĢāļ°āļŦāļ§āđāļēāļāļāļļāļāļāļĢāļāđāļāļģāđāļāđāļĒāļēāļ
āļāļąāļāļŦāļēāļŦāļĨāļąāļāļāļ·āļāļāļēāļĢāļāļąāļāļĨāļģāļāļąāļāđāļŦāļāļļāļāļēāļĢāļāđāđāļĨāļ°āļāļēāļĢāđāļāđāđāļāļāļ§āļēāļĄāļāļąāļāđāļĒāđāļāļāļāļāļāđāļāļĄāļđāļĨ
āđāļāđ Hybrid Logical Clocks (HLC) āđāļāļ·āđāļāļāļąāļāļĨāļģāļāļąāļāđāļŦāļāļļāļāļēāļĢāļāđāđāļāļāļāļĢāļ°āļāļēāļĒ
āđāļāđ CRDTs āđāļāļ·āđāļāļĢāļ§āļĄāļāđāļāļĄāļđāļĨāđāļāļĒāđāļĄāđāļŠāļđāļāđāļŠāļĩāļĒāļŦāļĢāļ·āļāđāļāļĩāļĒāļāļāļąāļāļāļąāļ
āđāļāļ§āļāļēāļāļāļēāļĢāđāļāđāļāļąāļāļŦāļē
SQLite āļāļđāļāđāļāđāđāļāđāļāļāļēāļāļāđāļāļĄāļđāļĨāļŦāļĨāļąāļāđāļāļĢāļēāļ°āđāļŠāļāļĩāļĒāļĢāđāļĨāļ°āļĄāļĩāļāļĒāļđāđāļāļļāļāđāļāļĨāļāļāļāļĢāđāļĄ
āļāļļāļāļāļēāļĢāđāļāļĨāļĩāđāļĒāļāđāļāļĨāļāļāļđāļāđāļāđāļāđāļāđāļāļāđāļāļāļ§āļēāļĄāļāļĢāđāļāļĄ timestamp
āđāļāđāļāļĨāļĒāļļāļāļāđ Last-Write-Wins (LWW) āđāļāļ·āđāļāđāļĨāļ·āļāļāļāđāļāļĄāļđāļĨāļĨāđāļēāļŠāļļāļ
āļĢāļ°āļāļāļŠāļēāļĄāļēāļĢāļāļāļģāļāļēāļāļāļāļāđāļĨāļāđāđāļāđāļāļēāļāđāļāļĒāđāļĄāđāļŠāļđāļāđāļŠāļĩāļĒāļāđāļāļĄāļđāļĨ
āļāđāļāļĄāļđāļĨāđāļŠāļĢāļīāļĄāļāļēāļāļ āļēāļĒāļāļāļ
Turso āđāļĨāļ° cr-sqlite āđāļāđāļāļāļąāļ§āļāļĒāđāļēāļāļāļāļāļĢāļ°āļāļāļāļĩāđāđāļāđ SQLite āđāļāļāļēāļĢāļāļīāļāļāđāđāļāļ Local-First
CRDTs āļāļđāļāđāļāđāđāļāļĢāļ°āļāļ collaboration āđāļāđāļ Automerge āđāļĨāļ° Yjs
HLCs āļāļđāļāđāļāđāđāļāļĢāļ°āļāļāļāļēāļāļāđāļāļĄāļđāļĨāļāļĢāļ°āļāļēāļĒ āđāļāđāļ CockroachDB āđāļĨāļ° Spanner
Local-First Apps āļāđāļ§āļĒāļĨāļāļāļēāļĢāļāļķāđāļāļāļēāđāļāļīāļĢāđāļāđāļ§āļāļĢāđāļāļĨāļēāļāđāļĨāļ°āđāļāļīāđāļĄāļāļ§āļēāļĄāđāļāđāļāļŠāđāļ§āļāļāļąāļ§
https://marcobambini.substack.com/p/why-local-first-apps-havent-become
ðą “Local-First Apps āļĒāļąāļāđāļĄāđāđāļāļīāļāļāļĢāļīāļ āđāļāļĢāļēāļ°āļāļēāļĢ Sync āđāļĄāđāļāđāļēāļĒāļāļĒāđāļēāļāļāļĩāđāļāļīāļ — āđāļāđ SQLite + HLC + CRDT āļāļēāļāđāļāđāļāļāļģāļāļāļ”
āđāļāļāļāļĨāļīāđāļāļāļąāļāđāļāļ Local-First āļŦāļĢāļ·āļ Offline-First āđāļāļĒāļāļđāļāļĄāļāļāļ§āđāļēāđāļāđāļāļāļāļēāļāļāļāļāļāļāļēāļĢāđāļāđāļāļēāļāļāļāļāļāđāđāļ§āļĢāđ āļāđāļ§āļĒāļāļļāļāļŠāļĄāļāļąāļāļīāļāļĩāđāđāļŦāļĨāļāđāļĢāđāļ§ āđāļāđāđāļāļāđāļĄāđāļāđāļāļāļāđāļāđāļāđāļ āđāļĨāļ°āđāļŦāđāļāļ§āļēāļĄāđāļāđāļāļŠāđāļ§āļāļāļąāļ§āļŠāļđāļāļŠāļļāļ āđāļāđāđāļāļāļ§āļēāļĄāđāļāđāļāļāļĢāļīāļ āđāļāļāļāļĩāđāļĢāļāļāļĢāļąāļāļāļēāļĢāļāļģāļāļēāļāđāļāļāļāļāļāđāļĨāļāđāļāļĢāļīāļ āđ āļĒāļąāļāļĄāļĩāļāđāļāļĒāļĄāļēāļ āđāļāļĢāļēāļ°āļāļēāļĢ “āļāļīāļāļāđāļāđāļāļĄāļđāļĨ” āļĢāļ°āļŦāļ§āđāļēāļāļāļļāļāļāļĢāļāđāļŦāļĨāļēāļĒāđāļāļĢāļ·āđāļāļāļāļąāđāļāļĒāļēāļāļāļ§āđāļēāļāļĩāđāļāļīāļ
Marco Bambini āļāļđāđāļāđāļāļāļąāđāļ SQLite Cloud āļāļāļīāļāļēāļĒāļ§āđāļē āļāļēāļĢāļŠāļĢāđāļēāļāđāļāļāđāļāļ Local-First āļāļ·āļāļāļēāļĢāļŠāļĢāđāļēāļāļĢāļ°āļāļāļāļĢāļ°āļāļēāļĒ (Distributed System) āļāļĩāđāļāđāļāļāđāļŦāđāļŦāļĨāļēāļĒāļāļļāļāļāļĢāļāđāļŠāļēāļĄāļēāļĢāļāđāļāđāđāļāļāđāļāļĄāļđāļĨāđāļāļāļāļāļāđāļĨāļāđ āđāļĨāļ°āļŠāļļāļāļāđāļēāļĒāļāđāļāļāļĢāļ§āļĄāļāđāļāļĄāļđāļĨāđāļŦāđāļāļĢāļāļāļąāļāđāļāļĒāđāļĄāđāļŠāļđāļāđāļŠāļĩāļĒāļāļ°āđāļĢāđāļĨāļĒ āļāļķāđāļāļĄāļĩāļŠāļāļāļāļąāļāļŦāļēāļŦāļĨāļąāļāļāļĩāđāļāđāļāļāđāļāđāļāļ·āļ:
1ïļâĢ āļĨāļģāļāļąāļāđāļŦāļāļļāļāļēāļĢāļāđāđāļĄāđāđāļāđāļāļāļ (Unreliable Ordering) āļāļļāļāļāļĢāļāđāđāļāđāļĨāļ°āđāļāļĢāļ·āđāļāļāļĄāļĩāđāļ§āļĨāļēāđāļĄāđāļāļĢāļāļāļąāļ āđāļĨāļ°āđāļŦāļāļļāļāļēāļĢāļāđāđāļāļīāļāļāļķāđāļāđāļĄāđāļāļĢāđāļāļĄāļāļąāļ āļŦāļēāļāļāļģāļāđāļāļĄāļđāļĨāļĄāļēāļĢāļ§āļĄāđāļāļĒāđāļĄāđāļāļąāļāļĨāļģāļāļąāļāđāļŦāđāļāļĩ āļāļēāļāđāļāļīāļāļāļ§āļēāļĄāļāļąāļāđāļĒāđāļ āđāļāđāļ āđāļāļĢāļ·āđāļāļ A āļāļąāđāļāļāđāļē x = 3 āļŠāđāļ§āļāđāļāļĢāļ·āđāļāļ B āļāļąāđāļ x = 5 āđāļĨāđāļ§āđāļāļĢāļāļ§āļĢ “āļāļāļ°”?
ð§ āļ§āļīāļāļĩāđāļāđāļāļ·āļ Hybrid Logical Clocks (HLC) — āļĢāļ°āļāļ timestamp āļāļĩāđāļĢāļ§āļĄāđāļ§āļĨāļēāđāļāļĢāļ·āđāļāļāļāļĢāļīāļāļāļąāļāļāļąāļ§āļāļąāļāđāļŦāļāļļāļāļēāļĢāļāđ āđāļāļ·āđāļāđāļŦāđāļŠāļēāļĄāļēāļĢāļāđāļĢāļĩāļĒāļāļĨāļģāļāļąāļāđāļŦāļāļļāļāļēāļĢāļāđāđāļāđāđāļĄāđāđāļĄāđāļĄāļĩāļāļēāļŽāļīāļāļēāļāļĨāļēāļ
2ïļâĢ āļāļ§āļēāļĄāļāļąāļāđāļĒāđāļāļāļāļāļāđāļāļĄāļđāļĨ (Conflicts) āđāļĄāđāļāļ°āļāļąāļāļĨāļģāļāļąāļāđāļāđāđāļĨāđāļ§ āđāļāđāļāđāļēāļāļļāļāļāļĢāļāđāļŠāļāļāđāļāļĢāļ·āđāļāļāđāļāđāđāļāļāđāļāļĄāļđāļĨāđāļāļĩāļĒāļ§āļāļąāļ āđāļāđāļ āļĒāļāļāđāļāļīāļāđāļāļāļąāļāļāļĩ āđāļĨāđāļ§āļāļīāļāļāđāđāļāđāļēāļĄāļē āļāļēāļāđāļāļīāļāļāļēāļĢāđāļāļĩāļĒāļāļāļąāļāđāļĨāļ°āļāđāļāļĄāļđāļĨāļŦāļēāļĒ
ð§ āļ§āļīāļāļĩāđāļāđāļāļ·āļ CRDTs (Conflict-Free Replicated Data Types) — āđāļāļĢāļāļŠāļĢāđāļēāļāļāđāļāļĄāļđāļĨāļāļĩāđāļŠāļēāļĄāļēāļĢāļāļĢāļ§āļĄāļāļąāļāđāļāđāđāļāļĒāđāļĄāđāļŠāļđāļāđāļŠāļĩāļĒāļāđāļāļĄāļđāļĨ āđāļāđāļ āđāļāđāļāļĨāļĒāļļāļāļāđ Last-Write-Wins (LWW) āļāļĩāđāđāļŦāđāļāđāļāļĄāļđāļĨāļĨāđāļēāļŠāļļāļāđāļāđāļāļāđāļēāļĒāļāļāļ°
āđāļāļ·āđāļāđāļŦāđāļĢāļ°āļāļāļāļĩāđāļāļģāļāļēāļāđāļāđāļāļĢāļīāļ SQLite āļāļđāļāđāļĨāļ·āļāļāđāļāđāļāļāļēāļāļāđāļāļĄāļđāļĨāļŦāļĨāļąāļ āđāļāļĢāļēāļ°āļĄāļĩāļāļ§āļēāļĄāđāļŠāļāļĩāļĒāļĢ āđāļāđāļāļēāļāļāđāļēāļĒ āđāļĨāļ°āļĄāļĩāļāļĒāļđāđāđāļāļāļļāļāđāļāļĨāļāļāļāļĢāđāļĄ āđāļāļĒ Bambini āđāļāđāļŠāļĢāđāļēāļ SQLite extension āļāļĩāđāđāļāđāļāļāļļāļāļāļēāļĢāđāļāļĨāļĩāđāļĒāļāđāļāļĨāļāđāļāđāļ “āļāđāļāļāļ§āļēāļĄ” āļāļĢāđāļāļĄ timestamp āļāļēāļ HLC āđāļĨāļ°āđāļāđ CRDT āđāļāļāļēāļĢāļāļąāļāļŠāļīāļāļ§āđāļēāđāļāļĨāļĩāđāļĒāļāđāļāļĨāļāđāļāļāļ§āļĢāļāļģāļĄāļēāđāļāđ
āļāļĨāļĨāļąāļāļāđāļāļ·āļāļĢāļ°āļāļāļāļĩāđāļŠāļēāļĄāļēāļĢāļāļāļģāļāļēāļāļāļāļāđāļĨāļāđāđāļāđāđāļāđāļāļŠāļąāļāļāļēāļŦāđāđāļāļĒāđāļĄāđāļŠāļđāļāđāļŠāļĩāļĒāļāđāļāļĄāļđāļĨ āđāļĨāļ°āđāļĄāļ·āđāļāļāļĨāļąāļāļĄāļēāļāļāļāđāļĨāļāđāļāđāļŠāļēāļĄāļēāļĢāļāļĢāļ§āļĄāļāđāļāļĄāļđāļĨāđāļāđāļāļĒāđāļēāļāđāļĄāđāļāļĒāļģāđāļāļĒāđāļĄāđāļāđāļāļāđāļāđāđāļāļīāļĢāđāļāđāļ§āļāļĢāđāļāļĨāļēāļ
â
āļāđāļāļĄāļđāļĨāļŠāļģāļāļąāļāļāļēāļāļāđāļēāļ§
âĄïļ Local-First Apps āļĒāļąāļāđāļĄāđāđāļāļĢāđāļŦāļĨāļēāļĒāđāļāļĢāļēāļ°āļāļēāļĢāļāļīāļāļāđāļāđāļāļĄāļđāļĨāļĢāļ°āļŦāļ§āđāļēāļāļāļļāļāļāļĢāļāđāļāļģāđāļāđāļĒāļēāļ
âĄïļ āļāļąāļāļŦāļēāļŦāļĨāļąāļāļāļ·āļāļāļēāļĢāļāļąāļāļĨāļģāļāļąāļāđāļŦāļāļļāļāļēāļĢāļāđāđāļĨāļ°āļāļēāļĢāđāļāđāđāļāļāļ§āļēāļĄāļāļąāļāđāļĒāđāļāļāļāļāļāđāļāļĄāļđāļĨ
âĄïļ āđāļāđ Hybrid Logical Clocks (HLC) āđāļāļ·āđāļāļāļąāļāļĨāļģāļāļąāļāđāļŦāļāļļāļāļēāļĢāļāđāđāļāļāļāļĢāļ°āļāļēāļĒ
âĄïļ āđāļāđ CRDTs āđāļāļ·āđāļāļĢāļ§āļĄāļāđāļāļĄāļđāļĨāđāļāļĒāđāļĄāđāļŠāļđāļāđāļŠāļĩāļĒāļŦāļĢāļ·āļāđāļāļĩāļĒāļāļāļąāļāļāļąāļ
â
āđāļāļ§āļāļēāļāļāļēāļĢāđāļāđāļāļąāļāļŦāļē
âĄïļ SQLite āļāļđāļāđāļāđāđāļāđāļāļāļēāļāļāđāļāļĄāļđāļĨāļŦāļĨāļąāļāđāļāļĢāļēāļ°āđāļŠāļāļĩāļĒāļĢāđāļĨāļ°āļĄāļĩāļāļĒāļđāđāļāļļāļāđāļāļĨāļāļāļāļĢāđāļĄ
âĄïļ āļāļļāļāļāļēāļĢāđāļāļĨāļĩāđāļĒāļāđāļāļĨāļāļāļđāļāđāļāđāļāđāļāđāļāļāđāļāļāļ§āļēāļĄāļāļĢāđāļāļĄ timestamp
âĄïļ āđāļāđāļāļĨāļĒāļļāļāļāđ Last-Write-Wins (LWW) āđāļāļ·āđāļāđāļĨāļ·āļāļāļāđāļāļĄāļđāļĨāļĨāđāļēāļŠāļļāļ
âĄïļ āļĢāļ°āļāļāļŠāļēāļĄāļēāļĢāļāļāļģāļāļēāļāļāļāļāđāļĨāļāđāđāļāđāļāļēāļāđāļāļĒāđāļĄāđāļŠāļđāļāđāļŠāļĩāļĒāļāđāļāļĄāļđāļĨ
â
āļāđāļāļĄāļđāļĨāđāļŠāļĢāļīāļĄāļāļēāļāļ āļēāļĒāļāļāļ
âĄïļ Turso āđāļĨāļ° cr-sqlite āđāļāđāļāļāļąāļ§āļāļĒāđāļēāļāļāļāļāļĢāļ°āļāļāļāļĩāđāđāļāđ SQLite āđāļāļāļēāļĢāļāļīāļāļāđāđāļāļ Local-First
âĄïļ CRDTs āļāļđāļāđāļāđāđāļāļĢāļ°āļāļ collaboration āđāļāđāļ Automerge āđāļĨāļ° Yjs
âĄïļ HLCs āļāļđāļāđāļāđāđāļāļĢāļ°āļāļāļāļēāļāļāđāļāļĄāļđāļĨāļāļĢāļ°āļāļēāļĒ āđāļāđāļ CockroachDB āđāļĨāļ° Spanner
âĄïļ Local-First Apps āļāđāļ§āļĒāļĨāļāļāļēāļĢāļāļķāđāļāļāļēāđāļāļīāļĢāđāļāđāļ§āļāļĢāđāļāļĨāļēāļāđāļĨāļ°āđāļāļīāđāļĄāļāļ§āļēāļĄāđāļāđāļāļŠāđāļ§āļāļāļąāļ§
https://marcobambini.substack.com/p/why-local-first-apps-havent-become
0 Comments
0 Shares
230 Views
0 Reviews