Aditya Dutt Pandey

Builds · 2025

Published · 4 min read

I keep building worse versions of software that already exists

Redis in Go, a load balancer in Bun, a gRPC mesh, an SFU, a small OS in C. None of them will ever replace the original, and that's the point. What I choose to rebuild, what I refuse to, and what it changes about how I run tunyt's stack.

I've spent weeks building worse versions of software that already exists. On purpose.

A Redis-compatible server in Go. A load balancer in Bun. A four-service gRPC mesh. An SFU on mediasoup. A small operating system in C.

None of them will ever replace the original. If you're running production on my Redis, please stop. But each one changed how I make decisions as a CTO, and that's worth explaining.

Decision 1: rebuild what holds my system up

I don't rebuild things at random. The rule is simple: if a tool is load-bearing for what I run, I want to understand it from the inside.

Every convenience is rent. What I can't rebuild owns me.

That's not a rule against using tools. I run Kafka, Redis and Kubernetes in production and wrote none of them. It's a rule about knowing them well enough to answer three questions: what does it cost, where does it break, and what will I do when it does?

Redis taught me about TCP

Redis speaks a protocol called RESP, and it's beautifully simple. A line starting with + is a string, - is an error, : is an integer, $ is a blob of bytes with its length up front, and * is an array.

*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n

That's SET key value. My version speaks it well enough that redis-cli connects and doesn't notice the difference. I wrote the parser, the storage and the command handling by hand.

The first real lesson wasn't about Redis at all. TCP gives you a stream of bytes, not messages. One command can arrive in two pieces, or three commands can arrive glued together in one read. Your parser has to handle both, or it works perfectly on your laptop and breaks under load. A whole class of "works locally, fails in production" bugs made sense to me after that.

The second lesson: the real Redis runs commands one at a time, on a single thread. Write the command loop yourself and that stops looking like a limitation. No locks around the data, no races between commands, very predictable latency.

The load balancer taught me what "healthy" means

Configuring a load balancer, you tick "health check" and move on. Building one, you have to decide what healthy means. Is a server that answers /health instantly but takes four seconds on real requests healthy? How many failures before you stop sending it traffic? How do you bring it back without stampeding it?

Mine does auto-scaling for Bun backends, active health checks, routing and live monitoring. I learned more about connection handling from it than from a year of configuring someone else's.

The SFU taught me why video calls need a middleman

In a naive group video call, everyone sends their video to everyone else. That's a mesh. With five people, each one uploads four copies of their own video. Home internet is usually much worse at uploading than downloading, so the mesh falls over long before you'd expect.

An SFU, a selective forwarding unit, fixes it. Everyone uploads once, to the server, and the server forwards streams to everyone else. You only really get why every serious video product works this way after you've built the mesh and watched it struggle.

Decision 2: stop at small

I never try to finish these. A small version is enough to teach the shape of the thing, and the last 10% of a database is years of other people's work I have no business redoing.

That's a real limitation. A small version hides the hard parts: replication, persistence, failure handling at scale. When I say I understand Redis, I mean I understand why it's shaped this way. I don't mean I could run it better than the people who maintain it.

Decision 3: let it change real choices

This is where it pays off.

When we choose infrastructure for tunyt, I'm not choosing from a feature table. I'm choosing from a picture of how the thing works inside. And when someone proposes adding a new moving part, my first question is what it costs per instance and where it breaks, because I've built enough small versions to know every moving part has an answer to both.

The other projects in the set:

  • go-grpc-micro. Account, catalog and order services over gRPC behind a GraphQL gateway, on PostgreSQL and Elasticsearch. Small enough to hold in your head, real enough to break.
  • cqrs. The read and write split Tixin ran on, extracted into its own repo. I could only pull it out cleanly because I'd built the pieces underneath.
  • OsU. A small operating system written from scratch in C.

I don't build these to own better software. I build them so the software I depend on stops being a black box.

← All writing