Most developers think DRY (Don’t Repeat Yourself) is about avoiding duplicate code.
It’s not.
At least, not primarily.
DRY is about protecting knowledge integrity inside a system.
And the difference between those two interpretations is what separates someone who “removes duplication” from someone who designs resilient systems.
Let’s unpack this properly.
Where DRY Actually Came From
The DRY principle was formally introduced in 1999 in the book The Pragmatic Programmer by Andrew Hunt and David Thomas.
But it didn’t emerge as a stylistic suggestion.
It emerged as a response to a painful, recurring problem in software engineering:
Systems were breaking because knowledge was scattered.
The original formulation was:
“Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.”
Notice something important.
It says knowledge, not “lines of code.”
At the end of the 90s, software systems were growing rapidly:
- Large monoliths
- Increasing web adoption
- Enterprise systems scaling fast
- Low discipline around refactoring
When business rules were duplicated across modules, updating them required changing multiple places. Inevitably, someone forgot one.
The result?
Inconsistent behavior.
Hidden bugs.
Loss of trust.
DRY was not about elegance.
It was about survival.
The Real Meaning of DRY
If you reduce DRY to “don’t copy-paste code,” you are already misunderstanding it.
DRY is about ensuring that a single business rule, assumption, or decision lives in one authoritative place.
For example:
Bad (violates DRY at the knowledge level):
def calculate_vat(price):
return price * 0.23
def calculate_invoice_total(price):
vat = price * 0.23
return price + vat
If VAT changes to 21%, you must remember to update two places.
That’s duplicated knowledge.
Better:
VAT_RATE = 0.23
def calculate_vat(price):
return price * VAT_RATE
def calculate_invoice_total(price):
vat = calculate_vat(price)
return price + vat
Now the tax rule has a single authoritative representation.
That’s DRY.
But here’s where it gets interesting.
DRY Is Not About Removing All Repetition
Many developers take DRY too far.
They see similar-looking code and immediately try to abstract it.
Two functions look 70% similar?
“Let’s create a generic helper!”
Three classes share some logic?
“Let’s create a base class!”
This is where DRY becomes dangerous.
Because similarity is not identity.
Two pieces of code can look similar but represent different knowledge.
And if they evolve differently later, your shared abstraction becomes a liability.
Experienced engineers ask:
Will these behaviors change together?
If the answer is uncertain, duplication might be safer than premature abstraction.
DRY in Modern Architectures
In monoliths, DRY is relatively straightforward.
In distributed systems, it becomes more nuanced.
Imagine two microservices:
- User Service
- Billing Service
Both define a User model.
Is that duplication?
Technically yes.
Architecturally? Not necessarily.
If both services depend on a shared library for User, you create:
- Versioning complexity
- Coordinated deployments
- Cross-team coupling
Sometimes duplicating the model protects service autonomy.
In this case, duplication is intentional decoupling.
That is mature DRY thinking.
Why DRY Matters Even More Now
Today software complexity is exploding:
- Distributed systems
- Cloud-native infrastructure
- CI/CD pipelines
- AI-generated code
- Rapid iteration cycles
AI tools, in particular, tend to generate repetitive patterns.
Without strong architectural discipline, systems accumulate silent duplication of knowledge.
The consequences:
- Business rules drift apart
- Bugs appear inconsistently
- Teams lose confidence in behavior predictability
DRY becomes less about code aesthetics and more about organizational coherence.
Where DRY Fails in Practice
There are common failure patterns:
1. Premature Abstraction
Developers abstract after noticing two similar implementations.
But two instances are not a pattern.
The Rule of Three exists for a reason.
Abstraction before stabilization creates rigid design.
2. Over-Centralization
Putting too much logic in a single shared module.
Now every change becomes high-risk.
Instead of reducing complexity, you concentrate it.
3. Accidental Coupling
Shared utility libraries across services.
Seems efficient.
But now one small change triggers a cascade of updates.
DRY at the code level.
Tight coupling at the system level.
4. Confusing DRY with Reusability
Reusability is a possible outcome of DRY.
It is not the definition.
DRY is about knowledge consistency.
Reusability is about convenience.
They overlap, but they are not identical.
A Practical Scenario
Let’s say you’re building an e-commerce platform.
You have:
- Checkout service
- Promotion engine
- Tax calculation module
The tax rule is identical across all flows.
Should you duplicate the tax formula in each service?
No.
Because tax calculation is a business invariant.
It must have one authoritative definition.
Now consider discount logic.
Promotions in checkout may differ from internal admin simulation tools.
They look similar.
But they evolve independently.
Forcing them into a shared abstraction may slow down both teams.
The correct DRY decision depends on:
- Stability of the rule
- Frequency of change
- Organizational structure
- Risk tolerance
This is engineering judgment.
Not dogma.
DRY and Engineering Maturity
DRY is not about writing less code.
It’s about designing systems that:
- Avoid inconsistent behavior
- Protect business rules
- Scale without logical divergence
But it requires restraint.
Blind DRY leads to over-engineering.
Ignoring DRY leads to entropy.
The real skill lies in balance.
And that balance is what turns a developer into an engineer.
Final Thought
DRY is not a rule to apply mechanically.
It is a lens to examine how knowledge flows through your system.
When applied correctly:
- It reduces systemic fragility.
- It improves maintainability.
- It increases trust in behavior consistency.
When applied blindly:
- It creates tight coupling.
- It freezes evolution.
- It increases cognitive overhead.
So next time you see duplication, don’t rush to refactor.
Pause.
And ask:
Are these two pieces of code the same knowledge, or just similar shapes?
That answer will define the quality of your system.
And your level as an engineer.
Thanks for reading!
If you have any questions, complaints or tips, you can leave them here in the comments. I will be happy to answer!
😊😊 See you! 😊😊
Support Me
Youtube - WalterNascimentoBarroso
Github - WalterNascimentoBarroso
Codepen - WalterNascimentoBarroso
Top comments (0)