extract on the third repeat, not the first

DRY -- Don't Repeat Yourself

DRY says every piece of knowledge has one authoritative home. The rule of three tempers it: don't abstract until the third occurrence, or you'll build the wrong abstraction and couple things that should move apart.

Two copies is a coincidence; three is a pattern that has earned a name.

01in the wild

In the wild

The Rule of Three

When to extract: the first copy is fine, the second is a coincidence, the third confirms a pattern.

example.py
# 1st time: just write it.
price_a = qty_a * unit_a * (1 - discount_a)
# 2nd time: a coincidence -- resist abstracting yet.
price_b = qty_b * unit_b * (1 - discount_b)
# 3rd time: NOW extract -- the pattern is proven.
def line_total(qty, unit, discount):
    return qty * unit * (1 - discount)
Two occurrences may be coincidence; the third confirms a real pattern. Extracting too early guesses the wrong shape.
// observed
early: an abstraction that fights the 3rd case
three: extract once the pattern is proven

Knowledge, Not Code

Two snippets that look identical can encode different decisions. DRY-ing them couples the unrelated.

example.js
// These LOOK identical, but encode two different policies:
const taxRate = (amt) => amt * 0.0825;   // sales tax (law)
const tipRate = (amt) => amt * 0.0825;   // suggested tip (today)

// WRONG-DRY: merge them and they change together by accident
const rate = (amt) => amt * 0.0825;      // now tip can never differ from tax

// RIGHT: same value, different KNOWLEDGE -- keep them apart
const SALES_TAX = 0.0825, DEFAULT_TIP = 0.0825;
DRY is about single sources of knowledge, not identical text. Merging coincidentally-equal code couples decisions that should evolve independently.
// observed
merged:   changing tip silently changes tax
separate: each rate evolves on its own

Single Source of Truth

Knowledge with one home cannot disagree with itself; copies eventually do.

example.go
// SMELL: the same rule compiled in three files, subtly drifted
var reA = regexp.MustCompile(`^\d{3}-\d{4}$`)
var reB = regexp.MustCompile(`^\d{3}-\d{3}$`)  // typo, drifted

// RIGHT: one exported pattern, defined once
var PhoneRE = regexp.MustCompile(`^\d{3}-\d{4}$`)
A rule with a single definition cannot contradict itself. The drifted copy is a bug the original never had.
// observed
copies: two patterns, one concept
shared: PhoneRE, defined once
02weakness catalog

Mapped weaknesses (CWE)

On its own, this defect is catalogued by MITRE as one or more of these weaknesses. The exploitable vulnerability usually appears only when it chains or combines with another.