--- id: wiki-2026-0508-primitive-obsession-기본-타입-집착 title: Primitive Obsession (기본 타입 집착) category: 10_Wiki/Topics status: verified canonical_id: self aliases: [Primitive Obsession, 기본 타입 집착, stringly-typed] duplicate_of: none source_trust_level: A confidence_score: 0.9 verification_status: applied tags: [refactoring, code-smell, type-system, ddd] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: python-typescript-rust framework: refactoring --- # Primitive Obsession (기본 타입 집착) ## 매 한 줄 > **"매 string/int이 매 domain concept를 매 가장한다"**. Primitive Obsession은 매 `UserId`, `Email`, `Money` 같은 매 domain concept를 매 raw `str`/`int`로 매 표현해 매 type system이 매 invariant 보장 못 하는 매 code smell. Fowler "Refactoring" (1999, 2nd ed. 2018) 의 매 classic smell — 매 modern fix는 매 newtype / value object. ## 매 핵심 ### 매 증상 - **매 String 폭주**: 매 `email: str`, `phone: str`, `country_code: str` 매 swap 가능. - **매 Magic numbers**: 매 `status: int = 3` 매 의미 불명. - **매 Validation duplication**: 매 every callsite마다 매 `if "@" in email`. - **매 Type confusion**: 매 `transfer(from_id, to_id)` 매 인자 swap 매 컴파일러 못 잡음. ### 매 Fix 전략 - **매 Newtype**: Rust `struct UserId(u64);`. - **매 Value Object**: DDD 의 매 `Email`, `Money` immutable class. - **매 Branded type**: TypeScript `type UserId = string & { __brand: "UserId" }`. - **매 NewType pattern**: Python `typing.NewType("UserId", int)`. ### 매 응용 1. Domain modeling (DDD) — Bounded context의 매 first-class concept. 2. Money handling (currency + amount tied). 3. Identifier safety (UserId vs OrderId mix-up 방지). ## 💻 패턴 ### Python NewType + dataclass ```python from typing import NewType from dataclasses import dataclass from decimal import Decimal UserId = NewType("UserId", int) OrderId = NewType("OrderId", int) @dataclass(frozen=True) class Money: amount: Decimal currency: str def __post_init__(self): if self.amount < 0: raise ValueError("negative") if len(self.currency) != 3: raise ValueError("ISO-4217") def transfer(src: UserId, dst: UserId, m: Money): ... # transfer(OrderId(1), UserId(2), Money(...)) # 매 mypy error ``` ### Rust newtype ```rust #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct UserId(u64); #[derive(Debug, Clone, Copy)] pub struct OrderId(u64); fn fetch_user(id: UserId) { /* ... */ } // fetch_user(OrderId(7)); // 매 compile error ``` ### TypeScript branded types ```typescript type Brand = T & { readonly __brand: B }; type Email = Brand; type UserId = Brand; function parseEmail(s: string): Email { if (!/^[^@]+@[^@]+$/.test(s)) throw new Error("invalid"); return s as Email; } ``` ### Value object with invariant ```python @dataclass(frozen=True) class Email: value: str def __post_init__(self): if "@" not in self.value: raise ValueError("invalid email") object.__setattr__(self, "value", self.value.lower()) ``` ### Refactor: Replace Type Code with Subclass ```python # Before — magic int status class Order: status: int # 0=pending, 1=paid, 2=shipped # After — sealed states class OrderStatus: pass class Pending(OrderStatus): pass class Paid(OrderStatus): pass class Shipped(OrderStatus): tracking: str ``` ## 매 결정 기준 | 상황 | Approach | |---|---| | Domain identifier | Newtype | | Domain value (Money, Email) | Value Object | | 매 enum-like int code | Sealed subclass / Enum | | Throwaway script | 매 raw primitive OK | **기본값**: Newtype for IDs, Value Object for domain values. ## 🔗 Graph - 부모: [[Code-Smell]] · [[Refactoring_Best_Practices|Refactoring]] - 변형: [[Value-Object]] · [[Branded-Types]] - 응용: [[DDD]] · [[Type-Safety]] - Adjacent: [[Stringly-Typed]] ## 🤖 LLM 활용 **언제**: domain model 설계, 매 API boundary type 선택, 매 refactoring 제안. **언제 X**: 매 1-time script. ## ❌ 안티패턴 - **매 Stringly-typed everything**: 매 모든 domain concept를 매 str. - **매 Validation lazy**: 매 boundary 통과 후 매 raw str 그대로 흘림. - **매 Tuple as struct**: 매 `(int, str, bool)` 매 의미 모름. - **매 매 시점 validation**: 매 매번 caller가 매 validate 수행. ## 🧪 검증 / 중복 - Verified (Fowler "Refactoring" 2nd ed. 2018, Evans "DDD" 2003). - 신뢰도 A. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — newtype/value-object patterns + refactoring guide |