Skip to main content
SEMastery
Fundamentalsbeginner

DRY Is the Most Misunderstood Rule in Programming

DRY is not about deleting repeated code. It is about knowledge. Learn the real meaning of Don't Repeat Yourself with simple C# examples.

11 min readUpdated January 12, 2026

Introduction

DRY is one of the first rules people learn in programming. It stands for Don't Repeat Yourself. Most students hear it like this: "If you see the same code twice, delete one copy and share it." That sounds smart. It feels clean. And it is wrong more often than people think.

The real rule is about knowledge, not about lines of code. The famous book The Pragmatic Programmer by Andy Hunt and Dave Thomas says it clearly: "Every piece of knowledge must have a single, unambiguous, authoritative representation within a system." Notice something. It never says the word code.

In this post we will fix that misunderstanding. We will use a simple real-life story, then some small C# examples. By the end you will know when to remove repetition and, just as important, when to leave it alone.

A simple everyday analogy

Think about two shops in your local market.

The vegetable shop has a price board. The sweet shop next door also has a price board. Both boards are made of the same green wood. They look the same. They are the same shape and size.

Now imagine someone says: "Two boards is wasteful. Let us join them into one shared board for both shops."

What happens the day the sweet shop has a festival sale and wants to change only its prices? Now you must touch the shared board, add a little note like "this part is only for sweets", and be careful not to break the vegetable prices. The shared board, which felt clever, now makes every small change harder.

The two boards looked the same. But they held different knowledge. The vegetable prices and the sweet prices are not the same fact. They just happened to look alike. This is the whole idea of DRY in one picture.

Same shape, different meaning: looking alike is not the same as being the same.

What DRY really says

Let us separate two ideas that students often mix up.

IdeaWhat it meansIs this DRY?
Code duplicationThe same text appears in two placesNot the real point
Knowledge duplicationThe same rule or fact is written twiceThis is the real DRY

DRY asks one question: Is this the same piece of knowledge written in two places? If yes, you have a problem. If two parts only look similar but mean different things, you do not have a DRY problem at all.

Here is a short way to remember it: similar is not the same as identical. Two methods can share every character and still be two separate ideas.

A C# example that fools people

Look at these two methods. They look almost identical.

// Rule for accepting a new user's age
public bool IsValidUserAge(int age)
{
    return age >= 18 && age <= 120;
}
 
// Rule for an allowed driver age in a rental booking
public bool IsValidDriverAge(int age)
{
    return age >= 18 && age <= 120;
}

The "clean code" reflex screams: "Merge them! One method!" So a developer does this:

public bool IsAgeInRange(int age)
{
    return age >= 18 && age <= 120;
}

It works. For now. Then the business changes. The law says car renters must be at least 21 and no older than 75. But the user signup rule stays at 18 to 120.

Now the shared method cannot serve both. The developer adds a flag:

// This is the smell. Conditions creeping into a "shared" method.
public bool IsAgeInRange(int age, bool isDriver)
{
    if (isDriver)
        return age >= 21 && age <= 75;
 
    return age >= 18 && age <= 120;
}

This is exactly the trap. The two rules were never the same knowledge. "Who can sign up" and "who can rent a car" are different business facts. They just looked alike on the day you wrote them.

The honest fix is to keep them apart:

public bool IsValidUserAge(int age) => age >= 18 && age <= 120;
 
public bool IsValidDriverAge(int age) => age >= 21 && age <= 75;

Two short methods. No flags. Each rule lives on its own and can change on its own. This is more DRY than the merged version, because each piece of knowledge now has one clear home.

Real duplication vs accidental duplication

There are two kinds of repetition. Telling them apart is the whole skill.

Should I remove this repetition?

See repetition
Ask: same knowledge?
Real duplication
Accidental duplication

Steps

1

See repetition

Two pieces look alike

2

Same knowledge?

Same rule or fact?

3

Real duplication

Merge into one home

4

Accidental duplication

Leave them separate

A quick mental check before merging two similar pieces of code.

Real duplication is when the same fact is written twice. If you change one and forget the other, you get a bug. For example, the tax rate of 18% written in five files. That is one fact in five places. Fix it with one shared source.

Accidental duplication is when two pieces of code look the same today but mean different things. They will drift apart over time. If you merge them, you tie two unrelated ideas together with a knot that is painful to untie later.

// REAL duplication: one fact (GST rate) copied around.
public decimal AddTaxToCart(decimal amount)   => amount + (amount * 0.18m);
public decimal AddTaxToInvoice(decimal amount) => amount + (amount * 0.18m);
public decimal AddTaxToReceipt(decimal amount) => amount + (amount * 0.18m);

The number 0.18m is the same single fact: the current tax rate. If the government changes it to 20%, you must edit three places and you will likely miss one. This is a DRY violation. Give that fact one home:

public static class TaxPolicy
{
    // One authoritative home for this piece of knowledge.
    public const decimal GstRate = 0.18m;
 
    public static decimal AddTax(decimal amount) => amount + (amount * GstRate);
}

Now the rate lives in exactly one place. Change it once, and the whole system follows.

The danger of the wrong abstraction

When you merge code that should not be merged, you create what Sandi Metz calls the wrong abstraction. She wrote a famous line every developer should remember: "Duplication is far cheaper than the wrong abstraction."

Here is how the trap usually grows, step by step.

How a helpful shared method slowly turns into a tangled mess.

Each new caller adds one more flag or one more if. After a year, the shared method is a maze of conditions. Nobody understands it fully. Everyone is scared to change it. That is the wrong abstraction in full bloom.

The good news from Sandi Metz: the way out is to go back. Copy the shared code back into each caller. Let the duplication return for a moment. Then look at each copy on its own and let it tell you what it really needs. Often the copies were never the same thing.

Helpful counter-rules: WET, AHA, and the Rule of Three

Smart developers came up with friendly reminders so DRY is not applied too early.

RuleMeaningWhen to use
WETWrite Everything TwiceIt is fine to repeat once; do not abstract on the first copy
Rule of ThreeWait until you see the same idea three timesThen consider extracting it
AHAAvoid Hasty AbstractionsDo not rush to share code; wait until the pattern is clear

The Rule of Three is the easiest to follow. The first time you write something, just write it. The second time you repeat it, sigh but allow it. The third time, stop and ask: "Is this truly one idea? If yes, now I extract it." By the third appearance, you can see the real shape of the pattern, so your abstraction fits well.

AHA (Avoid Hasty Abstractions) by Kent C. Dodds says the same thing in a gentle way: a little duplication is cheap, but a wrong shared piece is expensive. So wait. Let the code show you the right design before you commit.

The Rule of Three in action

First time
Second time
Third time
Extract

Steps

1

First time

Just write it

2

Second time

Allow the copy

3

Third time

Pattern is now clear

4

Extract

Make one shared home

A safe rhythm for deciding when to remove repetition.

A worked story in C#

Let us walk through a tiny order system to see good DRY thinking.

You start with one place that formats a customer's full name:

public string GetCustomerLabel(Customer c)
{
    return $"{c.FirstName} {c.LastName}".Trim();
}

Later you need to show a name for a supplier too:

public string GetSupplierLabel(Supplier s)
{
    return $"{s.FirstName} {s.LastName}".Trim();
}

Two copies. Should you merge them? Pause and ask the DRY question: is "how we show a customer name" the same knowledge as "how we show a supplier name"?

Right now, yes, they are the same idea: join first and last name. So this is real duplication of one rule. Extract it:

public static class NameFormatter
{
    public static string FullName(string first, string last)
        => $"{first} {last}".Trim();
}

But suppose instead that suppliers must always show in uppercase with a company tag, while customers stay normal. Then the two were never the same knowledge. In that case you keep them apart, even though the early code looked identical. The decision is not about how the text looks. It is about what the rule means and how it will change.

The single question that guides every DRY decision.

DRY beyond code

One more thing students miss: DRY is not only about code. It is about knowledge anywhere in your project. A few examples:

  • A database column name and a constant in code that must match. That is one fact in two places.
  • A list of valid order states written in the code and again in a document. If they drift, confusion follows.
  • A configuration value hard-coded in three services. One fact, three homes, future bugs.

The same rule applies. If it is truly one piece of knowledge, give it one source of truth. If two things merely look alike, let them be.

Common mistakes to avoid

  • Merging on looks alone. Never share code just because the characters match. Ask what it means first.
  • Abstracting too early. On the first or second copy, wait. Use the Rule of Three.
  • Fearing all duplication. A small, honest copy is often safer than a tangled shared method.
  • Never cleaning up real duplication. The opposite mistake. If one true fact lives in five files, fix it. DRY still matters when the knowledge is genuinely the same.

Balance is the goal. DRY is a tool, not a law you obey blindly.

Quick recap

  • DRY means Don't Repeat Yourself, but the real target is knowledge, not lines of code.
  • The full rule: every piece of knowledge should have one clear home in your system.
  • Similar is not the same. Two pieces of code can look identical and still mean different things.
  • Real duplication (same fact in many places) should be removed. Accidental duplication (looks alike, means differently) should be left alone.
  • The wrong abstraction is worse than duplication. Merging unrelated code leads to flags, if branches, and fear.
  • Use WET, the Rule of Three, and AHA to avoid rushing into a shared design.
  • When in doubt, ask one question: Is this the same piece of knowledge? That answer guides everything.

References and further reading

Related Posts