"매 every piece of knowledge 의 single, unambiguous, authoritative representation". Hunt & Thomas (Pragmatic Programmer). 매 duplication = 매 update bug. 매 modern caveat: 매 AHA (Avoid Hasty Abstraction) — 매 too-early DRY 의 wrong abstraction. 매 rule: 매 3rd repetition 의 abstract.
매 핵심
매 origin
Hunt & Thomas, Pragmatic Programmer (1999).
매 "knowledge" 의 emphasize — 매 code line 의 X.
매 vs WET / AHA
WET: Write Everything Twice / We Enjoy Typing.
AHA: Avoid Hasty Abstraction (Sandi Metz).
Rule of 3: 매 3 repetition 의 abstract.
Quote: "Duplication is far cheaper than the wrong abstraction." — Sandi Metz.
매 type of duplication
Imposed: 매 environment 의 force.
Inadvertent: 매 unaware.
Impatient: 매 deadline.
Interdeveloper: 매 communication 의 X.
매 응용
Constants: 매 magic number 의 named.
Functions: 매 logic 의 extract.
Templates / generics: 매 type 의 abstract.
Schema: 매 single source.
Config: 매 env-specific override.
Doc: 매 generate from code.
매 modern context
Microservices: 매 service 의 own data → 매 controlled duplication.
CQRS: 매 read / write model 의 separate.
Type-driven: 매 schema 의 source.
Codegen: 매 OpenAPI → client / server.
LLM era: 매 context-aware 의 inline 의 fine (token cost).
💻 패턴
Extract function
# 매 ❌ duplicateddeforder_total(items):total=0foriinitems:total+=i.price*i.qtytax=total*0.08returntotal+taxdefcart_total(cart):total=0foriincart:total+=i.price*i.qtytax=total*0.08returntotal+tax# 매 ✅ DRYdefcalculate_total(items,tax_rate=0.08):subtotal=sum(i.price*i.qtyforiinitems)returnsubtotal*(1+tax_rate)
Single source of truth (schema)
// 매 Zod schema → 매 type + 매 validation
import{z}from'zod';constUserSchema=z.object({id: z.string(),email: z.string().email()});typeUser=z.infer<typeofUserSchema>;// 매 runtime validation + compile-time type
Config (env override)
constconfig={apiUrl: process.env.API_URL??'http://localhost:3000',timeout: Number(process.env.TIMEOUT??5000),};// 매 single config object, env-specific override
// 매 schema 의 ORM model 의 single source
@Entity()classUser{@PrimaryColumn()id: string;@Column({unique:true})email: string;}// 매 migration 의 generate from model
Template (Mustache / Liquid)
{{!-- email-template.hbs --}}Hi {{user.name}}, your order #{{order.id}} ships {{order.shipDate}}.
# 매 ❌ premature abstractionclassGenericResourceHandler:def__init__(self,kind,...18params...):...# 매 ✅ duplicate first, abstract laterdefhandle_user(req):...defhandle_post(req):...# 매 → 매 3rd similar handler 의 의 emerge 의 pattern 의 see → 매 then abstract
Detect duplication (PMD / jscpd)
# 매 jscpd
npx jscpd --threshold 5 --reporters html src/
# 매 reports clones >= 5 lines
Refactor — Pull Up Method
# 매 beforeclassDog:defname(self):returnself._nameclassCat:defname(self):returnself._name# 매 afterclassAnimal:defname(self):returnself._nameclassDog(Animal):passclassCat(Animal):pass
Pragmatic limit (microservices)
# 매 service AclassUserDTO_A:id:str;email:str# 매 service B (separate codebase)classUserDTO_B:id:str;email:str# 매 ✅ controlled duplication — 매 services 의 independent deploy# 매 ❌ shared library 의 coupling 의 anti-pattern
매 결정 기준
상황
DRY Rule
2nd occurrence
Wait
3rd occurrence
Extract
Cross-service
Controlled duplicate
Schema
Single source + codegen
Config
Env-override
Wrong abstraction
Inline first
기본값: 매 rule of 3 + 매 AHA (avoid hasty abstraction) + 매 wrong abstraction > duplication.