← all writing
4 min read

Modernizing the Monolith Without Stopping the Line

Three times now I've led a platform through a generational rewrite — Objective-C to Swift, monolith to microservices — while it kept serving millions of users. The rule that made it survivable: you are never allowed to stop shipping.

  • Architecture
  • Modernization
  • Mobile

Editor’s note (draft): A starting draft written from Vincent’s experience to seed the blog. Review it, rewrite it in your own words, and delete this note before publishing.

Every few years I get the same call. A platform that millions of people depend on was built on assumptions that no longer hold — a language the team is migrating away from, an architecture that made sense at a tenth of the current scale — and someone has decided it’s finally time to modernize. The question is never whether. It’s how do we do this without the wheels coming off a product that can’t go down.

I’ve now led that work three times: migrating a 50-million-download streaming app from Objective-C to Swift, breaking monoliths into services, pulling a transit platform offline-first to cut its server dependency by 70%. Different stacks, same physics. Here’s what I’ve learned holds true every time.

The cardinal rule: never stop shipping

The single most dangerous sentence in modernization is “we’ll pause feature work and do the rewrite.” The moment you do that, three things happen. The business stops seeing value and starts asking why engineering went dark. Your best engineers, sensing a death march, start updating their résumés. And the rewrite — untested against real usage — drifts further from reality every week.

So the rule is absolute: the line keeps moving. Features keep shipping. The modernization happens underneath live traffic, in increments small enough that any one of them could be the last one if priorities changed tomorrow.

That constraint sounds like a tax. It’s actually the discipline that makes the whole thing work.

Strangle, don’t replace

The pattern that survives contact with reality is the strangler fig: you grow the new system around the old one, route by route, screen by screen, until one day the old thing is load-bearing for nothing and you delete it without ceremony.

In the Objective-C to Swift migration, that meant new surfaces were Swift from day one, and we converted legacy screens only when we were already in them for a feature. The two languages lived side by side for a long time — by design. A “big bang” rewrite would have meant a year of risk for a single terrifying cutover. The incremental path meant a hundred boring, reversible steps.

Boring and reversible beats elegant and irreversible every single time you are operating at scale.

Make the new way the easy way

You don’t move an organization by mandate. You move it by gradient. When I wanted teams on a shared component framework, the winning move wasn’t a policy — it was making the framework the path of least resistance. Building the screen the new way had to be genuinely faster and more pleasant than building it the old way. Once that’s true, adoption stops being a fight you manage and becomes a current you ride. On the streaming app, that shared framework is what turned the migration into a 30% acceleration in feature delivery rather than a drag on it.

Tests are the safety rail, not the afterthought

You cannot refactor what you cannot verify. Before touching a legacy subsystem, I want enough test coverage around its current behavior that I’ll know the instant I break it. Earlier in my career I watched teams reach 85%+ coverage org-wide and treat it as a vanity number; the real point of those tests was that they made aggressive change safe. Modernization without a test net isn’t engineering, it’s demolition.

Architecture is a people decision

Here’s the part that took me longest to internalize. The Objective-C-to-Swift question, the monolith-to-services question — these look like technical decisions, and they’re scored as technical decisions. But the thing that actually determines success is whether the team understands why, can make the hundred small calls consistently without you in the room, and won’t quietly route around the new pattern the moment it’s inconvenient.

That’s why I spend as much time on the curriculum and the standards as on the architecture diagram. A modernization is a coordinated behavior change across a lot of humans who all have their own deadlines. The diagram is the easy part. Getting fifty people to make the same decision the same way, under pressure, for two years — that’s the work.

The payoff is optionality

When it’s done well, you rarely get a fireworks moment. What you get is quieter and more valuable: a platform where the next change is cheap. Offline-first didn’t just remove 70% of server calls; it made a whole category of features possible that the old architecture would have rejected outright. That’s the real return on modernization. Not that the code is prettier. That the future got cheaper.

Modernize relentlessly. Just never stop shipping while you do it.