← LEFT BRAIN DOMINANT

Naming Things Is a Cache Invalidation Problem

Mar 30, 2025 · 5 MIN READ
See also, the right brain on this: What You Call It Changes What It Is

A name is a pointer. Renaming is migration. The old joke, attributed to Phil Karlton, is that there are only two hard problems in computer science, cache invalidation and naming things. I've started to suspect that's one problem told twice.

What a name does

A name is an indirection. It lets you refer to a thing without carrying the thing around. You say "the Johnson account" and everyone in the room dereferences it to the same pile of history, contacts, and grudges, without anyone having to recite the pile. That's the whole value. A name is a short string that resolves, at read time, to something large.

The resolution happens in a lookup table, and the lookup table is in people's heads. That's the part that makes it a cache. Every person who has ever heard the name has stored a mapping from string to referent, and they will use that mapping the next time they see the string, without checking whether it's still valid. There is no TTL. There's no invalidation protocol. There's just a great many caches, in a great many skulls, each holding whatever the name meant the last time it was loaded.

Renaming is migration

Now change the name. Or, worse, keep the name and change what it points to.

Every cache is now stale. Documentation refers to the old name. Muscle memory types the old name. The person who joined last year knows only the old name and has never been told there's a new one. Slack search finds the old name. The old name is in the URL, the config, the email footer, the name of the recurring meeting. There's no single place to update. The mapping was replicated into every reader, and every reader has to be individually reached, and some of them can't be, because they left, or because they're a script somebody wrote in 2019 that still works.

That is a migration, and like every migration it has a long tail. The main system moves in a week. The stragglers take years. There's always a straggler.

The corporate versions are instructive. When Twitter became X, the cost wasn't the logo. It was that every human on earth had a cached mapping from the word "tweet" to a thing, and the company was now asking a few billion people to flush that cache, and most of them simply did not. Two years on, people still said tweet. The old pointer kept resolving because the referent was still there. The rename didn't fail. It just never finished.

Facebook became Meta and had the reverse problem: the parent was renamed, the product was not, and the cache in most heads held "Facebook" as the company, so "Meta" resolved to nothing for a long time, and then to a specific VR headset, which wasn't the intent.

Places

Cities are the slowest caches. Istanbul had been Istanbul, officially, for a few years before most of the world's mail stopped arriving for Constantinople, and there is a song about it from 1953, twenty-three years after the change, still explaining the migration. Bombay became Mumbai in 1995 and the airport code is still BOM, because IATA codes are a cache with its own invalidation policy, which is approximately never. St. Petersburg became Petrograd became Leningrad became St. Petersburg, and each rename left a layer, so that the metro station names, the street names, the names of the institutions, and the names people actually use are four caches from four eras, all still live, all disagreeing.

Street renames are the small version. A city renames a road for a civil rights leader and for a generation the residents give directions using the old name, because the old name is what resolves in their heads, and the new sign is a string that points at nothing they have loaded.

None of this is resistance, mostly. It's just that the invalidation has to reach every reader, and the readers were never registered anywhere.

The trunk of the tree

The one everybody in software lived through recently was master becoming main in git. It is a perfect small case. The rename was one command. The migration took years, because the old name had been cached in every CI script, every deploy hook, every README, every branch protection rule, every tutorial, and every developer's fingers. New repos switched immediately. Old repos switched when someone got around to it, or never. For a long while you could not know which name a repo used without checking, which meant the name had stopped doing its job, which is to be the thing you don't have to check.

Content addressing, and why we cannot use it

There is a way out of this, in principle, and git already uses it under the hood. Address things by their content, not by a name. A git commit is identified by the hash of its contents. The hash can't go stale because it is the thing. Change the content and you have a different hash, a different object, no invalidation needed.

The problem is that humans can't use hashes. Nobody says "meet me at 3f2a9c." The reason we have names is that we need short, stable, memorable handles, and stability is exactly the property that makes them go stale. A name is stable so that it can be cached, and cacheable means invalidatable. The two hard problems are one problem because the feature that makes naming useful is the feature that makes invalidation necessary.

Names that leak

In code, the version of this that bites daily is the name that encodes an implementation detail, and then the implementation changes.

getUserById now accepts an email. tmp_fix_v2 has been in production for four years. The PaymentsService also sends notifications, because that is where the code happened to be when someone needed it. The Utils file is eleven thousand lines. Every one of these is a name that was accurate when written and has been quietly lying since, and every reader who dereferences it gets a stale result and doesn't know.

The usual advice is to name things for what they do, not how they do it. That is right, and it's also a cache strategy: name the interface, not the implementation, because the interface changes less often, so the cached mapping stays valid longer. Names with a longer TTL. It's the same reason a good URL doesn't contain the technology that serves it. /about will outlive /about.php.

What to actually do

You cannot fix this. You can lower the cost.

Rename early, when the caches are few. The right time to change a bad name is the day you notice, because every day after, another reader loads it.

Rename loudly. A rename that is announced once is a rename most readers miss. Leave the old name in place as a redirect, a deprecation warning, an alias, for longer than feels necessary, because the stragglers are real and you cannot find them.

And when you name something new, assume the name will be cached by people you'll never meet, for a duration you can't control, and that the referent will change under it. Pick the name that stays true the longest. The name is a promise about what will still be there when the pointer is followed. Most names break that promise. The good ones just break it later.