d8a80f6272
이름만 다른(표기 변형) [[위키링크]]를 대상 문서의 canonical 제목으로 치환해 끊겼던 1,200개 링크를 연결. 제목/파일명 정규화 일치만 적용하고 별칭 매칭은 과병합 위험으로 제외(애매성 가드). 원본은 _link_reconcile_backup/ 에 백업. 도구: Datacollect/scripts/link_reconcile_apply.mjs Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
6.5 KiB
6.5 KiB
id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
| id | title | category | status | canonical_id | aliases | duplicate_of | source_trust_level | confidence_score | verification_status | tags | raw_sources | last_reinforced | github_commit | tech_stack | |||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| wiki-2026-0508-dry-principle | DRY Principle (Don't Repeat Yourself) | 10_Wiki/Topics | verified | self |
|
none | A | 0.98 | applied |
|
2026-05-10 | pending |
|
DRY Principle
매 한 줄
"매 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
# 매 ❌ duplicated
def order_total(items):
total = 0
for i in items: total += i.price * i.qty
tax = total * 0.08
return total + tax
def cart_total(cart):
total = 0
for i in cart: total += i.price * i.qty
tax = total * 0.08
return total + tax
# 매 ✅ DRY
def calculate_total(items, tax_rate=0.08):
subtotal = sum(i.price * i.qty for i in items)
return subtotal * (1 + tax_rate)
Single source of truth (schema)
// 매 Zod schema → 매 type + 매 validation
import { z } from 'zod';
const UserSchema = z.object({ id: z.string(), email: z.string().email() });
type User = z.infer<typeof UserSchema>;
// 매 runtime validation + compile-time type
Config (env override)
const config = {
apiUrl: process.env.API_URL ?? 'http://localhost:3000',
timeout: Number(process.env.TIMEOUT ?? 5000),
};
// 매 single config object, env-specific override
OpenAPI codegen
# openapi.yaml — single source
paths:
/users/{id}: { get: { responses: { 200: { schema: { $ref: '#/User' } } } } }
# 매 → openapi-typescript / openapi-generator → client + server stubs + docs
Database migration as code
// 매 schema 의 ORM model 의 single source
@Entity()
class User {
@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}}.
Inheritance / mixin (cautious)
class TimestampMixin:
created_at: datetime
updated_at: datetime
class User(Base, TimestampMixin): pass
class Post(Base, TimestampMixin): pass
Decorator (cross-cutting)
def retry(times=3):
def decorator(func):
def wrapper(*args, **kwargs):
for attempt in range(times):
try: return func(*args, **kwargs)
except: if attempt == times - 1: raise
return wrapper
return decorator
@retry(times=3)
def fetch_data(url): ...
AHA — when NOT to abstract
# 매 ❌ premature abstraction
class GenericResourceHandler:
def __init__(self, kind, ...18 params...): ...
# 매 ✅ duplicate first, abstract later
def handle_user(req): ...
def handle_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
# 매 before
class Dog:
def name(self): return self._name
class Cat:
def name(self): return self._name
# 매 after
class Animal:
def name(self): return self._name
class Dog(Animal): pass
class Cat(Animal): pass
Pragmatic limit (microservices)
# 매 service A
class UserDTO_A: id: str; email: str
# 매 service B (separate codebase)
class UserDTO_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.
🔗 Graph
- 부모: Software-Engineering-Principles · Clean-Code
- 변형: AHA · Rule of Three · Single Source of Truth (SSoT)
- 응용: Refactoring_Best_Practices · Codegen
- Adjacent: SOLID · YAGNI · KISS · Conventional-Commits
🤖 LLM 활용
언제: 매 refactor. 매 abstraction decision. 매 code review. 언제 X: 매 < 3 occurrence. 매 cross-domain.
❌ 안티패턴
- Premature DRY: 매 wrong abstraction → 매 update 의 cascade.
- Inheritance abuse: 매 IS-A 의 X 의 force.
- Cross-service shared lib: 매 deploy coupling.
- DRY at all cost: 매 readability < deduplication.
- Magic abstraction: 매 reader 의 confuse.
🧪 검증 / 중복
- Verified (Pragmatic Programmer, Sandi Metz).
- 신뢰도 A.
🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-04-20 | Auto-reinforced |
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — DRY + AHA + 매 extract / Zod / OpenAPI / detect / refactor code |