At a glance
Twenty-three seconds. That was how long the main dashboard took to appear once there was a realistic amount of data behind it. Customers were, understandably, complaining.
It now loads in about two hundred milliseconds. Nothing was rewritten from scratch, no framework was swapped, and the work took a matter of weeks rather than months. This is what was actually wrong.
Why it was slow
Three causes, all of them completely ordinary, all of them invisible until there was real data.
It fetched everything, then threw most of it away. The dashboard needed about twenty rows. The code loaded every record the account had ever created, brought all of it back from the database, and filtered it in the application afterwards. With thirty records that is imperceptible. With sixty thousand it is a disaster.
There were no indexes. Every lookup meant the database reading the entire table start to finish. We will cover indexes properly in a later post, but the short version is that a database without them is a filing cabinet with no labels: still findable, one folder at a time.
It asked the same question hundreds of times. The classic pattern: fetch a list of orders, then for each order go back and fetch the customer separately. Two hundred orders meant two hundred and one round trips to the database when two would have done.
None of this is exotic or clever. It is the standard set, and we would expect to find some combination of it in almost any application that was never reviewed by someone thinking about scale.
What the fix involved
Roughly in order.
Measure first. Before changing anything, find out where the time is actually going. Developers guess wrong about this constantly, ourselves included, which is why we do not guess. An hour of profiling saves a fortnight of optimising the wrong thing.
Ask the database for what you need. Filtering, sorting and limiting belong in the query, not in the application afterwards. This one change did most of the heavy lifting.
Add the indexes. Once you know which columns are actually being searched on, this is close to trivial and the effect is dramatic.
Collapse the repeated queries. Fetch the related records in one go rather than one at a time.
Then stop. There was more that could have been done. It would have taken it from two hundred milliseconds to a hundred and eighty, and nobody on earth would have noticed. Knowing when to stop is part of the job.
The two things we fixed that nobody had asked about
Speed was the reason we were called. It was not the most important thing we did.
Ownership checks. As covered in the previous post, the application never verified that the record you requested belonged to you. Every query now establishes ownership as part of asking the question, rather than as an afterthought that can be forgotten.
Transactions. Several operations changed three or four things that had to succeed or fail together, and they were not grouped. If the process died halfway through, the data was left in a state that made no sense: an order marked paid with no payment recorded against it. Wrapping those operations properly means they either all happen or none of them do.
Neither of these was on the brief. Both mattered considerably more than the loading time.
What it did not involve
A rewrite. This is the part founders find hardest to believe.
The instinct on discovering problems of this kind is to assume the whole thing is rotten and start again. It almost never is. The screens were fine. The overall structure was reasonable. The business logic worked and reflected months of the founder's thinking about their own market.
What was missing was the engineering underneath, and that can be replaced without touching what sits on top. Starting again would have cost several times more, taken far longer, and thrown away a great deal of hard-won knowledge that had nothing to do with code quality.
The honest summary
Most AI-built applications we see are repairable. Not all, but most. The ones that genuinely need rebuilding are rare, and they tend to be the ones where nobody looked until the situation was dire.
The cost of fixing scales with how long you leave it, because every month of new features gets built on the same shaky foundation. That is the actual argument for looking early: not that disaster is imminent, but that the bill goes up quietly while you wait.
We have written up the full rescue process here: rescuing an AI-built app.
And once again, the pattern underneath it all: AI is a brilliant typist and a terrible architect. The code it wrote was fine. The decisions nobody made are what cost twenty-three seconds.
Got something slow, or just quietly worrying you? Our AI Code Audit is a fixed-price £495 review that tells you plainly what you are dealing with, or get in touch for a no-pressure conversation.