Connection · Interrupted

Something didn't load

Part of this page failed to reach you. Reload to try again — if it keeps happening, check your connection.

Skip to main content
Writing · № 03

All posts

Long-form notes on software, distributed systems, and the craft of building. Shipping one a week.

All Posts
12 posts · Engineering
Engineering01

What APISIX in the Trial Ring Actually Buys You: Notes on Its etcd-Backed Control Plane

Volume 34 of the Thoughtworks Technology Radar moved Apache APISIX into the Trial ring. I spent a week digging through the docs, source code, and a couple of bug reports to convince myself the etcd-backed dynamic-routing claim was real — and to weigh the operational cost it hides. These are my notes on the watch mechanism, the connection-scaling cliff at 263 long polls, and when I would and would not reach for APISIX in 2026.

Jul 1
Engineering02

Structured Concurrency Looks the Same in Four Runtimes — Until a Child Fails

I wrote the same fan-out four times — Java 25 StructuredTaskScope, Kotlin coroutineScope, Swift withThrowingTaskGroup, Python asyncio.TaskGroup — and the surface API is nearly interchangeable. The cancellation and exception-aggregation semantics are not. These are my notes on what diverges on the failure path and why only Python hands you every failure by default.

Jun 28
Engineering03

A Fitness Function Is Just a Test That Fails the Build When the Architecture Drifts

A fitness function is not a framework artifact — it is a build-failing test that encodes one architectural invariant. I encode a layering rule in about 60 lines of TypeScript using the compiler's own API, test the test against good, bad, and generated-code trees, then draw the line between an invariant worth gating and a metric gate that backfires under Goodhart's law.

Jun 24
Engineering04

Iceberg Schema Evolution: Drop-Then-Add Is Not a Rename

Apache Iceberg tracks every column by a unique numeric id, not by name. From my own digging into the spec and a small Kotlin program against a local catalog, the trap that bit me hardest is this: a drop followed by an add of the same column name is not a rename, and treating it as one quietly orphans your historical data.

Jun 21
Engineering05

Kotlin 2.4: The Three Changes That Moved My Hand on the Keyboard

Kotlin 2.4.0 shipped a long changelog, but only three features changed how I actually type: stable context parameters, explicit backing fields, and (still behind a flag) name-based destructuring. Here is my backend-engineer's cut, verified against the 2.4.0 compiler, plus the K1 removal I had to put on a calendar.

Jun 8
Engineering06

Idempotency Is a Protocol, Not a Key

The first time I shipped idempotency as a UUID header and a Redis lookup, a duplicate charge slipped through a week later. These are my notes on treating idempotency as a four-part protocol — dedup, determinism, concurrent safety, downstream propagation — with a minimal Kotlin plus Postgres implementation that holds up under retry.

May 9
Engineering07

What `dbos ontime` Actually Asks: Building a Distributed Cron on etcd Leases in Go

A 0-click query for `dbos ontime` showed up in my Search Console last week. The reader is not asking about DBOS — they are asking how to run a job every minute, exactly once, across a fleet. From my own notes, an etcd lease, the `concurrency.Election` package, and a fencing token cover that case in under 100 lines of Go, without pulling in a workflow engine.

May 7
Engineering08

Event-Log-as-Source-of-Truth Turns Schema Evolution Into a Forever Problem

When the log is the source of truth, every schema change is permanent. A Kotlin/Avro walkthrough of the rename that passed the Schema Registry check and silently corrupted every old event, plus the Protobuf and Avro invariants I now keep pinned above my desk.

May 5
Engineering09

Turning LLM Context Engineering Into an Evaluation Loop with DSPy

Notes from two weekends of digging into DSPy. I stopped treating prompts as the source of truth and started treating them as compiled output from a typed signature, a metric, and an optimizer. Here is the smallest end-to-end program I kept, how MIPROv2 actually searches, and where the approach breaks down in practice.

May 3
Engineering10

DBOS vs Temporal: When Postgres Is Enough for Durable Workflow Execution

DBOS reuses Postgres as the durability layer for workflows, while Temporal runs a dedicated cluster. The right choice depends on team size, workload shape, and where you want your operational budget to go. This is a practical rubric for picking between them.

Apr 26