DRY

Intro

DRY means one place should own a single piece of knowledge, so you do not have to change the same rule in multiple places.
It is not "never repeat code." It is "avoid duplicated business rules and duplicated decision logic."
You reach for DRY when duplication causes bugs, inconsistent behavior, or high change cost. In a payments codebase, the tax calculation formula was duplicated in the checkout API and the invoicing batch job — when tax rates changed, only the API was updated, causing a $43,000 discrepancy over two months before the invoicing path was discovered.

Deeper Explanation

DRY is about knowledge, not code. Two pieces of code that look identical but represent different business rules are NOT a DRY violation — they should stay separate because they will evolve independently. Two pieces of code that encode the same business rule ARE a DRY violation — when the rule changes, you must update both, and you will miss one.

The classic failure mode is accidental duplication: code that looks the same today but has different intent. Unifying it creates a shared abstraction that breaks when one side needs to change.

// Accidental duplication: looks the same, different intent
// User validation: name must be non-empty
bool IsValidUserName(string name) => !string.IsNullOrWhiteSpace(name);

// Product validation: name must be non-empty
bool IsValidProductName(string name) => !string.IsNullOrWhiteSpace(name);

// DO NOT unify these. User names and product names will diverge:
// User names: max 50 chars, no special characters
// Product names: max 200 chars, allow Unicode
// Unifying them creates a shared rule that doesn't fit either.
// Real DRY violation: the same business rule in two places
// Both endpoints validate email the same way for the same reason
// POST /users: if (!email.Contains('@')) return BadRequest();
// POST /invites: if (!email.Contains('@')) return BadRequest();

// Fix: centralize the rule
public static class EmailRules
{
    public static bool IsValid(string value) =>
        !string.IsNullOrWhiteSpace(value) && value.Contains('@');
}
// Now when the rule changes (add TLD check, use regex), one place to update.

Pitfalls

Tradeoffs

Questions


Whats next