2.2.1 · D4Design Principles

Exercises — DRY — Don't Repeat Yourself

2,455 words11 min readBack to topic

Level 1 — Recognition

Goal: can you spot whether a piece of text is a real DRY violation or a look-alike?

L1.1

Recall Solution (L1.1)

Here the same fact ("the tax rate is 18%") is written in places.

  • WHAT / WHY: we plug into the cost model because we want the concrete pain of this specific duplication. So there is a , i.e. 27.1%, chance you leave one copy wrong. This is a real DRY violation — one fact, three homes.

L1.2

Recall Solution (L1.2)

(B) is the violation. The email-validation rule is one piece of knowledge; if the rule changes (e.g. allow + addressing), you must edit both copies. (A) is not a violation — the two 25s answer different questions and would change for different reasons. Merging them into one constant would couple unrelated decisions. See The Wrong Abstraction.


Level 2 — Application

Goal: perform the extraction and count the savings.

L2.1

Recall Solution (L2.1)

Before (): After (): We cut edit time from 15 → 3 min and raised the "no bug" chance from 44.37% → 85%. This is exactly the Single Source of Truth payoff.

L2.2

Recall Solution (L2.2)

WHAT: extract the fact (0.18) into a constant and the logic (price + price*rate) into a function. WHY: so a tax change touches exactly one place.

TAX_RATE = 0.18                 # the FACT, one home
def with_tax(price):            # the LOGIC, one home
    return price + price * TAX_RATE
 
total_a = with_tax(price_a)
total_b = with_tax(price_b)
total_c = with_tax(price_c)

The "add tax" rule now has . Changing the rate is a one-line edit.


Level 3 — Analysis

Goal: reason about trade-offs where DRY fights another principle.

L3.1

Recall Solution (L3.1)

Do not extract yet. By the Rule of Three, we wait until the third occurrence before abstracting, because two examples cannot reveal the true axis of variation. A function with 4 boolean flags is a classic Premature Abstraction: every call site must now pass build_report(True, False, True, False) — unreadable, and each flag adds a branch. The duplicated 12 lines are honest and local; the flagged abstraction hides the differences behind parameters. Verdict: tolerate the duplication now. If a third report appears and the same pattern holds, extract then — the real shape will be visible.

L3.2

Recall Solution (L3.2)

Extra cost of the duplication per change: min. Extra cost of the wrong abstraction per change: min. The wrong abstraction is more expensive (). This is why Sandi Metz says “duplication is far cheaper than the wrong abstraction.” The correct move when you find a wrong abstraction is to inline it back (re-duplicate), then re-extract along the right seam.


Level 4 — Synthesis

Goal: design a solution combining DRY with sibling principles.

L4.1

Recall Solution (L4.1)

Step 1 — separate reasons to change (SRP). Email validation and country-code storage change for different reasons, so they belong in different homes — the Single Responsibility Principle tells us not to merge them just because they sit in the same class. Step 2 — one home each (DRY).

  • Email rule → a single validate_email() used by both frontend and backend.
  • Country codes → a Single Source of Truth: one config/table both layers read.

Step 3 — avoid over-DRY. Do not fuse the validator and the country list into one "validation module" god-object; they are unrelated (The Wrong Abstraction risk). Result: two independent single-source homes, each referenced everywhere. Both n values drop to 1.

L4.2

Recall Solution (L4.2)

Country list: before , after → saves 15 min. Email rule: before , after → saves 10 min. Total saved per change-pair = minutes, and the consistency risk on both drops to the single-copy best case.


Level 5 — Mastery

Goal: derive and defend a general threshold — the deepest reasoning.

L5.1

Recall Solution (L5.1)

WHAT / WHY: we compare "pay once" against "pay the duplication penalty every change," because whether to DRY depends on how often the code will change — a purely rational, YAGNI-aware criterion.

Extracting is worth it when the saved penalty over changes exceeds the one-time cost: Plugging in , , : So if you expect more than 3 future changes, extract; fewer, and the duplication is cheaper. Notice this lands right on the spirit of the Rule of Three — a beautiful coincidence that the arithmetic and the folk-rule agree.

L5.2

Recall Solution (L5.2)

WHAT / WHY: we invert the consistency formula because we want a budget — how much duplication a given reliability target allows. Require , i.e. . Take logs (log is the tool that turns an exponent into a multiplier we can solve for): Since must be a whole number, the largest allowed is . At : , which fails. So under a 90% reliability bar and a 5% slip, you may keep at most 2 copies — again echoing "two is tolerable, three, extract."

Figure — DRY — Don't Repeat Yourself

Active Recall

Recall Cost to edit a fact in

places at each? — linear in the number of copies.

Recall Break-even number of future changes to justify extraction, cost

, penalty ? .

Recall With

, how many copies keep consistency at or above 90%? At most 2, since .



Connections

  • DRY — Don't Repeat Yourself — the parent principle these exercises drill.
  • Rule of Three — the L3/L5 delay heuristic, confirmed by the break-even arithmetic.
  • The Wrong Abstraction / Premature Abstraction — the L3 trap.
  • Single Source of Truth — the L2/L4 data-DRY target.
  • Single Responsibility Principle — split by reason to change before DRYing (L4).
  • Refactoring — Extract Method — the L2 mechanical tool.
  • KISS Principle & YAGNI — bound DRY against over-engineering (L3/L5).
  • WET — Write Everything Twice — the anti-pattern being removed.