---
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, B> = T & { readonly __brand: B };
type Email   = Brand<string, "Email">;
type UserId  = Brand<number, "UserId">;

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 |
