All articles
AI News

AI Slop Starts in the Codebase: How LLMs Rewrite the Rewrite Calculus

FDE Coach EditorialJuly 11, 202610 min read

The Rewrite Calculus: A Brutal History

Every senior engineer knows the rule: never rewrite a working system. It’s the second hardest problem in computer science, right after cache invalidation and naming things. The lore is written in the corpses of companies that tried—Netscape, Digg, countless internal platforms that were “just six months away” for three years.

The calculus was simple and punishing. A rewrite meant rebuilding every edge case, every undocumented business rule, every bug that had been patched at 2 a.m. The original system, however ugly, contained years of institutional knowledge embedded in its very flaws. Rewriting it was an act of hubris that cost millions and delivered, at best, parity with fewer bugs and, at worst, a smoking crater where your product used to be.

This wasn't just folklore. It was economic reality. The cost of a rewrite scaled non-linearly with the system's age and complexity. The technical debt you wanted to escape was actually a form of capital—paid for with time, incidents, and user churn. Writing it off meant paying that price again, from scratch, with interest.

What Changed: The LLM as a Force Multiplier for Rewrites

Large Language Models didn't just add a new tool to the toolbox. They changed the fundamental unit of work. Previously, an engineer's output was measured in lines of code, functions, or components per day. Now, an engineer can generate an entire module, scaffold a service, or translate a legacy endpoint to a modern framework in minutes.

This isn't about Copilot auto-completing a function. It's about a paradigm shift where an engineer's role shifts from writing to specifying, reviewing, and integrating. The bottleneck moves from the keyboard to the brain—from "how do I type this out?" to "what exactly should this do, and how do I verify it?"

The source material from The Truth As I See It Now nails a critical insight: AI-generated code isn't just faster to write, it's cheaper to discard. When a human spends three months building a feature, it becomes precious. When an LLM generates it in an afternoon, you can throw it away without emotional attachment. This flips the rewrite calculus on its head.

The New Economics: Why 'Rewrite It' Is Suddenly the Cheaper Option

Let's run the numbers on a hypothetical legacy payment service—200,000 lines of Java 8, Spring 4, XML configuration hell, 15 years of accumulated cruft.

Old Calculus:

  • 5 engineers, 18 months, $1.5M+ in salary alone
  • Risk of missing undocumented edge cases (chargebacks, partial refunds, weird tax rules)
  • Opportunity cost of not building new features
  • High chance of cancellation or failure
  • Verdict: Refactor incrementally, despite the pain

New Calculus:

  • 2 engineers, 3 months, using LLMs to:
    • Auto-generate a modern Go/Rust equivalent from the original codebase and API specs
    • Generate comprehensive test suites from production traffic patterns
    • Translate legacy config to infrastructure-as-code
  • The generated code won't be perfect, but it's a starting point that would have taken 12 months manually
  • The remaining 2.5 months are for human review, edge-case hardening, and integration testing
  • Verdict: The rewrite is now the faster, cheaper path to reducing maintenance burden

The key shift is that the initial generation of the rewrite is no longer the expensive part. The expensive part is verification. And verification is a problem we already know how to solve with contracts, tests, and observability—all of which LLMs can also help generate.

The 'Slop' Phenomenon: When Quantity Masquerades as Quality

Here's the dark side, and it's where the term "AI slop" earns its keep. The same economics that make rewrites cheap also make it trivial to generate more bad code, faster than ever before.

Slop isn't just buggy code. It's code that:

  • Passes tests but doesn't handle real-world edge cases
  • Uses deprecated patterns the LLM learned from old GitHub repos
  • Lacks coherence with the rest of the codebase's idioms
  • Creates new technical debt that's harder to spot because it's syntactically clean

A human-written messy function looks messy. It signals "read carefully." An LLM-generated function looks pristine, well-commented, and follows all the style guides. It radiates competence. But it might silently swallow a critical exception or use a library version with a known vulnerability. The slop is plausible in a way that old-school spaghetti code never was.

This creates a perverse incentive. If you can generate a rewrite in a week, why not do it every quarter? The result is a codebase in constant churn, where nothing stabilizes long enough to be truly understood. The slop doesn't start at the user interface—it starts in the repository itself, in the very foundation of the system.

Engineering in the LLM Era: New Skills, New Risks

For the working engineer, this isn't a threat of replacement. It's a forced evolution of what "senior" means.

The skills that matter now:

  1. Specification writing. The quality of the output is bounded by the quality of the prompt. Vague instructions produce plausible slop. Precise, constrained specifications produce useful code. This is a writing skill as much as a technical one.
  2. Adversarial review. You must read generated code with the assumption that it's wrong in subtle ways. This is emotionally draining in a way that reviewing a colleague's PR isn't—you can't assume good intent or shared context.
  3. Test architecture. The lever that makes LLM rewrites safe isn't the generation; it's the verification harness. Engineers who can design property-based tests, chaos experiments, and production replay systems will be the ones who make this work.
  4. Incremental integration. The smart play isn't a big-bang rewrite. It's using LLMs to generate a parallel implementation, then routing a trickle of production traffic to it while comparing behavior. This is the strangler fig pattern on steroids.

How to Actually Use This Today: A Practical Framework

If you're staring at a legacy system and wondering whether the LLM era changes the math, here's a concrete approach you can try this sprint.

Step 1: Extract the Specification, Not the Code

Don't ask an LLM to "rewrite this Java service in Go." That's how you get slop. Instead, feed it the existing code and ask for a behavioral specification: "Generate a comprehensive OpenAPI spec and a set of Given-When-Then acceptance tests that capture every endpoint, error condition, and edge case you can infer from this codebase."

This gives you a human-reviewable artifact that captures the system's contract. It's also a forcing function—if the LLM can't infer the behavior, that's a red flag that the code is too convoluted for a safe rewrite.

Step 2: Generate the Rewrite from the Spec, Not the Code

Now feed that reviewed specification into a fresh context and ask for the implementation in your target stack. This breaks the "garbage in, garbage out" chain. The LLM is translating a clean spec, not a messy legacy codebase.

Step 3: The Verification Sandwich

Before you deploy a single line of generated code, build the verification layer:

  • Traffic replay: Capture a day's worth of production requests to the legacy service. Replay them against the new service and diff the responses.
  • Property tests: Define invariants—"for any valid request, the response status is either 200 or 4xx, never 5xx"—and let a fuzzer go wild.
  • Shadow mode: Deploy the new service alongside the old one. Send all production traffic to both, but only return the old service's response. Log every divergence.

This is where the economics of testing shift. Generating the code is cheap. Running a week of shadow traffic against a generated rewrite is also cheap. Finding and fixing the 50 edge cases that diverge is where the real engineering happens, but it's a fraction of the cost of writing the whole thing from scratch.

Step 4: The Disposability Test

Before you merge anything, ask: "If we find a fundamental flaw in this approach next week, can we throw this away?" If the answer is no—because you've already modified it, integrated it, or built dependencies on it—you've moved too fast. The power of LLM-generated code is its disposability. The moment you treat it as precious, you've lost the plot.

A Balanced Take: This Isn't a Panacea

Let's be clear about what this doesn't change.

It doesn't change the fact that rewrites are risky. The risk shifts from "we'll spend 18 months and fail" to "we'll spend 3 months, succeed superficially, and discover critical failures in production 6 months later." The failure mode is sneakier, not eliminated.

It doesn't eliminate the need for domain expertise. An LLM can generate a payment service, but it doesn't know your specific merchant agreements, your fraud patterns, or the regulatory quirks of every market you operate in. That knowledge still lives in your team's heads, and extracting it into specs is the hard part.

It doesn't work for everything. Systems with extreme performance requirements, novel algorithms, or deeply entangled data dependencies are still poor candidates for LLM-driven rewrites. The models are pattern-matchers, not innovators.

It amplifies the importance of code review culture. If your team already treats code review as a rubber-stamp exercise, LLM-generated code will accelerate your descent into chaos. If you have a strong review culture, it'll accelerate your velocity. The tool amplifies the existing culture, for better or worse.

This is also a good moment to revisit what we mean by technical debt. In the LLM era, "debt" isn't just about messy code. It's about code that's hard to specify. A clean, well-tested legacy system with clear behavioral contracts is low-debt, even if it's in an old framework. A spaghetti mess that nobody fully understands is high-debt, and an LLM won't magically fix that—it'll just generate plausible-looking spaghetti in a new language.

FAQ

Q: Won't this just create a new kind of technical debt—AI-generated code that nobody understands?

Yes, absolutely. That's the slop problem. The mitigation is to treat generated code as a starting point for human hardening, not a finished product. If your team can't explain what every generated module does and why, you're accumulating debt. The unit of progress isn't "lines generated"—it's "lines generated, reviewed, understood, and verified against production traffic."

Q: How do I convince my manager that a rewrite is now viable when it wasn't before?

Don't pitch a rewrite. Pitch a 2-week spike: extract a spec from the legacy system, generate a parallel implementation, and run it in shadow mode against production traffic. The results will speak for themselves. Either the divergence rate is low enough that the rewrite is clearly viable, or it's high enough that you've just learned something critical about your system's complexity without committing to a rewrite.

Q: What's the catch with using LLMs for legacy code that has no tests?

The catch is that you have no safety net. The LLM will happily generate code that passes zero verification because there is no verification. Your first step must be generating the tests from production traffic or from the code itself. This is a hard prerequisite. If you skip it, you're not engineering—you're gambling.

Q: Does this mean junior engineers are more or less valuable now?

More valuable, but in a different way. A junior engineer paired with an LLM can produce the raw output of a senior engineer from five years ago. But they need senior guidance to learn specification, review, and verification skills. The apprenticeship model isn't dead—it's accelerated. The risk is that companies will see the raw output and decide they don't need seniors at all, which is how you get a codebase of pure slop.

Q: Where does this break down first?

Security-critical code and anything with hard real-time constraints. LLMs don't understand timing, and they don't understand threat models. Generated authentication logic, cryptographic handling, or safety-critical control loops should be treated with extreme skepticism. The cost of failure is too high, and the models' training data is full of subtly insecure examples.

#software-architecture#tech-debt#code-quality#llm

Want to build like a Forward Deployed Engineer?

FDE Coach is a cohort-based program in frontend, backend, AWS, and AI. Build real products and get referred to 200+ hiring partners.

Explore the program

More ai news

August 15 · 0d left
Enroll Now