Logic League home
Back to insights
Case study

Modernizing a logistics platform in 90 days

How a senior team replaced a brittle legacy system with a modern, observable platform — without a big-bang cutover.

By Logic LeagueApr 28, 20268 min read
Case study8 min read

We were asked to modernise a logistics platform that nobody on its own team still wanted to touch. It dispatched real freight every working day, had not had a calm deploy in months, and the engineers who knew it best were the ones most nervous about changing it. The brief was easy to say and hard to do: make it safe to change again, without stopping the business for a year.

01A platform running blind

The platform belonged to a regional logistics operator and had grown into one large application handling dispatch, routing, billing and driver tracking, all leaning on a single shared database and a decade of accumulated workarounds. A forty-strong operations team ran on it from before first light until late into the evening. When something failed, and it failed often, the first signal was usually a phone call from a depot rather than an alert on a screen. There were almost no metrics, barely any traces, and logs that faithfully recorded everything except the thing you actually needed. Nobody could answer simple questions, like how many jobs were in flight or which step was slow, without reading the code and guessing.

Releases reflected that blindness. A change took roughly a week to reach production: manual testing, a hand-assembled deployment, and a Sunday-night window chosen so the fewest people would be hurt if it went wrong. The team had learned, sensibly, that the safest deploy was no deploy at all. So the backlog grew while confidence shrank, and the 2am pages kept coming.

02Why we turned down the rewrite

The instinct in a situation like this is to declare the old system a write-off and build a clean one beside it. We argued against that, hard. A full rewrite would have frozen useful changes for months, forced us to re-discover every undocumented rule the business quietly depended on, and staked the company on a single switchover that either worked or it didn't. The legacy code was genuinely unpleasant to work in, but it encoded years of hard-won edge cases about routes, exceptions and customers, and most of those rules lived nowhere except in the running system.

A rewrite asks a business to stop improving the thing that pays its bills and trust you for a year. It rarely deserves that much faith.

03Wrap the old system in a facade

So we did roughly the opposite of starting fresh. We put a thin facade in front of the legacy application and routed traffic through it, so that callers stopped talking to the old system directly and started talking to a seam we controlled. At first the facade did nothing but forward reads and writes straight through, unchanged. That sounds pointless, but it gave us the two things we lacked: a single place to observe behaviour, and later a single place to redirect a slice of that behaviour somewhere new without anyone upstream noticing.

04Observability before migration

Before moving any logic, we made the system legible. The facade was the natural place to start, because every request now passed through it. Within the first fortnight we instrumented the seam to expose:

  • Request rates, latencies and error rates per route, broken down by operation
  • Structured logs with a correlation id that followed a single job end to end
  • Traces spanning the facade and the database calls behind it
  • A handful of business signals: jobs dispatched, jobs stuck, and jobs failing late

05Migrate one slice at a time

With the system finally visible, we picked the first slice to move. Not the riskiest or the most glamorous one, but a well-bounded one: driver tracking, which was read-heavy, fairly self-contained, and painful enough that improving it would be felt immediately. We built the new implementation behind the facade and ran it in shadow first, still serving every request from the old path while quietly comparing the new path's answers against the old. Only once the two agreed for long enough did we let the new code actually serve traffic.

Writes were harder, so we used an expand-and-contract approach: write to both the old and new stores, keep reading from the old one until the new one had earned its place, then flip reads across and finally retire the old write. Every step sat behind a flag we could turn off in seconds, and because the facade owned routing, rolling back meant changing a value rather than shipping a release. Each migrated slice shrank the legacy core a little further, and the dashboards told us straight away whether a slice had made things better or worse.

Incremental migration is not slower than a rewrite. It just spreads the risk across many small days instead of one enormous one.

06How trust came back

The hardest thing to repair was not the code, it was the team's relationship with their own system, and that only changed as the facts changed. Week-long releases became same-day ones, because a small change could now go out behind a flag and be watched in real time. The Sunday-night ritual faded and the 2am pages largely stopped, not because nothing ever failed but because failures were now visible and reversible before a depot had to phone in. By the end of the 90 days the legacy system was still there, doing a little less each week, and for the first time in a long while the people who ran it were no longer afraid to touch it.

Key takeaways

  • Replacing a fragile system does not require a big-bang rewrite; routing traffic through a facade lets you change behaviour one slice at a time while the business keeps running.
  • Add observability before you migrate anything, because you cannot safely change a system you cannot see, and a facade is the natural place to instrument it.
  • Shadow reads, dual writes and an expand-and-contract sequence turn risky cutovers into reversible steps you can roll back with a flag rather than a redeploy.
  • Trust is rebuilt by evidence, not promises: once releases become same-day and failures become visible and reversible, the fear of deploying fades on its own.

Share this article

Back to insights

Have a project in mind? Let's talk.

Tell us where you want to go. We'll map the shortest credible path.