Posts

Part 3: Conflict Resolution in Offline-First Android Apps (LWW vs. CRDT Explained)

Image
 A Senior Engineer’s guide to LWW, Semantic Merging, and CRDTs for bulletproof data integrity. TL;DR Conflicts are unavoidable  in offline-first apps; ignoring them leads to silent data loss. LWW (Last Writer Wins)  is the simplest strategy but the riskiest. Semantic Merge  is the industry standard for 90% of mobile apps. CRDTs  are the gold standard for real-time collaborative editing. Integrity  requires atomic transactions between your local DB and the Sync Outbox. 1. The Anatomy of a Conflict When multiple devices update the same data without a persistent connection,  conflict resolution in distributed systems  becomes your top priority. Visualizing the Collision The Stale Read (Lost Update):  Your app reads a profile at  v1 . While offline, a web dashboard updates it to  v2 . The app eventually syncs its edit based on  v1 , wiping out the server’s newer data. The Write-Write Conflict:  Device A sets a status to “Done,...

Part 2: Designing the Core Sync Engine

Image
 How to design idempotent, resilient background synchronization using WorkManager and the Command Pattern. In  Part 1 , we established the “Offline-First” mindset: the UI observes the local database. But how do we ensure user actions — likes, comments, or edits — actually reach the server without getting lost in “Lie-Fi”? Welcome to the heart of the machine:  The Sync Engine. 1. The Action Outbox: Preserving Intent In a production-grade  mobile sync engine design , you don’t just “call an API.” You encapsulate intent. The  Outbox Pattern  ensures that an action survives process death and device reboots. Kotlin Implementation: The Action Entity @Entity (tableName = "pending_actions" ) data class PendingAction ( @PrimaryKey (autoGenerate = true) val id : Long = 0 , val type : String, // e.g., "ADD_COMMENT", "UPDATE_PROFILE" val payload : String, // Versioned JSON or Protobuf val status : ActionStatus = ActionStatus.PENDING, val retryCount...