Skip to content
Ryan de Melo
Go back

Post-Merger Tech Integration: Ten Systems, Nine Months, Zero Downtime

On the merger slide, the synergies were circled in green: two companies become one, half as many systems to run, savings that someone in finance had already counted. By the time that slide reached engineering, “half as many systems” meant picking, for each of ten overlapping pairs, which team’s life work got switched off.

That was the job. Two large consumer platforms had merged, and the day after, we owned two of everything: two payment stacks, two identity systems, two order pipelines, two notification services, two catalogs, two of every internal tool that two sets of competent engineers had spent years building because each company needed exactly that thing. None of it was broken, and that was the problem.

The customer was supposed to feel nothing: not a forced password reset, not a re-link of a payment method, not an order that vanished mid-flight. Zero downtime was the floor, not a stretch goal somebody added to look ambitious, because both platforms were live at the kind of scale where a bad hour shows up in the national press.

You do not migrate ten systems, you sequence them

The first instinct is to rank the pairs by how much money each consolidation saves and start with the biggest. That instinct is wrong, and it took one tense planning week to talk the room out of it.

Systems do not stand alone. Identity sits underneath everything, payments depends on identity, orders depend on both, and the notification service hangs off orders. Collapse payments before you have collapsed identity and you are reconciling two user tables in the middle of the money path, which is exactly where you least want a surprise. The sequence has to follow the dependency graph from the bottom up, not the savings column from the top down, boring foundations before anything with a big number on it. The systems with the fattest synergy number went late, because they sat highest in the stack and needed stable ground under them.

We picked identity to go first: lowest glamour, highest leverage. Once both platforms read from one source of truth for who a user is, every consolidation after it got simpler, because “which account is this” stopped being a question you had to ask twice.

The strangler, because the alternative is a war room and a prayer

There is a version of this where you build the unified system, pick a Saturday at 2am, cut everything over, and keep a bridge line open with forty people on it. I have lived that version. It works until the one time it does not, and the one time it does not is the time you remember.

Instead of cutting over, we strangled. For each pair, we stood a facade in front of both old systems: one interface, the two legacy implementations hidden behind it. Every caller in the company moved to the facade while it still routed to whichever original system already owned that traffic. Nobody downstream knew anything had changed, because from where they sat, nothing had. Behind the facade, we built the one consolidated system and moved traffic onto it a slice at a time, a percentage of users, then a region, then everything. The old systems kept serving until they served nothing, and only then did we turn them off.

Two platform stacks, A and B, each with its own identity, payments, and orders services, converging through a facade layer into one unified stack, with old systems strangled slice by slice

Two stacks become one through a facade per pair. The facade routes to the old systems first, then bleeds traffic onto the unified one a slice at a time, until the legacy boxes serve nothing and get switched off.

The facade is what buys you zero downtime, because the riskiest moment, the actual switch, becomes a routing change you can make for one percent of traffic and undo in seconds if the dashboards turn red. No Saturday cliff, no bridge line, just a dial you turn slowly with a hand on the rollback.

Which one wins, and how you actually decide

The decision of which system survives is almost never made on technical merit, and pretending otherwise is how you lose the room.

We tried, early, to run it as a clean technical bake-off, scoring each pair on scale headroom, code health, operational maturity, security posture, and total cost to run. It was tidy and defensible, but it produced answers that were politically radioactive, because in three of the ten pairs the technically stronger system belonged to the smaller company, the one that had just been acquired, and choosing it meant telling the larger, older engineering org that their thing was the one getting killed.

We kept the scorecard but added two columns the bake-off had ignored. Migration cost: how painful is it to move the losing system’s data and traffic onto this winner. Blast radius: if this winner has a bad day, how much of the merged company is down. A system that scored slightly lower on code health but sat on data that was ten times harder to migrate often won anyway, because the cheapest path to one system mattered more than which codebase was prettier. We wrote the criteria down, weighted them in the open, and let the scores fall where they fell. None of that removed the politics, but once the answer is unpopular, the rubric everyone agreed to in March is all you have left to stand on.

In the end the split was roughly even. The acquirer’s systems won about half, the acquired company’s won the other half, and that even split did more for morale than any all-hands speech, because nobody could tell a story where one side had simply eaten the other.

Data reconciliation is where the bodies are buried

Picking the winner is the easy decision. Moving the loser’s data onto it is where the months go, and none of that work ever makes it onto a slide.

The same user existed in both systems with different IDs, different normalization, and the occasional contradiction: a phone number that two systems disagreed on, an address one had updated and the other had not, a wallet balance that had to match to the cent or someone was getting robbed. You cannot just union two tables and hope. We built a reconciliation pass for every pair that ran in shadow for weeks before any cutover: pull both sources, apply the merge rules, and diff the result against what was already live, then surface every mismatch to a human who decided the rule for that class of conflict. The merge logic got smarter every week as the diff count fell. We did not turn a dial on real traffic until the shadow diff for that slice was boringly small and every remaining mismatch was understood.

For money, the bar was higher. Balances and ledgers got reconciled to the cent, both directions, and any system that could not prove its numbers matched did not get traffic. That is not paranoia so much as the difference between a migration and an incident report.

The near-miss

We almost lost the wallet.

Payments was one of the late, high-stakes consolidations, and we were bleeding a region onto the unified system, maybe a tenth of that region’s traffic. The reconciliation had been clean for weeks. A small but growing set of users then started seeing a wallet balance that was wrong by a few cents, sometimes a few dollars. On any one account it was not catastrophic, but as a pattern it was, because a payment platform that cannot agree with itself on how much money you have is a payment platform nobody should use.

The cause was the kind of thing no bake-off scorecard would have caught. The two old systems rounded fractional currency at different steps in the calculation, one before applying a promotional credit and one after, and for years each had been internally consistent so nobody had ever noticed. The reconciliation had matched the stored balances perfectly, because the stored balances were correct. The drift only appeared on new transactions computed by the unified system using one rounding convention against ledger history written under the other.

The facade bought us the way out: because the cutover was a routing dial and not a Saturday cliff, we turned the dial back to zero for payments in that region inside a few minutes, and the affected users were served by their original system again before most of them noticed. The wrong balances stopped accruing. We then spent two weeks doing the boring, correct thing: making the rounding convention explicit, replaying the affected transactions under it, reconciling every touched account to the cent, and adding the rounding case to the shadow diff so it could never sneak through again. Only then did we turn the dial back up, slowly.

If that had been a big-bang cutover, the same bug would have hit a whole region at once with no quick way back, and “a few cents wrong for a handful of users” would have been “the wallet is broken” on the front page.

What I would tell the next person doing this

Sequence by dependencies rather than savings, because the system with the biggest synergy number is usually the one that needs the most stable ground beneath it, so it goes last.

Put the migration cost and the blast radius into the decision rubric, in writing, before anyone knows which system each column favors, because a rubric earns its keep less by finding the right answer than by surviving the wrong-feeling one.

What I keep coming back to is that we were not switching off ten systems, we were telling ten teams, half of whom had just been acquired and were already wondering whether they still had a job, that what they had built with their own hands was being turned off. The strangler pattern was the easy half. Doing it so that both sides could look at the final architecture and see their own work in it, that was the part that actually shipped the merger.


Share this post:

Previous Post
Agents Are Coming. Most Demos Are Lying.
Next Post
Getting JSON Out of LLMs Without Crying