Audit BenchAi
← All posts

How Vibe Coding Breaks DRY: Duplicated Business Logic at Scale

·8 min read

Ask an AI assistant to add a discount calculation to checkout, and three months later ask it to add the same discount logic to an admin refund tool, and there's a real chance you end up with two separate implementations of the same business rule — each correct on its own, each subtly different in a rounding edge case, and neither aware the other exists. This is the most common way vibe coding breaks DRY, and it's structural rather than accidental: the assistant genuinely doesn't know the first implementation is there unless something tells it to look.

Why the model writes new code instead of finding old code

A human engineer who's worked in a codebase for months has a rough mental index of what already exists, and reaching for calculateDiscount()instead of writing it again is often just habit. An AI assistant's "memory" of the codebase is whatever fits in its current context window — the files it happened to read for this specific prompt. If the discount logic lives in a file the assistant didn't open, it doesn't exist as far as this prompt is concerned, and the fastest path to a working feature is writing the calculation fresh. This isn't a bug in the tool; it's a direct consequence of not having a persistent, searchable map of the codebase available at every prompt.

Why three copies is worse than it sounds

Duplicated logic written by a single careless human is usually duplicated consistently, because one person copy-pasted it. Duplicated logic written across separate AI sessions tends to diverge in small, specific ways — one copy rounds half-up, another rounds half-even; one copy applies the discount before tax, another after; one copy checks for a minimum order value, another doesn't. Each version reads as entirely reasonable in isolation. The business now has three slightly different definitions of "discount," and no single code review ever saw all three at once to notice they disagree.

Where this shows up beyond pricing math

  • Permission checks re-implemented per endpoint instead of calling a shared authorization function — exactly the kind of drift that produces broken access control.
  • Input validation rules duplicated between a form component and its corresponding API handler, which silently diverge as one gets updated and the other doesn't.
  • Date/timezone handling reimplemented per feature, each with its own assumption about which timezone the underlying timestamp is stored in.
  • Formatting and currency logic scattered across components instead of centralized, so a locale bug fix has to be found and applied in several places.

How to prevent it instead of finding it later

The fix is to make the existing implementation part of what the assistant sees before it writes anything. Prompting with "search the codebase for existing discount or pricing logic before implementing this, and reuse it if found" changes the assistant's default from write-first to search-first. Keeping a short reference of core business rules and where they live — in a README or a context file the assistant is pointed at — closes the gap that a limited context window otherwise leaves open.

Checklist for reviewing a diff that adds business logic

  1. Search the codebase for an existing implementation of the same rule before approving a new one — this is the one check a diff-only review will never surface on its own.
  2. When duplication is unavoidable in the short term, leave an explicit comment or ticket noting both locations, so a future fix doesn't update one copy and miss the other.
  3. Treat validation and business rules that exist in two layers (client and server, form and API) as a drift risk, and confirm they're either shared or tested for equivalence.
  4. For high-stakes logic — pricing, permissions, tax — prefer a single, well-tested shared function over convenience duplication, even when the duplication looks small at review time.

Read how to review AI-generated code without trusting it blindly →

See how to write tests that catch real bugs →