Back to Blog
godistributed-systemshtmxsqlitelearning-in-public

Learning Distributed Systems by Building My Own Budget App

Why I'm building a household budget that syncs across a desktop, a laptop and a VPS, and what this series will cover.

In short: I'm building a real application (a budget that stays in sync across a desktop, a laptop and a cloud server) to learn distributed systems properly, with an AI assistant as my coach. This series documents what I built, what broke, what I measured, and where the ideas apply in production systems.

Most distributed-systems material starts with a diagram of five identical servers and a key-value store. I read plenty of it, and I could recite the words: vector clocks, anti-entropy, consensus, idempotency. What I couldn't do was use them, because nothing in those diagrams was something I cared about.

So I'm building something I do care about: a budget for my own household, written in Go with HTMX and SQLite, that stays in sync across the three machines I actually use.

Machine Its job
Desktop PC Where I import bank statements and plan
Laptop The same budget when I'm out, including offline
VPS Always on: the hub the other two sync through

That setup forces every classic problem into the open. The laptop goes offline and comes back with changes. Two machines edit the same thing. A sync request gets retried. The VPS can't reach my home machines, because they're behind a router. None of these are hypothetical: they're the week-to-week reality of the project.

What I've built so far

Week 1: the unglamorous foundation. Configuration from environment variables, password hashing and sessions, structured JSON logs with request IDs, and a Docker image with health checks. Five boring things, each of which broke in an instructive way.

Week 2: a replication engine. Vector clocks to track what each machine has seen, a sync API that tolerates retries, Merkle-style bucket summaries so machines exchange only what differs, deterministic conflict resolution, and a background loop that keeps nodes converging on their own. Two real processes (and later a three-node Docker ring) converge after independent and conflicting writes, and a scripted demo proves it.

The honest part

By the end of Week 2 the engine worked, and I was struggling anyway. It moved placeholder data (item_id: "rent", value: 1200) and wasn't connected to the budget page I actually use. Every concept stayed abstract. So I changed course: from Week 3 on, the engine carries real budget data. Transactions, bank CSV imports, monthly limits. Every lesson gets explained through a concrete money problem. That turned out to be the most useful decision in the whole project, and one article in this series is about why.

The series

  1. The Boring First Week: What Broke While Setting Up a Small Go Service
  2. Vector Clocks, Explained With a Budget
  3. Retries Are Normal: Building an Idempotent Sync API
  4. How Two Computers Find Their Differences Without Sending Everything
  5. When Two Edits Collide: Deterministic Last-Write-Wins
  6. Go Gotchas I Hit Building a Replicated Service
  7. My Distributed Systems Project Felt Impossible Until I Made It About Money
  8. I Learned Distributed Systems With an AI Coach. Here's Where It Was Wrong.
  9. TLA+ Found Two Bugs in My Tested Sync Protocol on Its First Run

Each article is built around something that actually went wrong, because that's where I learned the most. The code is Go, but the ideas carry over to any language.

How each article is written

  • An "In short" summary at the top, for anyone who wants the point in thirty seconds.
  • The technical story, with real code, real bugs and real measurements.
  • "Where this shows up in real systems", connecting the idea to production: payments, databases, mobile and edge apps, team practices.

A note on AI

I'm building this with an AI assistant as coach and, at times, pair programmer. Mostly it explains and reviews while I write the code; for some stretches it wrote code while I reviewed. I verify everything against tests and measurements, and part 8 is about the times it was confidently wrong and how I caught it.


I write about building reliable software in Go, from the code up. If you're working on similar problems, I'd like to hear from you: get in touch or connect with me on LinkedIn.