Rapid Refactoring Without the Big-Bang Budget
- 23 hours ago
- 13 min read
How built-in feedback, iterative delivery, and disciplined use of AI replaced a failing public-facing system in a fraction of the quoted time and cost.

At a Glance
The argument. Big-bang rewrites are expensive for structural reasons, not budgetary ones. Feedback arrives too late to be cheap, undocumented behavior is rediscovered in production, and nothing is visible until the end. Change the delivery model and those costs move. The engagement described here is the evidence.
The evidence. A public-facing search tool that thousands of people depended on had become slow, inaccurate, and publicly embarrassing. The platform was out of support, so incremental fixes were effectively impossible.
The conventional path. A big-bang rewrite with a long time horizon and an expensive budget that the client could not absorb.
What we did instead. Treated the delivery method as a constraint rather than the budget. Built feedback mechanisms into the product itself, shipped in small visible increments, and used AI to compress the most expensive parts of the work under tight engineering control.
The outcome. A modern, accessible, fully documented replacement delivered in weeks and handed over with a complete test suite and no dependency on JMA to maintain it.
1. Why Big-Bang Rewrites Cost What They Cost
A legacy system in visible decline usually arrives with a quote attached, and the quote is what everyone argues about. That framing is the mistake. The budget is the most visible constraint on a replacement, not the binding one.
A big-bang rewrite is expensive for structural reasons. Feedback arrives late which means that mistakes are discovered when they are most expensive to fix. Undocumented behavior is rediscovered by accident and usually happens in production. And because nothing is visible until the end, the client is asked to extend trust for months without evidence. This is exactly what an organization already burned by a failing system has least appetite for.
Because those costs are structural, they respond to a change in method rather than a change in budget. That is the claim this paper makes. The evidence for it is a single engagement: a public-facing search service in public sector, replaced in weeks not months. If your situation looks like that one, the method below should transfer. Section 8 sets out where it does not.
2. A Public Service in Visible Decline
A client came to us in urgent trouble. They operated a public-facing search tool which was the front door to one of the organization's most visible services. Something thousands of people relied on to find information they needed.
The failures were obvious to everyone who used it. A typical search took at least 20 seconds to return with no visual indicator that the search was still in progress. The replacement returns the same search in seconds while indicating to the user that the system is still working. Users waited, and waited, and were then often rewarded with results that were duplicated, incomplete, or an error message. Every flaw was on display to precisely the audience the organization most wanted to serve.
That produced pressure from two directions at once. Externally, users complained loudly and publicly. Internally, the system had become politically sensitive and morale-draining. It was a topic nobody wanted to own. The software wasn't merely slow. It had become a source of organizational anxiety. That distinction matters because it changes what a successful project has to accomplish. Fixing the performance problem alone would not fix the trust problem.
The real shape of the cost
What put the client in a bind was the cost of replacement and "Cost" was not just money. The quotes they received were beyond the available budget, but the budget was only the most visible constraint. The others were harder:
Time and risk. The conventional path was a classic big-bang rewrite. Months of building in the dark followed by a risky all-at-once cutover. A long bet with the entire payoff at the end with no meaningful way to course-correct partway through.
Hidden knowledge. The legacy system had quietly accumulated years of undocumented business rules, including work arounds for quirks in data which were difficult to fix at the source. Replace it carelessly and you silently lose behavior nobody knew was there. Things like this you end up later finding out from users.
No off switch. This was a live public service. Taking it down for months was not an option. And because the underlying technology was no longer supported, small tweaks to the existing system were close to impossible. It was a full rewrite or nothing.
The choices for this organization looked bad. Keep limping along with software that was actively damaging the organization's reputation or commit budget they did not have to a project that might not land.
3. Challenging the Constraint
We offered this client a third choice. Everyone involved had assumed the constraint was the budget. We thought the real constraint was the way replacements are traditionally built.
Change the delivery model and those costs move. Our approach rested on three ideas that reinforce one another: make feedback part of the product rather than a phase at the end, use iterative delivery to continuously de-risk, and use AI to reduce the cost of the most labor-intensive work.
The three are not independent. AI is what made the fast feedback loop economically possible, and the feedback loop is what made aggressive use of AI safe. Either one alone might have made for a project that ran off its course.
Principle 1: Feedback built in, not bolted on
Rather than waiting for a big reveal, we made feedback cheap and constant. We did it by building the mechanisms into the software itself, not by adding tens of hours of requirements gathering meetings.
Every piece of stakeholder feedback became an automated test. When someone told us the result was wrong, we didn’t just fix it we locked the corrected behavior in place. The same issue could not quietly regress weeks later.
Open questions were tracked visibly in the user interface. Ambiguity was surfaced where reviewers were already looking, instead of living in a spreadsheet someone had to remember to open.
We demoed working software within days, and continuously after that. We deployed to an environment where stakeholders could put their own hands on it rather than receive screen captures.
When a system is designed to absorb feedback, course corrections cost hours instead of months. That is the whole argument for rapid iteration, Agile if you will.
Principle 2: Iterative delivery, worked in the open
We shipped in small, visible increments the client could react to rather than disappearing for a month at a time. Equally important, we worked transparently by creating living documentation, recording decisions as they were made, and having a paper trail anyone in the organization could follow.
This is what answered the internal problem from day one. Transparency is how you rebuild trust in a project that has become a politically sensitive subject. An executive sponsor can see real progress continuously and can see exactly which decisions were made. That is a deliverable in its own right even though it never appears on a statement of work.
Principle 3: AI as a force multiplier, under engineering judgment
AI is what collapsed the time and cost curves. It enabled a small team to move at a pace a traditionally staffed team cannot match. But the value did not come from pointing a model at a codebase and asking for a rewrite. It came from applying it to the specific tasks where it is strongest and human effort is most expensive:
Comprehending the legacy system. Reading a large, undocumented codebase and an unfamiliar data model is slow, high-effort work that historically consumes a large share of a rewrite. AI compressed the discovery phase dramatically. With AI the team was able to surface behaviors, edge cases, and data dependencies far faster than they could have manually.
Building a comprehensive test suite. Characterizing existing behavior in tests is exactly the kind of heavy work pattern that is tedious for engineers but is well suited for AI generation with review. This is the single highest-leverage application we found.
The rewrite itself. Implementation against a well-specified target, with tests as the contract.
The discipline mattered more than the tooling. Every AI contribution entered the codebase through the same gates as human work often does. It had to pass the test suite, it was reviewed by an engineer accountable for it, and it was measured against the behavior of the live legacy system. We treated the model as a very fast contributor with no context and no judgment. Always keep humans in part of any AI loop.
What model that was used as our work horse is the least interesting aspect of this conversation. The order of operations did the real work. Human-reviewed tests first, generated implementation second, one module at a time. Full test suites run on every code commit (continuous integration). The full-suite rule sounds like overhead but it caught the failures that mattered.
4. The Test Suite Was the Specification
If there is one transferable idea in this project, it is this one.
In a rewrite of an undocumented system, the hardest question is not "how do we build the new thing?" It is "what does the old thing actually do?" There were no requirements documents. The specification existed only as behavior in running code, distributed across years of accumulated decisions some of which were made because of upstream data structures that could not be modified.
We chose to make the test suite the specification. Rather than attempting to document the legacy system and then build from the document, we characterized its behavior directly in executable tests, then held the replacement to them. The finished suite contains 160+ tests and runs on every commit. That inverted the usual risk profile in three ways:
It made "did we lose something?" an answerable question. In a conventional rewrite, missing behavior is discovered by users after cutover. With behavior captured in tests, a gap shows up as a failing test before anyone outside the team sees it. This also allowed us to ask questions about what is and is not necessary.
It made AI-accelerated implementation safe to pursue. The legitimate concern about AI-generated code in a legacy replacement is that it will be subtly wrong. An executable specification converts that from a matter of reviewer vigilance into a mechanical check. The speed was only responsible because the safety net was built first.
It converted stakeholder feedback into permanent assets. Each correction became a test, so the specification grew more complete with every round of feedback rather than decaying. Over the engagement stakeholder corrections became permanent tests.
Blindly doing a re-write without assessing what is necessary or may have changed since the last build is a mistake. The tests also allowed us to ask questions about how the legacy system worked and remove or add business logic in many instances. We may not have done this without the tests to reference.
The tests also became the artifact that made handovers real, which is a point we will return to at the end of this paper. A client who receives a system plus the executable definition of what it is supposed to do has received something they can more easily maintain.
The same logic extended to our approach to accessibility requirements. Conformance is usually handled as an audit near the end of a project. That is a major mistake as it surfaces problems at the point where they're most costly to fix. We treated it as an ongoing part of our work. Accessibility checks ran as part of our automation on every change. A violation failed the build the same way a broken search result did. Compliance stopped being a phase and became a property of the codebase.
5. Where Human Judgment Was Non-Negotiable
It would be easy to read the previous sections as an argument that AI did the work. However, the places it could not are worth naming.
Deciding what counted as a requirement
The legacy system contained years of undocumented rules, some of them workarounds for messy data. When you surface a behavior like that, you face a question no model can answer: is this a business rule the organization depends on or is it years-old debt that should not be carried forward?
AI is genuinely excellent at finding these behaviors and describing them. It has no basis for deciding what matters. Answering requires knowing which stakeholder to ask, understanding what the organization is accountable for, and often recognizing that the person who originally made the decision may no longer be with the company. Every one of those judgments was human and getting them wrong would have produced a technically clean replacement that was wrong in ways nobody noticed until it was live.
Deciding what the new system should refuse to do
The old system passed bad upstream data straight through to users. Copying that would have reproduced the duplicated and incomplete results that caused the complaints in the first place, but with a prettier user interface. This was mitigated through continuous conversations and built-in mechanisms in the user interface that allowed us to asynchronously ask the questions we needed to ask.
Owning the outcome
Throughout, the team was fully accountable for every change that entered the codebase and solely responsible for interfacing with the users. There was no in between channels handing messages back and forth. Getting a prototype up live in days, not weeks, was essential to this being successful. Building mechanisms into the user interface to ask the questions that our test suite uncovered allowed building the right thing to happen quickly. Accountability is what makes review real rather than a rubber stamp. The team owned the output, the outcome, and the result. The goal was to “build the right thing and build the thing right” while leveraging the capabilities that AI could offer.
The general principle: use AI where the work is high-volume and verifiable and keep humans where the work is judgment under ambiguity. Deciding what is worth preserving, what an organization owes its users, and what an acceptable risk looks like should always be part of the equation.
6. What Didn't Go Smoothly
An account where nothing went wrong is not useful to anyone deciding whether to try this. Three things are worth being candid about:
A wrong assumption made permanent. Logic from the old system was copied, assumed correct, and locked in place by tests written against that assumption and it was wrong. The legacy code contained hard-coded rules that excluded certain data points. Those were carried forward into the rewrite, where the test suite confirmed the new system matched the old one. A test user spotted the discrepancy, a broader conversation followed, and the logic came out. The tests will tell you whether you preserved a behavior. They cannot tell you whether that behavior deserved to survive.
Correct rules, incorrect presentation. The logic was right, but the interface was wrong. We had made assumptions about how results should be displayed, and those assumptions did not match how users read them. The fix was to build user personas that could be tested against. What does this person need? What is being put in front of them?
Conversation can beat automation. The feedback mechanisms built into the prototype answered a large share of the questions that needed answering. On one feature, they stifled the answers rather than providing them. After a stretch of email back-and-forth, a fifteen-minute call produced answers that no amount of feedback automation was going to surface.
None of these were caught by cleverness. They surfaced because working software was in front of real people early, and because we kept looking. One was caught by a test suite. One by a test user. One by picking up the phone. Speed is only responsible when you have all three.
7. The Handoff: We Wanted to Be Replaceable
The client is not locked into us. That is the outcome we are proudest of and it was deliberate.
The most trust-building thing you can do for a client who has been burned by software is hand them something they fully own and understand. It is also the harder commercial choice. A dependent client is a more predictable revenue stream in the business that we are in. We think that trade is worth making, and we think the reason is visible in this project. The client came to us because the last system had become something nobody could or wanted to own. Recreating that condition with new technology would have solved nothing.
Concretely, our handover included:
The full application, buildable from scratch. The React/TypeScript frontend and .NET 10 API, with a Docker Compose setup that builds and runs the entire stack (database, API, web) in one command, no local SDKs required.
A complete operations and handoff guide (the repository README). A system architecture diagram, two documented deployment paths (Docker and IIS), a configuration reference, the legacy behaviors we deliberately preserved and why, the full database, local-development and database-restore instructions, and symptoms, cause, fix troubleshooting table.
The reasoning behind the build, not just the build itself. For every significant decision, it is documented why the choice was made. How the system stays fast, how it guards against known quirks in the client's own data, how the search behaves. The next engineer inherits the thinking, not a black box.
A self-contained setup, not a house of cards. Everything needed to run the system comes with it, including sample configuration and a copy of the database. A developer who has never seen the project can go from a fresh copy to a working system in minutes, with a single command. There are no hidden steps that live only in someone's head.
A documented security posture. The security scan's findings triaged package-by-package, with remediation and residual risk recorded.
This also answers the question a technically literate reader will already be holding: is AI-accelerated code maintainable by someone else's team? It is maintainable under the same conditions as any code is. It is conventional, it is documented, and its intended behavior is captured in tests that run on every change. A codebase is maintainable because of the artifacts around it and the standards it was held to, not because of who or what typed it. The test suite is what makes that claim checkable rather than reassuring.
8. Does This Approach Apply to Your Situation?
This method is not universal, and being clear about its edges is part of recommending it honestly.
It works well when
A working legacy system is still running. It is the reference implementation. Tests need something to model. Without that model, you are writing requirements from scratch and the economics change.
Behavior is verifiable. Search, retrieval, calculation, and reporting can be checked programmatically against known inputs. That is what makes aggressive acceleration safe.
The domain is bounded. A well-scoped service with clear inputs and outputs. Not a sprawling platform with dozens of integrations.
Stakeholders can engage weekly. Built-in feedback only compounds if someone is giving it. A client who can review rapid changes gets far more from this model than one who cannot dedicate the time and be available.
Trust needs rebuilding. If a prior effort fails or the system has become politically charged, visible incremental delivery is worth more than the schedule savings.
Be more cautious when
Regulatory audit trails govern the change process itself. The approach is compatible with regulated environments, but the documentation and approval overhead has to be planned into the process rather than be discovered.
Correctness cannot be expressed in tests. Systems whose behavior is subjective, or heavily dependent on human interpretation, lose the safety net that makes the speed responsible.
The legacy system is genuinely unavailable. No reference implementation means no out of the gate automated tests can be written. The risk profile reverts towards the age-old problems a conventional rewrite has always presented.
There is no engineering capacity to review. This model depends on accountable human review at volume. Without it, AI acceleration produces liability at speed. There needs to always be a knowledgeable human in the loop.
9. Closing
The client faced what looked like a choice between two bad options: living with software that was damaging their reputation or spending money they did not have on a project that might not land. That choice was real, but it was a product of an assumption about how replacements get built.
Built-in feedback, iterative delivery, and disciplined use of AI did not just make the project cheaper and faster. It made it theirs and resulted in a system the organization owns, understands, and can change without calling us. If you are looking at a legacy system in decline and a quote you cannot justify, the constraint may not be the budget.


