---
title: Syncing State with Immutable Tries
description: How a multi-device life tracking project used trie structure to diff, reconcile, and synchronize goal state.
date: 2026-05-05
projectPeriod: 'August-September 2019'
thumbnail:
  src: ./_assets/towers.jpg
  alt: Life Towers goal tracking interface with tower-like visual structures.
tags: ['systems', 'web', 'tools']
selected: true
featuredOrder: 3
project: towers
role: Full-stack author
stack: ['Python', 'Angular', 'State synchronization']
scale: Multi-device goal and task state shared between clients and a server
outcome: A working synchronization model built around immutable trie properties
audience: recruiter-relevant
links:
  - label: Source
    type: source
    url: https://github.com/schmelczer/life-towers/
  - label: Demo
    type: demo
    url: https://towers.schmelczer.dev
media:
  - type: image
    src: ./_assets/towers.jpg
    alt: Screenshot of a life tracking web interface represented with tower-like visual structures.
    caption: The visual idea was simple; the useful lesson was the synchronization model behind it.
---

Life Towers was a multi-device goal and task tracker with an intentionally visual interface. The surface idea was an aesthetic representation of previous and current goals. The more interesting part was synchronizing state across clients without sending more data than necessary.

This was not a large distributed system, but it had a real version of a common problem: clients and server drift apart, and the system needs a compact way to compare, reconcile, and update.

## The Problem

If a task model is stored as an ordinary mutable object graph, synchronizing it often becomes a choice between sending too much data or writing complicated ad hoc diff logic.

I wanted a structure where the shape of the data made synchronization easier. The client should be able to compare its state with the server's state, find a difference, reconcile it, and send only the delta.

## Design

I used a trie. A trie made the hierarchical shape explicit, and its properties made it easier to reason about differences between stored versions.

The immutable nature of the structure simplified much of the logic. Instead of mutating arbitrary branches in place, updates could produce new structure with shared unchanged parts. That made reconciliation easier to reason about and reduced the amount of data that needed to move across the network.

The project also gave me a reason to deepen my Python and Angular knowledge, but the synchronization structure was the main lesson.

## What Worked

The biggest win was choosing a data structure that matched the problem. Once the state was represented in a way that made comparison natural, the network protocol became simpler.

The other useful lesson was that visual products still need a strong internal model. A pleasant interface is fragile if the underlying state is hard to trust.

## What I Would Change

Today I would document the sync protocol more formally and add property-based tests around reconciliation. Synchronization code is exactly the kind of code that benefits from generated edge cases.

I would also separate the visual experiment from the state synchronization story more explicitly. The latter is the part that aged better.
