Skip to content

Case study

Taking over an abandoned codebase for a B2B SaaS team

An undocumented service whose authors had left, brought back under test and deployable on demand without a rewrite.

Client
B2B SaaS company
Sector
B2B SaaS
Duration
PLACEHOLDER — confirm engagement length
Stack
TypeScript, Docker, GitHub Actions

Published with the client’s permission. Their name, product names and any identifying figures have been removed or generalised.

The engagement

The situation

A revenue-critical service had been built by contractors who were no longer available. There were no tests, no documentation, and deployment was a sequence of steps one remaining employee performed by hand. The team had stopped changing it, which meant they had also stopped improving the product around it.

What we did

We resisted the rewrite the team expected to be told they needed. The first milestone was getting the service building reproducibly on a clean machine and deploying from a pipeline. Only then did we add characterisation tests pinning current behaviour — bugs included — so later changes could be made with evidence rather than hope.

The outcome

The service is deployable on demand and under test. The team resumed shipping changes to it. The rewrite that had been assumed necessary was not, and the budget went to features instead.

Deployment
PLACEHOLDER
Replace with a measured before-and-after, or delete this metric.
DecisionsWhat we chose, and what it cost

Every choice traded something away.

No rewrite

Incremental strangling behind a stable interface, starting with the riskiest module.

Trade-off The codebase still carries legacy patterns. In exchange the service kept earning throughout, and the team was never paying for two systems at once.

Pin bugs, do not fix them first

Characterisation tests that assert current behaviour, including behaviour that is clearly wrong.

Trade-off The test suite initially encodes bugs. That is uncomfortable, but it is the only way to distinguish "I changed this" from "this was always broken" when you did not write the original.

Pipeline before refactor

Reproducible build and automated deploy as milestone one.

Trade-off No visible feature progress for the first stretch. Everything after it was faster, and the team could finally verify their own changes.

Detail

What we found

The service was not badly written. It was undocumented, untested and unreproducible, which is a different problem with a different fix. Roughly a fifth of the code turned out to be unreachable — a fact we could only establish once there was enough instrumentation to prove it.

The genuine risk was not the code at all. It was that a single employee held the deployment procedure in their head, and had been on call for it, informally, for two years.

What we built

A reproducible Docker build, a deployment pipeline, and a characterisation test suite covering the paths that touch money. Then we removed the dead code, which was the first change anyone had made to the service in eight months.

What we would do differently

We under-communicated during the pipeline phase. From the outside it looked like nothing was happening for two weeks. A weekly written note explaining what had changed and why it mattered would have cost almost nothing and avoided a difficult conversation.

—Start a project

Start a project like this.

If something here resembles your situation, describe yours. We will tell you how close it actually is.

  1. 01

    Send a short brief

    Five minutes. What you are building, or what is broken.

  2. 02

    We reply within one business day

    From an engineer, with a real question or observation.

  3. 03

    A 30-minute technical call

    Free, no deck, no obligation.

Or read how we work first →