DEV Community

Cover image for Old apps still call home
Dominique Siacci for GoodBarber

Posted on

Old apps still call home

Somewhere this morning, a phone opened an app that was built on our platform years ago. Its owner hasn't touched it in a long time. The person holding the phone never updated the app, or no update ever came, because nobody rebuilt it. The app started, asked our servers for its content, and got an answer it could read.

That only works because we still answer in the format the app was built for, even though our own formats have changed since.

The client you can't upgrade

Most advice on API versioning assumes one of two things about your clients: you control them, or you can retire them. A web app ships its own front end, so a breaking change is a coordinated deploy. A public API has a deprecation calendar, a sunset header, an email to the developers. Either way, at some point the old client stops being your problem.

A platform that publishes apps can do neither. The client is a binary on someone's phone. It was built on a day we didn't choose, and its next version, if there is one, comes from the store on a day we don't choose either. We don't force updates: an app that works keeps working, and nobody is asked to rebuild because our own formats changed. I've written about what that promise costs when the world around an app moves. This piece is about what it costs when we move.

And we do move. The engine gets new generations, our answers change shape, newer endpoints get a cleaner design than the old ones. Meanwhile, the apps published before each of those changes are still installed, still speaking the dialect they were built with, and still expecting an answer in it.

Dialects, side by side

When a new generation of the engine arrived, the old one didn't move. It kept its paths, its file layout and the shape of its answers. The new generation got its own tree next to it. The same servers answer both today, and an app built against the old generation is served the old generation, for as long as it's around.

A phone only gets the new generation with a new build of the app, installed from the store. Until then, it runs the old binary, and the app's answers in the old tree are still there for it: they aren't deleted, and they keep the shape that binary was built for. The new build reads its own answers, written next to them in the new shape.

Why not just force the update?

Forcing an update would move the work onto other people. An update we force is a rebuild the owner has to run, a submission they have to make again, and a download the user has to accept: two parties doing work so that we can retire one code path. Multiplied by every app on the platform, that's a lot of work on their side to save some on ours.

Keeping a dialect alive is work we do once, on our side, instead of asking every owner for a rebuild. It has a cost: we keep testing every old path, and we keep maintaining a reader for every format we still serve. It's the same reasoning that keeps a link printed on a flyer years ago opening the right screen in today's version of the app.

There's a limit, and it comes from outside. When a store, an operating system or a certificate retires something an old binary relies on, that app needs a rebuild, whatever our servers answer.

Still asking

Some of the apps calling our servers this morning haven't been rebuilt in years, and people still use them. Keeping them working means keeping their vocabulary: answering in the words they were built with, and retiring nothing while someone still depends on it.

If you run an API for clients you can't upgrade, how do you decide when an old version can finally stop answering?

Top comments (0)