refactor(topics): 멀티 에이전트용 지식 재편 — _Common(공통 기본기) + Domain_* 구조

에이전트 8종(대화형/프로그래머 C·S/디자이너/설계자/기획자/QA/PD/PM)에게
[공통 기본 능력 + 롤별 Specialty] 2층으로 지식을 주입하기 위한 재분류.
문서 내용·포맷은 무수정, 폴더 이동만 (6,372개 문서 수 보존 확인).

- Topic_Programming → Domain_Programming (내부 구조 보존)
- Topic_Graphic → Domain_Design
- Topic_Business → Domain_Product
- Topic_General → Domain_General
- _Common 신설: Math(구 Topic_Math_Specialty), Reasoning(구 General/From_Thinking & Reasoning),
  Reasoning_Creativity(구 General/From_창의성), Communication(Poetic_Blog_Writing + From_writing)
- 타 도메인의 From_* 폴더는 유지 (출처 표기일 뿐, 이미 도메인에 맞게 분류된 문서)
- 빈 폴더 정리 (memory/procedures)
- 에이전트→폴더 매핑은 workspace의 .astra/agent-knowledge-map.json (9개 에이전트)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Antigravity Agent
2026-07-11 11:05:56 +09:00
parent 6549ead309
commit c24165b8bc
6193 changed files with 1717 additions and 31 deletions
@@ -0,0 +1,150 @@
---
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 |