<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Alex Benny</title>
    <description>The latest articles on DEV Community by Alex Benny (@alexbenny).</description>
    <link>https://dev.to/alexbenny</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3753313%2F15e9cc93-5474-4f76-abbf-4faf9939e78f.png</url>
      <title>DEV Community: Alex Benny</title>
      <link>https://dev.to/alexbenny</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alexbenny"/>
    <language>en</language>
    <item>
      <title>From Spaghetti Code to the Lazarus Protocol</title>
      <dc:creator>Alex Benny</dc:creator>
      <pubDate>Wed, 04 Feb 2026 16:18:07 +0000</pubDate>
      <link>https://dev.to/alexbenny/from-spaghetti-code-to-the-lazarus-protocol-24i9</link>
      <guid>https://dev.to/alexbenny/from-spaghetti-code-to-the-lazarus-protocol-24i9</guid>
      <description>&lt;p&gt;&lt;strong&gt;How We Built an &lt;a href="https://play.google.com/store/apps/details?id=com.firstbridgestudios.kfirst" rel="noopener noreferrer"&gt;Offline-First Engineering App&lt;/a&gt; with Flutter &amp;amp; SQLite&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I didn’t start by wanting to build software. I started by needing reliable systems where the internet fails.&lt;/p&gt;

&lt;p&gt;This is a technical post-mortem on building a production offline-first engineering app under real-world constraints: unreliable networks, low-end devices, strict budgets, and legal responsibility.&lt;/p&gt;

&lt;p&gt;Why Offline-First Was Non-Negotiable&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kfirst.in/" rel="noopener noreferrer"&gt;K-First&lt;/a&gt; started with a simple observation:&lt;/p&gt;

&lt;p&gt;Construction sites don’t have reliable internet, but engineers still need reliable data.&lt;/p&gt;

&lt;p&gt;Most apps assume:&lt;/p&gt;

&lt;p&gt;network first&lt;/p&gt;

&lt;p&gt;cache later&lt;/p&gt;

&lt;p&gt;sync as an optimization&lt;/p&gt;

&lt;p&gt;That model breaks down when:&lt;/p&gt;

&lt;p&gt;connectivity drops mid-form&lt;/p&gt;

&lt;p&gt;background processes are killed&lt;/p&gt;

&lt;p&gt;devices reboot unexpectedly&lt;/p&gt;

&lt;p&gt;data loss has legal or financial consequences&lt;/p&gt;

&lt;p&gt;So the core constraint from day one was clear:&lt;/p&gt;

&lt;p&gt;The app must function correctly even if the network never comes back.&lt;/p&gt;

&lt;p&gt;Offline-first wasn’t a feature.&lt;br&gt;
It was the architecture.&lt;/p&gt;

&lt;p&gt;V1: The “Zero-Burn” Monolith (December 2025)&lt;/p&gt;

&lt;p&gt;The first version of K-First had one brutal constraint:&lt;/p&gt;

&lt;p&gt;Zero burn.&lt;/p&gt;

&lt;p&gt;No servers&lt;/p&gt;

&lt;p&gt;No paid infrastructure&lt;/p&gt;

&lt;p&gt;No background sync unless a user explicitly paid&lt;/p&gt;

&lt;p&gt;The Initial Architecture (and the Trap)&lt;/p&gt;

&lt;p&gt;To move fast, we built a single large controller—effectively a God Class—that handled:&lt;/p&gt;

&lt;p&gt;navigation&lt;/p&gt;

&lt;p&gt;state&lt;/p&gt;

&lt;p&gt;database access&lt;/p&gt;

&lt;p&gt;UI orchestration&lt;/p&gt;

&lt;p&gt;All project data was eagerly loaded into memory at app startup.&lt;/p&gt;

&lt;p&gt;On paper, it worked.&lt;br&gt;
In reality, it created three serious problems.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Memory Pressure&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Large projects meant large in-memory state.&lt;br&gt;
Low-end Android devices didn’t appreciate that.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;“Passive Builder” Navigation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Forms returned data using:&lt;/p&gt;

&lt;p&gt;Navigator.pop(result)&lt;/p&gt;

&lt;p&gt;This failed when:&lt;/p&gt;

&lt;p&gt;Android killed background activities&lt;/p&gt;

&lt;p&gt;users deep-linked back into the app&lt;/p&gt;

&lt;p&gt;the process restarted mid-flow&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The “Ghost Data” Bug&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Users would save logs…&lt;br&gt;
…and later discover they never actually persisted.&lt;/p&gt;

&lt;p&gt;That’s unacceptable for an engineering logbook.&lt;/p&gt;

&lt;p&gt;By late December, the monolith was already collapsing under real usage.&lt;/p&gt;

&lt;p&gt;Phase 2: The Lazarus Refactor (January 2026)&lt;/p&gt;

&lt;p&gt;We stopped feature work and initiated what we internally called Operation Clean House.&lt;/p&gt;

&lt;p&gt;The goal wasn’t elegance.&lt;br&gt;
The goal was survivability.&lt;/p&gt;

&lt;p&gt;Breaking the God Class&lt;/p&gt;

&lt;p&gt;We migrated to a strict MVVM structure:&lt;/p&gt;

&lt;p&gt;Repository layer for persistence&lt;/p&gt;

&lt;p&gt;ViewModels for state and lifecycle safety&lt;/p&gt;

&lt;p&gt;UI reduced to pure rendering&lt;/p&gt;

&lt;p&gt;State stopped flowing through navigation.&lt;br&gt;
Navigation stopped being a data transport.&lt;/p&gt;

&lt;p&gt;The Lazarus Protocol: Self-Healing Local Storage&lt;/p&gt;

&lt;p&gt;The biggest risk in an offline-first app is silent database corruption.&lt;/p&gt;

&lt;p&gt;crashes happen&lt;/p&gt;

&lt;p&gt;battery pulls happen&lt;/p&gt;

&lt;p&gt;OEMs do weird things&lt;/p&gt;

&lt;p&gt;So we introduced what we call the Lazarus Protocol:&lt;/p&gt;

&lt;p&gt;Every critical database write is checkpointed&lt;/p&gt;

&lt;p&gt;On startup, the app validates the SQLite file&lt;/p&gt;

&lt;p&gt;If corruption is detected:&lt;/p&gt;

&lt;p&gt;the database is quarantined&lt;/p&gt;

&lt;p&gt;the last known-good backup is restored&lt;/p&gt;

&lt;p&gt;The user is informed, but never left with an empty app&lt;/p&gt;

&lt;p&gt;The principle was simple:&lt;/p&gt;

&lt;p&gt;A partially correct logbook is better than a wiped one.&lt;/p&gt;

&lt;p&gt;Android 15 and the 16KB Page Size Wall&lt;/p&gt;

&lt;p&gt;In January 2026, Google Play rejected our builds.&lt;/p&gt;

&lt;p&gt;The reason had nothing to do with Flutter.&lt;/p&gt;

&lt;p&gt;Android 15 introduced a mandatory 16KB page size requirement for native libraries.&lt;br&gt;
Our encryption stack was incompatible.&lt;/p&gt;

&lt;p&gt;The Fix&lt;/p&gt;

&lt;p&gt;Forced upgrade of sqflite_sqlcipher&lt;/p&gt;

&lt;p&gt;Migration safety nets to prevent existing users from being locked out&lt;/p&gt;

&lt;p&gt;Careful handling of encrypted database headers&lt;/p&gt;

&lt;p&gt;This reinforced a painful truth:&lt;/p&gt;

&lt;p&gt;Mobile platforms are not stable targets. They are moving ground.&lt;/p&gt;

&lt;p&gt;If you build offline-first, you inherit that responsibility.&lt;/p&gt;

&lt;p&gt;The Samsung “Zombie Key” Incident (S23 / S24)&lt;/p&gt;

&lt;p&gt;This was the most dangerous bug we’ve encountered so far.&lt;/p&gt;

&lt;p&gt;The Symptom&lt;/p&gt;

&lt;p&gt;Samsung users updated the app and saw:&lt;/p&gt;

&lt;p&gt;“0 Projects”&lt;/p&gt;

&lt;p&gt;No crash.&lt;br&gt;
No error.&lt;br&gt;
Just empty state.&lt;/p&gt;

&lt;p&gt;The Root Cause&lt;/p&gt;

&lt;p&gt;Samsung’s hardware-backed keystore (Knox) is sometimes not ready during cold start.&lt;/p&gt;

&lt;p&gt;Our app:&lt;/p&gt;

&lt;p&gt;requested the encryption key&lt;/p&gt;

&lt;p&gt;received a new key&lt;/p&gt;

&lt;p&gt;attempted to open the existing database&lt;/p&gt;

&lt;p&gt;failed silently&lt;/p&gt;

&lt;p&gt;We called this a Zombie Key:&lt;/p&gt;

&lt;p&gt;valid&lt;/p&gt;

&lt;p&gt;real&lt;/p&gt;

&lt;p&gt;completely wrong&lt;/p&gt;

&lt;p&gt;The Fix: The Samsung Patience Protocol&lt;/p&gt;

&lt;p&gt;Instead of assuming storage is instant, we implemented:&lt;/p&gt;

&lt;p&gt;retry loops&lt;/p&gt;

&lt;p&gt;exponential backoff&lt;/p&gt;

&lt;p&gt;up to ~7.5 seconds of patience&lt;/p&gt;

&lt;p&gt;Only after exhausting retries do we treat the app as a fresh install.&lt;/p&gt;

&lt;p&gt;Lesson learned:&lt;br&gt;
Never assume hardware security modules wake up on time.&lt;/p&gt;

&lt;p&gt;The Split-Brain Problem and the Unified Core Decision&lt;/p&gt;

&lt;p&gt;Originally, we planned:&lt;/p&gt;

&lt;p&gt;sqflite for free users (offline only)&lt;/p&gt;

&lt;p&gt;PowerSync for paid users (sync enabled)&lt;/p&gt;

&lt;p&gt;It looked clever.&lt;br&gt;
It was a maintenance nightmare.&lt;/p&gt;

&lt;p&gt;Two engines meant:&lt;/p&gt;

&lt;p&gt;double migrations&lt;/p&gt;

&lt;p&gt;double testing&lt;/p&gt;

&lt;p&gt;double failure modes&lt;/p&gt;

&lt;p&gt;The Pivot&lt;/p&gt;

&lt;p&gt;We chose a Unified Core:&lt;/p&gt;

&lt;p&gt;PowerSync everywhere&lt;/p&gt;

&lt;p&gt;SQLite as the single source of truth&lt;/p&gt;

&lt;p&gt;Sync toggled by capability, not architecture&lt;/p&gt;

&lt;p&gt;Free users run PowerSync in offline-only mode.&lt;br&gt;
Paid users simply enable connect().&lt;/p&gt;

&lt;p&gt;This eliminated an entire class of future migrations.&lt;/p&gt;

&lt;p&gt;Engineering Ethics: Trust Over Features&lt;/p&gt;

&lt;p&gt;During compliance review, we identified calculators whose results depended on:&lt;/p&gt;

&lt;p&gt;subjective land values&lt;/p&gt;

&lt;p&gt;inconsistent local rules&lt;/p&gt;

&lt;p&gt;We removed them.&lt;/p&gt;

&lt;p&gt;Not because we couldn’t implement them —&lt;br&gt;
but because shipping legally risky math is irresponsible.&lt;/p&gt;

&lt;p&gt;We also implemented:&lt;/p&gt;

&lt;p&gt;global disclaimers&lt;/p&gt;

&lt;p&gt;consent-gated analytics (DPDP Act)&lt;/p&gt;

&lt;p&gt;hard kill switches where confidence was insufficient&lt;/p&gt;

&lt;p&gt;Engineering responsibility doesn’t end at correctness.&lt;br&gt;
It includes consequences.&lt;/p&gt;

&lt;p&gt;The Final Stack (Early 2026)&lt;br&gt;
Mobile&lt;/p&gt;

&lt;p&gt;Flutter (Dart)&lt;/p&gt;

&lt;p&gt;MVVM architecture&lt;/p&gt;

&lt;p&gt;SQLite + SQLCipher&lt;/p&gt;

&lt;p&gt;Argon2id key derivation&lt;/p&gt;

&lt;p&gt;Firebase (Crashlytics, Auth)&lt;/p&gt;

&lt;p&gt;Web&lt;/p&gt;

&lt;p&gt;Astro (SSG, zero-JS default)&lt;/p&gt;

&lt;p&gt;Tailwind CSS&lt;/p&gt;

&lt;p&gt;React islands (calculators only)&lt;/p&gt;

&lt;p&gt;Motion One (mechanical animations)&lt;/p&gt;

&lt;p&gt;Vercel (CI/CD)&lt;/p&gt;

&lt;p&gt;Consent-first analytics loading&lt;/p&gt;

&lt;p&gt;What This Journey Taught Me&lt;/p&gt;

&lt;p&gt;Offline-first changes everything&lt;/p&gt;

&lt;p&gt;Storage is not an optimization — it is the product&lt;/p&gt;

&lt;p&gt;Hardware is unpredictable&lt;/p&gt;

&lt;p&gt;Especially when security modules are involved&lt;/p&gt;

&lt;p&gt;Architecture debt compounds faster than feature debt&lt;/p&gt;

&lt;p&gt;Removing features can be a sign of maturity&lt;/p&gt;

&lt;p&gt;Trust is the most expensive thing to lose — and the hardest to earn back&lt;/p&gt;

&lt;p&gt;Closing&lt;/p&gt;

&lt;p&gt;This architecture now powers K-First, an offline-first engineering logbook built for real site conditions where reliability matters more than polish.&lt;/p&gt;

&lt;p&gt;If you’re building tools for the physical world:&lt;/p&gt;

&lt;p&gt;Assume failure first — and design so your users never pay for it.&lt;/p&gt;

&lt;p&gt;Real-World Use of This Architecture&lt;/p&gt;

&lt;p&gt;The architecture described above powers the KFirst engineering toolkit, which includes practical calculators used by civil engineers on construction sites.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;p&gt;Concrete material estimation&lt;br&gt;
Land area conversion&lt;br&gt;
Kerala building permit fee estimation&lt;/p&gt;

&lt;p&gt;Some of the tools used by engineers:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kfirst.in/tools/material-estimator" rel="noopener noreferrer"&gt;Material estimator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Land area converter&lt;/p&gt;

&lt;p&gt;Building permit calculator&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>android</category>
      <category>architecture</category>
      <category>sqlite</category>
    </item>
  </channel>
</rss>
