Fill out this form to speak to a product expert.
Understand the DRY principle in programming, why it matters for safe, reliable AI-assisted development, and how to prevent AI agents from generating duplicate or inconsistent code.

In software development, some ideas are so powerful that they ripple across languages, frameworks, architectures, and even entire engineering cultures. The DRY principle is one of those ideas. Standing for “Don’t Repeat Yourself,” it’s a deceptively simple rule with profound implications for how we design, maintain, and scale software systems.
But the DRY principle is also among the most misunderstood concepts in programming. Many developers mistakenly reduce it to “don’t copy-paste code,” while others misuse it to create overly generic, painfully abstract systems. In reality, DRY is about something deeper: ensuring that every piece of knowledge in your system has a single, authoritative source of truth.
In this guide, we’ll explore:
By the end, you’ll understand not only what DRY is, but when to apply it, how to avoid over-abstracting, and how to use it as a tool (not a dogma) for creating maintainable, scalable systems.
{{cta}}
The DRY principle was introduced by Andy Hunt and Dave Thomas in their landmark 1999 book The Pragmatic Programmer, a book that has shaped how multiple generations of engineers think about software design.
One of the most memorable stories in the book involves a large financial system used by multiple departments: accounting, compliance, and auditing. Each department needed to produce nearly identical reports using the same financial rules.
Except… they didn’t use the same rules.
Each team had created its own implementation of the business logic—not because they wanted to, but because repeated logic had quietly crept into the codebase over years of incremental development. As a result:
The authors describe the chaos that unfolded: nobody trusted the system, every team blamed the others, and developers spent weeks tracking down inconsistencies caused not by complex mathematics, but by duplicated knowledge.
The solution was transformative.
The team consolidated the business logic into a single reporting engine. Instead of three systems with three interpretations of the rules, there was now one implementation consumed by all departments.
The result?
This experience crystallized a core insight:
“Duplication is the root of all evil in software.”
—Hunt & Thomas, The Pragmatic Programmer
And from that insight, the DRY principle was born:
Every piece of knowledge must have a single, unambiguous, authoritative representation in a system.
This idea, simple yet profound, became the foundation of modern DRY principle programming.
The DRY principle (“Don’t Repeat Yourself”) means that you should avoid writing the same logic in multiple places. Instead, you keep each piece of knowledge or functionality in one clear, central spot so it’s easy to update, reuse, and maintain without creating inconsistencies or extra work.
Since the premise of DRY seems simple, let’s look at what violating it looks like. Many developers incorrectly interpret DRY as: “Don’t duplicate code.” But the DRY principle in programming isn’t about code. It’s about meaning, knowledge, and intent.
You’re violating DRY when you duplicate:
These forms of duplication may not look like copy-paste code. They might exist as separate functions, modules, or services that encode the same concept in different ways. This type of duplication is dangerous, because it creates drift and inconsistency across your systems. Examples include:
In summary: You can violate DRY without copy-paste existing anywhere.
Duplication is cheap in the moment and expensive in the long run.
If you’ve ever had to fix a bug that was caused by overlooked duplicated logic, you know how painful it can be. The crippling cost of duplication shows up as:
Taken together, these costs erode the clarity and stability of the entire codebase. Consolidating business logic into a single, authoritative location is what allows a system to evolve predictably and sustainably.
When every rule and behavior has a single place to live, the whole system becomes easier to understand and work with. DRY strips away the noise, which in turn unlocks faster, safer iterations. A codebase organized around clear, singular sources of truth creates momentum with benefits that quickly compound:
DRY is powerful—but dangerous in the hands of someone who applies it mechanically. The number one mistake developers make is applying DRY too early, creating brittle abstractions that make the system harder to understand. The right way to apply DRY is gradual and semantic, not premature and syntactic.
1. Identify shared meaning, not shared syntax. Only abstract duplicated code when it represents the same concept.
Example: Two different discount calculation functions may look similar, but represent different rules. Don’t merge them unless they mean the same thing.
2. Use code generation. One schema → many outputs.
Tools like:
…allow you to generate:
This is the ultimate DRY solution for modern systems.
3. Refactor opportunistically. Don’t force abstractions too early. Instead, refactor when patterns emerge naturally.
Good DRY evolves—bad DRY is imposed.
4. Prefer declarative sources of truth. Declarative systems enforce DRY naturally.
Examples:
Declarative = self-documenting = DRY.
5. Use well-scoped modules. Encapsulate logic inside modules that own their domain meaningfully.
But don’t force unrelated modules to share logic just because they have similar structures.
There are times when duplication is safer, cleaner, and more intentional.
1. When the abstraction reduces clarity → If combining two pieces of logic hides meaning, don’t do it.
2. When two concepts look similar but are actually different → This is the most common place where DRY is misused. Two features might share code now but diverge later. Binding them together creates future pain.
3. When the abstraction creates unnecessary coupling → Sharing a utility library across several microservices might violate boundaries and increase the blast radius of changes.
4. In tests → A readable test suite often contains repetition, and for good reason. Each test should tell a clear short story. Over-DRYed tests become unreadable.
This idea comes directly from the spirit of The Pragmatic Programmer.
When in doubt:
Wait.
Keep the duplication.
Only abstract once you fully understand the domain.
Good abstractions come from maturity.
Bad abstractions come from fear of duplication.
Up to this point, we’ve been talking about DRY in the traditional, human sense—when to duplicate, when to wait, and when to abstract. But there’s a new layer now. AI is stepping into codebases, sometimes as a helper and sometimes as a decision-maker. And the moment machines start reading and modifying our code, the cost of duplication changes. Here’s how DRY plays out when AI becomes part of the team.
AI coding assistants, such as autocompletion tools, inline explainers, test generators, and refactor helpers, work best when the codebase tells a consistent story. These tools rely on patterns in your code to predict what you want next. When logic is centralized, an assistant can trace it, learn from it, and give suggestions that align with how your system actually behaves.
Duplication muddies that picture. If the same logic appears in multiple places (and one of those places is slightly outdated), the assistant has no way to know which one reflects the truth. This leads to odd completions, half-baked refactors, or suggestions that reinforce the wrong version of a pattern. And when you're moving quickly to accept suggestions or let the AI assistant fill in boilerplate code, those small inconsistencies compound over time.
DRY code gives AI coding tools a single, reliable reference point. It keeps the model’s understanding of your project clean and reduces the chance of misleading suggestions. You get sharper completions, smarter refactors, and fewer “why did it write that?” moments.
Autonomous agents raise the stakes. These AI systems go beyond helping with isolated tasks, and are now scanning whole codebases, forming plans, making decisions, and applying changes across many files. When the same logic appears in several places—especially with small differences—an agent can treat each instance as a separate concept. It may update one copy and overlook the others, causing the logic to drift apart in ways that are hard for the agent to notice and even harder for humans to debug.
Autonomous agents navigate code through internal “maps”—semantic clusters, dependency graphs, retrieval traces—and duplication clutters those maps with mixed signals. A DRY codebase, by contrast, gives the agent one clear, authoritative place to understand a piece of logic, and that clarity helps it reason more accurately, update safely, and avoid cascading side effects. Thus, as machines begin reading and modifying our software alongside us, DRY stops being just a best practice, and instead becomes a way of keeping the code understandable to both humans and AI alike.
{{cta}}
Once you bring autonomous agents into your workflow, DRY isn’t just something you can violate. Agents can violate it, too. Unlike humans, agents don’t pause to ask whether a function or pattern already exists; they simply produce output based on the context available to them at that moment. Two common scenarios make duplication especially likely:
1. When the agent’s context is missing or poorly structured, it may generate new code rather than reusing what already exists.
Agents will generate a result regardless of whether the correct function, pattern, or abstraction already exists. If the context is incomplete (whether due to misconfigured MCP servers, missing or outdated agent.md files, or unclear retrieval instructions) the agent may:
This isn’t to be attributed to a flaw in the model, as it’s merely a reflection of what the agent can “see.” When developers provide clear, well-organized context and point agents toward the correct sources of truth, the system naturally leans toward reuse rather than regeneration. Hence, thoughtful and thorough context design becomes a kind of DRY enforcement mechanism: give the agent the right map, and it’s much less likely to draw a new one.
2. When conversations exceed the model’s memory, the agent forgets and begins duplicating work.
Even with large context windows, agents have limits. Long sessions eventually push earlier messages out of memory, causing the agent to lose track of previous decisions. Once this happens, it may forget that certain abstractions or rules were already established and unintentionally create duplicates.
Model providers are working to mitigate this. Claude Code, for example, now compacts conversation history so earlier details are less likely to be lost as sessions grow. But until these solutions are consistently reliable across tools, developers can reduce duplication risk by following a few disciplined practices:
These habits give agents stable reference points even as conversations reset or grow long, which reduces the risk of accidental duplication and keeps your codebase consistent over time.
The DRY principle in programming has survived decades because it captures a simple truth:
duplication is the enemy of consistency, clarity, and maintainability.
But remember: the DRY principle is not about code style; it’s about knowledge management.
To use DRY well:
The magic of DRY is in developing the skill to understand the meaning behind code and ensuring that meaning lives in one authoritative place. And in an era where AI reads, suggests, and even modifies our code, keeping that meaning coherent has never mattered more.
{{cta}}
Apply DRY with wisdom, and your systems will be cleaner, more resilient, and far easier to evolve.
Misapply it, and you’ll create brittle abstractions that hurt more than they help.
Like all powerful tools in software development, DRY works best when used pragmatically, exactly as Hunt and Thomas intended.



