Everything is a pipe

Roman aqueducts and TCP solve the same problem the same way, two thousand years apart.


Revisions26 · oct 05Read notethe sources now sit beside each claim, and checking them moved a few things. The famous 100,000 km of blood vessels is a 1929 extrapolation from athletic muscle; an ordinary adult carries something like a tenth of it. TCP's congestion control came from Van Jacobson in 1988, after Cerf and Kahn, and the ARPANET was never designed to survive a nuclear war.

I had a weird realization the other day. I was reading about how the internet routes packets through TCP, and something in my brain went wait, this is just plumbing. I mean it literally, without hand-waving: the engineering is structurally identical to plumbing. The solutions are the same. The failure modes are the same. The math is the same.

And then I looked at blood circulation. Also plumbing. And then I looked at Unix pipes. Also plumbing. And then oil pipelines and electrical grids, all plumbing. Everything is plumbing.

It should have clicked earlier. When I was studying engineering, my diagrams kept looking the same from thermodynamics to control systems. Evolution built pipes. Romans built pipes. We built pipes. Apparently this is our thing. And a perceptron, I recently realized, is just a more sophisticated set of pipes.

This should not have been as unsettling as it was.

Rome ran on a gravity-fed network

The Roman aqueduct system is one of the most impressive engineering achievements in human history, and also basically a gravity-powered municipal water API.

Here's how it worked. You find a source of clean water in the hills (a spring, a lake, whatever) and you build a channel from there to the city. The channel has a very slight downward gradient. The aqueduct that fed Nîmes dropped about 17 meters over its 50 kilometers, roughly 1 meter for every 3,000, and on the Pont du Gard it falls 2.5 centimeters in 456 meters. That's barely a slope. That's less slope than most people's driveways. And yet water flows through it, reliably, for dozens of kilometers (more than two hundred at Constantinople), powered by nothing but gravity and the quiet confidence of Roman engineering.

The water doesn't go straight from the hills into your mouth. It hits a castellum divisorium first: a distribution tank at the city's edge, like the one that still stands at the end of the Nîmes aqueduct1. This tank splits the incoming flow into multiple smaller pipes heading to different neighborhoods. It's a load balancer, the same concept doing the same job two thousand years earlier.

1Wikipedia, Roman aqueduct, on the Nîmes castellum and its outlet pipes.

And when demand in one neighborhood spiked (say, everyone in Trastevere decided to take a bath at the same time because Trastevere apparently had one hobby), the flow to other neighborhoods would drop. So the Romans built reservoirs. Holding tanks that accumulated water during low-demand periods and released it during peaks.

That's a buffer. Literally a buffer. They invented buffering to manage throughput in a distributed delivery system and they did it using rocks.

They also had redundant supply lines. By the third century Rome had eleven aqueducts feeding the city1. Partly because one wasn't enough for a growing city, and partly because if one line goes down for repairs, you want a failover: Frontinus, the water commissioner, wrote around AD 97 that most basins now took water from two different aqueducts, so that if accident should put either of the two out of commission, the other may serve2. The Romans built high availability out of concrete and slave labor (Frontinus counts two gangs, of about 240 and 460 men), and it ran for more than eight centuries, until the Goths besieging Rome in 537 actually cut it.

1Wikipedia, Aqueducts of Rome, from the Aqua Appia of 312 BC to the Aqua Alexandrina of AD 226. 2Frontinus, De Aquis, II.87, translated by Charles Bennett, 1925.

Anyway.

Your blood is enterprise middleware

The circulatory system is (and I cannot stress this enough) also a pipe.

Your heart pumps blood. That blood carries oxygen (the payload) inside red blood cells (the packets) through arteries (the trunk lines) down to capillaries (the last-mile delivery network) and back through veins (the return path). This is a packet-switched delivery network. It has routing. It has flow control. It has congestion management. It has better uptime than most things humans have intentionally built.

When a muscle needs more oxygen (say, you're running from something with teeth), your body dilates the arterioles feeding that muscle, increasing flow. Simultaneously, it constricts arterioles to less critical areas. Your digestive system can wait. You're being chased. This is dynamic bandwidth allocation. Your body is doing QoS routing in real time, prioritizing critical traffic over background processes. It figured this out roughly 400 million years before Cisco did.

The failure modes are hilariously familiar. An aneurysm is a buffer overflow, a section of pipe that expanded beyond spec and burst. A blood clot is a packet that got stuck in the pipe and blocked all downstream traffic, a deadlock with fatal consequences. Atherosclerosis (plaque buildup in arteries) is literally pipe corrosion reducing throughput over time. Your cardiologist is basically a plumber with a medical degree and better handwriting.

Your body even has error detection. If a blood vessel gets damaged, platelets rush to the site and form a clot to seal the leak. That's a self-healing mechanism. Your circulatory system has better incident response than most Series B startups.

The figure everyone quotes for the total length of your blood vessels, 100,000 kilometers or two and a half times around the earth, traces back to August Krogh's 1929 extrapolation for the capillaries of a well-trained muscle, and a recount for an ordinary adult lands nearer 9,000 to 19,000 kilometers1. Even the small figure is a pipe network longer than many countries' highway systems, and it runs 24/7 without a maintenance window for about 80 years, an SLA you will not get from AWS.

1Kurzgesagt, We Fell For The Oldest Lie On The Internet, 2024; Krogh's original claim is recalled in Kissane, Al-Shammari and Egginton, The importance of capillary distribution in supporting muscle function, Comparative Biochemistry and Physiology A 254, 2021.

TCP/IP: the internet is literally plumbing

When Vint Cerf and Bob Kahn designed TCP in the 1970s1, they probably weren't thinking about Roman aqueducts or hemoglobin. But they independently arrived at the exact same solutions to the exact same problems, because the problems are the same: everything is a pipe.

1Cerf and Kahn, A Protocol for Packet Network Intercommunication, IEEE Transactions on Communications 22(5), 1974.

TCP breaks your data into packets (chunks of bytes, little buckets of water). It numbers them sequentially so the receiver can reassemble them in order, even if they arrive scrambled. It sends them through a network of routers (junctions in the pipe system). And it implements flow control to avoid overwhelming the receiver.

The Congestion Window.

TCP doesn't just blast data at full speed. It starts slow: sends a small window of packets (one in the original design, ten on most servers today1), waits for acknowledgment, then doubles the window with every round trip. This is called slow start, and it's TCP's way of probing the network's capacity without flooding it.

1Chu et al., Increasing TCP's Initial Window, RFC 6928, 2013.

If packets start getting dropped (the pipe is full), TCP halves its sending rate immediately, then creeps back up about one packet per round trip1. This is congestion avoidance. It's the exact same principle as Roman reservoirs managing demand spikes: buffer when you can, throttle when you must.

1Allman, Paxson and Blanton, TCP Congestion Control, RFC 5681, 2009.

The sluice gate came later, from Van Jacobson, after the internet's congestion collapses of 19861. He reinvented it using math. In 1988. Wearing a three-piece suit, presumably.

1Jacobson, Congestion Avoidance and Control, SIGCOMM, 1988.

And just like the Romans built redundant aqueducts, the internet routes around failures. If one path goes down, packets find another way, and that was the fundamental architecture from the start. The idea of a network you could literally nuke a chunk of, with traffic rerouting automatically, comes from Paul Baran's packet-switching studies at RAND; the ARPANET itself was built to share computers, and the story that it was meant to survive a nuclear war is a rumor1.

1Leiner et al., A Brief History of the Internet, Internet Society, 1997.

Cold war engineering at its finest, even if the cold war part belongs to the study next door.

Unix pipes, or cat universe | grep pattern

And then there's Unix pipes. Which might be the purest, most distilled expression of this whole concept.

In 1973, Ken Thompson (pushed for years by Doug McIlroy, while he and Dennis Ritchie were building Unix at Bell Labs like it was a weekend project and not the foundation of all modern computing) added pipes to Unix in one feverish night, and the pipe operator, |, came soon after1. It takes the output of one program and feeds it directly into the input of another. No intermediate files. No manual copying. Just a stream flowing from one process to the next.

1McIlroy, A Research UNIX Reader, Bell Labs CSTR 139, 1987.

BASH Copy

cat server.log | grep "ERROR" | sort | uniq -c | sort -nr | head -20

That one line reads a log file, filters for errors, sorts them, counts unique occurrences, sorts by frequency, and shows the top 20. Six programs. Zero of them know the others exist. They just read from a pipe and write to a pipe, which is plumbing, and elegant plumbing at that.

The Unix philosophy, as McIlroy wrote it down in 1978, is to make each program do one thing well and to expect the output of every program to become the input to another1. Each program is a simple, specialized valve in a pipeline. The power comes from composition. This is the same reason Roman aqueducts used standardized pipe sizes (Frontinus lists twenty-five official ones): interchangeable components, composable infrastructure. Ken Thompson and a Roman hydraulic engineer would have had a great conversation if you could get past the language barrier and the 2,000-year gap.

1McIlroy, Pinson and Tague, UNIX Time-Sharing System: Foreword, Bell System Technical Journal 57(6), 1978.

And the backpressure mechanism is perfect. If the receiving program can't process data fast enough, the pipe buffer (typically 64KB on Linux1) fills up. When it's full, the sending program just... stops. Blocks. Waits. No data loss. No overflow. The slow consumer controls the pace of the fast producer, which is what a narrowing arteriole does in the body.

1Linux man-pages, pipe(7), section on pipe capacity.

The pipe you're training

Every example so far is a pipe that moves something through space. But there's a pipe that moves something through abstraction, and it follows every rule in the table below.

A machine learning pipeline is a Unix pipe with extra steps and a GPU bill.

1Raw text2Tokenizer3Embeddings4Attention layers5Output logits6Token

Six stages. Each one reads from the previous, transforms, writes to the next. None of them need to know what the others are doing. The tokenizer doesn't care what the attention heads will find interesting. The attention heads don't care how the text was split. They just read from the pipe and write to the pipe. This is cat | grep | sort | uniq wearing a lab coat.

And the flow control is identical.

Batch size is backpressure. A GPU has finite memory: it can only process so many samples at once. Push too many through and you OOM1. So you batch. Send 32 samples, wait for the forward pass to clear, send the next 32. The slow consumer (GPU memory) controls the pace of the fast producer (your dataset). This is Unix pipe backpressure. This is TCP congestion windowing. This is a Roman sluice gate made of silicon.

1Out Of Memory: the GPU equivalent of a burst pipe. The buffer is full, the next write has nowhere to go, and the whole process crashes.

KV cache is buffering. During inference, a transformer doesn't recompute attention over every previous token from scratch. It caches the key-value pairs from previous positions, a reservoir of precomputed work that future tokens draw from without re-deriving it. The KV cache grows with every token generated and is drawn on at every step that follows. When it fills the memory, the server either pushes a request out and recomputes it later, swaps it to slower memory, or stops generating1. It behaves like a reservoir and it fails like one.

1Kwon et al., Efficient Memory Management for Large Language Model Serving with PagedAttention, SOSP, 2023.

Gradient accumulation is flow control. When your batch doesn't fit in memory, you accumulate. Process a micro-batch, store the gradients, process another, add them up, repeat. Only update the weights when you've collected enough. This is exactly what TCP does with its congestion window, sending a little and waiting for the receipt before it sends more. The optimizer sees one big update made of micro-batches, the same way the receiving end of a TCP connection sees a continuous flow made of packets.

The layer nobody extended.

Martin Kleppmann wrote the book on this. Literally. His Designing Data-Intensive Applications traces the pipe pattern from batch processing through stream processing through Kafka, through exactly the kind of flow-control math that makes distributed systems work. He stopped at the data infrastructure layer. Nobody extended it into the model itself. But the model is the pipe. The transformer architecture is a pipeline of transformations with its own buffers and its own backpressure, running on the same math that governs TCP windows and Roman water pressure. The book ends one abstraction layer too early.

The table that shouldn't exist

Put the five systems side by side, concept by concept, and the result is properly eerie.

concept aqueducts blood TCP unix pipes ML pipeline

payload water oxygen data packets text streams tensors

conduit stone channels arteries / veins cables / fiber file descriptors layers / forward pass

buffer reservoirs veins socket buffer pipe buffer (64KB) KV cache

flow control sluice gates vasoconstriction congestion window backpressure gradient accumulation

load balancing castellum heart chambers routers / BGP tee / split batch distribution

error detection human inspection platelets checksums exit codes loss function

redundancy 11 aqueducts collateral circulation multi-path routing fallback pipes multi-head attention

Seven solutions. Five domains. Every column fills every row. Independently discovered across two thousand years and five completely different substrates by people who mostly had no idea the others existed. That table should be illegal.

Why this keeps happening

Okay so a Roman hydraulic engineer and the people who designed Unix converge on identical solutions, evolution gets there too, and the convergence is too regular to be a coincidence. Every pipe system shares the same fundamental constraint: a producer and a consumer with a channel of finite capacity between them. That is the whole problem, and there are only so many mathematically valid solutions to it.

This is what queuing theory formalizes. Little's Law (published in 19611 but applicable to Roman water systems and human arteries alike) states:

1John D. C. Little, A Proof for the Queuing Formula, Operations Research 9(3), 1961.

L=λWL = \lambda WL=λW

The average number of items in a system (LLL) equals the average arrival rate (λ\lambdaλ) multiplied by the average time each item spends in the system (WWW). It doesn't care if LLL is packets or red blood cells; the math was always identical. Little's Law doesn't know what domain it's solving for, and that's the point.

Every pipe system discovers buffering, because variable demand plus fixed capacity overflows without a buffer. It discovers flow control because unregulated producers will always overwhelm finite channels, and redundancy because single points of failure will, given enough time, fail.

They behave more like theorems than design choices. Any engineer building any pipe system will rediscover them, because they are properties of the problem space. The Romans needed buffering long before anyone had a word for it, and evolution reached vasoconstriction because the physics of flow left it few other routes.

I keep coming back to a line: engineering is engineering: the substrate doesn't matter.

I used to think that was a nice sentiment. A philosophical position. A way of saying I work across domains and that's cool.

Now I think it's a mathematical statement. And the proof is sitting in a table comparing Roman concrete to TCP congestion windows, and every column says the same thing.

The patterns that work in pipe engineering are the patterns that work, whatever the pipe carries. The physics of flow through a bounded channel produces the same constraints, and the same constraints have produced the same solutions for two thousand years and counting.

Which means if you deeply understand one pipe system (I mean really understand it, down to the failure modes and the math), you already understand most of the others. The knowledge is portable. The only thing that changes is what's flowing through the tube, and the tube doesn't care.