Development
From the Scariest Problem to a Row of Simple Changes
Brant DeBow
Written on July 22, 2026
Years ago we built a dating app called Zazazu. At its heart was an in-app economy more complicated than anything a dating app had tried before. The original model was simple: a straightforward 1-1 currency per transaction. Then the business evolved, the way businesses do, and the founders needed something entirely different: free-to-play, a multi-tiered currency, bulk discounts, sales, incentives that responded to user behavior. A new financial model, top to bottom.
This particular change wasn’t just that the purchase screen had different pricing. It was something that touched literally every action a user could take that had an in-app currency attached to it. Rewriting the financial model meant changing code in every corner of the system, and everything it brushed against had to keep working. My fear wasn’t the difficulty of any one piece. It was the sprawl. How could we find every place that needed to change? What would we silently break and not discover until it was in front of users, mishandling their money?
Zazazu was built with Behavior Driven Development from day one, meaning the system’s behavior lived in plain-English scenarios that ran as automated tests against the real product. So we didn’t start the rewrite in the code. We started in the specifications. We rewrote the scenarios to describe the financial model we wanted, added new ones for the new behaviors, and ran the suite.
Every scenario that failed was a place the system didn’t yet do what the business now needed. Not a guess, not a grep, not a tribal-knowledge scavenger hunt. A list. Each failing test broke in exactly the right spot, and each spot was a small, comprehensible fix. I worked straight down the row, watching red turn to green, until the suite passed and the rewrite was done.
It took a day.
The problem was large, but every fix was simple. That’s what the specifications bought us. They decomposed a change I was genuinely afraid of into a sequence of changes no one would be afraid of, and when the last test passed, I didn’t have to wonder whether we’d caught everything. The suite was the definition of everything.
Tests are a confidence measure
The point of that test suite was never “coverage,” and it certainly wasn’t ceremony for its own sake. The point was confidence: knowing what the system does, and knowing it still does it after you change it. Executable specifications take that one step further, because the tests aren’t just checking code against a programmer’s assumptions. They’re checking the system against what the business actually asked for, in language the business can read. When those pass, “it works” isn’t an opinion. It’s a fact you can re-verify any time you like, in minutes.
Most teams live at the other end of this spectrum, and I meet them all the time. The system that runs the business and terrifies everyone. Nobody’s sure what it does in the corners. Every change is a risk calculation, so changes get smaller and rarer, and the fear compounds along with the debt. If that’s your system, the Zazazu story probably reads like a fairy tale. You can’t rewrite the scenarios first, because there are no scenarios.
Earning confidence you don’t have
The good news is that confidence can be retrofitted. It’s done piece by piece, and it follows a pattern that’s been well understood for years.
Start by carving off a seam: one piece of the system small enough to reason about, with inputs and outputs you can actually see. Don’t try to boil the whole codebase. Then pin down what that piece currently does with characterization tests, an idea Michael Feathers gave us the vocabulary for. Characterization tests don’t assert what the system should do. They record what it does do, bugs and all, so that you can change the code and know immediately whether you’ve altered behavior you didn’t mean to touch. It’s the humble version of a specification: not “this is what the business wants” but “this is what’s true today.” From there, the strangler fig pattern lets you grow the new system alongside the old, moving behavior over a seam at a time, with the old code still running underneath until the new code has earned its place. Piece by piece, “nobody knows what it does” becomes “the tests know what it does,” and fear starts converting into a suite.
That process has always worked. It’s also always been expensive, which is why so many teams never start. Characterizing a large legacy surface is months of careful grind, and it’s hard to fund grind.
What AI changes
This is where the calculus has genuinely shifted in the last few years. Modern AI tooling is very good at exactly the expensive part: ingesting large amounts of unfamiliar code, mapping what talks to what, and generating characterization tests quickly. At BiTE we run full codebase audits with AI on a regular basis, even on solid architectures we built ourselves, because bugs like to hide in the seams between components where no explicit test is looking. I regularly spin up quick Claude Code experiments just to verify my own understanding of a piece of architecture or pressure-test an assumption before I rely on it. The months-of-grind step, the one that kept teams from ever starting, is collapsing in cost.
What AI doesn’t change is the other half. AI can generate tests, but it cannot tell you what the system is supposed to do. That has to come from somewhere, and “the tests the AI wrote for itself all pass” is not confidence, it’s circular reasoning. The age of AI-assisted development raises the value of executable specifications, because now it isn’t just humans who need ground truth. The agents writing your code need a definition of correct that exists outside themselves, or they’ll happily converge on passing their own homework.
The tools are better than they’ve ever been. The principle hasn’t moved an inch. Confidence in software comes from specifications you can execute. When the day comes that you need to change a massive and important piece of the system, that confidence is the difference between a year of fear and a day of work.
