Six projects that changed how we build software
None of what we believe about delivery came out of a book. There was a rebuild we talked a client out of, a data warehouse we hid behind the spreadsheets it was meant to kill, an AI pilot that only shipped once we cut it down, and three projects that convinced us the technical decisions belong with the engineers. Here are all six, roughly in the order they happened, and what each one left us with.
The rebuild we talked a client out of
A national logistics operator came to us with a board-approved plan to replace the platform at the centre of their business - the system that took every booking, planned every route, and told hundreds of drivers where to be. It was over ten years old, every change seemed to break something else, and releases had slowed to one a quarter. Everyone agreed it had to go. We were asked to quote for the rebuild.
It would have been the biggest contract we had ever signed. But full rebuilds of systems like this have a habit of running for two years and delivering a slightly worse copy of what already exists. So we asked for four weeks inside the code first, at day rates, before anyone committed to anything.
What we found changed the conversation. The platform was not rotten. It was a mostly sound system with three genuinely bad corners, and a deploy process so frightening that nobody had shipped a small change in years. That, more than the code, was what everyone had learned to call legacy.
At a glance
- Client
- A UK national logistics & freight operator
- Engagement
- Modernising the core dispatch & booking platform
- Original ask
- Quote for a full 18-month rebuild
- What we did
- Fixed the platform in place instead
- Our role
- Assessment, remediation and delivery
- Team
- Three senior engineers alongside the client’s
The turning point
Four weeks of reading code saved eighteen months of rewriting it
We went through a year of incidents and change requests and marked where they actually landed. Most of the system had not caused trouble in years. The pain was concentrated in three places: route-planning queries that had outgrown their indexes, a pricing module with no tests that everyone was afraid to touch, and the deploy itself - manual, unrehearsed, done at 2am a few times a year.
So instead of a rebuild we did the unglamorous version. We automated the deploy until releasing was boring, which meant changes could be small, which meant they stopped being frightening. We wrote tests around the pricing module until it could be changed safely, then changed it. The slow queries took a fortnight. Ten months later the client still had the platform everyone had wanted to throw away - the same one, releasing weekly.
- 18 months
- the rebuild plan we were asked to price
- 4 weeks
- reading the system before recommending anything
- 10 months
- to fix in place what the plan said to replace
What we found
- “Legacy” turned out to mean three specific problems. The rest of the system was fine, and had been all along - nobody had looked closely enough to notice.
- The fear was about the deploy, not the code. Once releasing was safe and boring, the codebase everyone wanted to abandon became easy to change.
- Turning down the rebuild cost us the biggest contract we had been offered. It is also why the client is still with us.
The warehouse we hid behind the spreadsheets
A UK mutual insurer hired us to build a data warehouse, and the brief was blunt: get finance off spreadsheets. Month-end close ran across more than forty linked workbooks, took eleven days, and broke whenever someone renamed a tab.
Every vendor before us had pitched the same cure - dashboards, a BI tool, spreadsheet retirement - and two of those projects had already failed. So before writing anything we spent a week sitting with the finance team while they closed a month. Somewhere in that week it dawned on us that the spreadsheets were not the problem. Fifteen years of business rules lived in those cells, and they held the only numbers in the building anyone actually trusted.
So we did not take the spreadsheets away. We built the warehouse underneath them.
At a glance
- Client
- A UK mutual insurer
- Engagement
- A data warehouse under the finance reporting stack
- The brief
- “Get finance off spreadsheets”
- What we changed
- Kept the spreadsheets, replaced everything under them
- Our role
- Data architecture, delivery and analyst enablement
- Team
- Four engineers and an analytics lead alongside theirs
The turning point
We replaced what fed the spreadsheets, not the spreadsheets
The warehouse pushed clean, reconciled data into the same workbooks people already used. Same files, same tabs - the difference was that the numbers now arrived overnight from one governed source instead of being pasted in by hand from nine systems. Nobody was retrained, because on day one nothing visibly changed except that eleven days of copying stopped.
Trust moved slowly, and then it moved on its own. Once people had watched the warehouse agree with their own numbers month after month, they started going to it directly. Within a year about half the workbooks had been quietly retired by the people who owned them. We never ran a single migration workshop.
- 11 days
- to close the month when we arrived
- 0
- new tools finance had to learn on day one
- ~half
- of the workbooks retired within a year, by their owners
What we found
- People don’t trust systems, they trust numbers they have checked themselves. The spreadsheets had fifteen years of that trust; a new dashboard has none.
- The tool you are told to kill is usually where the business logic lives. Half the rules in our warehouse came straight out of those cells.
- Adoption you don’t have to push for is the only kind that lasts. We never migrated anyone - they moved when the numbers had earned it.
The AI pilot that shipped once we cut it down
A UK retail group had spent nine months and three vendor pilots trying to launch a customer-support assistant that could handle anything a shopper might ask. Every pilot demoed well. None of them ever reached a customer.
The models were never the problem. The problem was that “answers anything” has no pass mark. Nobody could say what good looked like, so nobody would sign it off, and each pilot stayed a pilot until the budget moved on.
We suggested something much less impressive: pick the one workflow with a clear right answer - returns triage - build a way to score it before building the feature, and put a person behind every call the model wasn’t sure about.
At a glance
- Client
- A UK multi-brand retail group
- Engagement
- A customer-support assistant, after three stalled pilots
- Original plan
- One assistant that could answer anything
- How it shipped
- One workflow - returns triage - live in 5 weeks
- Our role
- Scoping, evaluation harness, delivery and handover
- Team
- Three engineers and an ML specialist
The turning point
We cut it down until it could be measured
Returns triage was a good place to start precisely because it was boring: a few hundred cases a day, a written policy behind each one, and a decision you could mark right or wrong the next morning. We graded a set of real historical cases first, and only shipped once the assistant beat the human queue it was replacing on that set.
Anything it wasn’t confident about went to a person, and every one of those hand-offs was logged and reviewed. It was live behind a flag in five weeks. A quarter later it was clearing most of the queue on its own - and, more usefully, the team knew exactly which kinds of case it still couldn’t be trusted with.
- 9 months
- of pilots with nothing in production
- 5 weeks
- to put one scoped workflow live behind a flag
- 62%
- of returns triaged without reaching a human
What we found
- “Answers anything” can never be signed off, because nobody can say when it works. One measurable workflow can.
- Build the scoring before the feature. A model you can grade is a model you can improve; a model you can’t is a demo.
- The number that matters is deflection: how much work never reached a human - and that everything important still did.
The team got smaller and the work got faster
A UK B2B software business asked us to rebuild their customer portal, and the engagement arrived staffed the way these things have been staffed for twenty years: an external project manager, an external product owner, a design studio, an outsourced QA house - and, at the end of that chain, the people actually writing the code.
Nobody in the chain was doing a bad job, which is what made the problem hard to see. A change to a single screen took a fortnight, and when we traced one through, nine of those fourteen days were spent waiting: for the ticket to be groomed, for the mock-up to come back, for a regression pack to be re-run by testers who had never used the product.
We had spent the previous year building agentic tooling around our own engineers, and we knew what it had done to this kind of work. So we made an awkward proposal: shrink the team to four seniors, give them the tooling, and let them own the whole loop.
At a glance
- Client
- A UK B2B software business
- Engagement
- Rebuild of the customer portal
- How it was staffed
- External PM, PO, design studio and QA house
- What we changed
- Four senior engineers owning research through release
- The tooling
- Agentic assistants and harnesses built around the engineers
- Our role
- Delivery, tooling and clean handover
The turning point
We removed the hand-offs instead of managing them
The four of them took everything: the research, the spec they would build against, screens prototyped in code rather than in a design tool, tests generated and reviewed as they went. The agentic tooling absorbed most of what the client used to buy in - the exploratory test sweep, the first draft of a regression pack, the survey of a legacy codebase nobody had read in years - and did it the afternoon the question came up, not the sprint after.
What was left was the part that doesn’t automate: deciding what to build, and being answerable for it. That stayed with the people writing the code, where it had always belonged. The fortnight became a day.
- 5 hand-offs
- a single change made before it reached a user
- 9 of 14 days
- of a typical change spent waiting, not building
- Same day
- from agreed change to production, once the loop closed
What we found
- Every hand-off is a queue. The people in ours were good at their jobs; the waiting between them was the cost, and no amount of coordination was going to remove it.
- The engineers who do the research should build the thing. The understanding earned in week one is exactly what gets lost when the work is handed to someone else in week three.
- The tooling didn’t replace an engineer. It removed the reasons we had been hiring around one.
- It only worked because the tooling was built around the developers. The harnesses, generators and evaluation loops we wrote for that team are why four people could hold the whole loop.
- The old staffing model wasn’t wrong when it was written. It was written for a world where none of this existed.
The feature that never needed a model
An insurance broker engaged us to build what their roadmap called AI-powered invoice ingest. A handful of suppliers sent the same file every month, in the same fixed schema, columns in the same order - and a language model was going to read it, understand it, and post the totals to the ledger.
The product manager who designed the flow wasn’t technical and had never been asked to be. From the outside, a system that answers a question correctly is a system that answers a question correctly, and the newest way of doing it looks like the best one. The distinction the whole design turned on - a parser is either right or it stops, a model is only ever plausible - was one they had no reason to know existed.
We flagged it in the first week. But the flow was already signed off and had been demoed to the end users as “the AI reading your invoices”. So we spent two weeks teaching a language model to read a file whose shape had never once changed.
At a glance
- Client
- A UK insurance broker
- Engagement
- An “AI-powered” supplier invoice ingest
- Original plan
- A language model reading a fixed-schema file
- Why
- A non-technical PM owned the flow, and signed it off
- What we changed
- A parser for the columns, a model only for the free text
- Our role
- Delivery and integration - and, eventually, the parser
The turning point
The parser took an afternoon, and never got a row wrong
Eventually one of the engineers stopped arguing and just wrote it: about two hundred lines of parser, run against forty thousand historical rows in nine seconds. It matched every one. The model we had spent two weeks on was at 98.7% - and the misses were the dangerous kind. Not crashes. Totals that looked completely reasonable and were quietly wrong by a decimal place.
The model kept exactly one job - the free-text notes field, where the input really is unstructured and a good guess beats no answer. Everything with a column heading went back to plain code. The lesson wasn’t that the model was bad. It was that the decision about where to use it sat with someone who couldn’t evaluate the answer, and nobody had built a step where the people who could were asked first.
- 2 weeks
- teaching a model to read a file with a fixed schema
- 1 afternoon
- to write the parser that replaced it
- 98.7%
- model accuracy - and the 1.3% were silent, not loud
What we found
- A parser is right or it stops. A model is plausible. Those are not two flavours of the same thing, and if the input has a fixed schema you don’t need a guess.
- The failure to fear is the quiet one. A broken parser halts the run and someone looks at it; a wrong model posts a plausible number to the ledger.
- Use a model where the input is genuinely unstructured, and nowhere else. The notes field kept its assistant. The columns never needed one.
- The engineer who said all this in week one was right in week one. The two weeks were the cost of a sign-off process that never asked them.
The screens were beautiful, and the product didn’t work that way
We joined a field-services company three months after a design studio had finished its work: sixty-four screens, signed off, rendered to the pixel, for a tool that schedules the engineers who fix boilers and broadband in people’s houses. No code existed yet, and everyone was pleased.
The studio was good. It had also never sat with a dispatcher. The screens assumed a job has one engineer, at one address, on one day. Real jobs split in half, get handed to a second engineer at two in the afternoon, and finish at an address nobody had heard of that morning. There was no screen for any of that.
The developers built to the mock-ups anyway, because the mock-ups were what had been signed. Every state the designs hadn’t imagined became a workaround, and the workarounds became the product. Three weeks in, someone asked what the screen looked like when a job was reassigned mid-shift. There wasn’t one.
At a glance
- Client
- A UK field-services company
- Engagement
- Scheduling and dispatch for field engineers
- How it started
- 64 signed-off screens from an external design studio
- The problem
- The studio had never watched the work the product describes
- What we changed
- Build the functionality first, design it once it is real
- Our role
- Delivery, and rebuilding the flows the mock-ups had missed
The turning point
We built it plain first, and designed it once it was real
We stopped drawing and started building: plain screens, barely styled, wired to real data and put in front of real dispatchers. Within a fortnight we had found seventeen states a job could actually be in, against the three the mock-ups allowed for. Half of them were the awkward ones - reassigned, part-completed, cancelled while the engineer was already at the door.
Then we brought in a designer. One, embedded with the team, working on a product that existed rather than a picture of one. Their work was better for it: they weren’t guessing which states needed a screen, they could open the app and count all seventeen. Design stopped being a blueprint handed down to the developers and went back to being what it is good at - making something that already works clear and quick to use.
- 64 screens
- designed and signed off before any code existed
- 3 of 17
- real job states the mock-ups had allowed for
- 2 weeks
- of plain screens on real data to find the other fourteen
What we found
- A mock-up is a claim about how the domain behaves, usually made by whoever has watched the domain least.
- Developers will build the impossible state rather than argue with a signed picture. Authority sat with the artefact nobody could test.
- Ugly and correct comes first. A plain screen on real data tells you in a day which states exist; a beautiful one tells you what someone assumed.
- Design is neither the wrapping nor the blueprint. Brought in once the thing is real, a designer makes something true better - and their work improves, because the answers are in front of them.
Case studies
Six lessons we kept
One from each project above, in the order they came. Together they’re most of how we work now: understand the system before you build, measure before you automate, and keep the decisions with the people who can evaluate the answer.
Read the system before you replace it
Most of what gets called legacy is a few specific problems nobody has looked at closely. Four weeks in the code is cheaper than eighteen months of rebuild - and sometimes the right recommendation is the one that loses you the contract.
Replace the plumbing, not the tools people trust
Fifteen years of checked numbers beats any dashboard. Put the new system underneath what people already use, let it earn agreement month after month, and the migration largely takes care of itself.
Scope it until you can score it
“Answers anything” has no pass mark, so it never gets signed off. Cut the work down to one thing you can grade, build the scoring before the feature, and keep a person behind everything the system isn’t yet trusted with.
Remove the hand-offs, don’t manage them
Every hand-off is a queue, however good the people standing in it. Senior engineers who do the research should build what they researched - and agentic tooling has removed most of the reasons anyone ever staffed around them.
Reach for a model only when a guess beats nothing
A parser is right or it stops; a model is merely plausible. If the input has a fixed schema, certainty is cheaper, faster and safer than intelligence - and the decision belongs with people who can tell the difference.
Design what exists, not what might
Screens drawn before code are guesses about a domain nobody has watched yet, and developers will build the impossible state rather than argue with a picture. Get it working plainly first, then bring in a designer to make it good.
Six projects taught us this. Yours doesn’t have to.
Book a free consultation. We’ll talk through what you’re building, where the waiting and the risk are hiding, and the shortest route to working software in front of real users.