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,136 @@
---
id: wiki-2026-0508-2026년-3월-연구-드롭-march-2026-resear
title: 2026년 3월 연구 드롭 (March 2026 Research Drop)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [March 2026 Research Drop, 2026-03 Drop, Spring 2026 Releases]
duplicate_of: none
source_trust_level: B
confidence_score: 0.85
verification_status: applied
tags: [research, llm, releases, 2026, frontier-models]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: en
framework: research
---
# 2026년 3월 연구 드롭 (March 2026 Research Drop)
## 매 한 줄
> **"2026-03 한 달간의 frontier AI / systems research releases 의 묶음 timeline."** 매 Anthropic Claude Opus 4.7 1M context, 매 OpenAI GPT-5 family minor refresh, 매 DeepSeek-V4, 매 Llama 3.5, 매 Mistral Large 3, 매 vLLM 0.10, 매 MLX 0.30, 매 NVIDIA Blackwell-Ultra B300 GA — 매 single month 의 cluster 이벤트. 매 이 문서는 매 architecture / infra perspective 에서의 entry point.
## 매 핵심
### 매 model releases (March 2026)
- **Claude Opus 4.7**: 매 200K → 1M context (beta), 매 extended thinking budget tuning, 매 native interleaved tool calls.
- **GPT-5.1**: 매 reasoning model — 매 cheaper $/Mtok, 매 deterministic mode 추가.
- **DeepSeek-V4 (671B MoE)**: 매 open-weights, 매 MIT license, 매 vLLM Day-0 지원.
- **Llama 3.5 405B / 70B**: 매 Meta 의 incremental, 매 long-context 8M (research preview).
- **Mistral Large 3**: 매 EU sovereign deploy 강화, 매 Codestral 25 동반.
### 매 systems / infra
- **vLLM 0.10**: 매 PagedAttention v3, 매 disaggregated prefill/decode, 매 H200/B300 FP8.
- **MLX 0.30** (Apple Silicon): 매 unified memory 의 KV cache offload, 매 Llama 3.5 405B Q4 on M5 Ultra.
- **CUDA 13 + Blackwell-Ultra (B300)**: 매 FP4 native, 매 1.5×B300 perf vs B200.
- **TensorRT-LLM 0.20**: 매 speculative decoding native, 매 EAGLE-3 default.
### 매 응용
1. 매 long-context retrieval (1M+) 의 production 도입.
2. 매 on-prem MoE serving (DeepSeek-V4) 의 cost benchmark.
3. 매 Apple Silicon edge 의 frontier model.
## 💻 패턴
### 1) Claude Opus 4.7 with 1M context
```python
from anthropic import Anthropic
client = Anthropic()
resp = client.messages.create(
model="claude-opus-4-7",
extra_headers={"anthropic-beta": "context-1m-2025-08-07"},
max_tokens=8192,
messages=[{"role":"user","content": huge_corpus}]
)
```
### 2) Prompt caching (1M era 필수)
```python
client.messages.create(
model="claude-opus-4-7",
system=[{
"type":"text","text": codebase_dump,
"cache_control":{"type":"ephemeral"} # 매 5min TTL
}],
messages=[{"role":"user","content":"diff X vs Y"}]
)
```
### 3) vLLM 0.10 disaggregated serving
```bash
# 매 prefill node
vllm serve deepseek-ai/DeepSeek-V4 --role prefill --port 8001
# 매 decode node
vllm serve deepseek-ai/DeepSeek-V4 --role decode --port 8002 \
--kv-transfer-config '{"connector":"NIXL"}'
```
### 4) MLX 0.30 on M5 Ultra
```python
import mlx.core as mx
from mlx_lm import load, generate
model, tok = load("mlx-community/Llama-3.5-405B-4bit")
print(generate(model, tok, "What is...", max_tokens=512))
```
### 5) Speculative decoding (TRT-LLM 0.20 EAGLE-3)
```python
# 매 1.8-2.3× throughput on Blackwell
build_config = {
"speculative_decoding_mode": "eagle3",
"max_draft_len": 5
}
```
### 6) GPT-5.1 deterministic mode
```python
from openai import OpenAI
oa = OpenAI()
oa.responses.create(model="gpt-5.1", input="...", seed=42, temperature=0)
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 매 1M+ context 가 핵심 | Claude Opus 4.7 1M |
| 매 reasoning + 매 cheap | GPT-5.1 / DeepSeek-V4 |
| 매 self-host / EU sovereign | Mistral Large 3 / Llama 3.5 |
| 매 open MoE | DeepSeek-V4 + vLLM 0.10 |
| 매 Apple edge | MLX 0.30 |
**기본값**: 매 production agent → Claude Opus 4.7, 매 self-host → DeepSeek-V4 / Llama 3.5, 매 edge → MLX.
## 🔗 Graph
- Adjacent: [[LLM_Optimization_and_Deployment_Strategies|vLLM]]
## 🤖 LLM 활용
**언제**: 매 architecture decision 의 timeline reference, 매 "what changed in 2026-03" 매 quick lookup.
**언제 X**: 매 superseded 된 detail (매 매 quarter 마다 stale 가능).
## ❌ 안티패턴
- **Treat as exhaustive**: 매 일부 release 만 캡처. 매 official changelog 를 매 source of truth 로.
- **Stale benchmarks**: 매 vLLM 0.10 의 perf 는 매 0.11 에서 변경 가능.
- **Mix research preview vs GA**: 매 Llama 8M context 는 preview, 매 production 가정 X.
## 🧪 검증 / 중복
- Verified (Anthropic news 2026-03, OpenAI blog 2026-03, DeepSeek HuggingFace 2026-03, vLLM v0.10 release notes).
- 신뢰도 B (매 timeline 의 entry — 매 detail 은 individual page 에서).
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — March 2026 release roundup (models + infra) |
@@ -0,0 +1,127 @@
---
id: wiki-2026-0508-3의-법칙-rule-of-three
title: 3의 법칙 (Rule of Three)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Rule of Three, WET, Three Strikes Refactor]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [refactoring, dry, code-smell, abstraction]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: python
framework: general
---
# 3의 법칙 (Rule of Three)
## 매 한 줄
> **"매 두 번까지는 복사, 세 번째 등장하면 추출."** Don Roberts 가 *Refactoring* (Fowler, 1999) 에 정식화한 휴리스틱. 매 premature abstraction 을 피하면서 매 진짜 duplication 만 제거하는 trade-off rule. 2026 LLM 기반 codegen 시대에도 매 the cheapest signal — 매 abstraction 의 timing 을 결정.
## 매 핵심
### 매 왜 "3"인가
- **2회는 coincidence**: 매 same-shape 의 코드 두 개는 매 future 에 diverge 할 가능성이 높음. 매 abstraction 으로 묶으면 매 wrong abstraction lock-in.
- **3회는 pattern**: 매 third occurrence 에서 매 invariant 가 무엇인지 보임. 매 axis of variation 이 명확해짐.
- **AHA principle**: "Avoid Hasty Abstractions" (Sandi Metz). 매 duplication is far cheaper than the wrong abstraction.
### 매 vs DRY
- DRY: "Every piece of knowledge must have a single, authoritative representation" — 매 *knowledge* 에 대한 rule.
- Rule of 3: 매 *code shape* 에 대한 rule.
- 매 두 코드가 same-shape 이지만 different-knowledge 일 수 있음 → 매 DRY 가 적용되지 않음.
### 매 응용
1. Helper function 추출 timing 결정.
2. Component / Module 추출 timing 결정.
3. Configuration parameter 도입 timing 결정.
## 💻 패턴
### 1) 2회까지는 inline (resist abstraction)
```python
# Occurrence 1
user_email = data["user"]["email"].strip().lower()
# Occurrence 2 — DO NOT extract yet
admin_email = data["admin"]["email"].strip().lower()
```
### 2) 3회째에 추출 — invariant 가 분명해진 시점
```python
def normalize_email(raw: str) -> str:
return raw.strip().lower()
user_email = normalize_email(data["user"]["email"])
admin_email = normalize_email(data["admin"]["email"])
support_email = normalize_email(data["support"]["email"]) # ← trigger
```
### 3) 매 wrong-abstraction 의 anti-pattern
```python
# 2회만에 추출했다가 3회째가 다른 shape 으로 등장
def process_record(r, mode): # mode 가 점점 늘어남 — leaky abstraction
if mode == "user": ...
elif mode == "admin": ...
elif mode == "audit": ... # 완전히 다른 logic
```
### 4) 매 React component 의 Rule of 3
```tsx
// 2개 까지는 copy-paste
<Card title="A"><p>...</p></Card>
<Card title="B"><p>...</p></Card>
// 3번째 → extract <UserCard> abstraction
```
### 5) 매 LLM-assisted refactoring 의 trigger
```python
# Claude / Cursor 에게 "extract this duplication" 을 매 3회 occurrence 부터 요청.
# 2회 occurrence 에서는 "leave inline" 을 명시.
```
### 6) 매 test 에서의 예외
```python
# Test 코드는 Rule of 3 보다 readability 우선.
# 매 fixture 추출은 매 2회에도 OK (DAMP > DRY in tests).
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 매 same-shape 코드 2회 | Inline 유지 |
| 매 same-shape + same-knowledge 3회 | Extract |
| 매 same-shape + different-knowledge 3회 | Inline 유지 (DRY 위반 아님) |
| Test fixture | 2회에도 추출 OK |
| Cross-module duplication | 3회 + 매 stable interface 확인 후 |
**기본값**: 매 3회까지 wait, 매 4번째에 후회하지 않을 abstraction 만 추출.
## 🔗 Graph
- 부모: [[Refactoring_Best_Practices|Refactoring]] · [[DRY]]
- 변형: [[YAGNI]]
- 응용: [[Code Smell]]
## 🤖 LLM 활용
**언제**: 매 codegen 의 review 시 — "이거 2회만에 추출됐는데 3회 기다려야 하나?" 매 sanity check.
**언제 X**: 매 test 코드 / 매 boilerplate / 매 framework-required pattern 에는 적용 X.
## ❌ 안티패턴
- **Premature abstraction**: 매 1-2회 occurrence 에서 추출 → 매 wrong axis 로 lock-in.
- **Eternal copy-paste**: 매 5+ occurrence 인데도 추출 안 함 → 매 maintenance burden.
- **Mode-flag explosion**: 매 추출한 함수에 매 boolean / enum flag 가 계속 늘어남 → 매 wrong abstraction signal.
- **DRY-religious**: 매 "any duplication is sin" → 매 shape 만 같은 code 까지 강제 통합.
## 🧪 검증 / 중복
- Verified (Fowler *Refactoring* 2nd ed. 2018, Sandi Metz "The Wrong Abstraction" 2016).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Rule of 3 trade-off + AHA + LLM refactor trigger 정리 |
@@ -0,0 +1,172 @@
---
id: wiki-2026-0508-a2a
title: A2A (Agent-to-Agent Protocol)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Agent-to-Agent, A2A Protocol, Agent2Agent]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [agents, protocol, interop, anthropic, mcp]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: python
framework: anthropic-sdk
---
# A2A (Agent-to-Agent Protocol)
## 매 한 줄
> **"매 agent 가 다른 agent 와 모델/벤더 차이 없이 task 를 위임/협상/결과 교환 하기 위한 open protocol."** Google 이 2025 봄 announce, 2025-06 Linux Foundation 으로 stewardship 이전, 2026 현재 Anthropic / Microsoft / Salesforce 등 50+ 기업 adoption. 매 MCP (tool/data) 와 directly complementary — 매 A2A 는 *agent ↔ agent*, MCP 는 *agent ↔ tool*.
## 매 핵심
### 매 5 design principles
- **Agentic by default**: 매 agent autonomy 를 가정 (매 mere RPC 가 아님).
- **Modality-agnostic**: 매 text / audio / video / structured data 모두 transport.
- **Built on web standards**: HTTP + JSON-RPC 2.0 + SSE / WebSocket — 매 separate runtime 불필요.
- **Secure by design**: OAuth 2.1, 매 mTLS, 매 capability scoping.
- **Long-running task aware**: 매 minutes ~ days 의 async task — 매 polling + push-notification 모두 지원.
### 매 핵심 primitives
- **AgentCard** (`/.well-known/agent.json`): 매 agent 의 capability advertisement.
- **Task**: 매 unit of work — `submitted → working → input-required → completed/failed/canceled`.
- **Message + Artifact**: 매 conversation chunk + 매 final output.
- **Streaming**: SSE 로 매 partial token / 매 status update 전송.
### 매 응용
1. Cross-vendor agent orchestration (Claude → Gemini → in-house).
2. Specialist agent dispatch (legal, finance, code-review).
3. Marketplace 의 agent invocation.
## 💻 패턴
### 1) AgentCard 발행
```json
{
"name": "claude-research-agent",
"version": "1.2.0",
"url": "https://api.example.com/a2a",
"capabilities": {
"streaming": true,
"pushNotifications": true,
"stateTransitionHistory": true
},
"skills": [
{"id": "deep-research", "description": "Multi-source web research", "inputModes": ["text"], "outputModes": ["text", "file"]}
],
"auth": {"type": "oauth2.1", "scopes": ["task:submit"]}
}
```
### 2) Task 제출 (client agent)
```python
import httpx, uuid
resp = httpx.post(
"https://api.example.com/a2a/tasks/send",
json={
"jsonrpc": "2.0", "id": "1", "method": "tasks/send",
"params": {
"id": str(uuid.uuid4()),
"message": {
"role": "user",
"parts": [{"type": "text", "text": "Summarize Q4 earnings of NVDA."}]
}
}
},
headers={"Authorization": f"Bearer {token}"}
)
task = resp.json()["result"]
```
### 3) SSE streaming 으로 partial result 수신
```python
with httpx.stream("POST", url + "/tasks/sendSubscribe", json=req) as s:
for line in s.iter_lines():
if line.startswith("data:"):
event = json.loads(line[5:])
if event["type"] == "status": ...
elif event["type"] == "artifact": print(event["artifact"]["parts"])
```
### 4) Push notification 등록 (long task)
```python
httpx.post(url + "/tasks/pushNotification/set", json={
"taskId": task["id"],
"pushNotificationConfig": {
"url": "https://my-app.com/a2a/webhook",
"token": webhook_secret
}
})
```
### 5) Server-side handler (FastAPI 예)
```python
from fastapi import FastAPI
app = FastAPI()
@app.post("/a2a/tasks/send")
async def send(req: dict):
task_id = req["params"]["id"]
# 매 background worker 에게 dispatch
await queue.put((task_id, req["params"]["message"]))
return {"jsonrpc":"2.0","id":req["id"],"result":{"id":task_id,"status":{"state":"submitted"}}}
```
### 6) Multi-agent orchestration (A2A + MCP combo)
```python
# Orchestrator agent: A2A 로 specialist 호출, MCP 로 tool 사용
research = await a2a_call("research-agent", query)
draft = await claude.messages.create( # MCP tools attached
model="claude-opus-4-7",
tools=mcp_tools,
messages=[{"role":"user","content": f"Draft based on: {research}"}]
)
```
### 7) Capability negotiation
```python
card = httpx.get(agent_url + "/.well-known/agent.json").json()
if not card["capabilities"]["streaming"]:
# 매 polling fallback
use_polling = True
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 매 agent ↔ tool / data | MCP |
| 매 agent ↔ agent (cross-vendor) | A2A |
| 매 same-process agent | Direct call (no protocol) |
| 매 long-running (>30s) | A2A + push notification |
| 매 strict typing 필요 | A2A + JSON Schema in skill spec |
**기본값**: 매 cross-org / cross-vendor agent collaboration 에 매 A2A, 매 internal tool wiring 은 매 MCP.
## 🔗 Graph
- Adjacent: [[OAuth 2.1]]
## 🤖 LLM 활용
**언제**: 매 multi-vendor agent stack 의 interop, 매 long-running specialist agent 의 호출.
**언제 X**: 매 single-process tool 호출 (매 MCP 를 사용), 매 latency-critical (<50ms) 의 inner loop.
## ❌ 안티패턴
- **A2A 로 tool 호출**: 매 MCP scope. 매 protocol 혼동.
- **No AgentCard**: 매 capability 알려주지 않으면 매 client 가 fallback 못함.
- **Sync polling on long task**: 매 push notification 또는 SSE 필수.
- **Token leakage**: 매 webhook URL 의 token 검증 누락.
## 🧪 검증 / 중복
- Verified (a2aproject.org spec v0.3, Linux Foundation A2A Project 2025-06-23, Anthropic A2A blog 2025).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — A2A protocol primitives + MCP comparison + 7 working patterns |
@@ -0,0 +1,144 @@
---
id: wiki-2026-0508-acid-transactions
title: ACID Transactions
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [ACID, Database Transactions, Atomicity Consistency Isolation Durability]
duplicate_of: none
source_trust_level: A
confidence_score: 0.95
verification_status: applied
tags: [database, transactions, consistency, postgres]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: sql
framework: postgres-17
---
# ACID Transactions
## 매 한 줄
> **"Atomicity / Consistency / Isolation / Durability — 매 transaction 의 four guarantees."** Härder & Reuter (1983) 가 정식화한 properties. 매 RDBMS (Postgres, Oracle, MySQL InnoDB) 의 default 보장이며, 2026 distributed era 에도 매 NewSQL (CockroachDB, Spanner, TiDB, Neon) 가 매 ACID across nodes 를 표방. 매 단일 transaction 이 매 multi-statement 의 all-or-nothing + isolated + persisted 를 보장.
## 매 핵심
### 매 4 properties
- **Atomicity**: 매 all statements commit or all rollback. 매 partial state 없음.
- **Consistency**: 매 transaction 종료 시 매 모든 invariant (FK, check, unique) 가 valid.
- **Isolation**: 매 concurrent transactions 가 매 serially executed 처럼 보임. 매 isolation level 로 trade-off.
- **Durability**: 매 commit 후 매 crash / power loss 에도 매 data 가 살아남음 (WAL → fsync).
### 매 Isolation levels (SQL standard + Postgres)
- **Read Uncommitted**: 매 dirty read 허용 (Postgres 는 사실상 RC 로 mapping).
- **Read Committed** (Postgres default): 매 dirty read X, 매 non-repeatable read O.
- **Repeatable Read** (Postgres = snapshot isolation): 매 phantom read 거의 없음, 매 serialization anomaly O.
- **Serializable** (Postgres = SSI): 매 strictest, 매 overhead 큼.
### 매 응용
1. 매 financial / inventory 의 multi-row update.
2. 매 idempotent worker — 매 transaction + unique key.
3. 매 saga compensation 의 단위.
## 💻 패턴
### 1) Postgres BEGIN/COMMIT
```sql
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT; -- 매 atomic + durable
```
### 2) SAVEPOINT 로 partial rollback
```sql
BEGIN;
INSERT INTO orders(id, total) VALUES (1, 50);
SAVEPOINT before_items;
INSERT INTO items(order_id, sku) VALUES (1, 'BAD-SKU'); -- FK 위반
ROLLBACK TO SAVEPOINT before_items;
INSERT INTO items(order_id, sku) VALUES (1, 'OK');
COMMIT;
```
### 3) Isolation level 명시 (Python + asyncpg)
```python
async with conn.transaction(isolation="serializable"):
row = await conn.fetchrow("SELECT balance FROM accounts WHERE id=$1", 1)
await conn.execute("UPDATE accounts SET balance=$1 WHERE id=$2", row["balance"]-100, 1)
# 매 SSI — 매 serialization_failure 시 retry 필요
```
### 4) Optimistic concurrency (version column)
```sql
UPDATE doc SET body = $1, version = version + 1
WHERE id = $2 AND version = $3;
-- 매 affected_rows = 0 → conflict, 매 retry / 사용자 alert
```
### 5) SELECT FOR UPDATE (pessimistic lock)
```sql
BEGIN;
SELECT * FROM accounts WHERE id = 1 FOR UPDATE; -- 매 row lock
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT;
```
### 6) Outbox pattern (transaction + async publish)
```sql
BEGIN;
INSERT INTO orders(id, ...) VALUES (...);
INSERT INTO outbox(event_type, payload) VALUES ('OrderCreated', $1);
COMMIT;
-- 매 separate worker 가 outbox 를 읽고 매 broker 로 publish
```
### 7) Retry on serialization failure (Python)
```python
from psycopg.errors import SerializationFailure
for _ in range(5):
try:
with conn.transaction(): do_work()
break
except SerializationFailure:
time.sleep(random.uniform(0, 0.05))
```
## 매 결정 기준
| 상황 | Isolation level |
|---|---|
| 매 read-heavy dashboard | Read Committed |
| 매 report 의 consistent snapshot | Repeatable Read |
| 매 money / counter / unique reservation | Serializable |
| 매 high-conflict hot row | Pessimistic FOR UPDATE |
| 매 low-conflict OLTP | Optimistic version |
**기본값**: Postgres Read Committed + 매 critical path 만 매 Serializable / FOR UPDATE.
## 🔗 Graph
- 변형: [[BASE]] · [[Snapshot Isolation]]
- 응용: [[Idempotency]]
- Adjacent: [[CAP Theorem & PACELC]]
## 🤖 LLM 활용
**언제**: 매 codegen 의 SQL transaction boundary 검증, 매 isolation level mismatch 점검.
**언제 X**: 매 eventually-consistent NoSQL (DynamoDB single-region) — 매 BASE 모델로 reasoning.
## ❌ 안티패턴
- **App-side "transaction"**: 매 read-modify-write 가 매 BEGIN/COMMIT 밖. 매 race condition.
- **Long transaction**: 매 minutes 단위 hold → 매 lock contention + bloat.
- **Wrong isolation**: 매 default RC 에서 매 lost update 발생, 매 detect 못 함.
- **Ignoring serialization failure**: 매 SSI 에서 매 retry 안 함 → 매 user-facing error.
- **Transaction across services**: 매 distributed XA 시도 → 매 saga 로 대체.
## 🧪 검증 / 중복
- Verified (Postgres 17 docs, Härder & Reuter 1983, Bailis "Highly Available Transactions" 2014).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — ACID + Postgres isolation levels + 7 patterns |
@@ -0,0 +1,184 @@
---
id: wiki-2026-0508-adr-architecture-decision-record
title: ADR (Architecture Decision Records)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [ADR, Architecture Decision Record, Decision Log, Lightweight ADR]
duplicate_of: none
source_trust_level: A
confidence_score: 0.95
verification_status: applied
tags: [architecture, documentation, decisions, governance]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: markdown
framework: madr
---
# ADR (Architecture Decision Records)
## 매 한 줄
> **"매 architecturally significant decision 을 매 immutable, dated, numbered markdown 파일로 기록하는 lightweight practice."** Michael Nygard 의 2011 blog post 가 origin, 매 이후 MADR / Y-statement 등 variants 가 표준화. 2026 현재 매 GitOps + LLM agent 시대에 매 ADR 은 매 single source of truth — 매 *왜 이 design 인가* 의 history 를 매 codebase 안에 매 living document 로 유지.
## 매 핵심
### 매 5 essential fields (Nygard original)
- **Title**: 매 short, declarative — `0007: Use Postgres for OLTP`.
- **Status**: `proposed | accepted | deprecated | superseded by NNNN`.
- **Context**: 매 forces — 매 problem, 매 constraint, 매 stakeholder.
- **Decision**: 매 actually chosen approach (one paragraph).
- **Consequences**: 매 positive + negative + neutral. 매 honest trade-offs.
### 매 MADR (Markdown ADR) extras
- Decision drivers, considered options, pros/cons of each.
- 매 numbered (`adr/0001-record-architecture-decisions.md`).
- 매 PR 에 포함 — 매 code change 와 매 same review.
### 매 응용
1. 매 framework / DB / cloud provider 선택.
2. 매 API style (REST vs gRPC vs GraphQL).
3. 매 auth, observability, deploy strategy.
4. 매 LLM model / provider 선택.
## 💻 패턴
### 1) Nygard ADR template
```markdown
# 0007. Use Postgres for OLTP
Date: 2026-05-10
Status: Accepted
## Context
We need an OLTP store with strong ACID, JSON support, and managed offerings
across AWS/GCP/Azure. Team size 12. Expected QPS 5k.
## Decision
Adopt Postgres 17 (RDS / Aurora / Cloud SQL / Neon).
## Consequences
+ Mature ecosystem, ACID, JSONB, pgvector.
- Vertical scaling ceiling — needs Citus / sharding past ~30TB.
~ Team will invest in `psql` / pgbouncer expertise.
```
### 2) MADR full template
```markdown
# Use Postgres for OLTP
* Status: Accepted
* Deciders: @alice, @bob, @carol
* Date: 2026-05-10
## Context and Problem Statement
...
## Decision Drivers
* ACID, managed offering, ecosystem
* Cost ceiling at 5k QPS
* Vector search (pgvector)
## Considered Options
* Postgres
* MySQL
* CockroachDB
* DynamoDB
## Decision Outcome
Chosen option: "Postgres", because it dominates on drivers (1) and (3),
and matches (2) within budget.
### Positive Consequences
* JSONB, pgvector, mature tooling
### Negative Consequences
* Sharding burden later
```
### 3) Y-statement (one-liner ADR)
```text
In the context of <use case>,
facing <concern>,
we decided for <option>
to achieve <quality>,
accepting <downside>.
```
### 4) adr-tools (CLI)
```bash
brew install adr-tools
adr init doc/adr
adr new "Use Postgres for OLTP"
adr new -s 7 "Use CockroachDB instead of Postgres" # 매 supersede
adr generate toc > doc/adr/README.md
```
### 5) GitHub PR-based workflow
```bash
git checkout -b adr/0007-postgres
$EDITOR doc/adr/0007-use-postgres-for-oltp.md
git commit -m "ADR-0007: Use Postgres for OLTP"
gh pr create --label adr --reviewer @platform-team
```
### 6) Status transitions
```markdown
# 0007. Use Postgres
Status: Superseded by [0019](0019-use-cockroachdb.md)
```
### 7) LLM-assisted drafting (2026)
```text
You are an ADR scribe. Given a Slack discussion transcript,
output a MADR-format ADR with:
- Decision drivers extracted from the discussion
- All options mentioned with pros/cons
- Status: Proposed
Do not invent options not discussed.
```
### 8) Linking from code
```ts
// See ADR-0007 for why Postgres + pgvector instead of pinecone
import { Pool } from 'pg';
```
## 매 결정 기준
| 상황 | ADR 작성 여부 |
|---|---|
| 매 reversible (1 file 내 결정) | 작성 X |
| 매 cross-team / cross-service impact | 작성 |
| 매 vendor / framework 선택 | 작성 |
| 매 reverse 시 매 1주 이상 cost | 작성 |
| 매 trivial styling | 작성 X (lint config 로) |
**기본값**: 매 "되돌리는 데 1주 이상 걸리면 ADR". 매 Nygard 5-field minimum, 매 큰 결정만 MADR.
## 🔗 Graph
- 부모: [[Architecture Documentation]]
- 응용: [[ATAM]] · [[RFC Process]] · [[C4 Model (Architecture Documentation)]]
- Adjacent: [[GitOps]]
## 🤖 LLM 활용
**언제**: 매 design discussion 의 transcript → ADR draft 자동 생성, 매 ADR audit (status 누락 등).
**언제 X**: 매 LLM 이 매 invent 한 driver/option 을 매 사실로 commit X. 매 human verifier 필요.
## ❌ 안티패턴
- **Wiki-only ADR**: 매 codebase 밖 → 매 stale. 매 repo 안에 두고 매 PR 로 review.
- **Mutable ADR**: 매 기존 ADR 을 edit. 매 새 ADR 로 supersede.
- **Decision-only**: 매 Context / Consequences 누락 → 매 6개월 후 매 누구도 이유 모름.
- **Too coarse**: 매 "Use Microservices" — 매 specific 으로 (어떤 service, 매 boundary 어떻게).
- **Too fine**: 매 매 PR 마다 ADR — 매 noise.
## 🧪 검증 / 중복
- Verified (Nygard 2011 blog, MADR spec adr.github.io, Thoughtworks Tech Radar).
- 신뢰도 A.
- 매 [[ADR_(Architecture_Decision_Records)|ADR_(Architecture_Decision_Record)]] 가 매 redirect 로 본 문서를 가리킴.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Nygard + MADR templates + adr-tools workflow |
@@ -0,0 +1,159 @@
---
id: wiki-2026-0508-ai-assisted-refactoring-ai-기반-리팩
title: AI-Assisted Refactoring (AI 기반 리팩토링)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [AI Refactoring, LLM Refactoring, Agent Refactoring]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [refactoring, ai, llm, claude-code, cursor, codemod]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: claude-code
---
# AI-Assisted Refactoring (AI 기반 리팩토링)
## 매 한 줄
> **"매 LLM agent 가 codebase-wide refactoring 을 매 propose / apply / verify 하는 workflow."** 2026 현재 매 Claude Code (Opus 4.7), Cursor (Composer), Aider, Continue, Codex CLI 등이 매 multi-file edit + test loop 를 자동화. 매 핵심은 매 *deterministic checks* (test, type, lint) 로 매 LLM 의 stochasticity 를 매 제어. 매 "AI 가 짜준다"가 아닌 매 "AI 가 propose, CI 가 verify".
## 매 핵심
### 매 effective workflow
- **Plan → Apply → Verify → Commit**: 매 매 step 마다 매 human 또는 매 automated gate.
- **Small diffs**: 매 100-300 lines / commit. 매 1000+ line PR 은 매 review 불가능.
- **Test as oracle**: 매 LLM 의 output 을 매 existing test suite 로 검증. 매 test 없으면 매 refactoring 시도 X.
- **Type-driven**: 매 TS / Python (mypy/pyright) / Rust 등 매 strict typing 이 매 hallucination 을 매 catch.
### 매 적합 task
- Rename / move (매 IDE refactor 와 비슷하나 매 cross-language).
- Library migration (매 Express → Fastify, 매 enzyme → RTL, 매 moment → date-fns).
- API surface 변경의 매 callsite 일괄 업데이트.
- Style 통일 (매 callback → async/await, 매 class → hooks).
- 매 dead code 제거.
### 매 부적합 task
- 매 architectural redesign — 매 human 의 design 결정 필요.
- 매 perf-critical hot path — 매 measurement 없이 매 LLM 의 "looks faster" 신뢰 X.
- 매 security-sensitive (auth, crypto) — 매 human review 필수.
### 매 응용
1. Legacy codebase 의 점진적 modernization.
2. Mass dependency upgrade.
3. Test coverage 가속.
## 💻 패턴
### 1) Claude Code 의 대규모 rename
```bash
claude
> Rename `getUserData` to `fetchUserProfile` across the repo.
> Update all callsites, tests, and JSDoc.
> Run `npm test` after.
```
### 2) Plan-first prompt (Opus 4.7)
```text
Before editing, output a numbered PLAN of files & changes.
Wait for "approved" before applying any edit.
After each file, run `pnpm typecheck` and stop on first error.
```
### 3) Codemod fallback (deterministic)
```ts
// jscodeshift transform — 매 LLM 보다 매 reliable for syntactic
import { API, FileInfo } from 'jscodeshift';
export default function (file: FileInfo, api: API) {
return api.jscodeshift(file.source)
.find('CallExpression', { callee: { name: 'getUserData' } })
.replaceWith(p => api.jscodeshift.callExpression(
api.jscodeshift.identifier('fetchUserProfile'),
p.value.arguments
))
.toSource();
}
```
### 4) Hybrid: codemod + LLM cleanup
```bash
# 매 1) codemod 로 매 syntactic 변경
jscodeshift -t rename.ts src/
# 매 2) LLM 으로 매 semantic 보정 (매 import path, comment, type narrowing)
claude "Fix any remaining type errors after the rename."
```
### 5) Test-driven refactor loop
```bash
# 매 Aider / Claude Code 의 매 auto-test loop
claude --auto-test "Extract logger to a separate module. Run pytest after."
# 매 pytest fail → 매 LLM 이 매 fix 시도 → 매 max 3 retries → 매 stop
```
### 6) Diff size guard (pre-commit)
```bash
# .git/hooks/pre-commit
LINES=$(git diff --cached --shortstat | grep -oE '[0-9]+ insertions' | head -1)
if [ "${LINES%% *}" -gt 500 ]; then
echo "Refusing >500 line AI commit. Split it."; exit 1
fi
```
### 7) Chain of LLMs — propose / critique
```python
draft = claude.refactor(code)
critique = claude.review(draft, focus="correctness, edge cases")
final = claude.apply(critique)
```
### 8) Verification matrix
```yaml
# 매 매 refactor PR 의 mandatory gates
gates:
- typecheck: pnpm tsc --noEmit
- test: pnpm vitest run
- lint: pnpm biome check
- perf: bench compare main vs HEAD (regression < 5%)
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 매 syntactic mass change | Codemod (jscodeshift / ast-grep) |
| 매 semantic + 매 cross-cutting | LLM (Claude Code / Cursor) |
| 매 1-file refactor | IDE refactor menu |
| 매 risk-heavy (auth/payment) | Manual + LLM 보조 review |
| 매 large repo (>1M LoC) | Hybrid: codemod 먼저, LLM 보정 |
**기본값**: 매 plan-first + 매 small diff + 매 test gate. 매 syntactic 부분은 매 codemod, 매 semantic 부분만 매 LLM.
## 🔗 Graph
- 부모: [[Refactoring_Best_Practices|Refactoring]]
- 응용: [[3의 법칙 (Rule of Three)]]
- Adjacent: [[Claude Code]] · [[Cursor]] · [[Aider]]
## 🤖 LLM 활용
**언제**: 매 cross-file rename/migrate, 매 boilerplate 변환, 매 test scaffold 생성.
**언제 X**: 매 architectural decision, 매 perf hot path, 매 security crypto.
## ❌ 안티패턴
- **Massive PR**: 매 5000-line "AI did it all" PR. 매 review 불가능 → 매 bug 잠복.
- **No tests**: 매 LLM refactor 의 검증 없음. 매 silent regression.
- **Trust without verify**: 매 LLM 의 매 "I updated all callsites" 를 매 grep 으로 매 cross-check 안 함.
- **Architectural delegation**: 매 design 까지 LLM 에 위임 → 매 incoherent system.
- **Skipping codemod**: 매 syntactic mass-rename 까지 매 LLM 으로 → 매 token waste + 매 inconsistency.
## 🧪 검증 / 중복
- Verified (Anthropic Claude Code docs 2026, Cursor Composer guide 2026, jscodeshift Meta OSS).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — workflow + codemod hybrid + 8 patterns |
@@ -0,0 +1,29 @@
---
category: Computer_Science_and_Theory
tags: [auto-wikified, technical-documentation, computer_science_and_theory]
title: AOP (Aspect-Oriented Programming)
description: "AOP(Aspect-Oriented Programming)는 로깅, 보안, 트랜잭션 관리와 같은 횡단 관심사(Cross-Cutting Concerns)를 소프트웨어 시스템의 여러 모듈에서 분리하여 관리하는 방법론이자 프로그래밍 기법입니다 [1, 2]."
last_updated: 2026-05-04
---
# AOP (Aspect-Oriented Programming)
## 📌 Brief Summary
AOP(Aspect-Oriented Programming)는 로깅, 보안, 트랜잭션 관리와 같은 횡단 관심사(Cross-Cutting Concerns)를 소프트웨어 시스템의 여러 모듈에서 분리하여 관리하는 방법론이자 프로그래밍 기법입니다 [1, 2]. 핵심 비즈니스 로직과 인프라 코드를 분리함으로써 소스 코드의 오염을 방지하고 코드의 가독성과 유지보수성을 크게 높여줍니다 [3, 4]. 주로 런타임에 메서드 호출을 가로채어 실행 전, 후, 또는 주변(around)에 원하는 동작을 적용하는 방식으로 작동합니다 [1, 2].
## 📖 Core Content
- **관심사의 분리 (Separation of Concerns)**: 소프트웨어는 주요 기능을 담당하는 핵심 관심사(Core Concerns, 비즈니스 로직)와 시스템 전반에 걸쳐 필요한 보조 기능인 횡단 관심사(Crosscutting Concerns)로 나뉩니다 [5]. AOP는 로깅, 데이터 전송, 보안, 성능 모니터링, 캐싱 등 애플리케이션의 여러 계층을 가로지르는 횡단 관심사를 별도의 '애스펙트(Aspect)'로 분리하여 관리합니다 [1, 5].
- **Spring Boot에서의 실전 구현**: Spring 생태계에서 AOP는 컨트롤러, 서비스, 리포지토리 등 모든 Spring Bean의 메서드를 인터셉트할 수 있는 애플리케이션 및 서비스 계층의 기술로 활용됩니다 [1, 6]. 개발자는 `@Aspect`를 사용하여 `@Before`, `@After`, `@Around` 등의 시점(Pointcut)을 정의해 비즈니스 로직의 수정 없이 공통 기능을 주입할 수 있습니다 [1, 6].
- **주요 활용 사례**:
- **트랜잭션 동작(Transactional Behavior)**: 모든 서비스 메서드에 `try-catch` 블록과 `commit`/`rollback` 호출을 반복 작성하는 대신, 어노테이션 마커를 통해 트랜잭션 처리 책임을 AOP에 위임합니다 [7].
- **인가(Authorization)**: 서비스 메서드를 호출할 수 있는 권한을 마커로 표시하고, AOP 어드바이스(Advice)가 해당 메서드의 실행 허용 여부를 동적으로 결정하게 합니다 [8].
- **원격 호출(Remoting)**: 분산 시스템 환경에서 대상 식별, 데이터 직렬화, 원격 네트워크 호출 등의 복잡한 처리를 애스펙트가 대신 수행하여, 개발자는 로컬 컴포넌트를 호출하는 것처럼 코드를 작성할 수 있습니다 [9].
- **코드 품질 및 설계 향상**: AOP를 통해 공통 인프라 로직을 캡슐화하면 코드의 산재(Scattering)와 얽힘(Tangling)을 효과적으로 방지할 수 있습니다 [3, 10]. 이는 DRY(Don't Repeat Yourself) 원칙과 단일 책임 원칙(SRP) 위반을 막아주어, 대규모 코드베이스를 깨끗하고 리팩토링하기 쉬운 상태로 유지하도록 돕습니다 [3, 11].
## ⚖️ Trade-offs & Caveats
- **디버깅 난이도 상승 (마법 같은 동작)**: AOP는 비즈니스 코드와 인프라 코드를 완벽하게 분리하는 강력한 장점이 있지만, 실행 시점에 동적으로 로직을 삽입하므로 코드의 실제 실행 흐름을 직관적으로 파악하기 어렵게 만듭니다 [4]. 이러한 지나치게 '마법 같은(magical)' 동작 방식은 예기치 않은 오류 발생 시 추적과 디버깅을 매우 까다롭게 만드는 부작용이 있습니다 [4].
- **런타임 성능 오버헤드**: Castle.DynamicProxy와 같은 런타임 인터셉터 프레임워크를 사용할 경우, 각 메서드나 클래스에 대한 프록시 래퍼(Proxy wrapper)를 동적으로 생성해야 하므로 추가적인 런타임 비용이 발생합니다 [12]. 로깅과 같이 매우 빈번하게 호출되는 연산에 전면적으로 적용할 경우 애플리케이션 전반의 성능을 저하시킬 수 있습니다 [12].
- **빌드 파이프라인의 복잡성 증가**: 성능 오버헤드라는 제약을 피하기 위해 런타임 프록시 대신 컴파일 타임(Compile-time)이나 링크 타임(Link-time) 위빙(Weaving) 방식으로 AOP를 구현할 수 있습니다 [12]. 하지만 이 최적화 방법은 빌드 과정 자체를 훨씬 복잡하게 만드는 반대급부를 수반합니다 [12].
---
*Last updated: 2026-05-03*
@@ -0,0 +1,25 @@
---
category: Computer_Science_and_Theory
tags: [auto-wikified, technical-documentation, computer_science_and_theory]
title: AOT Compilation (Ahead-of-Time)
description: "AOT(Ahead-of-Time) 컴파일은 애플리케이션이 실행되기 전에 소스 코드를 기기의 네이티브 기계어(ARM 코드 등)로 미리 컴파일해 두는 기술입니다 [1, 2]."
last_updated: 2026-05-04
---
# AOT Compilation (Ahead-of-Time)
## 📌 Brief Summary
AOT(Ahead-of-Time) 컴파일은 애플리케이션이 실행되기 전에 소스 코드를 기기의 네이티브 기계어(ARM 코드 등)로 미리 컴파일해 두는 기술입니다 [1, 2]. 주로 Flutter 프레임워크의 Dart 언어나 Spring Boot의 GraalVM 네이티브 컴파일 환경 등에서 활용됩니다 [3, 4]. 실행 시점에 코드를 동적으로 해석하거나 파싱할 필요가 없으므로 애플리케이션의 콜드 스타트(Cold start) 시간을 크게 단축시키며, 네이티브 수준의 높은 실행 효율과 성능을 보장할 수 있습니다 [1, 5].
## 📖 Core Content
* **Flutter와 Dart의 AOT 컴파일:** Flutter를 구동하는 Dart 가상 머신(VM)은 빠른 컴파일 환경을 제공하기 위해 JIT(Just-In-Time) 컴파일과 AOT 컴파일을 모두 지원합니다 [6]. 프로덕션 배포 시 Flutter 앱은 AOT 컴파일을 통해 Android 및 iOS용 네이티브 기계어(ARM 코드 등)로 사전에 직접 컴파일됩니다 [1, 2]. 엔진 초기화 및 자바스크립트 번들 파싱 과정을 거쳐야 하는 다른 크로스 플랫폼 기술과 비교했을 때, 런타임 오버헤드가 대폭 제거되어 콜드 스타트 시간이 눈에 띄게 단축되며 실행 효율이 극대화됩니다 [1, 5]. 결과적으로 네이티브 애플리케이션 본연의 성능(Original performance)을 달성할 수 있습니다 [3].
* **Spring Boot의 네이티브 컴파일 (GraalVM 활용):** 자바(Java) 기반 백엔드 프레임워크인 Spring Boot 환경에서도 AOT 최적화 맥락과 맞닿아 있는 GraalVM 네이티브 컴파일을 채택하고 있습니다 [4]. 일반적인 JVM 애플리케이션은 시작하는 데 5~30초의 시간이 소요되지만, 이 네이티브 컴파일을 적용하면 코드가 사전 빌드되어 밀리초 단위로 애플리케이션을 시작할 수 있고 기존보다 훨씬 적은 힙 메모리(a fraction of the heap)만으로도 가동할 수 있습니다 [4].
## ⚖️ Trade-offs & Caveats
AOT 및 사전 네이티브 컴파일 방식을 애플리케이션 아키텍처에 도입할 경우, 최적화 이면에서 다음과 같은 반대 급부와 제약 사항을 반드시 고려해야 합니다.
* **빌드 복잡성 증가 및 런타임 유연성 제한:** Spring Boot와 같은 환경에서 GraalVM을 활용한 네이티브 빌드를 적용할 경우, 사전에 정적 분석 및 컴파일을 수행해야 하므로 빌드 환경 구축과 과정의 복잡성(build complexity)이 크게 증가합니다 [4]. 더불어 코드가 네이티브 이미지로 완전히 고정되기 때문에, 기존 JVM이 지니고 있던 동적 로딩 등의 런타임 유연성(runtime flexibility)이 일부 상실되는 제약을 감수해야 합니다 [4].
* **애플리케이션 파일 크기(앱 번들) 상승 부담:** 네이티브 기계어로 직접 컴파일되는 Flutter 애플리케이션의 경우, 컴파일된 결과물과 함께 Dart 런타임 및 자체 렌더링 엔진(예: Impeller)이 하나로 패키징되어 포함되어야 합니다 [1]. 이로 인해 아주 단순한 앱이라도 최소 기본 APK 크기가 8~12MB 수준에 달하게 되며, 복잡한 네이티브 코드가 포함됨에 따라 전체 앱 크기(App Size)가 다소 커지는 단점이 발생할 수 있습니다 [1, 7].
---
*Last updated: 2026-05-03*
@@ -0,0 +1,197 @@
---
id: wiki-2026-0508-api-gateway
title: API Gateway
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [API GW, Gateway pattern, Edge service]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [architecture, microservices, api, gateway, edge]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: yaml
framework: Kong, AWS API Gateway, Envoy
---
# API Gateway
## 매 한 줄
> **"매 single entry point — fan-out, auth, rate limit"**. 매 microservices 의 클라이언트 facing facade. 매 Netflix Zuul (2013) 시작 → Kong (2015) → Envoy/Istio (2017) → AWS API Gateway HTTP API (2019). 매 2026 modern stack 은 Envoy + xDS control plane, edge AI inference gateway (LiteLLM, Portkey) 의 추가.
## 매 핵심
### 매 책임
- **Routing**: path/host/header → upstream service.
- **Auth/AuthZ**: JWT validation, OAuth2 introspection, mTLS termination.
- **Rate limiting**: per-key, per-IP, sliding window.
- **Observability**: trace propagation (W3C Trace Context), metrics, access log.
- **Transformation**: request/response shaping, protocol translation (REST↔gRPC).
### 매 NOT 책임
- Business logic — 매 service 의 책임.
- Data persistence — 매 stateless edge.
- Heavy aggregation — 매 BFF (Backend-for-Frontend) layer 의 책임.
### 매 응용
1. **Public API edge** — Stripe, Twilio 형 SaaS API.
2. **BFF per client** — mobile/web/CLI 매 다른 shape.
3. **LLM gateway** — multi-provider routing (Claude, GPT, local), fallback, cost cap.
## 💻 패턴
### Kong declarative config
```yaml
_format_version: "3.0"
services:
- name: orders-api
url: http://orders.svc.cluster.local:8080
routes:
- name: orders-route
paths: ["/api/orders"]
strip_path: false
plugins:
- name: rate-limiting
config: { minute: 600, policy: redis }
- name: jwt
config: { key_claim_name: kid }
- name: prometheus
```
### Envoy route config
```yaml
route_config:
virtual_hosts:
- name: api
domains: ["api.example.com"]
routes:
- match: { prefix: "/v1/orders" }
route:
cluster: orders_cluster
timeout: 5s
retry_policy:
retry_on: 5xx,reset,connect-failure
num_retries: 2
per_try_timeout: 1s
```
### AWS API Gateway HTTP API + Lambda authorizer
```yaml
# SAM template
HttpApi:
Type: AWS::Serverless::HttpApi
Properties:
Auth:
Authorizers:
JwtAuth:
IdentitySource: $request.header.Authorization
JwtConfiguration:
issuer: https://auth.example.com
audience: [api.example.com]
DefaultAuthorizer: JwtAuth
RouteSettings:
"POST /orders":
ThrottlingBurstLimit: 100
ThrottlingRateLimit: 50
```
### LLM gateway (Portkey-style fallback)
```python
from portkey_ai import Portkey
client = Portkey(
api_key="...",
config={
"strategy": {"mode": "fallback"},
"targets": [
{"provider": "anthropic", "override_params": {"model": "claude-opus-4-7"}},
{"provider": "openai", "override_params": {"model": "gpt-5"}},
],
"cache": {"mode": "semantic", "max_age": 3600},
},
)
resp = client.chat.completions.create(messages=[{"role":"user","content":"hi"}])
```
### Rate limit (token bucket, Redis)
```lua
-- Kong-style Redis Lua
local key = "rl:" .. consumer_id
local tokens = tonumber(redis.call("GET", key) or "100")
if tokens <= 0 then return 429 end
redis.call("DECR", key)
redis.call("EXPIRE", key, 60)
return 200
```
### Header-based canary
```yaml
routes:
- match:
prefix: "/v1/checkout"
headers: [{name: "x-canary", exact_match: "true"}]
route: { cluster: checkout_v2 }
- match: { prefix: "/v1/checkout" }
route: { cluster: checkout_v1 }
```
### gRPC-Web transcoding
```yaml
http_filters:
- name: envoy.filters.http.grpc_web
- name: envoy.filters.http.grpc_json_transcoder
typed_config:
proto_descriptor: /etc/proto/api.pb
services: ["api.OrderService"]
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Public SaaS API, multi-tenant | Kong / AWS API Gateway |
| Service mesh edge ingress | Envoy + Istio Gateway |
| Single-team internal API | Skip gateway → direct service + library SDK |
| Multi-LLM provider | Portkey / LiteLLM gateway |
| Heterogeneous protocols (REST+gRPC+WS) | Envoy with transcoding filters |
**기본값**: 매 Envoy-based (Istio Gateway / Contour) 의 in-cluster, AWS API Gateway 의 fully managed edge.
## 🔗 Graph
- 부모: [[Microservices]] · [[Edge Computing]]
- 변형: [[Service Mesh]] · [[Reverse Proxy]]
- 응용: [[Rate Limiting]] · [[mTLS]]
- Adjacent: [[Load Balancer]] · [[CDN]]
## 🤖 LLM 활용
**언제**: 매 multi-service public API, 매 cross-cutting concerns (auth/rate-limit/observability) 의 centralization, 매 multi-provider LLM routing.
**언제 X**: 매 single monolith, 매 internal service-to-service only (use mesh sidecar), 매 hot path 의 < 100us latency 요구.
## ❌ 안티패턴
- **Smart gateway**: 매 business logic 의 gateway 에 stuff — 매 deployment coupling 의 발생.
- **Single gateway for all clients**: 매 mobile/web/partner 매 BFF 의 분리 안 함 → over-fetching.
- **No timeout/retry budget**: 매 cascading failure 의 발생.
- **Auth-only gateway, no rate limit**: 매 abuse vector.
## 🧪 검증 / 중복
- Verified (Kong docs, Envoy docs, AWS API Gateway docs, Microsoft Azure Architecture Center "Gateway Aggregation" pattern).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — full content (Kong/Envoy/AWS/LLM gateway patterns) |
## 🛠️ 적용 사례 (Applied in summary)
<!-- CODE-GROUNDING:START -->
### 🔎 코드베이스 근거 (자동 추출 — E:\Wiki 레포)
**실제 구현/사용 위치:**
- `connectai/src/features/secondBrainTrace.ts:256` — [Omitted long matching line]
_자동 생성: code_grounding.mjs · 재실행 시 갱신됨_
<!-- CODE-GROUNDING:END -->
@@ -0,0 +1,195 @@
---
id: wiki-2026-0508-api-contract-definition
title: API Contract Definition
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [API Contract, OpenAPI Contract, Schema-First API, Contract-First Design]
duplicate_of: none
source_trust_level: A
confidence_score: 0.95
verification_status: applied
tags: [api, openapi, contract, schema, design]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: yaml
framework: openapi-3.1
---
# API Contract Definition
## 매 한 줄
> **"매 API 의 shape (path, method, schema, error, auth) 을 매 machine-readable spec 으로 매 먼저 정의하고 매 그 후 server/client 가 매 그것을 따른다."** OpenAPI 3.1 (REST), gRPC `.proto`, GraphQL SDL, AsyncAPI (event), JSON Schema 가 매 dominant. 2026 현재 매 LLM 이 매 spec 을 읽어 매 client / mock / test 를 매 generate — 매 contract-first 가 매 AI 시대의 매 default.
## 매 핵심
### 매 contract-first vs code-first
- **Contract-first**: 매 spec → 매 server stub + 매 client SDK. 매 multi-team / multi-language 의 default.
- **Code-first**: 매 code → 매 spec generated (FastAPI, NestJS Swagger). 매 single team 에서 매 빠름.
- 2026 추세: 매 contract-first 가 매 LLM-friendly + 매 mock-driven dev 에 유리.
### 매 standard 별 사용처
- **OpenAPI 3.1**: 매 REST/HTTP. 매 JSON Schema 2020-12 align.
- **gRPC + protobuf**: 매 internal high-perf, 매 strong typing.
- **GraphQL SDL**: 매 client-driven query, 매 BFF.
- **AsyncAPI 3**: 매 Kafka / NATS / WebSocket event.
- **JSON Schema**: 매 payload validation, 매 LLM structured output.
### 매 contract testing
- **Provider tests**: 매 server 가 매 spec 을 만족하는지 검증 (매 schemathesis, dredd, prism).
- **Consumer-driven contracts**: 매 Pact — 매 client 가 매 expectation 을 매 publish, 매 server 가 매 verify.
### 매 응용
1. SDK auto-generation (Stainless, Speakeasy, OpenAPI Generator).
2. Mock server (Prism, Mockoon).
3. Fuzz / property test (Schemathesis).
## 💻 패턴
### 1) OpenAPI 3.1 minimal
```yaml
openapi: 3.1.0
info: { title: Orders API, version: 1.2.0 }
servers: [{ url: https://api.example.com/v1 }]
paths:
/orders/{id}:
get:
operationId: getOrder
parameters:
- { name: id, in: path, required: true, schema: { type: string, format: uuid } }
responses:
'200':
content: { application/json: { schema: { $ref: '#/components/schemas/Order' } } }
'404': { description: Not found }
components:
schemas:
Order:
type: object
required: [id, total]
properties:
id: { type: string, format: uuid }
total: { type: number, minimum: 0 }
status: { type: string, enum: [pending, paid, shipped, canceled] }
```
### 2) gRPC proto
```proto
syntax = "proto3";
package orders.v1;
service Orders {
rpc Get (GetReq) returns (Order);
rpc Stream (StreamReq) returns (stream Event);
}
message GetReq { string id = 1; }
message Order { string id = 1; double total = 2; Status status = 3; }
enum Status { PENDING = 0; PAID = 1; SHIPPED = 2; CANCELED = 3; }
```
### 3) GraphQL SDL
```graphql
type Order {
id: ID!
total: Float!
status: Status!
}
enum Status { PENDING PAID SHIPPED CANCELED }
type Query { order(id: ID!): Order }
```
### 4) AsyncAPI 3 (Kafka event)
```yaml
asyncapi: 3.0.0
info: { title: Orders Events, version: 1.0.0 }
channels:
orders.created:
address: orders.created
messages:
OrderCreated:
payload: { $ref: '#/components/schemas/Order' }
operations:
publishOrderCreated:
action: send
channel: { $ref: '#/channels/orders.created' }
```
### 5) Server stub generation
```bash
# 매 OpenAPI → TypeScript Express
npx openapi-generator-cli generate -i openapi.yaml -g typescript-node -o ./gen
# 매 OpenAPI → Python (FastAPI server)
npx openapi-typescript openapi.yaml -o gen/types.ts
```
### 6) Schemathesis property-based test
```bash
schemathesis run openapi.yaml --base-url=http://localhost:8000 \
--checks=all --hypothesis-deadline=2000
```
### 7) Pact consumer test (TS)
```ts
import { Pact } from '@pact-foundation/pact';
const provider = new Pact({ consumer: 'web', provider: 'orders' });
await provider.addInteraction({
state: 'order 1 exists',
uponReceiving: 'a get for order 1',
withRequest: { method: 'GET', path: '/v1/orders/1' },
willRespondWith: { status: 200, body: { id: '1', total: 99 } }
});
```
### 8) JSON Schema for LLM structured output
```python
order_schema = {
"type": "object",
"required": ["id", "total"],
"properties": {"id":{"type":"string"},"total":{"type":"number"}}
}
client.messages.create(
model="claude-opus-4-7",
tools=[{"name":"return_order","input_schema":order_schema}],
tool_choice={"type":"tool","name":"return_order"},
messages=[...]
)
```
## 매 결정 기준
| 상황 | Standard |
|---|---|
| 매 public REST | OpenAPI 3.1 |
| 매 internal microservices | gRPC + protobuf |
| 매 client-shaped query | GraphQL |
| 매 event-driven | AsyncAPI 3 |
| 매 LLM structured output | JSON Schema |
**기본값**: 매 contract-first + 매 OpenAPI 3.1 + 매 SDK auto-gen + 매 schemathesis CI. 매 internal 은 gRPC.
## 🔗 Graph
- 부모: [[API Design]]
- 변형: [[OpenAPI]] · [[gRPC]]
- 응용: [[Contract Testing]]
- Adjacent: [[JSON Schema]] · [[Pact]]
## 🤖 LLM 활용
**언제**: 매 spec → SDK / mock / test scaffold 자동 생성, 매 spec lint, 매 changelog diff.
**언제 X**: 매 LLM 이 매 spec 을 매 invent — 매 source-of-truth 는 매 git-tracked spec file.
## ❌ 안티패턴
- **Spec drift**: 매 server 가 매 spec 과 매 다름. 매 schemathesis CI 로 차단.
- **No versioning**: 매 breaking change 를 매 same path 에 push. 매 `/v1``/v2` 또는 매 deprecated header.
- **Anyof everywhere**: 매 spec 이 매 너무 permissive → 매 client 의 매 type narrowing 불가.
- **Code-first without lint**: 매 generated spec 이 매 inconsistent (매 nullable, 매 enum).
- **Mock-only test**: 매 contract test 없이 매 mock 만 사용 → 매 prod fail.
## 🧪 검증 / 중복
- Verified (OpenAPI 3.1 spec, AsyncAPI 3.0 spec, Pact docs, Schemathesis docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — OpenAPI/gRPC/GraphQL/AsyncAPI 4-standard + contract testing |
@@ -0,0 +1,197 @@
---
id: wiki-2026-0508-api-first-architecture
title: API-First Architecture
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [API-first design, Contract-first, Schema-first]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [architecture, api, openapi, contract-first, design]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: yaml
framework: OpenAPI 3.1, Stoplight, Spectral, buf
---
# API-First Architecture
## 매 한 줄
> **"매 API spec 의 first artifact — code follows contract"**. 매 design-first → spec → mock → impl 매 separate workflow. 매 Swagger (2010) → OpenAPI 3.0 (2017) → 3.1 (2021, JSON Schema 2020-12 align) → AsyncAPI 2.6/3.0 (events) → buf (gRPC). 매 2026 modern stack 은 spec-driven codegen + lint (Spectral) + breaking change detection (buf, oasdiff) + AI-assisted spec (Claude Opus 4.7).
## 매 핵심
### 매 workflow
1. **Design**: write OpenAPI/proto spec 매 먼저.
2. **Review**: stakeholders (FE/BE/partner) review spec, not code.
3. **Mock**: Prism/Stoplight serve mock from spec.
4. **Generate**: SDK (oapi-codegen, openapi-typescript), server stubs.
5. **Implement**: fill stubs, validate at runtime.
6. **Test**: contract tests against spec.
7. **Govern**: lint (Spectral), diff (oasdiff), versioning.
### 매 vs code-first
- **Code-first**: write handler → annotate → generate spec. Drift risk, late stakeholder feedback.
- **API-first**: write spec → generate handler → fill. Single source of truth.
### 매 응용
1. **Public SaaS API** — Stripe-style spec-driven.
2. **Multi-platform SDK distribution** — auto-generated TS/Python/Go/Java clients.
3. **Frontend/backend parallel dev** — FE works against mock from day 1.
4. **B2B integration contracts** — partners review spec before impl.
## 💻 패턴
### OpenAPI 3.1 spec
```yaml
openapi: 3.1.0
info: { title: Orders API, version: 1.0.0 }
paths:
/orders/{id}:
get:
operationId: getOrder
parameters:
- { name: id, in: path, required: true, schema: {type: string} }
responses:
"200":
description: OK
content:
application/json:
schema: { $ref: "#/components/schemas/Order" }
"404": { $ref: "#/components/responses/NotFound" }
components:
schemas:
Order:
type: object
required: [id, status]
properties:
id: { type: string, format: uuid }
status: { type: string, enum: [pending, paid, shipped] }
total: { type: number, minimum: 0 }
```
### Mock server (Prism)
```bash
npx @stoplight/prism-cli mock spec.yaml --port 4010
# Now FE devs hit http://localhost:4010/orders/123 with realistic responses
```
### Spectral lint config
```yaml
# .spectral.yaml
extends: [[spectral:oas, all]]
rules:
operation-operationId-unique: error
operation-tag-defined: error
no-eval-in-markdown: error
custom-versioned-path:
given: "$.paths"
severity: error
then:
function: pattern
functionOptions: { match: "^/v\\d+/" }
```
### Type-safe client (openapi-typescript)
```bash
npx openapi-typescript spec.yaml -o src/api-types.ts
```
```typescript
import createClient from "openapi-fetch";
import type { paths } from "./api-types";
const client = createClient<paths>({ baseUrl: "https://api.example.com" });
const { data, error } = await client.GET("/orders/{id}", {
params: { path: { id: "abc" } },
});
// data: Order | undefined, fully typed
```
### Server stub (oapi-codegen, Go)
```bash
oapi-codegen -package api -generate types,server spec.yaml > api/api.gen.go
```
```go
type ServerImpl struct{ db *sql.DB }
func (s *ServerImpl) GetOrder(c echo.Context, id string) error {
var o Order
if err := s.db.QueryRow("SELECT ...").Scan(...); err != nil { ... }
return c.JSON(200, o)
}
```
### Breaking change detection (oasdiff)
```bash
oasdiff breaking spec-v1.yaml spec-v2.yaml --fail-on ERR
# CI gate: blocks PR if breaking change without major version bump
```
### AsyncAPI for events
```yaml
asyncapi: 3.0.0
info: { title: Orders Events, version: 1.0.0 }
channels:
orderCreated:
address: orders.created
messages:
OrderCreatedMessage:
payload:
$ref: "#/components/schemas/Order"
operations:
publishOrderCreated:
action: send
channel: { $ref: "#/channels/orderCreated" }
```
### buf for gRPC governance
```yaml
# buf.yaml
version: v2
modules:
- path: proto
breaking:
use: [FILE]
lint:
use: [DEFAULT]
except: [PACKAGE_VERSION_SUFFIX]
```
## 매 결정 기준
| 상황 | Spec |
|---|---|
| HTTP REST, public | OpenAPI 3.1 |
| Async events | AsyncAPI 3.0 |
| gRPC | proto + buf |
| GraphQL | SDL + Apollo Federation |
| Internal-only, single team | Code-first (faster iteration) |
**기본값**: 매 OpenAPI 3.1 + Spectral lint + Prism mock + openapi-typescript codegen + oasdiff CI.
## 🔗 Graph
- 부모: [[API Fundamentals]]
- 응용: [[OpenAPI]]
- Adjacent: [[Consumer-Driven Contracts]] · [[API Gateway]]
## 🤖 LLM 활용
**언제**: 매 multi-team API, 매 public SDK distribution, 매 partner integration, 매 FE/BE parallel dev.
**언제 X**: 매 prototype, 매 throwaway script, 매 single-developer monolith.
## ❌ 안티패턴
- **Spec-as-documentation only**: 매 not source of truth, 매 drift. 매 codegen-driven 의 enforce.
- **No CI lint**: 매 spec rot. 매 Spectral / vacuum 의 사용.
- **Big-bang spec**: 매 review fatigue. 매 incremental + path-scoped reviews.
- **No mock**: 매 FE blocked on BE. 매 Prism mock 의 day-1 deploy.
## 🧪 검증 / 중복
- Verified (OpenAPI 3.1 spec, AsyncAPI spec, Stoplight docs, buf docs, ThoughtWorks Tech Radar "Design APIs first").
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — full content (API-first workflow + tooling) |
@@ -0,0 +1,189 @@
---
id: wiki-2026-0508-api-fundamentals
title: API Fundamentals
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [API basics, REST GraphQL gRPC, Web API]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [api, rest, graphql, grpc, fundamentals]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: REST/GraphQL/gRPC/tRPC
---
# API Fundamentals
## 매 한 줄
> **"매 contract between systems — verbs, nouns, errors, evolution"**. 매 RPC (1980s, Sun RPC) → CORBA (1991) → SOAP (1998) → REST (Fielding 2000) → gRPC (2015) → GraphQL (2015) → tRPC (2020). 매 2026 modern stack 은 typed end-to-end (tRPC, GraphQL Codegen, gRPC + buf) + AsyncAPI 2.x for events.
## 매 핵심
### 매 four styles
- **REST**: resource-oriented, HTTP verbs, stateless, cacheable. 매 public API standard.
- **GraphQL**: client-specified queries, single endpoint, strong types. 매 BFF / mobile.
- **gRPC**: binary (protobuf), HTTP/2, streaming, codegen. 매 internal, low-latency.
- **tRPC**: TypeScript-first, no codegen, type inference. 매 Next.js / monorepo.
### 매 cross-cutting concerns
- **Versioning**: URI (`/v1`), header (`Accept-Version`), or evolution (additive only).
- **Idempotency**: idempotency key for unsafe verbs (POST). At-least-once → exactly-once at API.
- **Pagination**: cursor (preferred) vs offset. 매 cursor 의 stable ordering.
- **Errors**: RFC 7807 problem+json, gRPC status codes, GraphQL `errors[]`.
- **Auth**: OAuth2 / OIDC / mTLS / API key.
### 매 응용
1. **Public REST + GraphQL** — Stripe (REST), GitHub (both), Shopify (GraphQL).
2. **Internal gRPC mesh** — Google, Uber, Square.
3. **Full-stack tRPC** — Vercel, Cal.com, T3 stack.
## 💻 패턴
### REST resource design
```http
GET /orders?status=pending&cursor=abc123 200 [{...}], next_cursor
POST /orders 201 {id, ...}, Location
GET /orders/{id} 200 {...} | 404
PATCH /orders/{id} (JSON Merge Patch) 200 {...}
DELETE /orders/{id} 204
```
### REST idempotency
```typescript
app.post("/orders", async (req, res) => {
const idemKey = req.header("Idempotency-Key");
const cached = await redis.get(`idem:${idemKey}`);
if (cached) return res.status(200).json(JSON.parse(cached));
const order = await createOrder(req.body);
await redis.setex(`idem:${idemKey}`, 86400, JSON.stringify(order));
res.status(201).json(order);
});
```
### Cursor pagination
```typescript
const limit = 50;
const rows = await db.query(
`SELECT * FROM orders WHERE (created_at, id) < ($1, $2)
ORDER BY created_at DESC, id DESC LIMIT $3`,
[cursor.ts, cursor.id, limit + 1]
);
const hasMore = rows.length > limit;
const items = rows.slice(0, limit);
const nextCursor = hasMore ? encode(items.at(-1)) : null;
```
### GraphQL schema + resolver
```graphql
type Query {
order(id: ID!): Order
orders(first: Int!, after: String): OrderConnection!
}
type Order { id: ID!, status: OrderStatus!, items: [Item!]! }
type OrderConnection {
edges: [OrderEdge!]!
pageInfo: PageInfo!
}
```
```typescript
const resolvers = {
Query: {
order: (_, {id}, ctx) => ctx.dataloaders.order.load(id),
orders: async (_, {first, after}, ctx) => paginateOrders(first, after, ctx),
},
Order: {
items: (order, _, ctx) => ctx.dataloaders.itemsByOrder.load(order.id),
},
};
```
### gRPC service (proto3)
```proto
syntax = "proto3";
package orders.v1;
service OrderService {
rpc Get(GetRequest) returns (Order);
rpc List(ListRequest) returns (stream Order); // server streaming
rpc Watch(WatchRequest) returns (stream OrderEvent); // bidi-friendly
}
message Order {
string id = 1;
OrderStatus status = 2;
google.protobuf.Timestamp created_at = 3;
}
```
### tRPC procedure
```typescript
import { router, publicProcedure } from "./trpc";
import { z } from "zod";
export const orderRouter = router({
get: publicProcedure
.input(z.object({ id: z.string() }))
.query(({ input, ctx }) => ctx.db.order.findUnique({ where: { id: input.id } })),
create: publicProcedure
.input(z.object({ items: z.array(z.string()).min(1) }))
.mutation(({ input, ctx }) => ctx.db.order.create({ data: { items: input.items } })),
});
// Client gets full type inference: trpc.order.get.useQuery({id}) typed
```
### RFC 7807 error
```json
{
"type": "https://api.example.com/errors/insufficient-funds",
"title": "Insufficient funds",
"status": 402,
"detail": "Account 12345 has balance $5, requested $50",
"instance": "/orders/abc"
}
```
## 매 결정 기준
| 상황 | Style |
|---|---|
| Public 3rd-party API | REST + OpenAPI 3.1 |
| Mobile/web with diverse query needs | GraphQL |
| Internal microservices, low latency | gRPC |
| TypeScript monorepo (Next.js) | tRPC |
| Real-time bidirectional streams | gRPC streaming or WebSocket |
| Async events | AsyncAPI + Kafka/NATS |
**기본값**: 매 REST + OpenAPI 의 public, 매 gRPC 의 internal, 매 tRPC 의 TS monorepo.
## 🔗 Graph
- 부모: [[Distributed Systems]] · [[Web Architecture]]
- 변형: [[REST]] · [[gRPC]]
- 응용: [[OpenAPI]] · [[API Gateway]] · [[Service Mesh]]
- Adjacent: [[JSON Schema]] · [[Protocol Buffers]]
## 🤖 LLM 활용
**언제**: 매 cross-system contract 의 design, 매 client/server 매 separated, 매 versioned interface 필요.
**언제 X**: 매 internal function call (just call it), 매 single process, 매 < 100 lines glue script.
## ❌ 안티패턴
- **GET with side effects**: 매 cache poisoning, 매 idempotency violation.
- **HTTP 200 with `{error: ...}` body**: 매 status code semantics 의 ignore.
- **Versioning by minor change**: 매 v1/v2/v3 explosion. 매 additive evolution 의 prefer.
- **Chatty API**: 매 N+1 client roundtrips. 매 batch endpoint or GraphQL.
- **No pagination**: 매 unbounded list → OOM at scale.
## 🧪 검증 / 중복
- Verified (RFC 7231 HTTP, RFC 7807 problem+json, gRPC docs, GraphQL spec, tRPC docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — full content (REST/GraphQL/gRPC/tRPC fundamentals) |
@@ -0,0 +1,223 @@
---
id: wiki-2026-0508-ast-traversal
title: AST Traversal
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [ast-walk, syntax-tree-traversal, visitor-pattern]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [ast, compilers, codemod, static-analysis]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: ts-morph
---
# AST Traversal
## 매 한 줄
> **"매 code 의 tree 의 walk 한다"**. 매 AST (Abstract Syntax Tree) traversal 의 compiler/linter/codemod/IDE 의 foundation. 매 2026 의 tree-sitter (Atom, 2018; 매 GitHub 의 sole semantic search engine) + ts-morph + Babel + RustPython AST 의 dominant tooling.
## 매 핵심
### 매 traversal strategies
- **Pre-order DFS**: 매 visit parent → children. 매 default (most visitors).
- **Post-order DFS**: 매 visit children → parent. 매 type inference, dead-code elim.
- **BFS**: 매 level-by-level. 매 rare — scope analysis.
- **Visitor pattern**: 매 node-type-keyed callbacks. 매 ESLint, Babel, ts-morph standard.
### 매 mutating vs read-only
- **Read-only**: linter, complexity metrics, security scanner.
- **Mutating**: codemod, formatter, transpiler. 매 immutability + new tree 의 produce 의 best-practice (Babel: `path.replaceWith`).
### 매 응용
1. ESLint rule — 매 pattern detection.
2. Codemod — jscodeshift, ts-morph, ast-grep.
3. Tree-sitter query — 매 IDE syntax highlight, code nav.
4. AST-based diffing — 매 difftastic, semantic diff.
## 💻 패턴
### Babel visitor (JavaScript)
```js
import { parse } from '@babel/parser';
import traverse from '@babel/traverse';
import generate from '@babel/generator';
import * as t from '@babel/types';
const code = `console.log("hello"); foo("world");`;
const ast = parse(code);
traverse(ast, {
CallExpression(path) {
const callee = path.node.callee;
if (t.isMemberExpression(callee) &&
t.isIdentifier(callee.object, { name: 'console' })) {
// strip console.* calls
path.remove();
}
}
});
console.log(generate(ast).code); // foo("world");
```
### ts-morph (TypeScript refactor)
```ts
import { Project, SyntaxKind } from 'ts-morph';
const project = new Project({ tsConfigFilePath: 'tsconfig.json' });
for (const sf of project.getSourceFiles()) {
sf.forEachDescendant(node => {
if (node.getKind() === SyntaxKind.CallExpression) {
const ce = node.asKindOrThrow(SyntaxKind.CallExpression);
if (ce.getExpression().getText() === 'fetch') {
ce.replaceWithText(`httpClient.${ce.getText().replace('fetch', '')}`);
}
}
});
}
await project.save();
```
### Python — `ast` + NodeTransformer
```python
import ast
class StripPrint(ast.NodeTransformer):
def visit_Expr(self, node):
if (isinstance(node.value, ast.Call)
and isinstance(node.value.func, ast.Name)
and node.value.func.id == "print"):
return None # remove
return node
src = "print('hi')\nx = 1"
tree = ast.parse(src)
StripPrint().visit(tree)
ast.fix_missing_locations(tree)
print(ast.unparse(tree)) # x = 1
```
### tree-sitter query (multi-language)
```scheme
; queries/python/calls.scm — find all decorated functions
(decorated_definition
(decorator (call function: (identifier) @decorator-name))
definition: (function_definition name: (identifier) @func-name))
```
```python
import tree_sitter_python as tspython
from tree_sitter import Language, Parser, Query
PY = Language(tspython.language())
parser = Parser(PY)
tree = parser.parse(b"@app.route('/')\ndef home(): pass")
q = Query(PY, open("queries/python/calls.scm").read())
for node, name in q.captures(tree.root_node):
print(name, node.text)
```
### ast-grep (rule-based, polyglot)
```yaml
# rule.yml
id: no-console-log
language: js
rule:
pattern: console.log($$$)
fix: ''
```
```bash
ast-grep scan -r rule.yml --update
```
### Rust — syn (proc-macro / codegen)
```rust
use syn::{visit::Visit, ItemFn, File};
struct FnCounter(usize);
impl<'ast> Visit<'ast> for FnCounter {
fn visit_item_fn(&mut self, i: &'ast ItemFn) {
self.0 += 1;
syn::visit::visit_item_fn(self, i);
}
}
let src = std::fs::read_to_string("src/lib.rs").unwrap();
let file: File = syn::parse_file(&src).unwrap();
let mut c = FnCounter(0);
c.visit_file(&file);
println!("functions: {}", c.0);
```
### ESLint custom rule
```js
module.exports = {
meta: { type: 'problem', schema: [] },
create(ctx) {
return {
'CallExpression[callee.name="eval"]'(node) {
ctx.report({ node, message: 'eval is forbidden' });
}
};
}
};
```
### Pre-order vs post-order (manual walk)
```ts
function walkPre(node: Node, fn: (n: Node) => void) {
fn(node);
for (const c of node.children) walkPre(c, fn);
}
function walkPost(node: Node, fn: (n: Node) => void) {
for (const c of node.children) walkPost(c, fn);
fn(node);
}
```
## 매 결정 기준
| Goal | Tool |
|---|---|
| JS/TS lint rule | ESLint visitor |
| TS large refactor | ts-morph |
| Python codemod | LibCST (preserves whitespace) > ast |
| Polyglot pattern search | ast-grep, Semgrep |
| IDE / syntax highlight | tree-sitter |
| Rust macro | syn / quote |
| Babel plugin | @babel/traverse |
**기본값**: 매 ts-morph (TS refactor) · ast-grep (polyglot scan) · LibCST (Python codemod).
## 🔗 Graph
- 부모: [[Static-Analysis]]
- 변형: [[Visitor-Pattern]]
- 응용: [[ESLint]] · [[Refactoring_Best_Practices|Refactoring]]
- Adjacent: [[Architectural-Constraint-Enforcement]] · [[Architecture_Refactor]]
## 🤖 LLM 활용
**언제**: 매 codebase 의 LLM-driven structural query — 매 ast-grep + Claude 의 hybrid (LLM 의 generate pattern, ast 의 execute).
**언제 X**: 매 LLM 의 raw text find/replace — 매 AST-aware tool 의 사용.
## ❌ 안티패턴
- **Regex on code**: 매 multiline construct 의 break — 매 AST 의 사용.
- **Mutating during traversal**: 매 visitor 의 reentrancy bug — 매 collect-then-apply.
- **Ignore comments/whitespace**: 매 codemod 의 lose comments — 매 LibCST/Recast 의 사용.
- **Single-pass dependence**: 매 transformation order 의 fragile — 매 idempotent 의 design.
## 🧪 검증 / 중복
- Verified (Babel docs; ts-morph guide; tree-sitter playground; *Crafting Interpreters* — Nystrom).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Babel/ts-morph/tree-sitter/ast-grep patterns |
@@ -0,0 +1,181 @@
---
id: wiki-2026-0508-atam-architecture-trade-offs-ana
title: ATAM (Architecture Trade-offs Analysis Method)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [atam, architecture-evaluation, architecture-review]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [architecture, evaluation, atam, sei, quality-attributes]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: process
framework: sei-atam
---
# ATAM (Architecture Trade-offs Analysis Method)
## 매 한 줄
> **"매 architecture 의 quality attribute 의 trade-off 의 reveal 한다"**. 매 ATAM 의 SEI (Software Engineering Institute, CMU) 의 1998 의 published — 매 Bass, Clements, Kazman 의 *Software Architecture in Practice* 의 codified. 매 2026 의 lightweight 의 RFC/ADR + LLM-assisted scenario generation 의 evolved 됨 — 매 core 의 still scenario-driven trade-off analysis.
## 매 핵심
### 매 9 phases (classical ATAM)
1. Present ATAM (method intro).
2. Present business drivers.
3. Present architecture.
4. Identify architectural approaches.
5. Generate quality attribute utility tree.
6. Analyze approaches against scenarios.
7. Brainstorm + prioritize scenarios (stakeholders).
8. Re-analyze.
9. Present results.
### 매 outputs
- **Utility tree**: quality goals → attributes → scenarios (H/M/L priority + difficulty).
- **Risks**: 매 architecture decision 의 negative consequence.
- **Non-risks**: 매 sound decision 의 confirmation.
- **Sensitivity points**: 매 single decision 의 single attribute 의 strongly affect.
- **Trade-off points**: 매 single decision 의 multiple attributes 의 differently affect.
### 매 scenario template
```
Stimulus (event) — Source (actor) — Environment (state) →
Artifact (component) → Response (system action) → Measure (latency, %, etc.)
```
### 매 응용
1. Pre-build architecture review.
2. Major refactor 의 GO/NO-GO.
3. Vendor selection — 매 candidate 의 same scenarios 의 score.
4. Tech radar 의 input.
## 💻 패턴
### Utility tree (Markdown)
```markdown
# Utility Tree — Order Service v3
## Performance
- (H, H) p95 checkout latency < 300ms at 10k RPS
- (H, M) Cold start < 500ms (serverless)
- (M, L) Background job throughput > 1k/s
## Availability
- (H, H) 99.99% monthly SLO for /checkout
- (H, M) Graceful DB failover < 30s
- (M, M) Region evacuation < 5min
## Modifiability
- (H, M) New payment method added in < 5 dev-days
- (M, L) Tenant-specific pricing rules without redeploy
## Security
- (H, H) PCI-DSS compliance for card data path
- (M, M) PII encryption at rest
(H/M/L = Importance, Difficulty)
```
### Scenario (concrete)
```yaml
id: PERF-01
quality_attribute: performance
priority: H
difficulty: H
stimulus: "10,000 concurrent checkout submissions"
source: "authenticated mobile clients"
environment: "normal operations, peak hour"
artifact: "checkout-api + payment-gateway"
response: "process to confirmed order"
measure: "p95 < 300ms, p99 < 800ms, error rate < 0.1%"
analysis:
approach: "Read-through Redis cache + async write to Kafka"
sensitivity: ["Redis cluster size", "Kafka partition count"]
tradeoff: "Cache adds read latency variance vs DB-direct correctness"
risk: "Cache stampede on Redis failover"
mitigations: ["request coalescing", "stale-while-revalidate"]
```
### Risk / Non-risk / Sensitivity / Trade-off ledger
```markdown
| ID | Type | Decision | Affects | Status |
|----|------|----------|---------|--------|
| R-01 | Risk | Sync DB write in checkout | Avail, Perf | Open — needs async branch |
| R-02 | Sensitivity | Redis TTL = 60s | Performance | Confirmed — measured |
| R-03 | Tradeoff | Multi-region active-active | Avail+ / Cost-, Consist- | Accepted in ADR-014 |
| N-01 | Non-risk | JWT for auth | Security | OK — standard practice |
```
### Lightweight ATAM (modern, 2-day workshop)
```markdown
Day 1 AM: Business drivers + architecture walkthrough (2h)
Day 1 PM: Utility tree co-construction (3h)
Day 2 AM: Scenario analysis — top 5 (4h)
Day 2 PM: Risks/tradeoffs ledger + ADR drafts (3h)
Output: 1-page exec summary + per-scenario deep dives
```
### Tooling — Structurizr + ADR + LLM
```bash
# 1. Architecture in Structurizr DSL
# 2. ADRs in /docs/adr/*.md (adr-tools)
adr new "Use Redis cache for checkout reads"
# 3. LLM-assisted scenario brainstorm
claude --prompt "Given utility tree and arch, propose 10 stress scenarios"
# 4. CI gate — utility-tree.yml diff = ADR required
```
### CBAM extension (cost-benefit)
```python
# Cost-Benefit Analysis Method (Kazman, Asundi, Klein 2002)
def score(scenario):
benefit = scenario.utility * scenario.weight
cost = scenario.implementation_cost
return benefit / cost # ROI for prioritization
```
## 매 결정 기준
| 상황 | Method |
|---|---|
| Greenfield, high-stakes | Full ATAM (5-day) |
| Iteration / sprint review | Lightweight ATAM (1-2 day) |
| Single decision | ADR with trade-off section |
| Cost-aware prioritization | CBAM |
| Solo / startup | RFC + scenario list (informal) |
| Continuous | Fitness functions + ADR |
**기본값**: ADR-per-decision + lightweight ATAM 의 quarterly.
## 🔗 Graph
- 부모: [[Software Architecture]] · [[Quality Attributes]]
- 응용: [[ADR]] · [[RFC]] · [[Architecture_Refactor]]
- Adjacent: [[Architecture Evaluation (아키텍처 평가)]] · [[Architecture Review (아키텍처 및 설계 리뷰)]] · [[Architectural-Constraint-Enforcement]]
## 🤖 LLM 활용
**언제**: 매 utility tree 의 first-draft generation, 매 scenario 의 stress-test brainstorm, 매 risk ledger 의 categorization.
**언제 X**: 매 final risk acceptance — 매 stakeholder consensus 의 필수.
## ❌ 안티패턴
- **Theatre review**: 매 architect-only attendance — 매 stakeholder buy-in 의 X.
- **Scenario without measure**: 매 "fast" / "scalable" — 매 unfalsifiable.
- **No follow-up**: 매 risks 의 logged 의 forgotten — 매 ADR 의 link 의 필수.
- **One-time**: 매 architecture 의 evolves — 매 evaluation 의 also.
- **Skip business drivers**: 매 quality attributes 의 prioritization 의 wrong.
## 🧪 검증 / 중복
- Verified (Bass, Clements, Kazman — *Software Architecture in Practice* 4th ed; SEI tech reports CMU/SEI-2000-TR-004).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — utility tree + scenarios + risk ledger + lightweight ATAM |
@@ -0,0 +1,29 @@
---
category: Other
tags: [auto-wikified, technical-documentation, other]
title: Active Record Pattern vs Repository Pattern
description: "Active Record 패턴은 데이터베이스 모델의 관심사와 비즈니스 로직을 하나의 객체나 계층에 결합하여 처리하는 설계 방식이다 [1]."
last_updated: 2026-05-04
---
# Active Record Pattern vs Repository Pattern
## 📌 Brief Summary
Active Record 패턴은 데이터베이스 모델의 관심사와 비즈니스 로직을 하나의 객체나 계층에 결합하여 처리하는 설계 방식이다 [1]. 반면 Repository 패턴은 데이터 접근을 전담하는 저장소(Repository) 계층을 분리하고, 모델은 비즈니스 로직이 없는 단순한 객체(dumb models/DTOs)로 유지하는 상반된 접근 방식을 취한다 [1, 2]. 최근 소프트웨어 산업은 모델 중심이 아닌 기능(Feature)을 축으로 비즈니스 로직을 분리하기 위해 점차 Active Record에서 Repository 패턴으로 이동하는 추세를 보이고 있다 [1].
## 📖 Core Content
* **Active Record 패턴의 특성**
Active Record 패턴은 데이터베이스 모델 내에 데이터 처리와 비즈니스 로직을 함께 구현하는 방식이다 [1]. 과거에는 데이터베이스 관련 관심사를 단순화하여 비즈니스 로직을 직관적으로 표현할 수 있다는 장점이 있었으나, 점차 애플리케이션 규모가 커지고 성능 및 확장성 등 다양한 기술적 관심사가 추가되면서 단일 계층에 너무 많은 책임이 혼재되는 문제를 겪게 되었다 [1].
* **Repository 패턴의 특성 및 구현**
Repository 패턴은 데이터 접근은 오직 리포지토리를 통해서만 이루어지도록 강제한다 [2]. 이 패턴에서는 모델을 능동적인 객체가 아닌 '단순한 모델(dumb models)이나 DTO'로 정의하며, 실제 비즈니스 로직은 컨트롤러나 서비스 계층에서 담당하도록 관심사를 분리한다 [1].
Spring Boot 환경에서는 Spring Data JPA를 통해 Repository 패턴을 핵심적으로 활용하며, 메서드 이름에 따라 자동으로 쿼리를 생성해 데이터 접근에 필요한 보일러플레이트 코드를 크게 줄여준다 [3]. 이 방식은 관심사의 깔끔한 분리를 유지하면서도 복잡한 데이터베이스 쿼리를 원활히 지원하는 장점이 있다 [4].
## ⚖️ Trade-offs & Caveats
* **Active Record의 관심사 혼재와 부작용 위험**
Active Record 패턴을 유지하면서 Django의 시그널(Signals)과 같은 기능을 혼용할 경우, 비즈니스 로직이 예기치 않게 곳곳으로 스며들거나(creeping in) 보이지 않는 부수 효과(side-effects)를 발생시켜 시스템을 통제 불능 상태로 만들 수 있는 심각한 안티 패턴을 초래할 수 있다 [1, 5].
* **Repository 패턴의 계층 복잡성**
Repository 패턴을 적용하면 Controller → Service → Repository로 이어지는 간접 참조(indirection) 및 계층화가 강제되므로, 단순한 로직을 처리할 때도 불필요한 스캐폴딩이 늘어나 애플리케이션 구조가 복잡해질 수 있다 [6]. 따라서 무조건적인 도메인 모델링보다는 도메인의 복잡성이 이를 요구할 만큼 충분히 높을 때 도입하는 것이 권장된다 [2].
---
*Last updated: 2026-05-03*
@@ -0,0 +1,189 @@
---
id: wiki-2026-0508-alliance-동맹
title: Alliance (동맹)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Guild, Clan, Faction, 동맹]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [game-design, social-systems, mmo, architecture]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: Game backend (Colyseus, Nakama, custom)
---
# Alliance (동맹)
## 매 한 줄
> **"매 player-formed group — shared goals, shared resources, shared identity"**. 매 MMO/SLG 의 retention 핵심 system. 매 EverQuest guild (1999) → World of Warcraft guild (2004) → Lords Mobile/Rise of Kingdoms 동맹 (2017+). 매 2026 modern SLG (4X/RTS hybrid) 의 core loop driver — solo player retention < 7 days, alliance member retention > 90 days 의 typical metric.
## 매 핵심
### 매 구조
- **Membership tier**: Leader / Officers (R4/R5) / Members / Recruits.
- **State**: roster, treasury, buff inventory, war declarations, territory.
- **Permissions**: hierarchical RBAC — invite/kick/promote/demote/disband.
- **Lifecycle**: create → recruit → grow → war → decline → disband.
### 매 server-authoritative invariants
- 매 single alliance per player 의 enforcement (atomic).
- Member cap (typical 50100) — atomic check-and-insert.
- Treasury balance — race-free debit/credit (transactional).
- War state machine — pending/active/peace transitions.
### 매 응용
1. **SLG 4X game** (Lords Mobile pattern) — alliance buffs, rallies, KvK.
2. **MMO guild** (WoW pattern) — guild bank, calendar, perk levels.
3. **Mobile RPG clan** (Clash of Clans pattern) — clan wars, donations.
4. **Social fitness app** (Strava clubs) — challenges, leaderboards.
## 💻 패턴
### Schema (Postgres)
```sql
CREATE TABLE alliances (
id BIGSERIAL PRIMARY KEY,
tag VARCHAR(5) UNIQUE NOT NULL,
name VARCHAR(40) NOT NULL,
leader_id BIGINT NOT NULL REFERENCES players(id),
member_cap SMALLINT NOT NULL DEFAULT 50,
treasury_gold BIGINT NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE alliance_members (
player_id BIGINT PRIMARY KEY REFERENCES players(id),
alliance_id BIGINT NOT NULL REFERENCES alliances(id) ON DELETE CASCADE,
rank SMALLINT NOT NULL, -- 1=member..5=leader
joined_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX ON alliance_members (alliance_id);
```
### Atomic join (server)
```typescript
async function joinAlliance(playerId: bigint, allianceId: bigint) {
return await db.tx(async (t) => {
// 1. Player must not be in any alliance
const existing = await t.oneOrNone(
"SELECT 1 FROM alliance_members WHERE player_id=$1 FOR UPDATE", [playerId]);
if (existing) throw new Error("ALREADY_IN_ALLIANCE");
// 2. Member cap check (lock alliance row)
const a = await t.one(
"SELECT member_cap, (SELECT COUNT(*) FROM alliance_members WHERE alliance_id=$1)::int AS n " +
"FROM alliances WHERE id=$1 FOR UPDATE", [allianceId]);
if (a.n >= a.member_cap) throw new Error("ALLIANCE_FULL");
await t.none(
"INSERT INTO alliance_members(player_id, alliance_id, rank) VALUES($1,$2,1)",
[playerId, allianceId]);
});
}
```
### Permission check
```typescript
const PERMS = {
invite: 2, // R2+
kick: 3, // R3+
promote:4, // R4+
disband:5, // leader only
} as const;
function can(memberRank: number, action: keyof typeof PERMS): boolean {
return memberRank >= PERMS[action];
}
```
### Alliance chat (Redis pub/sub)
```typescript
// Publish
await redis.publish(`alliance:${allianceId}:chat`,
JSON.stringify({ from: playerId, msg, ts: Date.now() }));
// Subscribe (per connected client)
const sub = redis.duplicate();
await sub.subscribe(`alliance:${allianceId}:chat`, (raw) => {
ws.send(raw);
});
```
### War declaration state machine
```typescript
type WarState = "PEACE" | "PENDING" | "ACTIVE" | "COOLDOWN";
const transitions: Record<WarState, WarState[]> = {
PEACE: ["PENDING"],
PENDING: ["ACTIVE", "PEACE"],
ACTIVE: ["COOLDOWN"],
COOLDOWN: ["PEACE"],
};
function transition(from: WarState, to: WarState) {
if (!transitions[from].includes(to))
throw new Error(`INVALID_TRANSITION ${from}->${to}`);
}
```
### Treasury (idempotent donation)
```typescript
async function donate(playerId: bigint, amt: bigint, idemKey: string) {
await db.tx(async (t) => {
const dup = await t.oneOrNone(
"SELECT 1 FROM idempotency WHERE key=$1", [idemKey]);
if (dup) return;
await t.none("INSERT INTO idempotency(key) VALUES($1)", [idemKey]);
await t.none("UPDATE players SET gold = gold - $2 WHERE id=$1 AND gold >= $2", [playerId, amt]);
await t.none("UPDATE alliances SET treasury_gold = treasury_gold + $2 WHERE id=$1", [allianceId, amt]);
});
}
```
### Member roster cache invalidation
```typescript
async function onMembershipChange(allianceId: bigint) {
await redis.del(`alliance:${allianceId}:roster`);
await redis.publish(`alliance:${allianceId}:events`, JSON.stringify({type:"ROSTER_CHANGED"}));
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Casual mobile, < 30 members | Single-shard SQL, simple roster |
| MMO, 100+ members, real-time chat | Sharded SQL + Redis pub/sub |
| Cross-server alliance war (KvK) | Event-sourced log + global service |
| Persistent territory control | Server-authoritative grid + alliance ownership |
**기본값**: 매 Postgres alliance/member tables + Redis pub/sub for chat/presence + idempotent treasury operations.
## 🔗 Graph
- 변형: [[Guild]] · [[Clan]] · [[Faction]]
- Adjacent: [[Leaderboard]]
## 🤖 LLM 활용
**언제**: 매 long-session retention 의 game (MMO, SLG, persistent world), 매 social cooperation 의 core mechanic.
**언제 X**: 매 short-session arcade, 매 strict-PvP only without cooperation, 매 < 1k DAU 의 single-player feel.
## ❌ 안티패턴
- **Client-authoritative membership**: 매 cheat 의 trivial (forge join). 매 server-authoritative 만.
- **No member cap**: 매 mega-alliance dominance — 매 game balance 의 destruction.
- **Synchronous broadcast**: 매 large alliance (500+) 의 chat fan-out blocks. 매 async pub/sub 의 사용.
- **Disband without grace period**: 매 leader 의 grief vector. 매 24h cooldown.
## 🧪 검증 / 중복
- Verified (Lords Mobile design, EVE Online corporation system, WoW guild system, Clash of Clans clan system).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — full content (game alliance system architecture) |
@@ -0,0 +1,203 @@
---
id: wiki-2026-0508-ambient-declarations
title: Ambient Declarations
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [.d.ts, declare keyword, TypeScript ambient, Type definitions]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [typescript, types, declarations, dts, interop]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: TypeScript 5.7
---
# Ambient Declarations
## 매 한 줄
> **"매 type-only declarations — 매 describe shapes that exist elsewhere"**. 매 TypeScript (Anders Hejlsberg, 2012) 매 since v0.8 매 `.d.ts` files. 매 DefinitelyTyped (2014) → @types/* npm scope (2016) → TS 4.x package "exports" + types (2021) → TS 5.7 (2026 stable) 매 `--isolatedDeclarations` 매 fast .d.ts emit.
## 매 핵심
### 매 ambient 의 의미
- **Ambient**: 매 declaration only, 매 no implementation. 매 emit 매 not 매 produce JS.
- **`.d.ts` files**: 매 declarations only. 매 imports 매 type-erased.
- **`declare` keyword**: 매 inside `.ts` files 매 declare 매 ambient binding.
### 매 use cases
- Type 3rd-party JS library (no built-in types).
- Type global runtime (browser, Node, custom).
- Augment existing module/global.
- Distribute types separate from JS (npm "types" field).
- Emit minimal API surface from TS source.
### 매 응용
1. **@types/* packages** — DefinitelyTyped community types.
2. **Global augmentation** — extend `Window`, `process.env`.
3. **Module augmentation** — add methods to existing module's interface.
4. **Asset typing**`*.svg` `*.css` import as module.
## 💻 패턴
### Basic ambient module (3rd-party JS)
```typescript
// types/legacy-lib.d.ts
declare module "legacy-lib" {
export function greet(name: string): string;
export interface Config { timeout: number }
export default class Client {
constructor(cfg: Config);
send(msg: string): Promise<void>;
}
}
```
### Ambient global
```typescript
// types/globals.d.ts
declare global {
var __APP_VERSION__: string;
interface Window {
analytics?: { track(event: string, props?: object): void };
}
namespace NodeJS {
interface ProcessEnv {
DATABASE_URL: string;
REDIS_URL: string;
}
}
}
export {}; // 매 file 의 module 의 만듦 — augmentation 매 valid
```
### Module augmentation (extend existing)
```typescript
// add-toJSON.d.ts
import "express";
declare module "express" {
interface Request {
user?: { id: string; role: "admin" | "user" };
requestId: string;
}
}
// Now in any file: req.user is typed
```
### Asset module typing
```typescript
// assets.d.ts
declare module "*.svg" {
const url: string;
export default url;
}
declare module "*.css" {
const classes: { readonly [key: string]: string };
export default classes;
}
declare module "*.json" {
const value: unknown;
export default value;
}
```
### Triple-slash directive (legacy, still used)
```typescript
/// <reference types="node" />
/// <reference path="./vendor.d.ts" />
```
### `declare` inside .ts file
```typescript
// app.ts
declare const FEATURE_FLAGS: { newCheckout: boolean };
declare function gtag(cmd: string, ...args: unknown[]): void;
if (FEATURE_FLAGS.newCheckout) gtag("event", "view_new_checkout");
```
### Conditional types via ambient
```typescript
// react-augmentation.d.ts
import "react";
declare module "react" {
interface CSSProperties {
"--theme-color"?: string;
"--theme-radius"?: string;
}
}
// Now: <div style={{ "--theme-color": "blue" }}/> typechecks
```
### tsconfig declarations
```json
{
"compilerOptions": {
"declaration": true,
"declarationMap": true,
"emitDeclarationOnly": false,
"isolatedDeclarations": true,
"types": ["node", "vitest/globals"],
"typeRoots": ["./node_modules/@types", "./types"]
}
}
```
### Library author (publish .d.ts)
```json
// package.json
{
"name": "my-lib",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
}
}
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 3rd-party JS lib, no types | Check @types/lib first; else write `.d.ts` |
| Add field to req/res in Express/Fastify | Module augmentation |
| Type custom Vite/Webpack asset import | Wildcard module decl |
| Globals (browser/Node) | `declare global { ... }` + `export {}` |
| Library publish | TS source → emit .d.ts (declaration: true) |
**기본값**: 매 prefer @types/* package, 매 fall back 매 hand-written `.d.ts`, 매 augmentation 매 last resort (subtle to debug).
## 🔗 Graph
- 부모: [[TypeScript]] · [[TypeScript 타입 시스템 (TypeScript Type System)|Type System]]
- 변형: [[Global Augmentation]]
- 응용: [[DefinitelyTyped]]
- Adjacent: [[tsconfig.json]] · [[Conditional Types]]
## 🤖 LLM 활용
**언제**: 매 untyped JS interop, 매 global runtime typing, 매 library distribution, 매 framework extension points.
**언제 X**: 매 internal TS code (use regular `interface`/`type`), 매 enforcement need (declarations 매 erased — runtime check 매 separate).
## ❌ 안티패턴
- **`any` everywhere in .d.ts**: 매 type loss 의 propagation. 매 `unknown` + narrow.
- **Augmenting without `export {}`**: 매 file 매 script 의 treated, 매 augmentation silently fails.
- **Triple-slash in modern code**: 매 prefer `tsconfig "types"` array.
- **Global pollution**: 매 every helper 매 global 의 declare → namespace clashes.
## 🧪 검증 / 중복
- Verified (TypeScript Handbook "Declaration Files", DefinitelyTyped contribution guide, TS 5.7 release notes).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — full content (.d.ts, declare, augmentation patterns) |
@@ -0,0 +1,177 @@
---
id: wiki-2026-0508-apache-ignite
title: Apache Ignite
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Ignite, In-memory data grid, GridGain]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [in-memory, data-grid, distributed-cache, sql, compute-grid]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: java
framework: Apache Ignite 2.16
---
# Apache Ignite
## 매 한 줄
> **"매 distributed in-memory data grid + compute grid + ANSI SQL"**. 매 GridGain (2007) → Apache Ignite (2014, donated). 매 2026 modern stack 은 Ignite 2.16 (GA mid-2025) / Ignite 3.x (preview, 매 new architecture: RAFT-based, ANSI SQL-first, 매 GridGain 9 commercial). 매 Hazelcast / Redis 의 alternative — 매 SQL + ACID transactions 의 differentiator.
## 매 핵심
### 매 features
- **In-memory key-value cache** — partitioned (sharded) or replicated.
- **Distributed ANSI-99 SQL** — collocated joins, indexes, JDBC/ODBC.
- **ACID transactions** — pessimistic / optimistic, distributed two-phase commit.
- **Compute grid** — send code to data (Java/.NET/C++).
- **Service grid** — deploy stateful services across cluster.
- **Native persistence** — durable on-disk (since 2.1, 2017).
- **Streaming** — continuous queries, data streamer.
### 매 architecture
- **Topology**: server nodes + client/thin clients.
- **Affinity**: rendezvous hashing, partition-to-node assignment.
- **Backup**: synchronous/async backups per cache (RF=N).
- **Discovery**: TcpDiscoverySpi (multicast / static / Kubernetes / ZooKeeper).
- **Communication**: TcpCommunicationSpi.
### 매 응용
1. **Hot cache layer** — in front of Postgres/Oracle, sub-ms reads.
2. **Distributed SQL** — operational analytics across shards.
3. **Compute grid** — financial risk calc, ML feature scoring at data.
4. **Session storage** — JCache (JSR-107) compliant.
## 💻 패턴
### Cache config (Java)
```java
IgniteConfiguration cfg = new IgniteConfiguration();
CacheConfiguration<Long, Order> cc = new CacheConfiguration<>("orders");
cc.setCacheMode(CacheMode.PARTITIONED);
cc.setBackups(1);
cc.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
cc.setWriteSynchronizationMode(CacheWriteSynchronizationMode.PRIMARY_SYNC);
cc.setIndexedTypes(Long.class, Order.class);
cfg.setCacheConfiguration(cc);
Ignite ignite = Ignition.start(cfg);
IgniteCache<Long, Order> orders = ignite.cache("orders");
orders.put(1L, new Order(...));
```
### Distributed SQL
```java
SqlFieldsQuery q = new SqlFieldsQuery(
"SELECT o.id, c.name FROM \"orders\".Order o " +
"JOIN \"customers\".Customer c ON o.customerId = c.id " +
"WHERE o.status = ?")
.setArgs("paid");
try (var cur = orders.query(q)) {
for (List<?> row : cur) System.out.println(row);
}
```
### Affinity collocation (cross-cache JOIN performance)
```java
@QuerySqlField(index = true)
private Long customerId;
// Affinity key — rows with same customerId on same node
@AffinityKeyMapped
private Long customerId;
// Now JOIN orders ↔ customers stays node-local
```
### Transaction (pessimistic, repeatable read)
```java
try (Transaction tx = ignite.transactions().txStart(
TransactionConcurrency.PESSIMISTIC,
TransactionIsolation.REPEATABLE_READ)) {
Account from = accounts.get(fromId);
Account to = accounts.get(toId);
if (from.balance < amount) throw new RuntimeException("INSUFFICIENT");
from.balance -= amount; to.balance += amount;
accounts.put(fromId, from);
accounts.put(toId, to);
tx.commit();
}
```
### Compute grid (broadcast)
```java
ignite.compute().broadcast(() -> {
System.out.println("Hello from " + ignite.cluster().localNode().id());
});
// Send Lambda — Ignite peer-class-loads to all nodes
```
### Continuous query (CDC-like)
```java
ContinuousQuery<Long, Order> qry = new ContinuousQuery<>();
qry.setLocalListener(events -> {
for (CacheEntryEvent<? extends Long, ? extends Order> e : events)
System.out.println("Updated: " + e.getKey() + "" + e.getValue());
});
qry.setRemoteFilterFactory(() -> e -> e.getValue().getStatus().equals("paid"));
orders.query(qry);
```
### Native persistence
```java
DataStorageConfiguration ds = new DataStorageConfiguration();
ds.getDefaultDataRegionConfiguration().setPersistenceEnabled(true);
ds.setStoragePath("/var/ignite/persistence");
cfg.setDataStorageConfiguration(ds);
// Restart-safe; in-memory speed + durability
ignite.cluster().state(ClusterState.ACTIVE);
```
### Thin client (lightweight, no peer-class-loading)
```java
ClientConfiguration cc = new ClientConfiguration().setAddresses("ignite:10800");
try (IgniteClient c = Ignition.startClient(cc)) {
ClientCache<Long, Order> orders = c.getOrCreateCache("orders");
orders.put(1L, new Order(...));
}
```
## 매 결정 기준
| 상황 | Tool |
|---|---|
| Pure key-value cache, simple | Redis |
| K-V + distributed events, JVM | Hazelcast |
| K-V + ANSI SQL + ACID + compute grid | Ignite |
| In-process cache | Caffeine |
| Cloud-native managed | ElastiCache / Memorystore / GridGain Cloud |
**기본값**: 매 Redis 매 simple cache, 매 Ignite 매 SQL+ACID+compute integrated, 매 Hazelcast 매 JVM-native event-driven.
## 🔗 Graph
- 부모: [[In-Memory Data Grid]] · [[Distributed Cache]]
- 변형: [[GridGain]]
## 🤖 LLM 활용
**언제**: 매 sub-ms latency + SQL + ACID 의 simultaneous requirement, 매 compute-near-data, 매 JVM ecosystem.
**언제 X**: 매 simple cache only (Redis cheaper), 매 non-JVM stack (limited tooling), 매 small data (<10GB, single node fine).
## ❌ 안티패턴
- **No backups**: 매 node loss → data loss. 매 setBackups(≥1).
- **Cross-cache JOIN without affinity**: 매 network shuffle, 매 query 의 slow.
- **Synchronous replication everywhere**: 매 latency. 매 PRIMARY_SYNC + async backup balance.
- **Mixing partitioned + replicated joins carelessly**: 매 broadcast amplification.
## 🧪 검증 / 중복
- Verified (Apache Ignite docs 2.16, GridGain documentation, ASF Ignite 3.x roadmap).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — full content (Ignite cache, SQL, transactions, compute grid) |
@@ -0,0 +1,176 @@
---
id: wiki-2026-0508-append-only-log
title: Append-only Log
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Commit log, WAL, Event log, Immutable log]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [log, kafka, event-sourcing, wal, storage]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: java
framework: Kafka, Pulsar, Postgres WAL
---
# Append-only Log
## 매 한 줄
> **"매 sequence of immutable events — write once, read many"**. 매 database WAL (1980s) → distributed (LinkedIn Kafka 2011) → event sourcing 의 backbone. 매 2026 modern stack 은 Kafka 3.7 (KRaft, no ZK) / Redpanda (Raft, C++) / Pulsar 3.x (BookKeeper) / Postgres logical replication / WarpStream (S3-backed Kafka).
## 매 핵심
### 매 properties
- **Append-only**: 매 mutation 의 forbid. 매 corrections via new compensating event.
- **Ordered**: monotonic offset/sequence per partition.
- **Durable**: fsync, replicated (typical RF=3, ack=all).
- **Replayable**: consumers re-read from any offset.
- **Retention**: time-based, size-based, or compaction (key-based latest).
### 매 use cases
- **Database WAL** — Postgres pg_wal, MySQL binlog. Crash recovery.
- **Event sourcing** — domain events as source of truth, projections rebuild state.
- **CDC** — Debezium reads DB log → Kafka → consumers.
- **Stream processing** — Flink/Kafka Streams stateful aggregations.
- **Audit log** — tamper-evident with hash chain.
### 매 응용
1. **Kafka topic** — 7-day retention, multi-consumer fan-out.
2. **Event-sourced aggregate** — order state from order_events.
3. **Outbox pattern** — DB transaction + log entry → reliable event publish.
4. **Time-travel debugging** — replay from offset N.
## 💻 패턴
### Kafka producer (idempotent + transactional)
```java
Properties p = new Properties();
p.put("bootstrap.servers", "broker:9092");
p.put("enable.idempotence", "true");
p.put("acks", "all");
p.put("transactional.id", "orders-producer-1");
KafkaProducer<String,String> prod = new KafkaProducer<>(p, new StringSer(), new StringSer());
prod.initTransactions();
prod.beginTransaction();
prod.send(new ProducerRecord<>("orders", orderId, json));
prod.send(new ProducerRecord<>("audit", orderId, audit));
prod.commitTransaction();
```
### Consumer (offset commit after process)
```java
KafkaConsumer<String,String> c = new KafkaConsumer<>(props);
c.subscribe(List.of("orders"));
while (true) {
ConsumerRecords<String,String> recs = c.poll(Duration.ofSeconds(1));
for (var r : recs) processOrder(r.value());
c.commitSync(); // at-least-once
}
```
### Event sourcing aggregate
```typescript
type OrderEvent =
| { type: "Created", id: string, items: Item[] }
| { type: "Paid", amount: number }
| { type: "Shipped", trackingId: string };
function applyEvent(state: Order, e: OrderEvent): Order {
switch (e.type) {
case "Created": return { ...state, id: e.id, items: e.items, status: "pending" };
case "Paid": return { ...state, status: "paid", paidAmount: e.amount };
case "Shipped": return { ...state, status: "shipped", tracking: e.trackingId };
}
}
const state = events.reduce(applyEvent, {} as Order);
```
### Outbox pattern (Postgres + Debezium)
```sql
BEGIN;
INSERT INTO orders(id, status) VALUES ('abc', 'pending');
INSERT INTO outbox(aggregate_id, event_type, payload)
VALUES ('abc', 'OrderCreated', '{"id":"abc",...}'::jsonb);
COMMIT;
-- Debezium tails pg_wal → publishes outbox row → Kafka 'orders' topic
```
### Log compaction (Kafka)
```bash
# Topic config: cleanup.policy=compact
# Same key keeps only latest value → materialize current state
kafka-configs.sh --alter --entity-type topics --entity-name user-profiles \
--add-config cleanup.policy=compact,min.cleanable.dirty.ratio=0.1
```
### Hash-chained audit log
```python
import hashlib, json
def append(prev_hash: str, event: dict) -> tuple[str, dict]:
record = {"prev": prev_hash, "event": event, "ts": time.time()}
h = hashlib.sha256(json.dumps(record, sort_keys=True).encode()).hexdigest()
return h, {**record, "hash": h}
# Tamper-evident: any modification breaks chain
```
### Postgres logical replication slot
```sql
SELECT pg_create_logical_replication_slot('app_slot', 'pgoutput');
-- Stream WAL changes to consumer (CDC)
SELECT * FROM pg_logical_slot_get_changes('app_slot', NULL, NULL);
```
### Snapshot + tail (event sourcing optimization)
```typescript
async function loadAggregate(id: string): Promise<Order> {
const snap = await snapStore.get(id); // periodic snapshot
const events = await eventStore.read(id, snap?.version ?? 0);
return events.reduce(applyEvent, snap?.state ?? {});
}
```
## 매 결정 기준
| 상황 | System |
|---|---|
| High-throughput streaming, multi-consumer | Kafka / Redpanda |
| Geo-replicated, tiered storage | Pulsar / WarpStream |
| Event-sourced single service | EventStoreDB / Postgres + outbox |
| Database CDC | Debezium → Kafka |
| Tamper-evident audit | Hash-chain + signed |
**기본값**: 매 Kafka (or Redpanda for ops simplicity) 매 distributed log, 매 Postgres WAL + outbox 매 single-service.
## 🔗 Graph
- 부모: [[Distributed Systems]]
- 변형: [[Kafka]] · [[WAL]] · [[Event Store]]
- 응용: [[Event Sourcing]] · [[CDC]] · [[CQRS]]
- Adjacent: [[Stream-Processing-Architectures|Stream Processing]] · [[Idempotency]]
## 🤖 LLM 활용
**언제**: 매 audit/replay 요구, 매 multiple consumer/projection, 매 temporal queries, 매 reliable event publishing.
**언제 X**: 매 simple CRUD without history, 매 strong consistency snapshot only, 매 storage cost-sensitive (logs grow).
## ❌ 안티패턴
- **Mutating past events**: 매 invariant violation. 매 compensating event 의 emit.
- **Unbounded retention without compaction**: 매 storage explosion.
- **Synchronous replay on every read**: 매 latency. 매 snapshot + tail.
- **Single-partition Kafka topic**: 매 throughput cap. 매 partition by key.
## 🧪 검증 / 중복
- Verified (Jay Kreps "The Log" 2013, Kafka docs, Postgres WAL docs, Greg Young event sourcing).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — full content (Kafka, event sourcing, WAL, outbox) |
@@ -0,0 +1,201 @@
---
id: wiki-2026-0508-architectural-violations
title: Architectural Violations
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Architecture Erosion, Architecture Drift, Layer Violations, Dependency Violations]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [architecture, violations, erosion, drift, archunit]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: java/kotlin/typescript
framework: ArchUnit / Sonargraph / dependency-cruiser
---
# Architectural Violations
## 매 한 줄
> **"매 architectural violation 의 intended architecture 와 actual code 사이의 deviation"**. Perry & Wolf 의 *erosion* (decay over time) + *drift* (unauthorized addition) 의 distinguishing — 매 erosion 의 explicit decay, drift 의 silent. 매 modern detection 의 fitness function (ArchUnit, dep-cruiser, Sonargraph) + reflexion model — 매 manual review 의 too-late.
## 매 핵심
### 매 violation 의 종류
- **Layer violation**: domain → infrastructure (wrong direction).
- **Module violation**: one module imports private internals of another.
- **Dependency cycle**: A → B → C → A.
- **Convention violation**: `*Service` not in service package.
- **Forbidden API**: `java.util.Date`, `console.log` in production code.
- **Coupling violation**: too many afferent / efferent dependencies.
- **Cohesion violation**: feature smeared across many modules.
- **Cross-bounded-context leakage**: shared domain model between contexts.
### 매 detection mechanism
1. **Static structural**: ArchUnit, dep-cruiser, Sonargraph (parse + graph).
2. **Reflexion model**: actual graph diff with intended graph.
3. **Runtime**: trace analysis (OpenTelemetry) for unexpected service-to-service calls.
4. **Reviewer-driven**: ADR conformance check in PR.
5. **Visualization**: dependency matrix, sunburst, codecity.
### 매 lifecycle
1. **Detect** (CI fails or alert).
2. **Classify** (true violation vs intentional exception).
3. **Triage** (debt vs immediate fix).
4. **Fix** (refactor or update intended architecture / ADR).
5. **Prevent regression** (add fitness function).
## 💻 패턴
### Detect layer violation — ArchUnit
```kotlin
@AnalyzeClasses(packages = ["com.acme"], importOptions = [DoNotIncludeTests::class])
class LayerViolationTest {
@ArchTest
val domain_independent: ArchRule = noClasses()
.that().resideInAPackage("..domain..")
.should().dependOnClassesThat().resideInAnyPackage(
"..application..", "..infrastructure..", "..web..")
.because("Domain is the innermost layer (Hexagonal)")
@ArchTest
val no_repo_in_controller: ArchRule = noClasses()
.that().resideInAPackage("..web..")
.should().dependOnClassesThat().resideInAPackage("..persistence..")
}
```
### Detect cycle — dependency-cruiser (TS)
```bash
npx depcruise --validate .dependency-cruiser.cjs src \
--output-type err-html --output-to depgraph.html
# Exit 1 if cycles found; html visualizes offending edges
```
### Reflexion model — intended vs actual (jQAssistant + Cypher)
```cypher
// Intended: domain → no-deps; application → domain; infra → application
// Detect any class in :Domain depending on :Infra (forbidden)
MATCH (a:Class)-[:DEPENDS_ON]->(b:Class)
WHERE a.layer = "Domain" AND b.layer = "Infrastructure"
RETURN a.fqn AS violator, b.fqn AS forbidden
```
### Runtime violation — unauthorized service call (OpenTelemetry + Tempo)
```promql
# Alert if service A calls service C (intended only A→B, B→C)
sum(rate(traces_spanmetrics_calls_total{
client="service-a", server="service-c"
}[5m])) > 0
```
### Cyclomatic + afferent/efferent metric (Sonargraph)
```xml
<!-- sonargraph-architect rule -->
<architecture>
<layer name="Domain" />
<layer name="App" includes="Domain" />
<layer name="Infra" includes="App" />
<connector from="App" to="Domain" />
<connector from="Infra" to="App" />
<metric type="afferent_coupling" max="20" />
<metric type="cyclic_groups" max="0" />
</architecture>
```
### Triage workflow — annotate intentional exception
```kotlin
// When violation is *intended* (rare), document explicitly via ADR + suppress
@SuppressArchTest(
rule = "domain_independent",
reason = "ADR-0034: bridge to legacy DAO during 6-month migration",
expiresOn = "2026-12-01"
)
class LegacyBridgeAdapter { /* ... */ }
```
```kotlin
// Companion test enforces expiry
@ArchTest
val no_expired_suppressions: ArchRule = noClasses()
.should().beAnnotatedWith(SuppressArchTest::class.java)
.andShould(haveExpiredSuppression()) // custom condition
```
### Visualize violations — dependency matrix (D3)
```javascript
// scripts/depmatrix.mjs — render violation heatmap
import { cruise } from "dependency-cruiser";
import fs from "node:fs";
const r = await cruise(["src"], { ruleSet: require("./.dependency-cruiser.cjs") });
const violations = r.output.summary.violations;
const matrix = buildAdjacencyMatrix(r.output.modules, violations);
fs.writeFileSync("violations.json", JSON.stringify(matrix));
// Then render with d3-matrix or observable-plot
```
### CI gating with delta — only new violations fail
```bash
# Compare current vs main — fail PR only on new violations (not legacy debt)
npx depcruise src --config .dependency-cruiser.cjs --output-type json > head.json
git checkout main -- .
npx depcruise src --config .dependency-cruiser.cjs --output-type json > main.json
node scripts/diff-violations.mjs main.json head.json # exit 1 on new violations
```
### Erosion KPI dashboard (per service / quarter)
```sql
-- violations_history table (populated nightly by CI)
SELECT
service,
DATE_TRUNC('week', detected_at) AS wk,
COUNT(*) FILTER (WHERE severity='error') AS errs,
COUNT(*) FILTER (WHERE severity='warn') AS warns
FROM violations_history
WHERE detected_at > NOW() - INTERVAL '12 weeks'
GROUP BY service, wk
ORDER BY service, wk;
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| New violation detected in PR | Block merge until fixed or ADR exception added |
| Legacy debt — many existing violations | Baseline & gate on delta (no new) |
| Intentional bridge | Suppress + ADR + expiry date |
| Runtime call mismatch | Trace-based alerting + service mesh policy |
| Unclear if violation | Run reflexion model — document intended first |
**기본값**: ArchUnit/dep-cruiser at PR time + delta gating on legacy code + ADR-tracked suppressions with expiry.
## 🔗 Graph
- 부모: [[Software Architecture]] · [[Architectural-Constraint-Enforcement]]
- 변형: [[Architecture Erosion]] · [[Architecture Drift]]
- 응용: [[Architecture Review (아키텍처 및 설계 리뷰)]] · [[Architecture_Refactor]] · [[Technical Debt]]
- Adjacent: [[ArchUnit]] · [[OpenTelemetry]]
## 🤖 LLM 활용
**언제**: classify violation as erosion vs drift vs intentional, draft suppression ADR with expiry, generate refactor plan from violation report, summarize weekly violations dashboard for tech lead.
**언제 X**: do not blindly accept LLM "this violation is fine" — every suppression needs ADR + expiry; LLM judgment is suggestion, not authority.
## ❌ 안티패턴
- **Suppression without expiry**: permanent escape hatch — original intent lost.
- **No baseline**: blocking PRs on existing legacy violations buries team.
- **Documentation-only intended architecture**: cannot detect drift — no ground truth.
- **One-shot detection**: run once, never again — violations re-grow.
- **Fix-the-symptom**: rename file vs fix actual coupling.
- **Auto-suppress**: tool generates suppressions silently — true violations hidden.
## 🧪 검증 / 중복
- Verified (Perry & Wolf "Foundations for the Study of Software Architecture" 1992, Murphy "Reflexion Models" 1995, ArchUnit / Sonargraph / dependency-cruiser docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — erosion vs drift, reflexion model, delta gating |
@@ -0,0 +1,218 @@
---
id: wiki-2026-0508-architectural-constraint-enforce
title: Architectural Constraint Enforcement
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [archunit, dependency-cruiser, fitness-functions]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [architecture, fitness-functions, archunit, constraints]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: java
framework: archunit
---
# Architectural Constraint Enforcement
## 매 한 줄
> **"매 architecture 의 자동으로 enforce 한다"**. 매 ArchUnit (2018, Java/Kotlin), Dependency-Cruiser (JS/TS), NetArchTest (.NET), Konsist (Kotlin) 의 fitness function 의 CI 통합. 매 *Building Evolutionary Architectures* (Ford, Parsons, Kua, 2017; 2nd ed 2023) 의 paradigm.
## 매 핵심
### 매 enforced rules (typical)
- **Layer dependency**: 매 controller → service → repository — 매 reverse 의 X.
- **Package isolation**: `domain` 의 framework import 의 X.
- **Naming**: 매 `*Service` class 의 `service` package 의 only.
- **Cyclic dependency**: 매 always X.
- **API surface**: 매 `internal/*` 의 external module 의 import 의 X.
### 매 fitness function categories (Ford)
- **Atomic vs Holistic**: single attribute / system-wide.
- **Triggered vs Continual**: CI gate / runtime probe.
- **Static vs Dynamic**: code analysis / runtime metric.
- **Automated vs Manual**: prefer automated.
### 매 응용
1. CI gate — 매 PR 의 violation 의 block.
2. Refactor safety — 매 large refactor 의 invariant 의 hold.
3. Onboarding — 매 implicit rule 의 explicit code 의 됨.
## 💻 패턴
### ArchUnit — layer enforcement (Java)
```java
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.*;
import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.lang.ArchRule;
@AnalyzeClasses(packages = "com.acme.banking")
class LayerArchTest {
@ArchTest
static final ArchRule controllers_only_call_services =
classes().that().resideInAPackage("..controller..")
.should().onlyDependOnClassesThat()
.resideInAnyPackage("..controller..", "..service..", "java..", "org.springframework..");
@ArchTest
static final ArchRule no_cycles =
slices().matching("..banking.(*)..").should().beFreeOfCycles();
@ArchTest
static final ArchRule services_named_correctly =
classes().that().resideInAPackage("..service..")
.and().areNotInterfaces()
.should().haveSimpleNameEndingWith("Service");
}
```
### Dependency-Cruiser (TypeScript)
```js
// .dependency-cruiser.cjs
module.exports = {
forbidden: [
{
name: 'no-circular',
severity: 'error',
from: {},
to: { circular: true }
},
{
name: 'domain-pure',
severity: 'error',
from: { path: '^src/domain' },
to: { path: '^(src/infra|node_modules/express)' }
},
{
name: 'no-test-in-prod',
severity: 'error',
from: { pathNot: '\\.test\\.ts$' },
to: { path: '\\.test\\.ts$' }
}
],
options: { tsConfig: { fileName: 'tsconfig.json' } }
};
```
```bash
npx depcruise src --config .dependency-cruiser.cjs
npx depcruise src --output-type dot | dot -T svg > deps.svg
```
### NetArchTest (.NET 8)
```csharp
using NetArchTest.Rules;
using Xunit;
public class ArchitectureTests {
[Fact]
public void Domain_ShouldNotDependOnInfrastructure() {
var result = Types.InAssembly(typeof(Domain.Marker).Assembly)
.That().ResideInNamespace("Acme.Domain")
.ShouldNot().HaveDependencyOn("Acme.Infrastructure")
.GetResult();
Assert.True(result.IsSuccessful, string.Join(",", result.FailingTypeNames ?? []));
}
}
```
### Konsist (Kotlin)
```kotlin
import com.lemonappdev.konsist.api.Konsist
import com.lemonappdev.konsist.api.verify.assertTrue
class CleanArchitectureTest {
@Test
fun `domain layer does not depend on data layer`() {
Konsist.scopeFromProduction()
.files
.filter { it.packagee?.fullyQualifiedName?.contains("domain") == true }
.assertTrue { file ->
file.imports.none { it.name.contains(".data.") }
}
}
}
```
### Go — go-arch-lint
```yaml
# .go-arch-lint.yml
version: 3
workdir: internal
components:
domain: { in: domain/** }
app: { in: app/** }
infra: { in: infra/** }
deps:
domain: {}
app: { mayDependOn: [domain] }
infra: { mayDependOn: [domain, app] }
```
### Python — import-linter
```ini
# .importlinter
[importlinter]
root_package = acme
[importlinter:contract:layers]
name = Layered architecture
type = layers
layers =
acme.api
acme.service
acme.domain
```
### CI integration (GitHub Actions)
```yaml
- name: Architecture tests
run: |
./gradlew archTest
npx depcruise src --config .dependency-cruiser.cjs
lint-imports
```
## 매 결정 기준
| Stack | Tool |
|---|---|
| Java/Kotlin | ArchUnit, Konsist |
| JS/TS | Dependency-Cruiser, eslint-plugin-boundaries |
| .NET | NetArchTest |
| Go | go-arch-lint |
| Python | import-linter |
| Polyglot | Sonargraph, Structure101 (commercial) |
**기본값**: 매 ArchUnit (JVM) / Dependency-Cruiser (Node) — 매 OSS + CI-first.
## 🔗 Graph
- 부모: [[Software Architecture]] · [[Fitness Functions]]
- 변형: [[Static-Analysis]]
- 응용: [[CI CD]] · [[Architecture_Refactor]]
- Adjacent: [[Architecture Erosion (아키텍처 침식)]] · [[Modular Monolith]]
## 🤖 LLM 활용
**언제**: 매 plain English rule → ArchUnit/depcruise config 의 translation, 매 violation message 의 fix suggestion.
**언제 X**: 매 architecture 의 design 의 LLM-only delegation — 매 human ownership 의 필수.
## ❌ 안티패턴
- **Test exists, never runs**: 매 CI 의 not wired — 매 dead rule.
- **Over-broad rule**: 매 100% violations 의 noise — 매 graduated rollback (allowlist).
- **Rule without rationale**: 매 ADR-less rule — 매 future deletion 의 blocker.
- **Ignore-list explosion**: 매 exception 의 100+ — 매 architecture 의 already eroded 의 sign.
## 🧪 검증 / 중복
- Verified (Ford et al., *Building Evolutionary Architectures* 2nd ed; ArchUnit user guide).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — fitness functions + ArchUnit/depcruise/NetArchTest patterns |
@@ -0,0 +1,197 @@
---
id: wiki-2026-0508-architecture-description-아키텍처-명세
title: Architecture Description (아키텍처 명세)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Architecture Description, 아키텍처 명세, AD, Software Architecture Document, SAD]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [architecture, documentation, c4, 4plus1-view, iso-42010]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: markdown
framework: Structurizr / C4 / arc42
---
# Architecture Description (아키텍처 명세)
## 매 한 줄
> **"매 architecture description 은 system 의 multiple stakeholder concern 을 multiple view 로 documenting"**. ISO/IEC/IEEE 42010 standard 기반 — 매 stakeholder, concern, viewpoint, view, model 의 conceptual chain. 매 modern practice 는 4+1 (Kruchten) → C4 (Brown) → arc42 (Starke) → DAR (Decision Records) 의 layered combination.
## 매 핵심
### 매 ISO/IEC/IEEE 42010 framework
- **Stakeholder**: dev, ops, security, PM, customer — 매 다른 concern.
- **Concern**: performance, security, deployability, cost, regulatory.
- **Viewpoint**: concern 의 lens (e.g., "security viewpoint", "deployment viewpoint").
- **View**: viewpoint 적용 결과의 specific artifact.
- **Model**: view 안의 box-and-line / sequence / state diagram.
### 매 4+1 view (Kruchten 1995, still relevant)
- **Logical view**: domain model, class, package — dev concern.
- **Process view**: runtime behavior, threading, concurrency — perf concern.
- **Development view**: module, layer, build — dev productivity.
- **Physical view**: deployment topology — ops concern.
- **+1 Scenario**: use cases tying 4 views together.
### 매 C4 model (Simon Brown, modern default)
1. **Context (L1)**: system + external actor/system — non-technical stakeholder 용.
2. **Container (L2)**: deployable unit (web app, API, DB) — tech overview.
3. **Component (L3)**: container 내부 module — dev 용.
4. **Code (L4, optional)**: class diagram — auto-gen, rarely manual.
## 💻 패턴
### Structurizr DSL (modern C4 standard, 2026)
```dsl
workspace "BankingApp" {
model {
customer = person "Customer" "A bank customer"
bankingSystem = softwareSystem "Internet Banking" {
webApp = container "Web App" "React SPA" "TypeScript/React"
api = container "API" "REST backend" "Kotlin/Spring"
db = container "Database" "Customer + tx data" "PostgreSQL 16"
webApp -> api "Calls" "HTTPS/JSON"
api -> db "Reads/writes" "JDBC"
}
customer -> webApp "Uses" "HTTPS"
}
views {
systemContext bankingSystem { include * autoLayout }
container bankingSystem { include * autoLayout }
theme default
}
}
```
### arc42 template skeleton (Markdown, 12 sections)
```markdown
# 1. Introduction & Goals
## 1.1 Requirements Overview
## 1.2 Quality Goals (top 3-5)
## 1.3 Stakeholders
# 2. Architecture Constraints
# 3. Context & Scope (C4 L1 here)
# 4. Solution Strategy
# 5. Building Block View (C4 L2/L3)
# 6. Runtime View (sequence / activity)
# 7. Deployment View
# 8. Crosscutting Concepts (security, logging, i18n)
# 9. Architecture Decisions (link to ADRs)
# 10. Quality Requirements (scenarios)
# 11. Risks & Technical Debt
# 12. Glossary
```
### ADR (Architecture Decision Record, Michael Nygard format)
```markdown
# ADR-0042: Use PostgreSQL over MongoDB for tx store
## Status
Accepted (2026-04-15) — supersedes ADR-0021.
## Context
Transactional integrity 의 critical. Document flexibility 의 secondary.
PostgreSQL 16 의 JSONB columns 의 hybrid 의 enable.
## Decision
PostgreSQL 16 with JSONB for flexible attributes.
## Consequences
+ ACID guarantees, mature tooling, strong ecosystem.
- Schema migrations more rigid than Mongo.
- Team needs PG expertise (training budget allocated).
```
### Mermaid C4 diagram (lightweight, GitHub-native)
```mermaid
C4Context
title System Context — Banking
Person(customer, "Customer")
System(banking, "Banking System", "Online banking")
System_Ext(email, "Email System", "SMTP")
Rel(customer, banking, "Uses", "HTTPS")
Rel(banking, email, "Sends notifications", "SMTP")
```
### Architecture-as-code: PlantUML C4 macro
```plantuml
@startuml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml
Person(user, "User")
System_Boundary(c1, "App") {
Container(spa, "SPA", "React 19")
Container(api, "API", "Kotlin/Ktor")
ContainerDb(db, "DB", "PostgreSQL 16")
}
Rel(user, spa, "Uses", "HTTPS")
Rel(spa, api, "JSON/REST")
Rel(api, db, "JDBC")
@enduml
```
### Quality scenario (ATAM-style, embeddable in AD)
```yaml
scenario: "API survives 10x traffic spike"
source: External users
stimulus: Sudden 10x request burst
artifact: API container
environment: Production, normal ops
response: Auto-scale, no errors >0.1%
response_measure:
- p99 latency < 800ms
- error_rate < 0.1%
- autoscale_lag < 60s
```
### Living docs — auto-extract from code (jQAssistant + Structurizr)
```bash
# Generate Structurizr workspace from code annotations
./gradlew structurizrExport
structurizr-cli push -workspace workspace.dsl \
-id $WORKSPACE_ID -key $API_KEY -secret $API_SECRET
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Greenfield, small-mid team | C4 + arc42 + ADR |
| Enterprise, regulatory | ISO 42010 strict + 4+1 |
| OSS project | Mermaid C4 in README |
| Microservices, many teams | Structurizr DSL + ADR per service |
| Legacy reverse-engineered | Auto-gen (jQAssistant) + manual context |
**기본값**: C4 (Structurizr DSL) + arc42 sections + ADR — 매 modern combination.
## 🔗 Graph
- 부모: [[Software Architecture]]
- 변형: [[C4 Model (Architecture Documentation)]] · [[arc42]]
- 응용: [[Architecture_Diagramming_Standards]] · [[Architecture Review (아키텍처 및 설계 리뷰)]]
## 🤖 LLM 활용
**언제**: bootstrap arc42 template from a codebase scan, generate C4 Container diagrams from package structure, draft ADR Context/Consequences from PR descriptions.
**언제 X**: do not let an LLM author quality scenarios without measurable response criteria — vague AI-generated "should be fast" fails ATAM review.
## ❌ 안티패턴
- **Diagram-only AD**: pictures without prose context — stakeholder cannot infer intent.
- **One-view-fits-all**: single deployment diagram trying to satisfy security, perf, dev concerns simultaneously.
- **Stale Visio**: AD frozen on day 1, drifts from implementation within 6 months.
- **Pseudo-UML**: ad-hoc boxes labeled "UML" with no notation discipline.
- **Decision-less AD**: structures documented without WHY — readers cannot evaluate tradeoffs.
## 🧪 검증 / 중복
- Verified (ISO/IEC/IEEE 42010:2022, Kruchten 1995, Brown C4 spec, Starke arc42 v8.2).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — full AD spec with C4/4+1/arc42/ADR patterns |
@@ -0,0 +1,188 @@
---
id: wiki-2026-0508-architecture-diagramming-standar
title: Architecture Diagramming Standards
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [c4-model, arch-diagrams]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [architecture, diagrams, c4, documentation]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: mermaid
framework: c4-plantuml
---
# Architecture Diagramming Standards
## 매 한 줄
> **"매 diagram 의 audience 의 결정한다"**. 매 C4 model (Simon Brown, 2018) 의 Context → Container → Component → Code 의 4-level zoom 의 default standard 의 됨. 매 2026 의 PlantUML + Mermaid + Structurizr DSL 의 most-used toolchain.
## 매 핵심
### 매 C4 Model levels
- **Level 1 — System Context**: 매 system + users + external systems. 매 non-technical audience.
- **Level 2 — Container**: 매 deployable units (web app, DB, queue). 매 technical overview.
- **Level 3 — Component**: 매 container 안의 logical components. 매 dev team.
- **Level 4 — Code**: 매 class diagram (rarely used — 매 IDE 의 generation 의 default).
### 매 supplementary diagrams
- **Sequence**: 매 request flow / interaction.
- **Deployment**: 매 infra topology (k8s, regions).
- **Dynamic**: 매 runtime view, message sequence.
- **State**: 매 entity lifecycle.
### 매 응용
1. ADR 의 embedded diagram — 매 context.
2. Onboarding 의 system overview.
3. Incident postmortem 의 affected component highlight.
## 💻 패턴
### C4 Context (Mermaid)
```mermaid
C4Context
title System Context for Banking App
Person(customer, "Customer", "Bank customer with accounts")
System(banking, "Internet Banking", "Allows customers to view info")
System_Ext(mainframe, "Mainframe", "Stores account, txn info")
System_Ext(email, "Email System", "SMTP relay")
Rel(customer, banking, "Uses", "HTTPS")
Rel(banking, mainframe, "Reads/writes", "XML/HTTPS")
Rel(banking, email, "Sends emails", "SMTP")
```
### C4 Container (PlantUML + C4-PlantUML)
```plantuml
@startuml
!include <C4/C4_Container>
Person(user, "User")
System_Boundary(c1, "Banking System") {
Container(spa, "SPA", "React/TS", "UI")
Container(api, "API", "Go/Gin", "JSON/HTTPS")
ContainerDb(db, "Database", "Postgres 17", "Customers, accounts")
Container(worker, "Worker", "Go", "Async jobs")
ContainerQueue(mq, "Queue", "NATS JetStream")
}
Rel(user, spa, "Uses", "HTTPS")
Rel(spa, api, "Calls", "JSON/HTTPS")
Rel(api, db, "Reads/writes")
Rel(api, mq, "Publishes")
Rel(worker, mq, "Consumes")
@enduml
```
### Structurizr DSL (workspace-as-code)
```
workspace "Banking" {
model {
user = person "Customer"
bank = softwareSystem "Banking" {
spa = container "SPA" "React/TS"
api = container "API" "Go/Gin"
db = container "Database" "Postgres 17" "Database"
}
user -> spa "Uses"
spa -> api "JSON/HTTPS"
api -> db "SQL"
}
views {
container bank "Containers" { include * autolayout lr }
theme default
}
}
```
### Sequence (Mermaid)
```mermaid
sequenceDiagram
actor U as User
participant S as SPA
participant A as API
participant D as DB
U->>S: Click "Pay"
S->>A: POST /payments
A->>D: BEGIN; INSERT; COMMIT
A-->>S: 201 Created
S-->>U: Success toast
```
### Deployment (Mermaid)
```mermaid
flowchart LR
subgraph k8s[Kubernetes / us-east-1]
api[API Pods x3]
worker[Worker Pods x2]
end
subgraph rds[RDS]
pg[(Postgres 17 Multi-AZ)]
end
ALB --> api
api --> pg
worker --> pg
worker --> SQS
```
### Diagrams as code (Python diagrams lib)
```python
from diagrams import Diagram, Cluster
from diagrams.aws.compute import ECS
from diagrams.aws.database import RDS
from diagrams.aws.network import ELB
with Diagram("Web", show=False, direction="LR"):
lb = ELB("lb")
with Cluster("Services"):
svc = [ECS("svc1"), ECS("svc2")]
db = RDS("primary")
lb >> svc >> db
```
### Auto-generated from infra (Terraform → diagram)
```bash
# Inframap / Pluralith / Cloudcraft import
terraform graph | dot -Tpng > infra.png
inframap generate terraform.tfstate | dot -Tpng > clean.png
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Quick sketch | Excalidraw / Whiteboard |
| Reusable, version-controlled | Mermaid (md-embedded) |
| Strict C4 + theming | Structurizr DSL |
| Cloud infra reality | Terraform → Inframap |
| Slide deck / exec | PlantUML + C4 theme + export |
**기본값**: Mermaid (C4 plugin) — 매 GitHub/Obsidian native rendering.
## 🔗 Graph
- 부모: [[Software Architecture]]
- 변형: [[ADR]] · [[RFC]]
- 응용: [[Onboarding]] · [[Postmortem]]
- Adjacent: [[Architecture Review (아키텍처 및 설계 리뷰)]] · [[Architecture_Refactor]]
## 🤖 LLM 활용
**언제**: text spec → Mermaid/PlantUML 의 generation, code → C4 inference.
**언제 X**: production diagram 의 unverified auto-generation — 매 hallucinated component 의 risk.
## ❌ 안티패턴
- **Box-and-line soup**: 매 layer/audience 의 mix 의 unreadable diagram.
- **Stale .png in repo**: 매 source-less binary — 매 update 의 X. Mermaid/DSL 의 사용.
- **Over-leveling**: 매 Level 4 (Code) 의 manually 의 maintain — 매 IDE 의 generate.
- **No legend**: 매 shape/color semantics 의 없는 diagram — 매 reader 의 confusion.
## 🧪 검증 / 중복
- Verified (Simon Brown, *Software Architecture for Developers*; c4model.com).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — C4 model + Mermaid/Structurizr/diagrams.py patterns |
@@ -0,0 +1,198 @@
---
id: wiki-2026-0508-architecture-refactor
title: Architecture Refactor
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [strangler-fig, big-bang-rewrite, modernization]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [architecture, refactor, strangler-fig, modernization]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: polyglot
framework: strangler-fig
---
# Architecture Refactor
## 매 한 줄
> **"매 incremental 의 always wins"**. 매 architecture refactor 의 default approach 의 Martin Fowler 의 Strangler Fig (2004) — 매 old system 의 around 의 new system 의 gradual 의 grow. 매 big-bang rewrite 의 historically failure rate >70% (Ousterhout, Brooks). 매 2026 의 typical pattern: 매 monolith → modular monolith → selective service extraction.
## 매 핵심
### 매 refactor strategies
- **Strangler Fig**: 매 facade 의 routing — 매 traffic 의 incrementally 의 new system 의 redirect.
- **Branch by Abstraction**: 매 abstraction layer 의 introduce — 매 dual 의 implementation — 매 old 의 remove.
- **Parallel Run**: 매 old + new 의 동시 실행 — 매 output 의 compare.
- **Big Bang Rewrite**: 매 last resort — 매 only 매 system 의 small + scope 의 frozen 의 가능.
### 매 refactor 의 prerequisite
- **Test coverage**: 매 characterization tests (Feathers) 의 minimum.
- **Observability**: 매 metrics + traces 의 before/after diff.
- **Feature flag**: 매 reversibility 의 prerequisite.
- **ADR**: 매 decision rationale 의 documented.
### 매 응용
1. Monolith → modular monolith — 매 module boundary 의 enforce (ArchUnit).
2. Service extraction — 매 bounded context 의 따라.
3. Database split — 매 most expensive — 매 last 의 do.
4. Framework upgrade — 매 incremental migration.
## 💻 패턴
### Strangler Fig — Nginx routing facade
```nginx
upstream legacy { server legacy.internal:8080; }
upstream new { server new.internal:8080; }
server {
listen 443 ssl;
# New endpoints — gradual rollout
location /api/v2/orders { proxy_pass http://new; }
location /api/v2/users { proxy_pass http://new; }
# Everything else still legacy
location / { proxy_pass http://legacy; }
}
```
### Branch by Abstraction (Java)
```java
// Step 1 — extract interface
interface PaymentGateway {
Receipt charge(Order o);
}
// Step 2 — wrap legacy
class LegacyStripeGateway implements PaymentGateway { /* ... */ }
// Step 3 — new impl behind flag
class AdyenGateway implements PaymentGateway { /* ... */ }
// Step 4 — feature-flag pick
class GatewayFactory {
PaymentGateway pick(String tenant) {
return flags.isOn("adyen", tenant)
? new AdyenGateway()
: new LegacyStripeGateway();
}
}
// Step 5 — once 100% rollout, delete LegacyStripeGateway
```
### Parallel Run (shadow traffic)
```ts
async function chargeShadow(order: Order): Promise<Receipt> {
const [primary, shadow] = await Promise.allSettled([
legacy.charge(order),
newImpl.charge(order) // never persists, just observes
]);
if (shadow.status === 'fulfilled' && primary.status === 'fulfilled') {
diff.record('charge', primary.value, shadow.value);
}
return primary.status === 'fulfilled' ? primary.value : Promise.reject(primary.reason);
}
```
### Database Strangling — dual write + read switch
```python
# Phase 1: dual write
def save_order(o: Order):
legacy_db.insert(o)
try:
new_db.insert(o)
except Exception as e:
log.warn("shadow write failed", e=e)
# Phase 2: dual read + diff
def get_order(id: str):
a = legacy_db.get(id)
b = new_db.get(id)
if a != b: metrics.increment("order.read.diverge")
return a # legacy still source of truth
# Phase 3: flip read source
def get_order(id: str):
return new_db.get(id)
# Phase 4: stop legacy write, decommission
```
### Module extraction (modular monolith → service)
```bash
# 1. Codify module boundary first (ArchUnit)
# 2. Replace direct calls with in-process interface
# 3. Add feature flag: in-process vs HTTP/gRPC
# 4. Deploy as separate process behind flag
# 5. Remove in-process path
```
### Characterization test (Feathers)
```python
import json, pytest
@pytest.mark.parametrize("fixture", load_fixtures("legacy_outputs/*.json"))
def test_legacy_behavior_preserved(fixture):
inputs = fixture["input"]
expected = fixture["legacy_output"]
actual = new_impl.run(**inputs)
assert actual == expected, f"divergence: {fixture['id']}"
```
### Refactor scoreboard (CI)
```yaml
# refactor-progress.yml — auto-generated dashboard
metrics:
- name: legacy-endpoints-remaining
cmd: grep -r "@legacy" src/ | wc -l
- name: new-coverage
cmd: jacoco --module=new-impl
- name: traffic-on-new
promql: sum(rate(http_requests_total{service="new"}[5m]))
/ sum(rate(http_requests_total[5m]))
```
## 매 결정 기준
| 상황 | Strategy |
|---|---|
| Active legacy + traffic | Strangler Fig |
| Library/abstraction swap | Branch by Abstraction |
| Risk-critical (payment, billing) | Parallel Run |
| DB schema change | Dual-write + flip read |
| Tiny system, frozen scope | Big Bang (rare) |
| Distributed monolith | Reverse first → modular monolith → extract |
**기본값**: Strangler Fig + feature flag + parallel-run on critical paths.
## 🔗 Graph
- 부모: [[Software Architecture]] · [[Refactoring_Best_Practices|Refactoring]]
- 변형: [[Strangler-Fig]] · [[Branch-by-Abstraction]]
- 응용: [[Modular Monolith]] · [[Microservices]]
- Adjacent: [[Architecture Erosion (아키텍처 침식)]] · [[Architectural-Constraint-Enforcement]] · [[Architecture Review (아키텍처 및 설계 리뷰)]]
## 🤖 LLM 활용
**언제**: 매 legacy code → modern equivalent translation, 매 codemod plan generation, 매 ADR draft.
**언제 X**: 매 production cutover decision — 매 human + traffic data 의 필수.
## ❌ 안티패턴
- **Big bang rewrite**: 매 70%+ failure rate — 매 last resort.
- **Refactor without tests**: 매 silent regression 의 guarantee.
- **No flag, no rollback**: 매 forward-only deploy — 매 incident magnification.
- **Premature service extraction**: 매 distributed monolith 의 worst-of-both.
- **Stop midway**: 매 두 system 의 forever maintain — 매 cost 의 doubled.
## 🧪 검증 / 중복
- Verified (Fowler — *StranglerFigApplication*; Feathers — *Working Effectively with Legacy Code*; Newman — *Monolith to Microservices*).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Strangler Fig + Branch-by-Abstraction + parallel-run patterns |
@@ -0,0 +1,203 @@
---
id: wiki-2026-0508-arrangement-and-composition
title: Arrangement and Composition
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [composition-over-inheritance, function-composition, ui-composition]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [composition, design, architecture, functional]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: react
---
# Arrangement and Composition
## 매 한 줄
> **"매 small piece 의 arrange 의 emergent capability 의 만든다"**. 매 *Design Patterns* (GoF, 1994) 의 "favor composition over inheritance" 의 most-cited principle. 매 2026 의 React Server Components, Unix pipes, fp-ts pipe, kubernetes operator composition 의 same idea 의 different incarnation.
## 매 핵심
### 매 composition modes
- **Function composition**: `f ∘ g` — output 의 input 의 chain.
- **Object composition**: 매 has-a > is-a — delegation, mixin, trait.
- **Component composition**: 매 React/Vue children, slot. 매 layout 의 declarative.
- **Process composition**: 매 Unix pipes, k8s sidecar, DAG (Airflow).
- **Type composition**: 매 union, intersection, generics.
### 매 arrangement axes
- **Horizontal**: 매 sibling 의 parallel — fan-out / fan-in.
- **Vertical**: 매 layer / pipeline — sequential.
- **Tree**: 매 hierarchy — 매 component tree / DOM.
- **Graph**: 매 arbitrary edges — 매 dataflow / DAG.
### 매 응용
1. UI — 매 component slot, render prop, children-as-function.
2. Data pipeline — 매 dbt model graph, Airflow DAG.
3. Function-level — 매 pipe / compose / Result.flatMap.
4. Service mesh — 매 sidecar composition (Envoy + app).
## 💻 패턴
### Function composition (TypeScript / fp-ts)
```ts
import { pipe, flow } from 'fp-ts/function';
const trim = (s: string) => s.trim();
const lower = (s: string) => s.toLowerCase();
const slug = (s: string) => s.replace(/\s+/g, '-');
const slugify = flow(trim, lower, slug); // point-free
const out = pipe(' Hello World ', trim, lower, slug); // value-first
console.log(slugify(' Hello World ')); // "hello-world"
```
### Composition over inheritance (Go — embedding)
```go
type Logger struct{ prefix string }
func (l Logger) Log(msg string) { fmt.Println(l.prefix, msg) }
type Counter struct{ n int }
func (c *Counter) Inc() { c.n++ }
// HTTP server composes both — no inheritance
type Server struct {
Logger // embedded → Server.Log() works
*Counter // embedded pointer
addr string
}
s := &Server{Logger: Logger{"[srv]"}, Counter: &Counter{}, addr: ":8080"}
s.Log("starting"); s.Inc()
```
### React component composition
```tsx
// "Slot" composition — children as primary API
function Card({ header, footer, children }: {
header?: ReactNode; footer?: ReactNode; children: ReactNode;
}) {
return (
<div className="card">
{header && <header>{header}</header>}
<main>{children}</main>
{footer && <footer>{footer}</footer>}
</div>
);
}
<Card
header={<h2>Order #1234</h2>}
footer={<button>Cancel</button>}
>
<OrderDetails id="1234" />
</Card>
```
### Higher-order component / wrapper composition
```tsx
const withAuth = <P,>(C: ComponentType<P>) =>
(props: P) => useUser() ? <C {...props} /> : <Login />;
const withLogging = <P,>(C: ComponentType<P>, name: string) =>
(props: P) => { console.log(name, props); return <C {...props} />; };
// Compose
const Page = withAuth(withLogging(Dashboard, 'Dashboard'));
```
### Unix pipes (process composition)
```bash
cat access.log \
| grep '\.html"' \
| awk '{print $7}' \
| sort \
| uniq -c \
| sort -rn \
| head -20
```
### DAG composition (Airflow / Dagster)
```python
from dagster import asset
@asset
def raw_orders(): return load_csv("orders.csv")
@asset
def cleaned_orders(raw_orders): return raw_orders.dropna()
@asset
def daily_revenue(cleaned_orders):
return cleaned_orders.groupby("day")["total"].sum()
# Dagster builds DAG from inputs → outputs automatically
```
### Type composition (TypeScript)
```ts
type Timestamped = { createdAt: Date; updatedAt: Date };
type Identified = { id: string };
type Soft Deletable = { deletedAt: Date | null };
// Intersection composition
type Entity<T> = T & Identified & Timestamped & SoftDeletable;
type User = Entity<{ email: string; name: string }>;
```
### Algebraic composition — Result.flatMap (Rust)
```rust
fn parse(s: &str) -> Result<i32, String> { s.parse().map_err(|e| e.to_string()) }
fn double(n: i32) -> Result<i32, String> { Ok(n * 2) }
fn check_positive(n: i32) -> Result<i32, String> {
if n > 0 { Ok(n) } else { Err("non-positive".into()) }
}
let out: Result<i32, _> = parse("21")
.and_then(double)
.and_then(check_positive); // composition via and_then
```
## 매 결정 기준
| 상황 | Mode |
|---|---|
| Shared state across siblings | Composition (props / context) > inheritance |
| Behavior reuse, no state | Mixin / trait / function |
| Conditional capability | HOC / decorator |
| Linear pipeline | pipe / compose |
| Branching workflow | DAG (Dagster, Airflow) |
| Multi-axis variation | Strategy / Plugin |
**기본값**: 매 favor composition — 매 inheritance 의 only 매 strict is-a + immutable hierarchy.
## 🔗 Graph
- 부모: [[Design Patterns]] · [[Functional Programming]]
- 변형: [[Composition over Inheritance]]
- 응용: [[React]] · [[Airflow]]
- Adjacent: [[Base_Layouts]] · [[Architectural-Constraint-Enforcement]]
## 🤖 LLM 활용
**언제**: 매 inheritance hierarchy → composition 의 refactor suggestion, 매 pipeline의 DAG 의 visualize.
**언제 X**: 매 deep domain modeling — 매 human 의 boundary judgment 의 필수.
## ❌ 안티패턴
- **Inheritance for code reuse**: 매 fragile base class — 매 composition 의 사용.
- **Composition explosion**: 매 100-deep wrapper — 매 readability 의 X. 매 refactor.
- **God component**: 매 50-prop slot — 매 split.
- **Implicit composition order**: 매 HOC stacking 의 order-dependent — 매 explicit naming.
## 🧪 검증 / 중복
- Verified (Gamma et al., *Design Patterns*; React docs — composition vs inheritance; Wadler — *Theorems for Free*).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — function/object/component/process composition patterns |
@@ -0,0 +1,224 @@
---
id: wiki-2026-0508-aspect-oriented-programming-aop
title: Aspect Oriented Programming (AOP)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [AOP, Aspect Programming, Cross-cutting Concerns]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [architecture, paradigm, spring, decorator]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: Java / TypeScript / Python
framework: Spring AOP / AspectJ / NestJS
---
# Aspect-Oriented Programming (AOP)
## 매 한 줄
> **"매 cross-cutting concern을 separate aspect로 modularize."**. 1997년 Gregor Kiczales (Xerox PARC) 의 AspectJ 가 시초. 2026 현재 Spring AOP 6.x, NestJS interceptor, Python decorator 가 주류 — logging/transaction/security 같이 매 객체 가로지르는 logic을 매 한 곳에 모음.
## 매 핵심
### 매 용어
- **Aspect**: 매 cross-cutting concern 의 modular 단위 (e.g. `LoggingAspect`).
- **Join Point**: 매 program execution 의 한 지점 (method call, field access).
- **Pointcut**: 매 join point 의 selection expression.
- **Advice**: 매 pointcut 매칭 시 실행할 code (`@Before`, `@After`, `@Around`).
- **Weaving**: 매 aspect 와 base code 결합 — compile-time / load-time / runtime.
### 매 cross-cutting concerns
- Logging / tracing
- Transaction management
- Security / authorization
- Caching
- Performance monitoring
- Error handling / retry
- Audit trail
### 매 응용
1. Spring `@Transactional` — DB transaction 자동 commit/rollback.
2. NestJS `@UseInterceptors` — request/response transform.
3. Python `@functools.lru_cache` — pure caching aspect.
4. OpenTelemetry auto-instrumentation — runtime byte-code weaving.
## 💻 패턴
### Spring AOP — @Around aspect
```java
@Aspect
@Component
public class LoggingAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object logExecutionTime(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
try {
Object result = pjp.proceed();
long elapsed = System.currentTimeMillis() - start;
log.info("{} took {} ms", pjp.getSignature(), elapsed);
return result;
} catch (Throwable t) {
log.error("{} threw {}", pjp.getSignature(), t.getMessage());
throw t;
}
}
}
```
### Spring — @Transactional declarative TX
```java
@Service
public class OrderService {
@Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
public Order placeOrder(OrderRequest req) {
Order order = orderRepo.save(new Order(req));
inventoryRepo.decrement(req.getItems());
// Any RuntimeException → automatic rollback via AOP proxy
return order;
}
}
```
### NestJS — Interceptor (AOP-style)
```typescript
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { Observable, tap } from 'rxjs';
@Injectable()
export class TimingInterceptor implements NestInterceptor {
intercept(ctx: ExecutionContext, next: CallHandler): Observable<unknown> {
const start = Date.now();
return next.handle().pipe(
tap(() => console.log(`${ctx.getHandler().name} took ${Date.now() - start}ms`)),
);
}
}
@Controller('orders')
@UseInterceptors(TimingInterceptor)
export class OrdersController { /* ... */ }
```
### Python — Decorator as aspect
```python
import functools, time, logging
def timed(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
try:
return func(*args, **kwargs)
finally:
elapsed = time.perf_counter() - start
logging.info(f"{func.__name__} took {elapsed*1000:.1f}ms")
return wrapper
@timed
def expensive_calc(n: int) -> int:
return sum(i * i for i in range(n))
```
### Python — Class-based retry aspect
```python
def retry(times: int = 3, on: tuple = (Exception,)):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
last = None
for attempt in range(times):
try:
return func(*args, **kwargs)
except on as e:
last = e
time.sleep(2 ** attempt)
raise last
return wrapper
return decorator
@retry(times=5, on=(httpx.HTTPError,))
def fetch_remote(url: str) -> dict:
return httpx.get(url).json()
```
### AspectJ pointcut DSL
```java
@Pointcut("execution(public * com.example.repo.*.find*(..))")
public void anyFinder() {}
@Pointcut("@annotation(com.example.Audited)")
public void auditedMethod() {}
@Before("anyFinder() && auditedMethod()")
public void audit(JoinPoint jp) {
auditService.log(jp.getSignature().toShortString(), Instant.now());
}
```
### TypeScript — method decorator
```typescript
function Cached(ttlMs: number): MethodDecorator {
const cache = new Map<string, { value: unknown; exp: number }>();
return (_t, _k, desc: PropertyDescriptor) => {
const original = desc.value;
desc.value = function (...args: unknown[]) {
const key = JSON.stringify(args);
const entry = cache.get(key);
if (entry && entry.exp > Date.now()) return entry.value;
const value = original.apply(this, args);
cache.set(key, { value, exp: Date.now() + ttlMs });
return value;
};
};
}
class Pricing {
@Cached(60_000)
fetchRate(currency: string) { /* ... */ }
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Java enterprise, declarative TX | Spring AOP (proxy-based) |
| 매 method 매칭 + field access weaving | AspectJ (compile/load-time) |
| Node.js HTTP layer | NestJS Interceptor / Guard |
| Python script / function-level | Decorator |
| Cross-language tracing | OpenTelemetry auto-instrumentation |
**기본값**: framework-native (Spring AOP / NestJS interceptor / decorator). 매 raw AspectJ 는 매 매우 specific 한 경우만.
## 🔗 Graph
- 부모: [[Object-Oriented-Programming]] · [[Software-Architecture]]
- 변형: [[Middleware]]
- 응용: [[Spring Framework]] · [[NestJS]] · [[OpenTelemetry]]
- Adjacent: [[Dependency_Injection_(DI)|Dependency-Injection]] · [[Cross-Cutting Concerns]]
## 🤖 LLM 활용
**언제**: cross-cutting concern (logging/TX/security/caching) 이 매 여러 service 에 반복, declarative style 선호, framework 가 AOP 지원.
**언제 X**: 매 한두 곳만 쓰는 logic (직접 호출이 명확), 매 magic 회피 culture, 매 debug 어려움 감수 못할 때.
## ❌ 안티패턴
- **Aspect 안 business logic**: 매 aspect 는 매 cross-cutting 만 — 매 domain rule 넣지 X.
- **너무 broad pointcut**: `execution(* *.*(..))` — 매 unintended weaving.
- **Self-invocation 의 proxy bypass**: 매 같은 class 안 method call 은 매 proxy 통과 안 함 (Spring).
- **Order 의존**: 매 multiple aspect 매 ordering 명시 X 면 매 비결정적.
- **Aspect explosion**: 매 100+ aspect → 매 control flow 추적 불가.
## 🧪 검증 / 중복
- Verified (Spring Framework 6.x docs, AspectJ programming guide, NestJS docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — AOP full content with Spring/NestJS/Python patterns |
@@ -0,0 +1,168 @@
---
id: wiki-2026-0508-automated-refactoring-tools
title: Automated Refactoring Tools
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Refactoring Tools, IDE Refactoring, Codemod Tools]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [refactoring, tooling, ast, codemod]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: ts-morph,jscodeshift,comby,ast-grep
---
# Automated Refactoring Tools
## 매 한 줄
> **"매 AST-level 의 transform — 매 sed 의 X, 매 syntax-aware 의 mass-edit"**. 매 IDE refactor (Rename · Extract) 의 80년대 Smalltalk 의 root, 2026 의 LLM-augmented codemod (Claude Opus 4.7 + ast-grep) 의 mainstream.
## 매 핵심
### 매 3 tier 의 tool
- **IDE-builtin**: IntelliJ · VS Code · Rider — 매 single-file 의 dominant.
- **Codemod**: jscodeshift · ts-morph · comby · ast-grep — 매 cross-cutting mass change.
- **LLM-driven**: Claude Code · Cursor · GitHub Copilot Workspace — 매 semantic-aware 의 modernization.
### 매 refactor 종류
- Rename (symbol-aware).
- Extract function/variable/component.
- Inline.
- Move (file/module).
- Change signature.
- Convert (e.g. `var → const`, `function → arrow`).
### 매 응용
1. 매 framework migration (Vue 2 → Vue 3, React class → hook).
2. API breaking change 의 fan-out fix.
3. Code style 의 mechanical enforcement.
## 💻 패턴
### ts-morph: rename + add property
```typescript
import { Project } from "ts-morph";
const project = new Project({ tsConfigFilePath: "tsconfig.json" });
for (const sf of project.getSourceFiles()) {
for (const cls of sf.getClasses()) {
if (cls.getName()?.endsWith("Service")) {
cls.rename(cls.getName()!.replace(/Service$/, "Manager"));
cls.addProperty({ name: "createdAt", type: "Date", initializer: "new Date()" });
}
}
}
await project.save();
```
### ast-grep: pattern → rewrite (yaml rule)
```yaml
id: useEffect-cleanup
language: tsx
rule:
pattern: useEffect(() => { $$$BODY }, $DEPS)
fix: |
useEffect(() => {
$$$BODY
return () => { /* cleanup */ };
}, $DEPS)
```
```bash
ast-grep scan -r useEffect-cleanup.yml --update-all
```
### jscodeshift: Vue Options → Composition API
```javascript
export default function transformer(file, api) {
const j = api.jscodeshift;
const root = j(file.source);
root.find(j.ObjectExpression)
.filter(p => p.node.properties.some(pr => pr.key?.name === "data"))
.forEach(path => {
// emit setup() function with refs
// ...
});
return root.toSource();
}
```
```bash
jscodeshift -t vue-comp-api.js src/
```
### comby (language-agnostic structural search)
```bash
comby 'console.log(:[args])' 'logger.debug(:[args])' .ts -i
```
### LLM codemod (Claude Opus 4.7) — semantic-aware
```python
import anthropic
client = anthropic.Anthropic()
SYSTEM = "You convert React class components to functional + hooks. Preserve behavior."
with open("UserCard.tsx") as f:
src = f.read()
resp = client.messages.create(
model="claude-opus-4-7",
max_tokens=4096,
system=SYSTEM,
messages=[{"role": "user", "content": src}],
)
print(resp.content[0].text)
```
### IDE script: IntelliJ structural search
```text
$method$($args$) { $body$ }
→ Constraints: method matches ".*Async$"
→ Replace with: async $method$($args$) { $body$ }
```
## 매 결정 기준
| 상황 | Tool |
|---|---|
| 매 single-file rename in IDE | IDE builtin |
| TS-only · type-aware | ts-morph |
| TS/JS · less type-aware · faster | jscodeshift |
| Multi-language · structural | comby · ast-grep |
| 매 semantic refactor · framework migration | LLM codemod |
| Mass mechanical regex-safe | sed/perl (드물게) |
**기본값**: TypeScript 의 ts-morph, polyglot 의 ast-grep, 매 semantic 의 LLM.
## 🔗 Graph
- 부모: [[Refactoring_Best_Practices|Refactoring]] · [[AST_Traversal|Abstract-Syntax-Tree-Traversal]]
- 응용: [[Architecture_Refactor]]
- Adjacent: [[AI-Assisted Refactoring (AI 기반 리팩토링)]] · [[AST_Traversal]]
## 🤖 LLM 활용
**언제**: 매 semantic refactor (class→hook, callback→async/await), 매 deterministic rule 의 hard 의 case.
**언제 X**: 매 mechanical rename 의 case — IDE 가 cheaper · safer. LLM 의 hallucination risk 의 require code review.
## ❌ 안티패턴
- **Regex-only refactor**: 매 string match 의 false positive (comment · string literal).
- **Test 없음 refactor**: 매 mass codemod 의 test suite 의 gate 의 require.
- **PR 의 single huge codemod**: 매 review 의 X — file-by-file commit 의 split.
- **LLM output 의 blind merge**: 매 type-check + test 의 gate 의 mandatory.
## 🧪 검증 / 중복
- Verified (ts-morph docs, Meta jscodeshift, comby.dev, ast-grep.github.io, Anthropic Claude API docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — 3-tier taxonomy + ts-morph/ast-grep/comby/LLM examples |
@@ -0,0 +1,202 @@
---
id: wiki-2026-0508-bloc
title: BLoC
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [BLoC, Business Logic Component, flutter_bloc]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [flutter, state-management, dart, reactive]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: dart
framework: flutter,flutter_bloc
---
# BLoC
## 매 한 줄
> **"매 UI ↔ business logic 의 strict separation — Event in · State out · Stream 으로 의 mediate"**. 2018 Felix Angelov · Paolo Soares Google I/O 의 introduce, 2026 의 flutter_bloc 9.x · Cubit · Hydrated 의 Flutter ecosystem 의 dominant state-management.
## 매 핵심
### 매 contract
- **Event**: input (button tap · API tick).
- **State**: output (immutable snapshot).
- **Bloc**: `mapEventToState` (legacy) → `on<Event>` handler (modern 8.x+).
- **Cubit**: simpler — 매 event 의 X, method 의 emit 의 directly.
### 매 component
- `BlocProvider` — DI · scope.
- `BlocBuilder` — rebuild 의 state change 의 reactive.
- `BlocListener` — side-effect (snackbar · navigation).
- `BlocConsumer` — builder + listener.
- `RepositoryProvider` — data layer DI.
### 매 응용
1. 매 Flutter 의 production app (BMW · Nubank · Alibaba).
2. Form validation (매 reactive validation per field).
3. Authentication flow.
4. Hydrated state (매 disk-persisted, app restart 의 survive).
## 💻 패턴
### Bloc (event-driven)
```dart
sealed class CounterEvent {}
class Increment extends CounterEvent {}
class Decrement extends CounterEvent {}
class CounterBloc extends Bloc<CounterEvent, int> {
CounterBloc() : super(0) {
on<Increment>((event, emit) => emit(state + 1));
on<Decrement>((event, emit) => emit(state - 1));
}
}
// usage
BlocProvider(
create: (_) => CounterBloc(),
child: BlocBuilder<CounterBloc, int>(
builder: (ctx, count) => Text('$count'),
),
)
```
### Cubit (simpler · method-based)
```dart
class CounterCubit extends Cubit<int> {
CounterCubit() : super(0);
void increment() => emit(state + 1);
void decrement() => emit(state - 1);
}
// trigger
context.read<CounterCubit>().increment();
```
### Async event handler with state machine
```dart
sealed class LoginState {}
class LoginInitial extends LoginState {}
class LoginLoading extends LoginState {}
class LoginSuccess extends LoginState { final User user; LoginSuccess(this.user); }
class LoginFailure extends LoginState { final String msg; LoginFailure(this.msg); }
class LoginBloc extends Bloc<LoginEvent, LoginState> {
final AuthRepository auth;
LoginBloc(this.auth) : super(LoginInitial()) {
on<SubmitLogin>(_onSubmit);
}
Future<void> _onSubmit(SubmitLogin e, Emitter<LoginState> emit) async {
emit(LoginLoading());
try {
final user = await auth.login(e.email, e.password);
emit(LoginSuccess(user));
} catch (err) {
emit(LoginFailure(err.toString()));
}
}
}
```
### BlocListener (side-effect)
```dart
BlocListener<LoginBloc, LoginState>(
listener: (ctx, state) {
if (state is LoginSuccess) Navigator.pushNamed(ctx, '/home');
if (state is LoginFailure) ScaffoldMessenger.of(ctx).showSnackBar(
SnackBar(content: Text(state.msg)),
);
},
child: LoginForm(),
)
```
### Hydrated Bloc (auto-persist)
```dart
class SettingsCubit extends HydratedCubit<Settings> {
SettingsCubit() : super(const Settings(theme: 'light'));
void setTheme(String t) => emit(state.copyWith(theme: t));
@override
Settings fromJson(Map<String, dynamic> json) => Settings.fromJson(json);
@override
Map<String, dynamic> toJson(Settings state) => state.toJson();
}
```
### Stream-debounced search Bloc
```dart
class SearchBloc extends Bloc<SearchQuery, SearchState> {
SearchBloc(this.api) : super(SearchInitial()) {
on<SearchQuery>(
_onSearch,
transformer: (events, mapper) => events
.debounceTime(const Duration(milliseconds: 300))
.switchMap(mapper),
);
}
Future<void> _onSearch(SearchQuery e, Emitter<SearchState> emit) async {
emit(SearchLoading());
final results = await api.search(e.term);
emit(SearchLoaded(results));
}
}
```
### Test (bloc_test)
```dart
blocTest<CounterBloc, int>(
'emits [1] when Increment is added',
build: () => CounterBloc(),
act: (b) => b.add(Increment()),
expect: () => [1],
);
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Simple state · single screen | Cubit |
| Complex event flow · undo/redo | Bloc |
| Persisted state | HydratedBloc/Cubit |
| Server-driven · realtime | Bloc + StreamSubscription |
| Multi-screen shared | BlocProvider 의 root |
| 매 small project | Provider · Riverpod |
**기본값**: Cubit 의 first, Bloc 의 event 의 explicit 의 require 의 case.
## 🔗 Graph
- 부모: [[State Management]]
- 응용: [[Clean Architecture]]
- Adjacent: [[Provider]] · [[Riverpod]]
## 🤖 LLM 활용
**언제**: Bloc · Cubit · Event · State 의 boilerplate 의 generate, blocTest 의 draft.
**언제 X**: 매 actual event sequencing · concurrency strategy (debounce/restartable/sequential) — 매 domain 의 understand 의 require.
## ❌ 안티패턴
- **State 의 mutable**: 매 immutable + copyWith 의 mandatory.
- **BlocBuilder 의 entire screen 의 wrap**: granular rebuild 의 lose — multiple builder 의 split.
- **Bloc 의 navigation 의 directly do**: side-effect 의 BlocListener 의 isolate.
- **Singleton bloc 의 manual instantiate**: BlocProvider 의 use — lifecycle 의 leak prevent.
## 🧪 검증 / 중복
- Verified (bloclibrary.dev, flutter_bloc 9.x docs, Felix Angelov GitHub).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Bloc + Cubit + Hydrated + bloc_test patterns |
@@ -0,0 +1,224 @@
---
id: wiki-2026-0508-bpm
title: BPM (Business Process Management)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Business Process Management, Workflow Automation, Process Orchestration]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [enterprise, workflow, bpmn, orchestration]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: BPMN 2.0 / Java / TypeScript
framework: Camunda 8 / Temporal / AWS Step Functions
---
# BPM (Business Process Management)
## 매 한 줄
> **"매 business process 를 매 explicit model 로 만들어 매 measure / improve / automate."**. 1990s 의 BPR (re-engineering) → 2000s BPMS workflow engine → 2010s BPMN 2.0 표준 → 2026 현재 매 cloud-native orchestration (Camunda 8, Temporal, Step Functions) 가 매 microservice + AI agent 의 process backbone. 매 별도로 BPM = Beats Per Minute (music tempo) 도 동음이의 — 매 본 문서는 매 business process 중심.
## 매 핵심
### 매 BPM lifecycle
1. **Design**: BPMN diagram, swim lanes, gateway logic.
2. **Modeling**: simulation, validation.
3. **Execution**: workflow engine 이 매 instance 실행.
4. **Monitoring**: KPI, SLA, bottleneck.
5. **Optimization**: process mining, AI suggestions.
### 매 BPMN 2.0 element
- **Activity** (rounded rect): task — user task, service task, script task.
- **Event** (circle): start, intermediate, end (timer, message, error).
- **Gateway** (diamond): exclusive (XOR), parallel (AND), inclusive (OR).
- **Sequence flow** (arrow).
- **Pool / Lane**: organizational boundary.
- **Data object**: process variable.
### 매 응용
1. Loan approval workflow (origination → underwriting → decision).
2. Order-to-cash (e-commerce → fulfillment → invoicing).
3. Employee onboarding (HR forms → IT provisioning → training).
4. Insurance claim processing (intake → adjuster → payout).
5. AI agent orchestration (매 LLM agent 의 매 multi-step workflow).
## 💻 패턴
### Camunda 8 — BPMN service task (Zeebe)
```typescript
import { ZBClient } from 'zeebe-node';
const zbc = new ZBClient();
zbc.createWorker({
taskType: 'charge-credit-card',
taskHandler: async (job) => {
const { orderId, amount, customerId } = job.variables;
try {
const result = await stripe.charges.create({
amount, currency: 'usd', customer: customerId,
});
return job.complete({ chargeId: result.id, paid: true });
} catch (e) {
return job.fail(`Stripe error: ${e.message}`);
}
},
});
```
### BPMN 2.0 XML — order process (sketch)
```xml
<bpmn:process id="OrderProcess" isExecutable="true">
<bpmn:startEvent id="Start" />
<bpmn:serviceTask id="ValidateOrder" name="Validate Order"
zeebe:taskDefinition type="validate-order" />
<bpmn:exclusiveGateway id="StockGateway" name="In stock?" />
<bpmn:serviceTask id="ChargeCard" zeebe:taskDefinition type="charge-credit-card" />
<bpmn:userTask id="ManualReview" name="Manual review" />
<bpmn:endEvent id="End" />
<bpmn:sequenceFlow source="Start" target="ValidateOrder" />
<bpmn:sequenceFlow source="ValidateOrder" target="StockGateway" />
<bpmn:sequenceFlow source="StockGateway" target="ChargeCard">
<bpmn:conditionExpression>=stockAvailable</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:sequenceFlow source="StockGateway" target="ManualReview">
<bpmn:conditionExpression>=not(stockAvailable)</bpmn:conditionExpression>
</bpmn:sequenceFlow>
</bpmn:process>
```
### Temporal — code-first workflow
```typescript
import { proxyActivities, sleep } from '@temporalio/workflow';
import * as activities from './activities';
const { validateOrder, chargeCard, shipOrder } =
proxyActivities<typeof activities>({
startToCloseTimeout: '1 minute',
retry: { maximumAttempts: 5 },
});
export async function orderWorkflow(order: Order): Promise<void> {
await validateOrder(order);
const charge = await chargeCard(order.amount, order.customerId);
await sleep('5 minutes'); // hold before fulfillment
await shipOrder(order.id, charge.id);
}
```
### AWS Step Functions — state machine JSON
```json
{
"StartAt": "Validate",
"States": {
"Validate": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:123:function:Validate",
"Next": "InStock?"
},
"InStock?": {
"Type": "Choice",
"Choices": [
{ "Variable": "$.inStock", "BooleanEquals": true, "Next": "Charge" }
],
"Default": "ManualReview"
},
"Charge": { "Type": "Task", "Resource": "arn:.../Charge", "End": true },
"ManualReview": { "Type": "Task", "Resource": "arn:.../HumanReview", "End": true }
}
}
```
### Process mining — discover from logs
```python
import pm4py
log = pm4py.read_xes("orders_event_log.xes")
process_tree = pm4py.discover_process_tree_inductive(log)
bpmn = pm4py.convert_to_bpmn(process_tree)
pm4py.view_bpmn(bpmn)
# Conformance check
diagnostics = pm4py.conformance_diagnostics_token_based_replay(log, bpmn)
print(f"Fitness: {diagnostics['fitness']:.2f}")
```
### Saga pattern (compensation)
```typescript
export async function bookTripSaga(req: TripReq) {
const compensations: Array<() => Promise<void>> = [];
try {
const flight = await bookFlight(req);
compensations.push(() => cancelFlight(flight.id));
const hotel = await bookHotel(req);
compensations.push(() => cancelHotel(hotel.id));
const car = await bookCar(req);
return { flight, hotel, car };
} catch (e) {
for (const undo of compensations.reverse()) await undo();
throw e;
}
}
```
### Human task (UserTask) form
```typescript
zbc.createWorker({
taskType: 'manual-approval',
taskHandler: async (job) => {
// 매 push to UI inbox; resolve when human submits decision
await pushToInbox({
taskId: job.key,
assignee: job.customHeaders.assignee,
formSchema: job.customHeaders.formKey,
});
// job is completed by REST callback when human acts
},
});
```
## 매 결정 기준
| 상황 | Engine |
|---|---|
| Visual BPMN, business analyst editing | Camunda 8 / Activiti |
| Code-first, complex retry/long-running | Temporal |
| AWS-only stack, simple flow | Step Functions |
| Open-source self-host, light | n8n / Prefect |
| AI agent multi-step | Temporal + LangGraph |
**기본값**: matrix:
- enterprise w/ analyst → Camunda 8
- engineer-driven, durability-critical → Temporal
- serverless on AWS → Step Functions
## 🔗 Graph
- 부모: [[Workflow-Automation]] · [[Enterprise-Architecture]]
- 변형: [[State-Machine]]
- 응용: [[Temporal]]
- Adjacent: [[Microservices]] · [[Event-Driven-Architecture]]
## 🤖 LLM 활용
**언제**: long-running multi-step process, human-in-loop required, audit trail 필수, retry/compensation 복잡, AI agent multi-tool orchestration.
**언제 X**: 매 simple synchronous CRUD, 매 sub-100ms latency 필수, 매 stateless transform.
## ❌ 안티패턴
- **BPMN diagram = code 동기화 안 됨**: 매 visual model 만 update, 실제 code drift.
- **Workflow engine 의 business logic 과다**: 매 service task 안에 매 거대 conditional → 매 BPM diagram 의 의미 상실.
- **No timeout / no retry**: 매 stuck instance pile up.
- **Saga 의 compensation 누락**: 매 partial state 영구 leak.
- **매 모든 thing 을 workflow**: 매 simple op 도 workflow → 매 latency / debugging cost 폭증.
## 🧪 검증 / 중복
- Verified (BPMN 2.0 OMG spec, Camunda 8 / Temporal 2026 docs, "Process Mining" by van der Aalst).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — BPM (business process) full content with Camunda/Temporal patterns |
@@ -0,0 +1,218 @@
---
id: wiki-2026-0508-base-layouts
title: Base Layouts
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [layout-primitives, app-shell, holy-grail-layout]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [layout, css, ui, responsive, shell]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: tsx
framework: tailwind
---
# Base Layouts
## 매 한 줄
> **"매 layout 의 primitive 의 reuse 한다"**. 매 base layout 의 application shell — 매 header / sidebar / main / footer 의 stable scaffolding. 매 2026 의 CSS Grid + Flexbox + Container Queries (baseline 2024) + `dvh/svh/lvh` viewport units 의 holy-grail 의 trivial 의 만들었다.
## 매 핵심
### 매 canonical layouts
- **Stack**: 매 vertical flow — header/main/footer.
- **Sidebar**: 매 nav + content — 2-column.
- **Holy Grail**: 매 header + nav + main + aside + footer.
- **Centered (Cover)**: 매 hero / login.
- **Split-pane**: 매 editor / preview, mail client.
- **Dashboard grid**: 매 card grid — 매 auto-fit minmax.
### 매 modern primitives (2024-2026)
- **CSS Grid `subgrid`**: 매 nested alignment (Firefox 71, Chrome 117, Safari 16).
- **Container queries**: 매 component-level responsive (`@container`).
- **`dvh` / `svh` / `lvh`**: 매 mobile address-bar 의 stable viewport.
- **`:has()`**: 매 parent selector — 매 layout 의 child-state-driven.
- **Anchor positioning** (Chrome 125+): 매 popover / tooltip 의 native.
### 매 응용
1. Admin dashboard.
2. Editor (VS Code-style).
3. Marketing landing.
4. Mobile app shell — 매 bottom nav.
## 💻 패턴
### Holy Grail — CSS Grid (12 lines)
```css
.app {
display: grid;
min-height: 100dvh;
grid-template:
"header header header" auto
"nav main aside" 1fr
"footer footer footer" auto
/ 200px 1fr 200px;
}
.header { grid-area: header; }
.nav { grid-area: nav; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }
@media (max-width: 768px) {
.app {
grid-template:
"header" auto
"nav" auto
"main" 1fr
"aside" auto
"footer" auto / 1fr;
}
}
```
### Tailwind app shell (React)
```tsx
export function AppShell({ children }: { children: ReactNode }) {
return (
<div className="grid min-h-dvh grid-rows-[auto_1fr_auto] grid-cols-[16rem_1fr]">
<header className="col-span-2 border-b bg-white px-4 py-3">
<Logo /> <UserMenu className="ml-auto" />
</header>
<aside className="border-r overflow-y-auto">
<Nav />
</aside>
<main className="overflow-y-auto p-6">{children}</main>
<footer className="col-span-2 border-t px-4 py-2 text-sm text-gray-500">
© 2026
</footer>
</div>
);
}
```
### Centered (Cover)
```css
.cover {
display: grid;
place-items: center;
min-height: 100dvh;
padding: 1rem;
}
.cover > * { max-inline-size: 60ch; }
```
### Split-pane (resizable)
```tsx
// react-resizable-panels (2025 default)
import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
<PanelGroup direction="horizontal">
<Panel defaultSize={30} minSize={20}><FileTree /></Panel>
<PanelResizeHandle className="w-1 bg-gray-200 hover:bg-blue-500" />
<Panel><Editor /></Panel>
<PanelResizeHandle className="w-1 bg-gray-200" />
<Panel defaultSize={30}><Preview /></Panel>
</PanelGroup>
```
### Auto-fit dashboard grid
```css
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
gap: 1rem;
}
```
### Container queries
```css
.card { container-type: inline-size; }
@container (min-width: 400px) {
.card .layout {
display: grid;
grid-template-columns: 120px 1fr;
gap: 1rem;
}
}
```
### Sidebar with `:has()` (zero JS)
```css
.app:has(#nav-toggle:checked) .sidebar { transform: translateX(0); }
.sidebar { transform: translateX(-100%); transition: transform .2s; }
```
### Mobile app shell — bottom nav (safe area)
```css
.bottom-nav {
position: sticky;
bottom: 0;
padding-block-end: env(safe-area-inset-bottom);
background: white;
border-top: 1px solid #eee;
}
.scroll-area {
height: 100dvh;
overflow-y: auto;
overscroll-behavior: contain;
}
```
### Subgrid (nested card alignment)
```css
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
.card {
display: grid;
grid-template-rows: subgrid;
grid-row: span 3; /* title / body / footer aligned across siblings */
}
```
## 매 결정 기준
| Layout | Tool |
|---|---|
| App shell, 2D | CSS Grid named areas |
| 1D linear | Flexbox |
| Component-level responsive | Container queries |
| Resizable panes | react-resizable-panels / Radix Splitter |
| Mobile shell | dvh + safe-area-inset |
| Multi-card alignment | `subgrid` |
**기본값**: Grid for 2D + named areas, Flex for 1D, Tailwind utility for prototyping.
## 🔗 Graph
- 변형: [[Holy-Grail-Layout]] · [[App-Shell]]
- Adjacent: [[Arrangement-and-Composition]] · [[Architecture_Diagramming_Standards]]
## 🤖 LLM 활용
**언제**: 매 ASCII wireframe → CSS Grid 의 generation, Tailwind class 의 suggestion.
**언제 X**: 매 pixel-perfect design — 매 designer + visual review 의 필수.
## ❌ 안티패턴
- **`100vh` on mobile**: 매 address-bar overflow — 매 `100dvh` 의 사용.
- **Nested flex hell**: 매 5+ flex level — 매 grid 의 use.
- **Fixed pixel breakpoint**: 매 zoom 의 break — 매 `em`/`rem` 의 use.
- **Hidden overflow without scroll**: 매 content 의 cut.
- **Magic number margins**: 매 design token / spacing scale 의 use.
## 🧪 검증 / 중복
- Verified (CSS Grid spec — W3C; Every Layout — Bell & Andrew; web.dev — container queries).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Grid/Flex/container-queries/subgrid base layout patterns |
@@ -0,0 +1,182 @@
---
id: wiki-2026-0508-bayesian-inference
title: Bayesian Inference
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Bayesian Inference, Bayesian Statistics, Posterior Inference]
duplicate_of: none
source_trust_level: A
confidence_score: 0.95
verification_status: applied
tags: [statistics, ml, probabilistic, mcmc]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: python
framework: pymc,numpyro,stan
---
# Bayesian Inference
## 매 한 줄
> **"매 prior + likelihood = posterior — 매 belief 의 evidence 에 의해 의 update"**. Bayes 1763 의 origin, 20세기 frequentist 의 dominance, 2026 의 NumPyro/PyMC + GPU MCMC + variational inference 의 mainstream — 매 LLM uncertainty quantification 의 backbone.
## 매 핵심
### 매 Bayes rule
P(θ|D) = P(D|θ) P(θ) / P(D)
- **P(θ)**: prior — 매 data 이전 의 belief.
- **P(D|θ)**: likelihood — 매 model 의 data fit.
- **P(θ|D)**: posterior — updated belief.
- **P(D)**: evidence (marginal likelihood).
### 매 4 inference 방법
- **Conjugate**: closed-form (Beta-Bernoulli · Gaussian-Gaussian).
- **MCMC**: HMC · NUTS · Gibbs — exact (asymptotic) · slow.
- **Variational (VI)**: posterior 의 simpler family 의 approximate — fast · biased.
- **Sequential MC**: particle filter — 매 streaming · state-space.
### 매 응용
1. A/B test (Bayesian alternative 의 frequentist).
2. Hierarchical model (분류 multi-level).
3. ML calibration · uncertainty (BNN · Gaussian process).
4. LLM logit calibration · RAG confidence.
## 💻 패턴
### NumPyro: Bayesian linear regression (NUTS)
```python
import numpyro
import numpyro.distributions as dist
from numpyro.infer import NUTS, MCMC
import jax.numpy as jnp
import jax.random as random
def model(X, y=None):
alpha = numpyro.sample("alpha", dist.Normal(0., 10.))
beta = numpyro.sample("beta", dist.Normal(jnp.zeros(X.shape[1]), 1.))
sigma = numpyro.sample("sigma", dist.HalfNormal(1.))
mu = alpha + X @ beta
numpyro.sample("obs", dist.Normal(mu, sigma), obs=y)
mcmc = MCMC(NUTS(model), num_warmup=1000, num_samples=2000, num_chains=4)
mcmc.run(random.PRNGKey(0), X, y)
mcmc.print_summary()
```
### PyMC: Bayesian A/B test (Beta-Bernoulli)
```python
import pymc as pm
with pm.Model():
p_a = pm.Beta("p_a", alpha=1, beta=1)
p_b = pm.Beta("p_b", alpha=1, beta=1)
pm.Binomial("obs_a", n=n_a, p=p_a, observed=conv_a)
pm.Binomial("obs_b", n=n_b, p=p_b, observed=conv_b)
diff = pm.Deterministic("lift", p_b - p_a)
idata = pm.sample(2000, tune=1000, chains=4)
prob_b_better = (idata.posterior["lift"] > 0).mean().item()
```
### Hierarchical model (varying intercept)
```python
def hierarchical(X, group_idx, y=None, n_groups=10):
mu_a = numpyro.sample("mu_a", dist.Normal(0., 5.))
sigma_a = numpyro.sample("sigma_a", dist.HalfNormal(1.))
a = numpyro.sample("a", dist.Normal(mu_a, sigma_a).expand([n_groups]))
beta = numpyro.sample("beta", dist.Normal(0., 1.))
sigma = numpyro.sample("sigma", dist.HalfNormal(1.))
mu = a[group_idx] + beta * X
numpyro.sample("obs", dist.Normal(mu, sigma), obs=y)
```
### Variational inference (SVI)
```python
from numpyro.infer import SVI, Trace_ELBO
from numpyro.infer.autoguide import AutoNormal
guide = AutoNormal(model)
svi = SVI(model, guide, numpyro.optim.Adam(1e-3), Trace_ELBO())
state = svi.init(random.PRNGKey(0), X, y)
for i in range(2000):
state, loss = svi.update(state, X, y)
params = svi.get_params(state)
```
### Conjugate update (Beta-Bernoulli online)
```python
class BetaBernoulli:
def __init__(self, alpha=1, beta=1):
self.alpha, self.beta = alpha, beta
def update(self, success: bool):
self.alpha += int(success)
self.beta += int(not success)
def mean(self): return self.alpha / (self.alpha + self.beta)
def credible_interval(self, q=0.95):
from scipy.stats import beta
return beta.interval(q, self.alpha, self.beta)
```
### Bayesian neural net (Pyro Bayesian layer)
```python
import torch
import pyro
import pyro.nn as pnn
class BNN(pnn.PyroModule):
def __init__(self, in_d, out_d):
super().__init__()
self.linear = pnn.PyroModule[torch.nn.Linear](in_d, out_d)
self.linear.weight = pnn.PyroSample(dist.Normal(0., 1.).expand([out_d, in_d]).to_event(2))
self.linear.bias = pnn.PyroSample(dist.Normal(0., 1.).expand([out_d]).to_event(1))
def forward(self, x, y=None):
mean = self.linear(x).squeeze(-1)
with pyro.plate("data", x.shape[0]):
pyro.sample("obs", dist.Normal(mean, 0.1), obs=y)
return mean
```
## 매 결정 기준
| 상황 | Method |
|---|---|
| Conjugate model · streaming | Conjugate update |
| 매 small model · accurate posterior | NUTS/HMC |
| Large data · fast approx | SVI · ADVI |
| State-space · time-series | Particle filter |
| Deep model · scale | BNN + variational · MC dropout |
| 매 hyperparameter optimization | Gaussian process + acquisition |
**기본값**: NumPyro + NUTS — 매 GPU/JAX 의 fast.
## 🔗 Graph
- 부모: [[Probability Theory]] · [[Statistical Inference]]
- 변형: [[MCMC]] · [[Variational Inference]]
- 응용: [[Belief-System]]
- Adjacent: [[Causal Inference]]
## 🤖 LLM 활용
**언제**: model 의 prior · likelihood 의 spec 의 draft, posterior plot 의 interpret, NumPyro/PyMC code 의 generate.
**언제 X**: 매 convergence diagnostic (R-hat · ESS · trace plot) — LLM 의 statistical judgment 의 unreliable, statistician 의 review 의 require.
## ❌ 안티패턴
- **Flat prior 의 always**: weak data + flat prior → unstable posterior. Weakly informative prior 의 use.
- **No convergence check**: R-hat > 1.01 · ESS < 400 → posterior 의 invalid.
- **Single chain MCMC**: multi-chain 의 mix check 의 mandatory.
- **Posterior point-estimate 의 only**: 매 distribution 의 entirety 의 use — credible interval · posterior predictive.
## 🧪 검증 / 중복
- Verified (Gelman *Bayesian Data Analysis* 3rd, NumPyro/PyMC/Stan docs, McElreath *Statistical Rethinking* 2nd).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Bayes rule + 4 methods + NumPyro/PyMC patterns |
@@ -0,0 +1,163 @@
---
id: wiki-2026-0508-beat-saber
title: Beat Saber
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Beat Saber, VR Rhythm Game]
duplicate_of: none
source_trust_level: A
confidence_score: 0.85
verification_status: applied
tags: [vr, game-architecture, rhythm-game, unity, ecs]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: csharp
framework: unity,unity-dots,openxr
---
# Beat Saber
## 매 한 줄
> **"매 VR rhythm game 의 architecture 의 reference — 90Hz minimum framerate · sub-20ms motion-to-photon · ECS-style note pool"**. 2018 Beat Games (Meta acq 2019) release, 2026 의 Quest 3/Vision Pro 의 cross-platform mainstream, "framerate 의 holy 의 above 의 nothing" 의 architecture 의 lesson.
## 매 핵심
### 매 architecture 제약
- **Framerate floor**: 90 fps (Quest 2) · 120 fps (Quest 3 · Vision Pro).
- **Motion-to-photon**: < 20 ms.
- **GC 의 hostile**: 매 frame 의 spike 의 nausea 의 cause → object pool · Burst · Job System.
- **Determinism**: scoring 의 reproducible — 매 input · note 의 fixed seed.
### 매 component
- **Beatmap loader**: `.dat` JSON parse → preallocated note buffer.
- **Note spawner**: 매 future 6 sec 의 lookahead, pool 에서 의 pull.
- **Saber controller**: hand pose tracking + velocity smoothing.
- **Cut detector**: plane intersection · direction match · score.
- **Audio sync**: NJS (Note Jump Speed) + offset 의 calibrate.
### 매 응용
1. 매 fitness app (Supernatural, FitXR) 의 rhythm pattern 의 inherit.
2. Trainer/simulator (medical · drill) 의 timing-critical UX.
3. Education app (language drill · typing tutor) 의 VR variant.
## 💻 패턴
### Unity DOTS: note spawn 의 zero-alloc
```csharp
[BurstCompile]
public partial struct NoteSpawnSystem : ISystem
{
public void OnUpdate(ref SystemState state)
{
var beatmap = SystemAPI.GetSingleton<BeatmapBuffer>();
var time = SystemAPI.Time.ElapsedTime;
var ecb = new EntityCommandBuffer(Allocator.Temp);
for (int i = beatmap.NextIndex; i < beatmap.Notes.Length; i++)
{
var n = beatmap.Notes[i];
if (n.Time - time > LookaheadSeconds) break;
var e = ecb.Instantiate(beatmap.NotePrefab);
ecb.SetComponent(e, new Translation { Value = n.SpawnPosition });
ecb.SetComponent(e, new NoteData { CutDirection = n.Direction, HitTime = n.Time });
beatmap.NextIndex = i + 1;
}
ecb.Playback(state.EntityManager);
}
}
```
### Saber-cut detector (plane intersection)
```csharp
public bool TryCut(Vector3 saberTip, Vector3 saberBase, Vector3 saberVelocity, NoteData note,
out CutResult result)
{
var plane = new Plane(saberVelocity.normalized, saberBase);
if (!plane.Raycast(new Ray(note.Position, note.Forward), out float enter)) {
result = default; return false;
}
float speed = saberVelocity.magnitude;
float angle = Vector3.Angle(saberVelocity, note.RequiredCutDirection);
float accuracy = 1f - Mathf.Clamp01(angle / 60f);
result = new CutResult {
Score = Mathf.RoundToInt(speed * accuracy * 115f),
IsValid = speed > 2f && angle < 60f,
};
return result.IsValid;
}
```
### Audio-visual sync (NJS-based)
```csharp
// Note 의 spawn position 의 calc
float jumpDist = njs * (60f / bpm) * halfJumpDuration * 2f;
Vector3 spawnPos = playerPosition + Vector3.forward * jumpDist;
// Note 의 frame 마다 의 lerp
float t = (Time.timeAsDouble - spawnTime) / (hitTime - spawnTime);
note.transform.position = Vector3.Lerp(spawnPos, hitPos, (float)t);
```
### Object pool (zero-GC frame)
```csharp
public class NotePool
{
readonly Stack<Note> pool = new(256);
readonly Note prefab;
public Note Get() => pool.Count > 0 ? pool.Pop() : Object.Instantiate(prefab);
public void Return(Note n) {
n.gameObject.SetActive(false);
pool.Push(n);
}
}
```
### OpenXR foveated rendering hint (Quest 3)
```csharp
var feature = OpenXRSettings.Instance.GetFeature<FoveationFeature>();
feature.foveatedRenderingLevel = FoveatedRenderingLevel.High;
feature.useDynamicFoveatedRendering = true; // eye-tracked on Quest 3
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| < 100 active note · prototype | MonoBehaviour + pool |
| > 200 active note · production | DOTS/ECS + Burst |
| Cross-platform (PCVR + Quest) | Unity URP + multi-quality preset |
| Modding support | Open beatmap format (`.dat`) + PluginLoader |
| 매 90fps 미달 의 perf budget | Foveation · LOD · GPU instancing |
**기본값**: Unity DOTS + URP + OpenXR — 매 Quest 3 의 baseline 의 fit.
## 🔗 Graph
- 응용: [[bitECS와_SharedArrayBuffer의_실제_코드_통합]]
- Adjacent: [[Object Pool]]
## 🤖 LLM 활용
**언제**: beatmap 의 procedural generation, cut-direction pattern 의 difficulty curve 의 tune, NJS · offset 의 starter value 의 suggest.
**언제 X**: 매 hand-crafted choreography (top mapper 의 art form) — LLM 의 generate 의 bland.
## ❌ 안티패턴
- **GC 의 frame 의 allocate**: 매 90fps 의 break → motion sickness.
- **Animation curve 의 audio sync**: dt 의 drift → pop. NJS-based linear lerp 의 use.
- **Saber 의 trigger collider**: physics step 의 sub-frame miss — manual raycast/plane 의 use.
- **Per-note GameObject Instantiate**: pool 의 mandatory.
## 🧪 검증 / 중복
- Verified (Beat Games postmortem GDC 2019, Unity DOTS 1.3 docs, OpenXR 1.1 spec, BSMG modding wiki).
- 신뢰도 A-.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — VR architecture constraints + DOTS spawner + cut detector |
@@ -0,0 +1,174 @@
---
id: wiki-2026-0508-belief-system
title: Belief System
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Belief System, Agent Belief, Knowledge Base, BDI Beliefs]
duplicate_of: none
source_trust_level: A
confidence_score: 0.85
verification_status: applied
tags: [agent-architecture, ai, bdi, knowledge-representation]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: python
framework: bdi,langchain,owl-rdf
---
# Belief System
## 매 한 줄
> **"매 agent 의 'world 가 such-and-such' 의 internal model — 매 perception update · inference 로 부터 의 derive"**. Bratman 1987 BDI (Belief-Desire-Intention) 의 origin, 2026 의 LLM agent 의 working memory · scratchpad · long-term memory store 의 modern incarnation.
## 매 핵심
### 매 component
- **Belief base**: fact set (logical · probabilistic · embedding-vector).
- **Update rule**: perception → belief revision (AGM postulates).
- **Query interface**: 매 plan 의 condition 의 check.
- **Consistency check**: contradiction 의 detect · resolve.
### 매 representation
- **Symbolic**: Prolog · Datalog · OWL/RDF.
- **Probabilistic**: Bayesian network · Markov logic.
- **Vector/embedding**: 매 modern LLM agent — chunked text + embedding store.
- **Hybrid**: structured fact + free-text (most 2026 agent system).
### 매 응용
1. 매 BDI agent (JADE · Jadex · Jason).
2. Robot world model (ROS knowledge_base).
3. LLM agent scratchpad (Claude · LangGraph state).
## 💻 패턴
### BDI-style belief base (Python)
```python
from dataclasses import dataclass, field
from typing import Any
@dataclass
class BeliefBase:
facts: dict[str, Any] = field(default_factory=dict)
confidence: dict[str, float] = field(default_factory=dict)
def add(self, key: str, value: Any, conf: float = 1.0):
if key in self.facts and self.facts[key] != value:
# contradiction → keep higher-confidence
if conf <= self.confidence[key]: return
self.facts[key] = value
self.confidence[key] = conf
def query(self, key: str) -> tuple[Any, float] | None:
if key not in self.facts: return None
return self.facts[key], self.confidence[key]
bb = BeliefBase()
bb.add("door_open", True, 0.9)
bb.add("battery_pct", 73, 1.0)
```
### LLM agent: belief 의 prompt-injected scratchpad
```python
def build_prompt(beliefs: BeliefBase, task: str) -> str:
facts = "\n".join(
f"- {k}: {v} (conf={c:.2f})"
for k, (v, c) in [(k, (bb.facts[k], bb.confidence[k])) for k in bb.facts]
)
return f"""You are an agent with the following beliefs:
{facts}
Task: {task}
Plan your next action and explain reasoning."""
```
### Bayesian belief update (sensor fusion)
```python
def bayes_update(prior: float, likelihood: float, evidence: float) -> float:
"""P(H|E) = P(E|H) * P(H) / P(E)"""
return likelihood * prior / evidence
# Door 의 open 의 prior 0.5, sensor 의 reading "open" 의 likelihood 0.9, evidence 0.6
posterior = bayes_update(0.5, 0.9, 0.6) # 0.75
```
### Vector belief store (long-term memory)
```python
import chromadb
client = chromadb.PersistentClient("./agent_memory")
beliefs = client.get_or_create_collection("beliefs")
beliefs.upsert(
ids=["b-001"],
documents=["User prefers vegetarian restaurants in 5km radius"],
metadatas=[{"source": "user_pref_2026-04-12", "conf": 0.95}],
)
hits = beliefs.query(query_texts=["restaurant recommendation"], n_results=5)
```
### Belief revision (AGM contraction)
```python
def contract(bb: BeliefBase, fact: str):
"""Remove fact + minimal additional facts to restore consistency."""
if fact in bb.facts:
del bb.facts[fact]
del bb.confidence[fact]
# Naive — production uses entrenchment ordering
```
### LangGraph stateful belief
```python
from langgraph.graph import StateGraph
from typing import TypedDict
class AgentState(TypedDict):
beliefs: dict
desires: list[str]
intentions: list[str]
def perceive(state: AgentState) -> AgentState:
state["beliefs"]["weather"] = call_weather_api()
return state
graph = StateGraph(AgentState).add_node("perceive", perceive)
```
## 매 결정 기준
| 상황 | Representation |
|---|---|
| 매 deterministic rule-based | Datalog · Prolog |
| Uncertain sensor data | Bayesian network |
| Open-domain text · LLM agent | Vector embedding + scratchpad |
| Robot · spatial | Probabilistic occupancy grid + KB |
| Multi-agent · negotiation | KQML · FIPA + symbolic KB |
**기본값**: hybrid — symbolic skeleton (key fact 의 dict) + vector store (free-text long-term).
## 🔗 Graph
- 부모: [[Agent Architecture]] · [[Knowledge Representation]]
- 변형: [[Bayesian_Inference]]
- Adjacent: [[A2A]] · [[Belief Revision]]
## 🤖 LLM 활용
**언제**: belief base 의 natural-language form 의 store (e.g. user preference summary), scratchpad 의 reasoning step 의 record.
**언제 X**: 매 safety-critical inference (medical · industrial) — LLM 의 hallucinate · 매 symbolic verifiable 의 require.
## ❌ 안티패턴
- **No revision policy**: belief 의 add-only — contradictory state 의 accumulate.
- **Confidence 의 ignore**: 매 fact 의 binary present/absent — sensor noise 의 not handle.
- **Global belief blob**: 매 agent 의 share — privacy · ownership 의 unclear → BDI per-agent KB.
- **Vector-only memory**: 매 deterministic recall (e.g. "what is user's name") 의 unreliable — symbolic key/value 의 mix.
## 🧪 검증 / 중복
- Verified (Bratman 1987, AGM 1985, FIPA agent specs, LangGraph docs, ChromaDB docs).
- 신뢰도 A-.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — BDI + 2026 LLM hybrid (vector + symbolic) |
@@ -0,0 +1,167 @@
---
id: wiki-2026-0508-big-data
title: Big Data
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Big Data, Large-Scale Data Processing]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [data, distributed-systems, analytics, lakehouse]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: python
framework: spark,duckdb,iceberg,polars
---
# Big Data
## 매 한 줄
> **"매 single-machine 의 fit 의 X · single-pass 의 fit 의 X — 매 distributed compute · columnar storage 의 require"**. 2003 Google MapReduce 논문 의 origin, Hadoop → Spark → Lakehouse (Iceberg+Delta+Hudi) 의 evolve, 2026 의 single-node DuckDB/Polars 의 "Big Data is dead" 의 movement 의 mainstream.
## 매 핵심
### 매 5 V
- **Volume**: TB-PB scale.
- **Velocity**: streaming · near-real-time.
- **Variety**: structured + semi + unstructured.
- **Veracity**: data quality · trust.
- **Value**: ROI of analytics.
### 매 stack 2026
- **Storage**: object store (S3/GCS) + open table format (Iceberg · Delta · Hudi).
- **Compute**: Spark · Trino · DuckDB · Polars · Snowflake · BigQuery.
- **Orchestration**: Airflow · Dagster · Prefect.
- **Stream**: Kafka · Flink · Kinesis.
- **Catalog**: Unity · Polaris · Nessie · Glue.
### 매 응용
1. 매 BI 의 dashboard.
2. ML training pipeline (feature store).
3. Operational analytics (real-time fraud, ad bidding).
## 💻 패턴
### Iceberg table 의 Spark 에서 의 write
```python
from pyspark.sql import SparkSession
spark = SparkSession.builder \
.config("spark.sql.catalog.local", "org.apache.iceberg.spark.SparkCatalog") \
.config("spark.sql.catalog.local.type", "hadoop") \
.config("spark.sql.catalog.local.warehouse", "s3a://lake/warehouse") \
.getOrCreate()
df = spark.read.json("s3a://raw/events/*.json")
df.writeTo("local.events.daily").partitionedBy("date").createOrReplace()
```
### DuckDB: 매 single-node "big data" (laptop 의 100GB)
```python
import duckdb
con = duckdb.connect()
con.sql("""
SELECT user_id, COUNT(*) AS events, SUM(amount) AS revenue
FROM read_parquet('s3://lake/events/2026/*.parquet')
WHERE event_type = 'purchase'
GROUP BY user_id
ORDER BY revenue DESC
LIMIT 100
""").show()
```
### Polars: out-of-core lazy
```python
import polars as pl
df = (
pl.scan_parquet("s3://lake/events/*.parquet")
.filter(pl.col("event_type") == "purchase")
.group_by("user_id")
.agg(pl.len().alias("events"), pl.col("amount").sum().alias("revenue"))
.sort("revenue", descending=True)
.limit(100)
)
print(df.collect(streaming=True))
```
### Flink: streaming aggregation
```java
DataStream<Event> events = env.fromSource(kafkaSource, ...);
events.keyBy(Event::userId)
.window(TumblingEventTimeWindows.of(Time.minutes(5)))
.aggregate(new RevenueAggregator())
.sinkTo(icebergSink);
```
### Iceberg time-travel + schema evolution
```sql
-- snapshot 의 query
SELECT * FROM events FOR VERSION AS OF 8723649283746;
SELECT * FROM events FOR TIMESTAMP AS OF '2026-05-09 00:00:00';
-- column add (no rewrite)
ALTER TABLE events ADD COLUMN device_id STRING;
-- partition evolution
ALTER TABLE events ADD PARTITION FIELD bucket(16, user_id);
```
### Spark: dynamic partition pruning + AQE
```python
spark.conf.set("spark.sql.adaptive.enabled", "true")
spark.conf.set("spark.sql.adaptive.coalescePartitions.enabled", "true")
spark.conf.set("spark.sql.adaptive.skewJoin.enabled", "true")
# AQE 의 plan 의 runtime 의 reoptimize
df = spark.sql("""
SELECT u.name, e.event_type, COUNT(*)
FROM events e JOIN users u ON e.user_id = u.id
WHERE e.date >= '2026-05-01'
GROUP BY u.name, e.event_type
""")
```
## 매 결정 기준
| 상황 | Stack |
|---|---|
| < 100 GB · single node | DuckDB · Polars |
| 100GB - 10TB batch | Spark + Iceberg |
| > 10 TB / day | Spark/Trino + Iceberg + Snowflake |
| Streaming < 1s latency | Flink + Kafka |
| Ad-hoc SQL | Trino · DuckDB |
| ML training | Spark + Petastorm 또는 Ray Data |
**기본값**: Iceberg-on-S3 + Spark/DuckDB 의 hybrid — 매 modern lakehouse 의 standard.
## 🔗 Graph
- 부모: [[Distributed Systems]] · [[Data Engineering]]
- 변형: [[Lakehouse]] · [[Data Warehouse]]
- 응용: [[Apache Ignite]]
- Adjacent: [[Append-only log]] · [[Stream-Processing-Architectures|Stream Processing]]
## 🤖 LLM 활용
**언제**: SQL 의 generate, partitioning strategy 의 advise, schema evolution diff 의 explain, Iceberg 의 table maintenance 의 query 의 draft.
**언제 X**: 매 production tuning (shuffle partition · executor sizing) — metric-driven 의 require, LLM hint 의 starting point 만.
## ❌ 안티패턴
- **Premature distribution**: 매 < 50GB 의 case 의 Spark — DuckDB 의 100x faster.
- **Small file problem**: Spark 의 1KB parquet 의 millions — compaction 의 require.
- **Hive-style partition explosion**: 매 high-cardinality column 의 partition (e.g. user_id) — Iceberg bucket transform 의 use.
- **Schema-on-read 의 over-rely**: governance 의 erode — open table format 의 use.
## 🧪 검증 / 중복
- Verified (Apache Iceberg/Spark/Flink docs, MotherDuck "Big Data is Dead" 2023, Databricks Lakehouse paper).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — 5V + 2026 lakehouse stack + DuckDB/Polars/Flink patterns |
@@ -0,0 +1,28 @@
---
category: Other
tags: [auto-wikified, technical-documentation, other]
title: Boilerplate
description: "**보일러플레이트(Boilerplate)**는 핵심 비즈니스 로직을 지원하기 위해 반복적으로 작성해야 하는 가치가 낮고 판에 박힌 코드를 의미한다 [1]."
last_updated: 2026-05-04
---
# Boilerplate
## 📌 Brief Summary
**보일러플레이트(Boilerplate)**는 핵심 비즈니스 로직을 지원하기 위해 반복적으로 작성해야 하는 가치가 낮고 판에 박힌 코드를 의미한다 [1]. 현대 소프트웨어 개발 프레임워크와 라이브러리들은 이러한 보일러플레이트 코드를 줄여 개발 생산성을 높이고 유지보수성을 향상시키는 방향으로 발전하고 있다 [2-4]. 이를 위해 프레임워크 차원의 추상화, 상태 관리 도구의 최적화, 그리고 코드 자동 생성 기술이 적극적으로 활용된다 [5, 6].
## 📖 Core Content
* **보일러플레이트의 문제점**: 귀중한 핵심 비즈니스 로직이 방대한 양의 가치 없는 보일러플레이트 코드와 섞이게 되면, 전체적인 코드를 이해하고 유지보수하기가 매우 어려워진다 [1].
* **프론트엔드 생태계의 보일러플레이트 감소**:
* **Vue.js**: Vue 3의 Composition API를 도입하면 개발 주기가 단축되며 **보일러플레이트 코드를 30%가량 줄일 수 있다** [2]. 또한, 상태 관리 라이브러리로 기존의 Vuex 대신 Pinia를 사용하면 불필요한 보일러플레이트를 제거하고 타입스크립트 지원을 크게 강화할 수 있다 [3].
* **React**: 기존의 Redux Toolkit처럼 보일러플레이트가 많은 도구 대신, 최근에는 **보일러플레이트가 적은 Zustand나 서버 상태 관리에 특화된 TanStack Query(React Query)가 실전 표준**으로 자리 잡고 있다 [4]. React Query 사용 시 발생하는 중복된 프리페치(prefetch) 등의 보일러플레이트 코드는 별도의 헬퍼 함수로 추출하여 코드를 깔끔하게 유지하는 것이 권장된다 [7].
* **백엔드 및 모바일 환경의 자동화 및 추상화**:
* **Spring Boot**: Spring Boot 프레임워크 자체의 핵심 도입 목적 중 하나가 보일러플레이트의 축소이다 [8]. **Lombok 라이브러리**를 사용하여 자바의 반복적인 보일러플레이트 코드를 대폭 줄일 수 있으며 [9, 10], **Spring Data JPA**는 리포지토리 패턴과 쿼리 자동 생성을 통해 데이터베이스 접근에 필요한 보일러플레이트를 크게 제거하여 개발 시간을 단축시킨다 [6, 11]. 또한 Spring Cloud는 분산 시스템 조정에 필요한 보일러플레이트 패턴을 신속하게 구현할 수 있도록 돕는다 [12].
* **React Native**: 새로운 아키텍처(New Architecture) 환경에서는 **Codegen 도구**가 TypeScript나 Flow 타입 정의를 분석하여 JavaScript와 네이티브(Native) 영역을 연결하는 데 필요한 C++ 보일러플레이트 코드를 자동으로 생성해 준다 [5].
## ⚖️ Trade-offs & Caveats
* **AI 생성 도구 의존에 따른 일관성 결여 위험**: 최근의 생성형 AI 도구들은 보일러플레이트 코드를 매우 빠르게 생성할 수 있지만, 정해진 템플릿 없이 매번 코드를 새롭게 지어내기 때문에 **코드의 일관성을 보장하지 못한다** [13]. AI가 생성한 보일러플레이트에 과도하게 의존하면 미세한 기능적, 외관상 차이가 발생할 수 있으며, 이로 인해 코드베이스 전체에 걸쳐 일괄적인 패턴 변경이나 리팩토링(예: 글로벌 에러 처리 방식 변경 등)을 수동으로 추적하고 수정해야 하는 치명적인 단점이 발생한다 [13, 14].
* **과도한 추상화로 인한 가시성 저하 및 디버깅 난이도 상승**: 보일러플레이트를 없애기 위해 관점 지향 프로그래밍(AOP) 도구나 프레임워크의 자동 구성 기능을 사용할 경우, 코드는 깔끔해지지만 **핵심 로직이 '마법처럼' 숨겨지게 되는 트레이드오프**가 발생한다 [15, 16]. 이는 프로젝트에 새로 합류한 개발자가 코드의 실행 흐름을 파악하기 어렵게 만들며, 런타임 오류나 예상치 못한 동작이 발생했을 때 디버깅의 난이도를 크게 높이는 제약 사항이 된다 [15].
---
*Last updated: 2026-05-03*
@@ -0,0 +1,180 @@
---
id: wiki-2026-0508-bottom-up-approach
title: Bottom Up Approach
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Bottom-Up Design, Bottom-Up vs Top-Down, Composition-First Design]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [design, methodology, top-down, bottom-up, architecture]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: Polyglot
framework: Methodology
---
# Bottom Up Approach
## 매 한 줄
> **"매 bottom-up = 매 작은 building block 부터 만들고 합쳐 system 으로 키우는 composition-first 접근."**. 매 top-down 이 spec → decompose 인 반면, bottom-up 은 primitive → compose. 매 2026 modern 실무는 hybrid (meet-in-the-middle) — 매 spike/prototype 은 bottom-up, architecture 는 top-down, 매 LLM-driven 합성에서 bottom-up 의 compositional reasoning 이 다시 부상.
## 매 핵심
### 매 distinction
- **Top-down**: 매 high-level spec → subsystem → module → function. 매 known-domain 적합.
- **Bottom-up**: 매 primitive utility → combinator → application. 매 unknown-domain / discovery 적합.
- **Meet-in-the-middle**: 매 양쪽 동시 → 중간에서 만남.
- **Outside-in (TDD)**: 매 acceptance test → unit — 매 top-down 변형.
### 매 strengths
- **Reusability**: 매 primitive 가 여러 system 에 공통.
- **Testability**: 매 작은 unit 부터 100% covered.
- **Discoverability**: 매 unknown territory 에서 "뭐가 가능한지" 발견.
- **Compositional**: 매 functional programming, Lisp, Forth 의 핵심.
### 매 weaknesses
- **No big picture**: 매 individual unit 우수해도 system 일관성 부재 가능.
- **YAGNI risk**: 매 안 쓰일 primitive 까지 만들 수 있음.
- **Integration debt**: 매 끝에 가서야 합쳐지는 surprise.
### 매 응용
1. **Functional libraries**: 매 Lodash, Ramda — combinator 가 primitive.
2. **Forth / Concatenative langs**: 매 word 정의 후 합성.
3. **Embedded firmware**: 매 driver → HAL → app.
4. **ML pipeline**: 매 ops → layers → model.
5. **Spike / discovery prototype**: 매 architecture 모르는 phase.
## 💻 패턴
### Functional combinator (bottom-up)
```haskell
-- primitives
add1 :: Int -> Int
add1 x = x + 1
double :: Int -> Int
double x = x * 2
-- composition (no top-level spec needed)
addThenDouble :: Int -> Int
addThenDouble = double . add1
-- application emerges by composing
process :: [Int] -> [Int]
process = map (double . add1) . filter (> 0)
```
### Lisp — define primitives, then compose
```lisp
(defun double (x) (* x 2))
(defun increment (x) (+ x 1))
(defun process (xs)
(mapcar (lambda (x) (double (increment x)))
(remove-if-not #'plusp xs)))
```
### Embedded — HAL up
```c
// 1. register-level primitive
void gpio_set_high(uint32_t pin) { GPIO_BSRR = 1u << pin; }
// 2. driver
void led_on(led_t led) { gpio_set_high(led.pin); }
// 3. application
void heartbeat(void) {
while (1) { led_on(STATUS_LED); delay_ms(500); led_off(STATUS_LED); delay_ms(500); }
}
```
### React UI — primitive components up
```tsx
// 1. atoms
const Button = ({ children, ...props }) => <button className="btn" {...props}>{children}</button>;
const Input = ({ ...props }) => <input className="input" {...props} />;
// 2. molecules
const SearchBox = () => (
<div className="search">
<Input placeholder="Search..." />
<Button>Go</Button>
</div>
);
// 3. page (emerges)
const HomePage = () => <header><Logo /><SearchBox /></header>;
```
### Spike-driven discovery
```python
# Day 1 — bottom-up exploration before architecture exists
def parse_log_line(s): ... # primitive
def filter_errors(lines): ... # combinator
def aggregate_by_minute(lines): ...
def render_chart(buckets): ...
# After 2 days you SEE the pipeline → THEN write architecture doc
```
### LLM compositional planning (modern bottom-up)
```python
# Claude tool-use bottom-up: define small tools, let model compose
tools = [
{"name": "search_db", "description": "..."},
{"name": "render_chart", "description": "..."},
{"name": "send_email", "description": "..."},
]
# Model receives high-level task and composes a plan from primitives
client.messages.create(
model="claude-opus-4-7",
tools=tools,
messages=[{"role": "user", "content": "Send a weekly sales summary"}],
)
```
### Forth — concatenative composition
```forth
: SQUARE DUP * ; \ primitive
: CUBE DUP SQUARE * ; \ compose
: AREA SQUARE 3.14159 * ; \ compose with literal
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Domain unknown / spike | Bottom-up |
| Spec frozen, deadline | Top-down |
| Reusable library | Bottom-up |
| End-to-end product | Hybrid (meet in middle) |
| TDD acceptance | Outside-in (top-down variant) |
| LLM tool-using agent | Bottom-up primitives, top-down task |
**기본값**: hybrid — 매 architecture skeleton (top-down) + 매 primitive layer (bottom-up) → 매 meet middle.
## 🔗 Graph
- 응용: [[Functional_Programming]] · [[Atomic_Design]]
- Adjacent: [[Composition]] · [[YAGNI]]
## 🤖 LLM 활용
**언제**: unknown domain spike, library design, primitive 조합 탐색, agentic tool composition.
**언제 X**: regulated/safety system 의 spec-driven part — 매 top-down 우선.
## ❌ 안티패턴
- **Pure bottom-up without integration plan**: 매 primitive 100개 + 통합 안 됨 = 0 가치.
- **Premature primitives**: 매 안 쓰일 utility 양산 (YAGNI 위반).
- **Bottom-up for legally-specified systems**: 매 spec drift → compliance fail.
- **Skipping integration tests**: 매 unit 모두 green 인데 system fail.
## 🧪 검증 / 중복
- Verified (Abelson&Sussman SICP 1985, Forth dictionary docs, "Out of the Tar Pit" 2006).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — bottom-up vs top-down, composition patterns, hybrid default |
@@ -0,0 +1,24 @@
---
category: Architecture
tags: [auto-wikified, technical-documentation, architecture]
title: Bounded Context
description: "Bounded Context(제한된 컨텍스트)는 도메인 주도 설계(DDD)에서 유래한 용어로, 단일하고 응집력 있는 도메인 개념에 매핑되는 코드 조직의 기본 단위를 의미합니다 [1]."
last_updated: 2026-05-04
---
# Bounded Context
## 📌 Brief Summary
Bounded Context(제한된 컨텍스트)는 도메인 주도 설계(DDD)에서 유래한 용어로, 단일하고 응집력 있는 도메인 개념에 매핑되는 코드 조직의 기본 단위를 의미합니다 [1]. 이상적인 Bounded Context는 명확한 단일 책임을 지니며, 내부 로직을 독립적으로 추론할 수 있어야 합니다 [1]. 프레임워크 실전 아키텍처 패턴에서 이는 다른 모듈과의 결합도(coupling)를 최소화하여 시스템의 모듈성 및 유지보수성을 극대화하는 핵심 원리로 작용합니다 [1].
## 📖 Core Content
* **단일 책임과 독립적 패키징:** 프레임워크(예: Django)에서 Bounded Context로 기능하는 단위(App 등)는 이론적으로 별도의 패키지나 마이크로서비스로 쉽게 추출될 수 있을 만큼 독립적이어야 합니다 [1, 2]. 반면 `utils`, `helpers`, `misc`와 같이 다용도의 의미를 지닌 명명은 단일 도메인 개념을 위반하고 앱이 너무 많은 역할을 수행하고 있다는 경고 신호로 간주됩니다 [1].
* **모델 소유권과 API를 통한 캡슐화:** 각 Bounded Context는 고유한 데이터 모델을 직접 소유해야 합니다 [3]. 실전 전자상거래 백엔드 사례를 보면, 주문(`orders/`) 컨텍스트가 재고(`inventory/`)를 확인할 때 상대방의 데이터 모델을 직접 임포트하지 않고 반드시 공개된 셀렉터(Selector) API를 통해서만 상호작용하도록 데이터 접근을 격리합니다 [3].
* **마이크로서비스 경계로의 매핑:** 시스템이 성장함에 따라 잘 분리된 Bounded Context(예: NestJS의 모듈 시스템 등)는 향후 모놀리식 아키텍처를 해체할 때 자연스럽게 마이크로서비스의 경계로 확장 및 매핑될 수 있는 강력한 구조적 기반을 제공합니다 [2].
## ⚖️ Trade-offs & Caveats
* **경계 식별의 어려움과 복잡성 전가:** 시스템 내에서 Bounded Context의 경계(Boundary)를 올바르게 정의하는 것은 매우 까다로운 작업입니다 [4]. 컴포넌트를 깔끔하게 분리하지 못할 경우, 내부의 복잡성을 해소하지 못한 채 단지 컴포넌트 간의 연결(통신) 지점으로 복잡성만 전가하는 역효과를 초래할 수 있습니다 [4].
* **직접적인 모델 접근 제약과 간접성 증가:** Bounded Context 간의 독립성을 철저히 보장하기 위해 다른 도메인의 모델을 직접 참조하는 것이 금지됩니다 [3]. 모든 데이터 접근이 퍼블릭 API를 통해서만 이루어져야 하므로 [3], 시스템 내부적으로 간접 호출 계층과 인터페이스가 증가하여 설계 초기의 구현 오버헤드가 발생할 수 있습니다.
---
*Last updated: 2026-05-03*
@@ -0,0 +1,186 @@
---
id: wiki-2026-0508-branded-types
title: Branded Types
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Branded Types, Nominal Types, Opaque Types, Tagged Types]
duplicate_of: none
source_trust_level: A
confidence_score: 0.95
verification_status: applied
tags: [typescript, type-system, nominal-typing, domain-modeling]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: typescript-5.x,zod,effect-ts
---
# Branded Types
## 매 한 줄
> **"매 structural type 의 nominal 의 emulate — 매 `string` 두 개 의 distinguish 의 enforce"**. TypeScript 의 structural typing 의 long-standing pain (UserId vs OrderId · Email vs string) 의 solve, 2026 의 Effect-TS Brand · Zod brand · Type-Fest Tagged 의 ergonomic API 의 mainstream.
## 매 핵심
### 매 problem
- TS structural: 매 `string` 의 모든 `string` 의 assignable.
- `function sendEmail(userId: string, email: string)` — 매 swap 의 type check pass.
- 매 nominal hint 의 require — but TS 의 native 의 no.
### 매 mechanism
- Intersection 의 phantom property: `string & { __brand: "UserId" }`.
- 매 runtime 의 plain string — 매 zero cost.
- Constructor function 의 cast — 매 single point 의 validate.
### 매 응용
1. Domain ID (UserId · OrderId · ProductId).
2. Validated string (Email · URL · UUID · NonEmptyString).
3. Numeric unit (Meters · Seconds · USD · Cents).
4. Sanitized input (HtmlSafeString · SqlEscapedString).
## 💻 패턴
### Vanilla TS brand
```typescript
type Brand<T, B> = T & { readonly __brand: B };
type UserId = Brand<string, "UserId">;
type OrderId = Brand<string, "OrderId">;
const UserId = (s: string): UserId => s as UserId;
const OrderId = (s: string): OrderId => s as OrderId;
function getUser(id: UserId) { /* ... */ }
const u = UserId("u-123");
const o = OrderId("o-456");
getUser(u); // OK
getUser(o); // ❌ Type error — 매 nominal 의 distinguish
getUser("u-123"); // ❌ raw string 의 reject
```
### Branded with smart constructor (validate + brand)
```typescript
type Email = Brand<string, "Email">;
function Email(s: string): Email {
if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(s)) {
throw new Error(`invalid email: ${s}`);
}
return s as Email;
}
// safer Result variant
function tryEmail(s: string): { ok: true; value: Email } | { ok: false; error: string } {
return /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(s)
? { ok: true, value: s as Email }
: { ok: false, error: "invalid email" };
}
```
### Zod brand (runtime + type)
```typescript
import { z } from "zod";
const UserIdSchema = z.string().uuid().brand<"UserId">();
type UserId = z.infer<typeof UserIdSchema>;
const id = UserIdSchema.parse("550e8400-e29b-41d4-a716-446655440000");
// id is branded UserId — 매 raw uuid string 의 reject elsewhere
```
### Effect-TS Brand
```typescript
import { Brand } from "effect";
type USD = number & Brand.Brand<"USD">;
const USD = Brand.refined<USD>(
(n) => Number.isInteger(n) && n >= 0,
(n) => Brand.error(`expected positive integer cents, got ${n}`),
);
const price = USD(1999); // OK
const bad = USD(-5); // BrandErrors
```
### Numeric units (compile-time dimensional)
```typescript
type Meters = Brand<number, "Meters">;
type Seconds = Brand<number, "Seconds">;
type MPS = Brand<number, "MetersPerSecond">;
const m = (n: number) => n as Meters;
const s = (n: number) => n as Seconds;
function speed(d: Meters, t: Seconds): MPS {
return (d / t) as MPS;
}
speed(m(100), s(9.58)); // OK
speed(s(9.58), m(100)); // ❌ swapped
```
### Type-Fest Tagged (lighter syntax)
```typescript
import type { Tagged } from "type-fest";
type Email = Tagged<string, "Email">;
type UserId = Tagged<string, "UserId">;
```
### Phantom param (alternate encoding)
```typescript
declare const brand: unique symbol;
type Brand<T, K> = T & { readonly [brand]: K };
```
### Runtime parsing layer (input boundary)
```typescript
// API boundary — single point of validation
function handleRequest(raw: { userId: string; email: string }) {
const userId = UserId(raw.userId); // brand at boundary
const email = Email(raw.email); // validate + brand
return processOrder(userId, email); // internal: branded everywhere
}
```
## 매 결정 기준
| 상황 | Encoding |
|---|---|
| Lightweight ID 의 distinguish | Vanilla `__brand` |
| Runtime validation + brand | Zod brand · Effect Brand |
| Functional pipeline · refinement | Effect-TS Brand |
| Library ergonomics | Type-Fest `Tagged` |
| Numeric unit · dimensional | Brand<number, "Unit"> |
**기본값**: domain ID 의 vanilla brand, validated value 의 Zod, numeric/refinement 의 Effect Brand.
## 🔗 Graph
- 부모: [[TypeScript Type System]]
- 변형: [[Nominal-Typing-in-TypeScript|Nominal Typing]] · [[Opaque Types (TypeScript)]]
- 응용: [[Parse Don't Validate]]
- Adjacent: [[Ambient_Declarations]] · [[Schema Validation]]
## 🤖 LLM 활용
**언제**: domain ID 의 brand 의 generate, smart constructor + validator 의 draft, Zod schema 의 brand 의 add.
**언제 X**: 매 brand 의 over-applying — 매 internal helper 의 brand 의 X · 매 boundary 의 only.
## ❌ 안티패턴
- **Brand 의 everywhere**: function signature 의 noise 의 explode — 매 domain primitive 만.
- **Cast 의 sprinkled**: 매 single constructor 의 collapse — validation 의 single source.
- **Brand 의 leak through serialization**: JSON.parse 의 raw string 의 return — boundary parse 의 require.
- **Multiple brand 의 same value**: `Brand<string, "A"> & Brand<string, "B">` — 매 union 의 use 의 X · 매 새 brand 의 prefer.
## 🧪 검증 / 중복
- Verified (TypeScript handbook, Effect-TS docs, Zod 4 docs, Type-Fest Tagged docs, "Parse Don't Validate" Alexis King).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — vanilla + Zod + Effect-TS + Type-Fest variants |
@@ -0,0 +1,258 @@
---
id: wiki-2026-0508-breaking-dependencies
title: Breaking Dependencies
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Decoupling, Dependency Breaking, Refactoring Legacy]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [refactoring, architecture, legacy-code, testing]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: Java / TypeScript / Python
framework: language-agnostic
---
# Breaking Dependencies
## 매 한 줄
> **"매 untestable code 를 매 test 가능하게 만드는 첫 단계 = 매 hard dependency 를 매 break."**. Michael Feathers 의 *Working Effectively with Legacy Code* (2004) 의 24 가지 dependency-breaking technique 가 매 canonical reference. 2026 현재 modern DI / 매 hexagonal architecture 가 매 prevention layer, but 매 legacy 에는 여전히 매 Sprout Method / Extract Interface / Adapter 가 핵심.
## 매 핵심
### 매 dependency types
- **Construction dependency**: 매 `new SomeService()` hardcoded.
- **Static dependency**: 매 `Date.now()`, `Math.random()`, `Singleton.getInstance()`.
- **Hidden dependency**: 매 method 안에서 file / DB / network 직접 호출.
- **Temporal coupling**: 매 method A → B 순서 강요.
- **Inheritance dependency**: 매 base class 가 매 hard-to-test 행위 가짐.
### 매 Feathers 의 핵심 24 technique 중 top 8
1. **Sprout Method**: 매 new behavior 를 매 새 method 로 분리해 매 test 가능하게.
2. **Sprout Class**: 매 new behavior 를 매 new class 로.
3. **Extract Interface**: 매 concrete dep → 매 interface → mock.
4. **Extract and Override Call**: 매 hard call 을 매 protected method 로 → subclass 에서 override.
5. **Subclass and Override Method**: 매 testing subclass.
6. **Adapt Parameter**: 매 untestable arg → 매 wrapper interface.
7. **Break Out Method Object**: 매 거대 method → 매 클래스.
8. **Introduce Instance Delegator**: 매 static → 매 instance method 로.
### 매 응용
1. Legacy Java/C# enterprise codebase 의 unit test 도입.
2. Module 간 cyclic dependency 끊기.
3. 매 third-party SDK 의 hard wiring 제거.
4. Microservice extraction 전 prep.
5. 매 monolith 의 plugin 화.
## 💻 패턴
### Extract Interface (Java)
```java
// BEFORE — hard wired
public class OrderService {
public Receipt placeOrder(Order o) {
EmailSender sender = new EmailSender(); // hard dep
sender.send(o.customerEmail, "...");
return Receipt.from(o);
}
}
// AFTER — Extract Interface + DI
public interface Notifier {
void send(String to, String body);
}
public class EmailSender implements Notifier { /* impl */ }
public class OrderService {
private final Notifier notifier;
public OrderService(Notifier notifier) { this.notifier = notifier; }
public Receipt placeOrder(Order o) {
notifier.send(o.customerEmail, "...");
return Receipt.from(o);
}
}
// Test
@Test void placesOrderAndNotifies() {
var fake = mock(Notifier.class);
var svc = new OrderService(fake);
svc.placeOrder(testOrder());
verify(fake).send(eq("a@b.com"), anyString());
}
```
### Sprout Method (TypeScript)
```ts
// BEFORE — 매 huge method, 매 add new logic 못 testable
class Invoice {
process(): void {
// 200 lines 의 legacy
// 매 new logic 추가하면 매 테스트 X
}
}
// AFTER — sprout 로 새 행동만 분리
class Invoice {
process(): void {
// 200 lines 의 legacy (그대로)
this.applyLoyaltyDiscount(); // 매 sprouted
}
applyLoyaltyDiscount(): number { // 매 testable in isolation
if (this.customer.tier === 'gold') return this.total * 0.1;
if (this.customer.tier === 'silver') return this.total * 0.05;
return 0;
}
}
```
### Extract and Override Call (Python)
```python
# BEFORE
class Job:
def run(self):
now = datetime.utcnow() # 매 hard
if now.weekday() >= 5: return
self.do_work()
# AFTER
class Job:
def run(self):
if self._now().weekday() >= 5: return
self.do_work()
def _now(self) -> datetime: # 매 protected — override in test
return datetime.utcnow()
class TestJob(Job):
def __init__(self, fixed_dt): self.fixed_dt = fixed_dt
def _now(self): return self.fixed_dt
# Test
def test_skips_weekend():
j = TestJob(datetime(2026, 5, 9)) # 매 Saturday
j.do_work = MagicMock()
j.run()
j.do_work.assert_not_called()
```
### Adapt Parameter (Java)
```java
// BEFORE — HttpServletRequest hard to construct in test
public Result handle(HttpServletRequest req) {
String userId = req.getHeader("X-User-Id");
return repo.find(userId);
}
// AFTER — adapter interface
public interface RequestAdapter {
String header(String name);
}
public Result handle(RequestAdapter req) {
return repo.find(req.header("X-User-Id"));
}
// Production wraps; test = trivial map
class ServletRequestAdapter implements RequestAdapter {
private final HttpServletRequest delegate;
public String header(String n) { return delegate.getHeader(n); }
}
```
### Subclass and Override (Python — break DB)
```python
class ReportGenerator:
def fetch(self) -> list[dict]:
return db.query("SELECT * FROM orders") # 매 hard
def render(self) -> str:
rows = self.fetch()
return "\n".join(f"{r['id']}: {r['total']}" for r in rows)
class TestableReport(ReportGenerator):
def __init__(self, fake_rows): self.fake_rows = fake_rows
def fetch(self): return self.fake_rows
def test_renders():
r = TestableReport([{"id": 1, "total": 100}])
assert r.render() == "1: 100"
```
### Wrap Method (legacy 호환 유지)
```java
// 매 old API 깨면 안 됨 → 매 wrap
public void payInvoice(Invoice i) {
audit.log(i); // 매 new behavior
payInvoiceLegacy(i); // 매 unchanged
}
private void payInvoiceLegacy(Invoice i) { /* 매 untouched */ }
```
### Seam mapping checklist
```
1. List 매 untestable thing in target method
- Static call? → Introduce Instance Delegator / Replace Function with Function Object
- new? → Extract Interface + inject
- Time/random? → Extract & Override Call
- File/DB/HTTP? → Repository / Adapter
2. Pick 1 dep / day. 매 small step + commit.
3. 매 Test 먼저 (characterization test)
- 매 current behavior 를 lock down
4. Refactor under green tests.
```
### Hexagonal post-state (prevention)
```
[Domain Core] ← [Port (interface)] ← [Adapter (DB / HTTP / FS)]
매 NO direct import 매 from core to adapter
매 Test = stub adapter against port
```
## 매 결정 기준
| 상황 | Technique |
|---|---|
| 매 add new feature 매 large method | Sprout Method |
| 매 hard dep on concrete class | Extract Interface + DI |
| 매 static / time / random | Extract and Override Call |
| 매 framework type 의 arg | Adapt Parameter |
| 매 file / DB / network | Repository / Port-Adapter |
| 매 huge method 의 internal logic | Break Out Method Object |
| 매 base class behavior bad | Subclass and Override |
**기본값**: characterization test 먼저 → 매 minimal mechanical refactor (compiler-driven) → 매 small commit.
## 🔗 Graph
- 부모: [[Refactoring_Best_Practices|Refactoring]]
- 변형: [[Sprout-Method]]
- 응용: [[Test-Driven Development]] · [[Hexagonal Architecture]]
- Adjacent: [[Dependency_Injection_(DI)|Dependency-Injection]] · [[SOLID Principles]] · [[Mocking]]
## 🤖 LLM 활용
**언제**: legacy code unit test 도입, untestable method 마주침, monolith 분해 직전 prep, third-party SDK lock-in 제거.
**언제 X**: 매 already clean architecture (over-refactor 금지), 매 throwaway prototype.
## ❌ 안티패턴
- **Big-bang rewrite**: 매 일부 break → 매 전체 unstable.
- **Test 없이 refactor**: 매 behavior 변경 모름 → 매 silent regression.
- **너무 많은 mock**: 매 test 가 매 implementation 에 결합.
- **Interface 의 1 implementation 영구**: 매 YAGNI — 매 두 번째 user 생기면 그때 추출.
- **God adapter**: 매 1 interface 에 30 method.
- **Refactor + feature 동시 commit**: 매 review 불가.
## 🧪 검증 / 중복
- Verified (Feathers "Working Effectively with Legacy Code" 2004, Fowler "Refactoring" 2nd ed).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Breaking Dependencies with Feathers techniques |
@@ -0,0 +1,202 @@
---
id: wiki-2026-0508-broker-topology
title: Broker Topology
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Event Broker Topology, Pub-Sub Topology]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [event-driven, architecture, kafka, messaging]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: kafka-nats-rabbitmq
---
# Broker Topology
## 매 한 줄
> **"매 distributed pub-sub mesh — 매 central mediator 없이, broker (queue/topic) 가 routing fabric."**. Broker topology는 Event-Driven Architecture 의 두 종류 중 하나 (vs Mediator topology). 매 single-purpose events 의 fan-out 에 최적. 2026년 Kafka, NATS JetStream, AWS EventBridge, Redpanda, Pulsar 가 dominant brokers.
## 매 핵심
### 매 Broker vs Mediator
| 측면 | Broker | Mediator |
|---|---|---|
| Coordination | None — events fan out | Central mediator orchestrates |
| Coupling | Loosest | Some (mediator knows steps) |
| Use case | Simple fan-out, async notify | Complex multi-step workflow |
| Failure recovery | Each consumer handles | Mediator retries/compensates |
| Examples | Kafka topics, NATS subjects | Apache Camel, Step Functions |
### 매 컴포넌트
- **Producer**: events 의 publish.
- **Broker**: topic/subject/queue store + routing.
- **Consumer**: subscribe + react.
- **Schema Registry** (Confluent, Apicurio): event contract 의 versioning.
- **Dead Letter Queue (DLQ)**: failed messages.
### 매 broker 종류
- **Log-based** (Kafka, Redpanda, Pulsar): replay 가능, partitioned, ordered per partition.
- **Queue-based** (RabbitMQ, SQS): consumed once, no replay.
- **Subject-based** (NATS): lightweight, JetStream 으로 persistence.
- **Cloud-native** (EventBridge, Pub/Sub, EventHubs).
### 매 응용
1. Order events (e-commerce fan-out).
2. CDC (Debezium → Kafka → multiple sinks).
3. IoT telemetry ingestion.
4. Analytics event pipeline.
## 💻 패턴
### Kafka producer (TypeScript / KafkaJS)
```typescript
import { Kafka } from 'kafkajs';
const kafka = new Kafka({
clientId: 'orders',
brokers: ['kafka-1:9092', 'kafka-2:9092'],
});
const producer = kafka.producer();
await producer.connect();
await producer.send({
topic: 'order.created',
messages: [{
key: order.id,
value: JSON.stringify(order),
headers: { 'content-type': 'application/json' },
}],
});
```
### Kafka consumer (consumer group fan-out)
```typescript
const consumer = kafka.consumer({ groupId: 'shipping-svc' });
await consumer.connect();
await consumer.subscribe({ topic: 'order.created' });
await consumer.run({
eachMessage: async ({ message }) => {
const order = JSON.parse(message.value!.toString());
await createShipment(order);
},
});
```
### NATS JetStream
```typescript
import { connect, JSONCodec } from 'nats';
const nc = await connect({ servers: 'nats://localhost:4222' });
const js = nc.jetstream();
const jc = JSONCodec();
await js.publish('orders.created', jc.encode(order));
const sub = await js.subscribe('orders.>', {
config: { durable_name: 'shipping' },
});
for await (const m of sub) {
const order = jc.decode(m.data);
await createShipment(order);
m.ack();
}
```
### Schema Registry (Avro + Confluent)
```typescript
import { SchemaRegistry } from '@kafkajs/confluent-schema-registry';
const registry = new SchemaRegistry({ host: 'http://schema-registry:8081' });
const schema = `{
"type": "record",
"name": "OrderCreated",
"fields": [
{ "name": "id", "type": "string" },
{ "name": "amount", "type": "double" }
]
}`;
const { id } = await registry.register({ type: 'AVRO', schema });
const encoded = await registry.encode(id, order);
await producer.send({ topic: 'order.created', messages: [{ value: encoded }] });
```
### DLQ pattern
```typescript
await consumer.run({
eachMessage: async ({ topic, message }) => {
try {
await handleOrder(JSON.parse(message.value!.toString()));
} catch (err) {
await producer.send({
topic: `${topic}.dlq`,
messages: [{
value: message.value,
headers: {
...message.headers,
error: String(err),
retryCount: '0',
},
}],
});
}
},
});
```
### Partitioning for ordering
```typescript
// Same orderId always goes to same partition → ordered per order
await producer.send({
topic: 'order.events',
messages: [{
key: order.id, // partitioner uses key hash
value: JSON.stringify(event),
}],
});
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| High throughput, replay 필요 | Kafka / Redpanda |
| Lightweight, low-latency | NATS JetStream |
| Cloud serverless | EventBridge, Pub/Sub |
| Strong work-queue + ack | RabbitMQ, SQS |
| Multi-tenant, geo | Pulsar |
**기본값**: Kafka (or Redpanda — Kafka API compat) + Schema Registry + Avro/Protobuf for events.
## 🔗 Graph
- 부모: [[Event-Driven Architecture]]
- 변형: [[Mediator Topology]] · [[Choreography]]
- 응용: [[Kafka]] · [[NATS]]
- Adjacent: [[CDC]]
## 🤖 LLM 활용
**언제**: fan-out events, decoupled microservices, CDC pipelines, telemetry ingestion.
**언제 X**: synchronous request-reply (use gRPC/HTTP), small monolith (events 가 overhead).
## ❌ 안티패턴
- **No schema registry**: 모든 producer/consumer 가 schema drift — production 깨짐.
- **Topic per service**: scalability impossible — topic per event type.
- **No DLQ**: poison messages 가 consumer halt — DLQ + alerting.
- **Sync over async**: HTTP request-reply 를 broker 위에 — synchronous 면 broker 의 X.
## 🧪 검증 / 중복
- Verified (Richards "Software Architecture Patterns" / Confluent docs / NATS docs 2026).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Broker vs Mediator + Kafka/NATS/DLQ 패턴 |
@@ -0,0 +1,183 @@
---
id: wiki-2026-0508-browser
title: Browser
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Web Browser, Browser Internals, Rendering Engine]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [browser, web, rendering, javascript, networking]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: C++/Rust
framework: Chromium/Gecko/WebKit
---
# Browser
## 매 한 줄
> **"매 browser = networking stack + parsing + rendering + JS engine + sandbox 의 거대한 OS-like 시스템."**. 매 2026 현재 Chromium-derived (Chrome, Edge, Brave, Arc) 가 ~70% market share, Firefox/Gecko 와 Safari/WebKit 이 나머지. 매 process-per-site isolation, GPU-accelerated compositing, V8 의 Sparkplug+Maglev+TurboFan tier 가 modern baseline.
## 매 핵심
### 매 multi-process architecture
- **Browser process**: 매 UI, networking, IPC orchestration.
- **Renderer process**: 매 site-per-process — Blink + V8.
- **GPU process**: 매 compositing, WebGL/WebGPU.
- **Network service**: 매 별도 process — credential isolation.
- **Utility processes**: 매 audio, video decode, storage.
### 매 rendering pipeline
1. **Parse** HTML → DOM.
2. **Parse** CSS → CSSOM.
3. **Style** — match rules → ComputedStyle.
4. **Layout** — geometry computation.
5. **Paint** — layer 별 display list.
6. **Composite** — GPU 가 layer 합성.
### 매 JS engine tiers (V8)
- **Ignition** (interpreter) → **Sparkplug** (baseline JIT) → **Maglev** (mid-tier) → **TurboFan** (optimizing JIT).
- 매 hot function 만 점진적 promotion.
### 매 응용
1. **Web app development**: 매 performance budgeting.
2. **Extension / DevTools**: 매 internal API.
3. **Embedded webview**: 매 Electron, Tauri, CEF.
4. **Headless**: 매 Puppeteer, Playwright scraping/test.
## 💻 패턴
### Performance: Critical Rendering Path
```html
<!-- inline above-the-fold CSS, defer non-critical -->
<style>/* critical CSS here */</style>
<link rel="preload" href="/fonts/main.woff2" as="font" crossorigin>
<link rel="stylesheet" href="/non-critical.css" media="print" onload="this.media='all'">
<script type="module" src="/app.js" defer></script>
```
### Avoid layout thrash
```javascript
// BAD — read/write/read/write triggers sync layouts
boxes.forEach(b => {
const w = b.offsetWidth; // forces layout
b.style.width = (w * 2) + 'px'; // invalidates
});
// GOOD — batch reads then writes
const widths = boxes.map(b => b.offsetWidth);
boxes.forEach((b, i) => b.style.width = (widths[i] * 2) + 'px');
```
### Service worker — offline + cache
```javascript
// sw.js
self.addEventListener('install', e => {
e.waitUntil(caches.open('v1').then(c => c.addAll([
'/', '/app.js', '/styles.css'
])));
});
self.addEventListener('fetch', e => {
e.respondWith(
caches.match(e.request).then(r => r || fetch(e.request))
);
});
```
### Intersection observer (lazy load)
```javascript
const io = new IntersectionObserver(entries => {
for (const e of entries) {
if (e.isIntersecting) {
e.target.src = e.target.dataset.src;
io.unobserve(e.target);
}
}
}, { rootMargin: '200px' });
document.querySelectorAll('img[data-src]').forEach(img => io.observe(img));
```
### Web Workers — off-main-thread
```javascript
// main.js
const w = new Worker('worker.js', { type: 'module' });
w.postMessage({ buffer: bigArray }, [bigArray.buffer]); // transfer, not copy
w.onmessage = e => console.log(e.data);
// worker.js
onmessage = e => {
const result = heavyCompute(e.data.buffer);
postMessage(result);
};
```
### Performance API — measure real users
```javascript
new PerformanceObserver(list => {
for (const entry of list.getEntries()) {
if (entry.name === 'LCP') sendBeacon('lcp', entry.startTime);
if (entry.entryType === 'layout-shift') sendBeacon('cls', entry.value);
if (entry.entryType === 'event') sendBeacon('inp', entry.duration);
}
}).observe({ type: 'largest-contentful-paint', buffered: true });
```
### CSP header
```http
Content-Security-Policy: default-src 'self'; script-src 'self' 'sha256-AbCd...';
style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; frame-ancestors 'none';
```
### WebGPU compute (modern)
```javascript
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const shader = device.createShaderModule({ code: `
@group(0) @binding(0) var<storage, read_write> v: array<f32>;
@compute @workgroup_size(64) fn main(@builtin(global_invocation_id) g: vec3u) {
v[g.x] = v[g.x] * 2.0;
}`});
// ... pipeline + dispatch
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Hydration TTI 느림 | islands / partial hydration (Astro, Qwik) |
| Heavy compute on UI thread | Web Worker / WebAssembly |
| Repeated tiny renders | requestAnimationFrame batch |
| Need GPU for ML inference | WebGPU + ONNX Runtime Web |
| Cross-origin embed | iframe + CSP frame-ancestors |
**기본값**: HTTP/3 + service worker cache + defer non-critical JS + Web Vitals monitoring.
## 🔗 Graph
- 변형: [[Chromium]] · [[WebKit]]
- 응용: [[Single_Page_Application]] · [[PWA]] · [[Electron]]
- Adjacent: [[V8]] · [[WebAssembly]] · [[WebGPU]] · [[Service_Worker]]
## 🤖 LLM 활용
**언제**: web perf 최적화, browser API 선택, rendering pipeline 디버깅.
**언제 X**: server-side rendering 내부 (Node/Bun 영역).
## ❌ 안티패턴
- **document.write**: 매 parser blocking — 절대 X.
- **Synchronous XHR**: 매 main thread freeze — deprecated.
- **Layout thrash loop**: 매 read-write 교차 → forced sync layouts.
- **Massive bundle (>1MB JS)**: 매 mobile TTI 폭망 — code splitting 필수.
- **Too many compositor layers**: 매 will-change 남발 → GPU memory exhaustion.
## 🧪 검증 / 중복
- Verified (web.dev/architecture, Chromium design docs 2024, V8 blog 2025).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — multi-process arch, rendering pipeline, modern web APIs |
@@ -0,0 +1,167 @@
---
id: wiki-2026-0508-c4-modeling-framework
title: C4 Modeling Framework
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [C4 Model, C4 Diagrams, Simon Brown C4]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [architecture, c4, diagram, structurizr, documentation]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: DSL
framework: Structurizr
---
# C4 Modeling Framework
## 매 한 줄
> **"매 software architecture = 4 zoom levels (Context → Container → Component → Code)."**. 매 Simon Brown 이 2006년경 제안한 lightweight visualization framework. 매 2026 현재 Structurizr DSL + Mermaid C4 plugin 으로 diagram-as-code 가 standard, 매 audience-specific abstraction level 이 핵심 가치.
## 매 핵심
### 매 4 levels
- **L1 — System Context**: 매 system + users + external systems. 매 non-technical stakeholder 용.
- **L2 — Container**: 매 deployable unit (web app, API, DB, queue). 매 technical lead 용.
- **L3 — Component**: 매 container 내부 logical grouping (controller, service, repo). 매 dev team 용.
- **L4 — Code**: 매 class diagram (UML). 매 거의 안 그림 — IDE 가 대신.
### 매 supplementary diagrams
- **Deployment diagram**: 매 container → infrastructure node mapping.
- **Dynamic diagram**: 매 runtime sequence/collaboration.
- **System landscape**: 매 enterprise-wide multi-system view.
### 매 응용
1. **Onboarding doc**: 매 새 dev 의 codebase orientation.
2. **ADR illustration**: 매 architecture decision record 의 visual aid.
3. **Stakeholder communication**: 매 PM/exec 에게 system scope 설명.
4. **Compliance audit**: 매 data flow / boundary 시각화.
## 💻 패턴
### Structurizr DSL (canonical)
```dsl
workspace "Banking System" {
model {
customer = person "Customer"
bankSystem = softwareSystem "Internet Banking" {
webApp = container "Web Application" "Spring Boot" "Java"
mobileApp = container "Mobile App" "React Native" "TypeScript"
api = container "API" "Spring Boot" "Java"
db = container "Database" "PostgreSQL" "RDBMS"
webApp -> api "uses" "JSON/HTTPS"
mobileApp -> api "uses" "JSON/HTTPS"
api -> db "reads/writes" "JDBC"
}
mainframe = softwareSystem "Mainframe" "External"
customer -> bankSystem "uses"
bankSystem -> mainframe "fetches account data" "MQ"
}
views {
systemContext bankSystem { include * autolayout }
container bankSystem { include * autolayout }
theme default
}
}
```
### Mermaid C4 (in-repo markdown)
```mermaid
C4Context
title System Context — Banking
Person(customer, "Customer")
System(bank, "Internet Banking", "Allows customers to view accounts")
System_Ext(mainframe, "Mainframe", "Legacy core banking")
Rel(customer, bank, "Uses")
Rel(bank, mainframe, "Fetches data", "MQ")
```
### Component-level decomposition
```dsl
api = container "API" {
signInController = component "SignIn Controller" "Spring MVC"
accountsController = component "Accounts Controller" "Spring MVC"
authService = component "Auth Service" "Spring Bean"
accountsRepo = component "Accounts Repository" "Spring Data JPA"
signInController -> authService "uses"
accountsController -> accountsRepo "reads"
authService -> db "verifies credentials"
}
```
### Deployment view
```dsl
deploymentEnvironment "Production" {
deploymentNode "AWS us-east-1" {
deploymentNode "EKS Cluster" {
containerInstance webApp
containerInstance api
}
deploymentNode "RDS" {
containerInstance db
}
}
}
```
### Generated docs pipeline
```bash
# CI step — render diagrams from DSL
docker run --rm -v $PWD:/usr/local/structurizr structurizr/cli \
export -workspace workspace.dsl -format plantuml/c4plantuml
plantuml -tsvg *.puml
mv *.svg docs/architecture/
```
### ADR + C4 link
```markdown
# ADR-007: Move auth to dedicated service
**Status**: Accepted
**Context**: See [Container diagram](../diagrams/banking-containers.svg)
**Decision**: Extract `authService` component into its own container.
**Consequences**: New diagram in `diagrams/v2-containers.svg`.
```
## 매 결정 기준
| 상황 | Diagram level |
|---|---|
| Pitch to exec / new joiner intro | L1 Context |
| Tech selection / deployment plan | L2 Container |
| Code review / refactor discussion | L3 Component |
| Inheritance question | IDE (skip L4) |
| Multi-system enterprise view | System Landscape |
**기본값**: L1 + L2 (둘만 있어도 90% communication 충족).
## 🔗 Graph
- 부모: [[Software_Architecture]] · [[Architecture_Documentation]]
- 변형: [[arc42]]
- 응용: [[ADR]] · [[Structurizr]]
- Adjacent: [[Mermaid]] · [[PlantUML]] · [[DDD]]
## 🤖 LLM 활용
**언제**: greenfield architecture 문서화, legacy reverse-engineering, ADR illustration.
**언제 X**: real-time runtime monitoring (observability tool 영역).
## ❌ 안티패턴
- **All 4 levels for every system**: 매 L4 거의 무의미 — IDE 대체.
- **Mixing levels in one diagram**: 매 abstraction 깨짐 → audience 혼란.
- **No legend / inconsistent shapes**: 매 reader 가 element type 못 구분.
- **Diagram drift**: 매 DSL 없이 manual draw → 6개월 후 stale.
## 🧪 검증 / 중복
- Verified (c4model.com — Simon Brown, Structurizr DSL spec 2024).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — C4 levels, Structurizr DSL, Mermaid C4 examples |
@@ -0,0 +1,183 @@
---
id: wiki-2026-0508-cad-렌더링-최적화
title: CAD 렌더링 최적화
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [CAD Rendering Optimization, CAD Performance, Engineering Visualization]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [cad, rendering, gpu, lod, webgpu]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: TypeScript
framework: WebGPU/Three.js
---
# CAD 렌더링 최적화
## 매 한 줄
> **"매 millions-of-triangles model 의 60fps 표시 = LOD + culling + GPU instancing 의 합."**. 매 CAD assembly 는 mechanical part 가 hundreds-of-thousands 단위로 쌓여 brute-force rendering 시 GPU 가 즉사. 매 2026 모던 stack 은 WebGPU + meshlet (Nanite-style) + indirect draw 를 사용해 browser 에서도 native-like performance 달성.
## 매 핵심
### 매 bottleneck axis
- **Geometry**: 매 triangle count — 매 fillet/thread 같은 detail 이 수십 million 까지 폭증.
- **Draw call**: 매 part 별 separate draw → CPU/GPU sync overhead 가 frame budget 잠식.
- **Overdraw**: 매 transparent assembly 의 layered fragment shading.
- **Memory**: 매 32-bit index + per-vertex normal/UV/color → VRAM 빠르게 saturate.
### 매 technique stack
- **Tessellation control**: 매 NURBS → mesh 변환 시 view-dependent chord tolerance.
- **LOD**: 매 distance / screen-coverage 기반 mesh swap.
- **Frustum / occlusion culling**: 매 BVH + Hi-Z buffer.
- **Instancing**: 매 동일 part (bolt/screw) 의 single draw call.
- **Meshlet (Nanite-like)**: 매 cluster 단위 GPU culling + virtual geometry.
- **Deferred shading**: 매 overdraw 비용 절감.
### 매 응용
1. **Onshape / Fusion 360 web**: 매 browser 안 assembly editing.
2. **Plant 3D walkthrough**: 매 oil refinery / factory digital twin.
3. **AR overlay**: 매 Vision Pro / Quest 3 의 maintenance instruction.
4. **VR design review**: 매 stakeholder 의 immersive walkthrough.
## 💻 패턴
### Screen-space LOD selection
```typescript
function pickLOD(part: CadPart, camera: Camera): number {
const screenCoverage = projectedRadius(part.bounds, camera) / camera.viewport.height;
if (screenCoverage > 0.3) return 0; // full mesh
if (screenCoverage > 0.1) return 1; // 1/4 triangles
if (screenCoverage > 0.03) return 2; // 1/16 triangles
if (screenCoverage > 0.005) return 3; // billboard
return -1; // cull entirely
}
```
### GPU instancing for fasteners
```typescript
const boltMesh = loadMesh('m6_socket_head.glb');
const transforms = new Float32Array(boltCount * 16); // packed mat4
fillTransforms(transforms, boltInstances);
device.queue.writeBuffer(instanceBuffer, 0, transforms);
pass.setPipeline(instancedPipeline);
pass.setVertexBuffer(0, boltMesh.vertices);
pass.setVertexBuffer(1, instanceBuffer);
pass.drawIndexed(boltMesh.indexCount, boltCount); // single call for 50k bolts
```
### BVH-based frustum culling
```typescript
class BVHNode {
bounds: AABB;
children?: [BVHNode, BVHNode];
parts?: CadPart[];
}
function cullVisible(node: BVHNode, frustum: Frustum, out: CadPart[]) {
const test = frustum.testAABB(node.bounds);
if (test === 'outside') return;
if (test === 'inside' || !node.children) {
out.push(...(node.parts ?? collectAll(node)));
return;
}
cullVisible(node.children[0], frustum, out);
cullVisible(node.children[1], frustum, out);
}
```
### Meshlet cluster (Nanite-style)
```wgsl
// WebGPU compute shader — cluster culling
@group(0) @binding(0) var<storage, read> meshlets: array<Meshlet>;
@group(0) @binding(1) var<storage, read_write> visibleList: array<u32>;
@group(0) @binding(2) var<uniform> camera: Camera;
@compute @workgroup_size(64)
fn cullMeshlets(@builtin(global_invocation_id) gid: vec3u) {
let idx = gid.x;
if (idx >= arrayLength(&meshlets)) { return; }
let m = meshlets[idx];
if (frustumTest(m.boundingSphere, camera) &&
coneTest(m.normalCone, camera.position)) {
let slot = atomicAdd(&visibleList[0], 1u);
visibleList[slot + 1u] = idx;
}
}
```
### Indirect draw aggregation
```typescript
// One draw call dispatches all visible meshlets
const drawArgs = new Uint32Array([
indexCount, instanceCount, firstIndex, baseVertex, firstInstance
]);
device.queue.writeBuffer(indirectBuffer, 0, drawArgs);
pass.drawIndexedIndirect(indirectBuffer, 0);
```
### Progressive streaming
```typescript
async function streamAssembly(modelId: string) {
const manifest = await fetch(`/cad/${modelId}/manifest.json`).then(r => r.json());
// load coarse first → user sees something instantly
for (const lod of [3, 2, 1, 0]) {
await Promise.all(manifest.parts.map(p =>
cache.has(`${p.id}_lod${lod}`) ? null : loadPart(p, lod)
));
requestRedraw();
}
}
```
### Hi-Z occlusion
```typescript
// Down-sampled depth pyramid → occluder test before draw
const hiZ = buildHiZPyramid(depthTexture);
for (const part of visibleAfterFrustum) {
if (occludedByHiZ(part.bounds, hiZ, camera)) continue;
drawList.push(part);
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| < 100k triangles, single part | brute force, no LOD |
| 1M-10M triangles, assembly | BVH + frustum culling + LOD |
| 10M-100M triangles | + GPU instancing + meshlets |
| > 100M (plant/ship) | virtual geometry + streaming + occlusion |
| Mobile / VR | aggressive LOD + foveated rendering |
**기본값**: BVH culling + 4-tier LOD + instanced fasteners (covers 90% mid-size assemblies).
## 🔗 Graph
- 부모: [[Computer_Graphics]] · [[GPU Architecture]]
- 응용: [[Digital_Twin]]
- Adjacent: [[WebGPU]] · [[Three.js]] · [[Level_of_Detail]]
## 🤖 LLM 활용
**언제**: CAD/BIM viewer 설계, performance bottleneck 분석, LOD threshold tuning.
**언제 X**: photorealistic offline rendering (path tracing 영역).
## ❌ 안티패턴
- **Per-part separate draw call**: 매 50k draws/frame 은 어떤 GPU 도 죽음.
- **CPU-side culling only**: 매 GPU-driven culling 없이는 modern bandwidth 활용 불가.
- **Uniform LOD across assembly**: 매 close-up bolt 는 detail 필요, far wall 은 billboard 충분.
- **No tessellation budget**: 매 NURBS → mesh 변환 시 chord tolerance 가 화면 무관하면 메모리 폭발.
## 🧪 검증 / 중복
- Verified (Onshape engineering blog 2025, Unreal Nanite SIGGRAPH 2021, WebGPU spec 2024).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — CAD rendering pipeline, LOD, meshlet, WebGPU patterns |
@@ -0,0 +1,185 @@
---
id: wiki-2026-0508-cst
title: CST
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Concrete Syntax Tree, Parse Tree, Lossless Syntax Tree]
duplicate_of: none
source_trust_level: A
confidence_score: 0.95
verification_status: applied
tags: [parser, compiler, ast, cst, ide, refactoring]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: Polyglot
framework: tree-sitter/Roslyn/rust-analyzer
---
# CST
## 매 한 줄
> **"매 Concrete Syntax Tree (CST) = 매 source text 의 모든 문자 (whitespace, comment, trivia) 까지 보존하는 lossless tree."**. 매 AST 가 의미만 남기고 trivia 를 버린 반면, CST 는 매 round-trip print 가 가능. 매 2026 모던 IDE / formatter / refactor tool 의 backbone — tree-sitter, Roslyn, rust-analyzer 가 모두 CST.
## 매 핵심
### 매 AST vs CST
- **AST**: 매 abstract — 매 keyword/punctuation 생략, semantics 만.
- **CST**: 매 concrete — 매 every token + whitespace + comment.
- **Round-trip**: 매 CST → exact source text 복원 가능.
- **Incremental update**: 매 edit 시 affected subtree 만 reparse.
### 매 use-case where CST > AST
- **Code formatter** (prettier, gofmt, rustfmt): 매 trivia 제어 필요.
- **Refactor tool**: 매 comment 보존 + 정확한 source range.
- **Linter with auto-fix**: 매 source position 정확.
- **Syntax highlighting**: 매 every token 위치 필요.
- **IDE error tolerance**: 매 partial parse 도 tree 반환.
### 매 응용
1. **tree-sitter**: 매 GitHub/Atom/Neovim grammar — 매 incremental.
2. **Roslyn (C#)**: 매 `SyntaxNode` 가 CST.
3. **rust-analyzer**: 매 `rowan` library 의 lossless syntax tree.
4. **Babel `@babel/parser`**: 매 AST + tokens (semi-CST).
5. **Prettier**: 매 input 의 doc-IR 변환.
## 💻 패턴
### tree-sitter — incremental CST
```javascript
const Parser = require('tree-sitter');
const Java = require('tree-sitter-java');
const parser = new Parser();
parser.setLanguage(Java);
const source = `class A { int x = 1; }`;
const tree = parser.parse(source);
// edit: insert at offset 17
const newSource = `class A { int x = 1; int y = 2; }`;
tree.edit({
startIndex: 19, oldEndIndex: 19, newEndIndex: 31,
startPosition: {row: 0, column: 19},
oldEndPosition: {row: 0, column: 19},
newEndPosition: {row: 0, column: 31},
});
const newTree = parser.parse(newSource, tree); // reuses unchanged subtrees
```
### Roslyn — preserve trivia in refactor
```csharp
var tree = CSharpSyntaxTree.ParseText(source);
var root = tree.GetRoot();
var oldMethod = root.DescendantNodes().OfType<MethodDeclarationSyntax>().First();
var newMethod = oldMethod
.WithIdentifier(SyntaxFactory.Identifier("RenamedMethod"))
.WithLeadingTrivia(oldMethod.GetLeadingTrivia())
.WithTrailingTrivia(oldMethod.GetTrailingTrivia());
var newRoot = root.ReplaceNode(oldMethod, newMethod);
File.WriteAllText(path, newRoot.ToFullString()); // round-trip, comments intact
```
### rust-analyzer rowan
```rust
use rowan::{GreenNode, SyntaxNode};
// Green tree = immutable, shareable
let green: GreenNode = parse(source);
// Red tree = lazy wrapper with parent pointers + offset
let syntax: SyntaxNode<MyLang> = SyntaxNode::new_root(green);
for token in syntax.descendants_with_tokens() {
println!("{:?} @ {:?}", token.kind(), token.text_range());
// includes whitespace, comments, error tokens
}
```
### Lossless tree → AST view
```rust
// AST is a typed view over CST
pub struct FnDef(SyntaxNode);
impl FnDef {
pub fn name(&self) -> Option<Name> {
self.0.children().find_map(Name::cast)
}
pub fn body(&self) -> Option<Block> {
self.0.children().find_map(Block::cast)
}
}
// Original text, comments, whitespace = always retrievable via self.0.text()
```
### CST-based formatter
```typescript
function format(node: CSTNode, ctx: PrintCtx): Doc {
switch (node.type) {
case 'function_declaration':
return concat([
node.leadingTrivia.filter(isComment), // preserve doc comments
'function ',
format(node.name, ctx),
format(node.params, ctx),
' ',
format(node.body, ctx),
]);
// ...
}
}
```
### Error-tolerant parse
```javascript
// tree-sitter inserts ERROR / MISSING nodes; tree still walkable
const tree = parser.parse(`function f() { return ; }`);
tree.rootNode.descendantsOfType('ERROR').forEach(n => {
console.log('parse error at', n.startPosition);
});
// IDE keeps working even with incomplete code
```
### Source range — exact byte spans
```csharp
foreach (var diag in compilation.GetDiagnostics()) {
var span = diag.Location.SourceSpan;
Console.WriteLine($"[{span.Start}..{span.End}] {diag.GetMessage()}");
}
```
## 매 결정 기준
| 상황 | CST or AST |
|---|---|
| Code formatter | CST (trivia 필요) |
| Compiler optimization pass | AST (semantics 만) |
| IDE / refactor tool | CST |
| Pure code generation (template) | AST |
| Syntax highlighter | CST tokens |
| Bytecode emit | AST + lowered IR |
**기본값**: developer-tool 빌드 = CST first (tree-sitter or rowan); compiler = CST → AST → IR.
## 🔗 Graph
- 부모: [[Parser]]
- 변형: [[AST]] · [[Lossless_Syntax_Tree]]
- 응용: [[Code_Formatter]] · [[IDE]] · [[Refactoring_Tools]]
## 🤖 LLM 활용
**언제**: parser tool 선택, refactor 구현, formatter 설계.
**언제 X**: runtime semantic analysis (type checker 영역 — AST 기반).
## ❌ 안티패턴
- **Regex 로 source rewrite**: 매 trivia 망가지고 nested 구조 무시.
- **AST refactor + reprint**: 매 comment 모두 사라짐.
- **Full reparse on every keystroke**: 매 IDE freeze — incremental 필수.
- **Mutable shared CST**: 매 race condition; immutable green tree 사용.
## 🧪 검증 / 중복
- Verified (tree-sitter docs, Roslyn API ref, "Lossless Syntax Tree" Aleksey Kladov 2020).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — CST vs AST, tree-sitter, Roslyn, rowan patterns |
@@ -0,0 +1,171 @@
---
id: wiki-2026-0508-call-stack-analysis
title: Call Stack Analysis
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Call Stack, Stack Trace Analysis, Flame Graph, Profiling Stack]
duplicate_of: none
source_trust_level: A
confidence_score: 0.95
verification_status: applied
tags: [profiling, performance, flame-graph, debugging, observability]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: Polyglot
framework: perf/eBPF/pprof
---
# Call Stack Analysis
## 매 한 줄
> **"매 performance bug 의 95% 는 'where is CPU time spent?' — 매 call stack sampling 이 답한다."**. 매 stack trace 를 statistical 하게 sampling → flame graph 로 visualize 하면 hot path 가 즉시 보임. 매 2026 표준 stack 은 Linux perf + eBPF, 매 inferno / pyroscope / Datadog Continuous Profiler.
## 매 핵심
### 매 sampling vs instrumentation
- **Sampling profiler**: 매 N Hz (보통 99/999Hz) 마다 stack capture → low overhead, statistical.
- **Instrumented profiler**: 매 every entry/exit hook → exact, but 10-100x overhead.
- **현대 default**: 매 sampling — 매 production-safe.
### 매 stack source
- **Frame pointer (RBP) walk**: 매 fastest, requires `-fno-omit-frame-pointer`.
- **DWARF unwind**: 매 .eh_frame 사용 — frame pointer 불필요하나 expensive.
- **ORC unwinder**: 매 Linux kernel 의 lightweight DWARF subset.
- **eBPF stackmap**: 매 user+kernel stack 통합.
### 매 visualization
- **Flame graph (Brendan Gregg)**: 매 x=share of samples, y=stack depth, width=hot.
- **Icicle graph**: 매 flipped flame — root at top.
- **Differential flame graph**: 매 두 profile diff — perf regression 사냥.
### 매 응용
1. **CPU bottleneck 진단**: 매 hot function 식별.
2. **Lock contention**: 매 off-CPU profile + futex stack.
3. **GC pressure**: 매 alloc-stack profile.
4. **Cold start**: 매 startup phase flame graph.
5. **Continuous profiling**: 매 prod 24/7 sample → regression alerting.
## 💻 패턴
### Linux perf — basic
```bash
# 30s sample at 99Hz
perf record -F 99 -a -g --call-graph dwarf -- sleep 30
perf script > out.stack
# render
git clone https://github.com/brendangregg/FlameGraph
./FlameGraph/stackcollapse-perf.pl out.stack | \
./FlameGraph/flamegraph.pl > flame.svg
```
### eBPF profile (BCC)
```bash
profile-bpfcc -F 99 -f 30 > out.folded
flamegraph.pl out.folded > flame.svg
# advantages: lower overhead, kernel+user merged
```
### Go pprof
```go
import _ "net/http/pprof"
func main() {
go http.ListenAndServe(":6060", nil)
// ... app
}
```
```bash
go tool pprof -http=:8080 http://localhost:6060/debug/pprof/profile?seconds=30
# interactive flame graph in browser
```
### Python py-spy (no code change)
```bash
py-spy record -o flame.svg -d 30 --pid $(pgrep -f myapp.py)
# zero instrumentation, samples a running process
```
### Node.js / V8
```bash
node --prof app.js
# ... run workload ...
node --prof-process isolate-0xNNN-v8.log > profile.txt
# or 0x: npx 0x -- node app.js
```
### JVM async-profiler
```bash
# attach to running JVM, 60s flame graph
asprof -d 60 -f flame.html $PID
# also captures lock contention, alloc, wall-clock
```
### Rust — pprof crate
```rust
use pprof::ProtoBuf;
let guard = pprof::ProfilerGuardBuilder::default()
.frequency(999)
.blocklist(&["libc", "libgcc", "pthread"])
.build()?;
// ... workload ...
let report = guard.report().build()?;
let mut file = std::fs::File::create("profile.pb")?;
report.pprof()?.encode(&mut file)?;
```
### Continuous profiling (Pyroscope / Grafana)
```yaml
# pyroscope agent — runs alongside app
pyroscope:
server: http://pyroscope:4040
app_name: api-prod
spy_name: ebpfspy # auto-detect language
sample_rate: 100
```
### Differential flame graph
```bash
./FlameGraph/difffolded.pl before.folded after.folded | \
./FlameGraph/flamegraph.pl > diff.svg
# red = got slower, blue = got faster
```
## 매 결정 기준
| 상황 | Tool |
|---|---|
| Linux native (C/C++/Rust/Go) | perf + FlameGraph |
| Container / k8s (no SYS_ADMIN) | pprof endpoint |
| Python prod | py-spy |
| JVM prod | async-profiler |
| Continuous 24/7 | Pyroscope / Datadog |
| Off-CPU (lock/IO) | offcputime-bpfcc |
**기본값**: 99Hz sampling → folded → flamegraph.pl. 매 첫 5분 안에 hot path 보임.
## 🔗 Graph
- 부모: [[Observability]]
- 변형: [[Flame_Graph]]
- Adjacent: [[eBPF]]
## 🤖 LLM 활용
**언제**: hot function 분석, regression diff, profile 결과 해석.
**언제 X**: tail latency / distributed trace (분산 환경은 OpenTelemetry).
## ❌ 안티패턴
- **Time.time printf 로그 profiling**: 매 statistical 안 되고 hot loop 망침.
- **Frame pointer 없는 build**: 매 unwind 망가짐 — `-fno-omit-frame-pointer` 필수.
- **너무 낮은 sample rate (10Hz)**: 매 30초 = 300 samples — noise dominate.
- **너무 높은 rate (10kHz)**: 매 self-overhead 가 측정 결과 왜곡.
- **Single-run profile 만 보기**: 매 variance — minimum 5 runs 권장.
## 🧪 검증 / 중복
- Verified (Brendan Gregg "Systems Performance" 2nd ed 2020, Linux perf docs, async-profiler README 2024).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — sampling profilers, flame graphs, multi-language tooling |
@@ -0,0 +1,223 @@
---
id: wiki-2026-0508-characterization-tests-특성화-테스트
title: Characterization Tests (특성화 테스트)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Golden Master Tests, Approval Tests, Pinning Tests, Snapshot Tests]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [testing, legacy-code, feathers, refactoring]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript-python
framework: jest-pytest-approvaltests
---
# Characterization Tests (특성화 테스트)
## 매 한 줄
> **"매 legacy code 의 actual behavior 의 capture — 매 spec 이 X, 매 photo 가 O."**. Michael Feathers 의 *Working Effectively with Legacy Code* (2004) 에서 정립. 매 untested legacy 의 refactoring 시작점. 매 "what should it do" X — 매 "what does it do right now" 의 lock down. 2026년 snapshot tests, ApprovalTests, golden master tests 모두 같은 family.
## 매 핵심
### 매 정의 (Feathers)
> "A characterization test is a test that characterizes the actual behavior of a piece of code. There's no 'correct'... it just records what the system does."
### 매 vs unit/spec test
| 측면 | Spec Test | Characterization Test |
|---|---|---|
| Source of truth | Requirements / spec | Actual current behavior |
| Failing means | Code has bug | Behavior changed (maybe intended) |
| When to write | TDD, before code | Before refactoring legacy code |
| Update on change | Fix code | Review diff, accept if intended |
### 매 procedure (Feathers)
1. Pick code 의 region.
2. Write test 가 invokes the code with realistic inputs.
3. Assert with **placeholder** (e.g. `assert result == "FILL_ME"`).
4. Run, capture actual output.
5. Replace placeholder with actual output.
6. Now test pins behavior — refactor with confidence.
### 매 variants
- **Snapshot test** (Jest, Vitest): serialize output, compare next run.
- **Approval test** (ApprovalTests): write to `.approved.txt`, manual review on diff.
- **Golden master**: large input/output pair, often UI screenshot.
- **Property-based regression**: random inputs, save outputs as golden.
### 매 응용
1. Refactoring legacy monolith without specs.
2. Migration (framework upgrade, language port).
3. Compiler / parser output stability.
4. Report generation (PDFs, CSVs).
5. UI visual regression (Percy, Chromatic).
## 💻 패턴
### Feathers procedure (TypeScript + Jest)
```typescript
import { calculateInvoice } from './legacy';
describe('calculateInvoice — characterization', () => {
it('records current behavior for typical input', () => {
const result = calculateInvoice({
items: [
{ sku: 'A', qty: 2, price: 19.99 },
{ sku: 'B', qty: 1, price: 5.00 },
],
customerType: 'premium',
country: 'KR',
});
// Step 1: write `expect(result).toBe('PLACEHOLDER')`
// Step 2: run, observe actual:
// { subtotal: 44.98, discount: 4.50, vat: 4.05, total: 44.53 }
// Step 3: paste it as expected
expect(result).toEqual({
subtotal: 44.98,
discount: 4.50,
vat: 4.05,
total: 44.53,
});
});
});
```
### Jest snapshot
```typescript
import { renderInvoiceHtml } from './render';
test('invoice html — characterized', () => {
const html = renderInvoiceHtml(SAMPLE_INVOICE);
expect(html).toMatchSnapshot();
});
// First run: writes __snapshots__/invoice.test.ts.snap
// Future runs: diffs. Use `--update-snapshot` after intentional change.
```
### ApprovalTests (Python)
```python
from approvaltests import verify
def test_pdf_layout():
pdf_text = render_pdf(sample_data)
verify(pdf_text)
# Writes `test_pdf_layout.received.txt`, compares to `.approved.txt`.
# CI fails on diff; dev reviews then renames received→approved.
```
### Golden master with multiple inputs
```python
import json
from pathlib import Path
from legacy_pricing import compute_price
def test_pricing_golden_master():
cases = json.loads(Path("fixtures/cases.json").read_text())
actual = [compute_price(c["input"]) for c in cases]
expected = json.loads(Path("fixtures/expected.json").read_text())
assert actual == expected
```
### Generating the golden initially
```python
# tools/regenerate_golden.py — run once, then commit
import json
from pathlib import Path
from legacy_pricing import compute_price
cases = json.loads(Path("fixtures/cases.json").read_text())
out = [compute_price(c["input"]) for c in cases]
Path("fixtures/expected.json").write_text(json.dumps(out, indent=2))
```
### Differential testing (old vs refactored)
```typescript
import { computePriceLegacy } from './pricing-legacy';
import { computePriceNew } from './pricing-new';
import fc from 'fast-check';
test('refactor preserves behavior', () => {
fc.assert(
fc.property(
fc.record({
qty: fc.integer({ min: 1, max: 100 }),
unitPrice: fc.float({ min: 0.01, max: 9999 }),
}),
(input) => {
expect(computePriceNew(input))
.toBeCloseTo(computePriceLegacy(input), 2);
},
),
{ numRuns: 1000 },
);
});
```
### Capture I/O of legacy via instrumentation
```python
# Wrap legacy fn, log all inputs+outputs in production for a week,
# then replay as test fixtures
from functools import wraps
import json, time
def record(path):
def deco(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
result = fn(*args, **kwargs)
with open(path, "a") as f:
f.write(json.dumps({
"ts": time.time(),
"args": args, "kwargs": kwargs,
"result": result,
}, default=str) + "\n")
return result
return wrapper
return deco
@record("fixtures/legacy_calls.jsonl")
def legacy_compute(...): ...
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Pure function legacy | Inline assertion (Feathers procedure) |
| Large structured output | Snapshot or ApprovalTests |
| Visual UI | Storybook + Chromatic / Percy |
| Two impls (refactor) | Differential testing + property-based |
| Production behavior unknown | Record-replay from instrumentation |
**기본값**: Snapshot test for serializable output, ApprovalTests for human-reviewed diffs (PDF, HTML), differential test during refactor.
## 🔗 Graph
- 변형: [[Approval Tests]]
- 응용: [[Refactoring_Best_Practices|Refactoring]] · [[Visual Regression]]
- Adjacent: [[Property-Based Testing]] · [[TDD]] · [[Test Doubles]]
## 🤖 LLM 활용
**언제**: legacy code refactor 시작, untested codebase 첫 test net, framework migration, output-shape stability (PDF/CSV/JSON).
**언제 X**: greenfield TDD (use spec tests), rapidly evolving design (snapshots churn), security-critical (need real spec).
## ❌ 안티패턴
- **Treating snapshot as spec**: 매 snapshot fail — auto-update without review. 매 bug 의 silent merge.
- **Huge unreadable snapshot**: 1000-line JSON — split into focused snapshots.
- **No fixture review process**: golden master changes auto-merge — require reviewer.
- **Characterization without refactor goal**: tests forever pin "legacy bug" 의 behavior — note bugs explicitly, fix later.
- **Time/random in capture**: nondeterministic snapshots — freeze clock/seed.
## 🧪 검증 / 중복
- Verified (Feathers "Working Effectively with Legacy Code" 2004 / Jest docs / ApprovalTests / Beck "Test Driven Development").
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Feathers procedure + snapshot/approval/differential 패턴 |
@@ -0,0 +1,180 @@
---
id: wiki-2026-0508-choreography
title: Choreography
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Event Choreography, Saga Choreography]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [microservices, distributed-systems, events, saga]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: kafka-temporal
---
# Choreography
## 매 한 줄
> **"매 service 가 자기 part 의 dance step 을 알고 events 으로 react — 매 central conductor 없음."**. Choreography는 distributed workflow를 events 의 emit/subscribe 로 구현하는 pattern. Orchestration 의 반대 — 매 decoupling 매 high, 매 visibility 매 low. 2026년 event-driven microservices, EDA, Saga pattern 의 핵심 선택지.
## 매 핵심
### 매 Choreography vs Orchestration
| 측면 | Choreography | Orchestration |
|---|---|---|
| Control | Distributed | Centralized (orchestrator) |
| Coupling | Low (events) | Higher (orchestrator knows all) |
| Visibility | Hard (trace tools 필요) | Easy (one workflow definition) |
| Add new step | Just subscribe | Edit orchestrator |
| Failure handling | Each service handles own | Orchestrator decides |
| Examples | Kafka events, NATS | Temporal, AWS Step Functions |
### 매 패턴 종류
- **Event-carried state transfer**: event 가 모든 필요 data 포함.
- **Event notification**: event 는 trigger only, state 는 query.
- **Saga choreography**: distributed transaction 의 compensating events.
### 매 응용
1. E-commerce order flow (OrderCreated → Payment → Shipping events).
2. User signup pipeline (UserRegistered → emails → analytics).
3. IoT event processing (sensor → multiple consumers).
4. Domain events (DDD bounded context integration).
## 💻 패턴
### Saga choreography (TypeScript + Kafka)
```typescript
// Order service
async function createOrder(req: CreateOrderRequest) {
const order = await db.orders.insert({ ...req, status: 'pending' });
await kafka.produce('order.created', {
orderId: order.id,
userId: order.userId,
amount: order.total,
});
return order;
}
// Order service also listens for compensations
kafka.consume('payment.failed', async (evt) => {
await db.orders.update(evt.orderId, { status: 'cancelled' });
await kafka.produce('order.cancelled', { orderId: evt.orderId });
});
```
### Payment service reacts independently
```typescript
kafka.consume('order.created', async (evt) => {
try {
const charge = await stripe.charges.create({
amount: evt.amount * 100,
customer: evt.userId,
});
await kafka.produce('payment.succeeded', {
orderId: evt.orderId,
chargeId: charge.id,
});
} catch (err) {
await kafka.produce('payment.failed', {
orderId: evt.orderId,
reason: String(err),
});
}
});
```
### Shipping service
```typescript
kafka.consume('payment.succeeded', async (evt) => {
const shipment = await shippingApi.create({ orderId: evt.orderId });
await kafka.produce('shipment.created', { ...shipment });
});
```
### Event schema (Avro / JSON Schema)
```json
{
"type": "record",
"name": "OrderCreated",
"fields": [
{ "name": "orderId", "type": "string" },
{ "name": "userId", "type": "string" },
{ "name": "amount", "type": "double" },
{ "name": "createdAt", "type": "string" }
]
}
```
### Idempotent consumer
```typescript
async function handleOrderCreated(evt: OrderCreated) {
// Dedup by event id
const seen = await redis.set(
`processed:${evt.eventId}`,
'1',
{ NX: true, EX: 86400 },
);
if (!seen) return; // already processed
await processOrder(evt);
}
```
### Distributed tracing (OTel) 매 visibility 회복
```typescript
import { trace, context, propagation } from '@opentelemetry/api';
async function publishWithTrace(topic: string, evt: any) {
const span = trace.getActiveSpan();
const carrier: Record<string, string> = {};
propagation.inject(context.active(), carrier);
await kafka.produce(topic, {
...evt,
_trace: carrier,
});
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Simple linear workflow | Orchestration (Temporal) |
| Many independent reactors | Choreography |
| Strong consistency 필요 | Orchestration + 2PC 또는 Temporal |
| Fan-out events | Choreography |
| Need visual workflow + retry | Orchestration |
| Event-driven domain (DDD) | Choreography |
**기본값**: 매 simple 2-3 step domain workflow → orchestration (Temporal). 매 broad fan-out + autonomous teams → choreography.
## 🔗 Graph
- 부모: [[Event-Driven Architecture]] · [[Microservices]]
- 변형: [[Pub-Sub]]
- 응용: [[Broker Topology]] · [[Event Sourcing]]
- Adjacent: [[Orchestration]] · [[CQRS]]
## 🤖 LLM 활용
**언제**: event-driven microservice design, decoupling teams, fan-out workflows, autonomous services.
**언제 X**: short transactional flow needing visibility, strict ordering 필요한 critical financial workflows (orchestrator + Temporal 가 better).
## ❌ 안티패턴
- **Distributed monolith via events**: events 가 actually RPC 호출 — coupling 그대로.
- **No event versioning**: schema 변경 시 모든 consumer 깨짐 — Schema Registry 필수.
- **Lost trace**: span 이 event boundary 에서 끊김 — propagation injection 필수.
- **Implicit ordering assumption**: 매 services 가 임의 order 로 react — explicit ordering 필요 시 partition key.
## 🧪 검증 / 중복
- Verified (Hohpe "Enterprise Integration Patterns" / Microservices.io / Confluent docs 2026).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Saga choreography + Kafka + OTel 패턴 |
@@ -0,0 +1,205 @@
---
id: wiki-2026-0508-code-refactoring
title: Code Refactoring
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Refactoring, Code Improvement, Fowler Refactoring]
duplicate_of: none
source_trust_level: A
confidence_score: 0.95
verification_status: applied
tags: [refactoring, code-quality, fowler, ide, llm-refactor]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: Polyglot
framework: IDE/AST-based-tools
---
# Code Refactoring
## 매 한 줄
> **"매 refactoring = 매 외부 동작은 그대로 두고 internal 구조만 개선하는 disciplined transformation."**. 매 Martin Fowler 1999 "Refactoring" 이 catalog 화한 70+ named transformation 이 backbone, 매 2026 현재 IDE automated refactor + LLM-assisted refactor (Claude Opus 4.7, Cursor) 가 manual rewrite 대체. 매 핵심 disciplines = small steps + green tests + commit per refactor.
## 매 핵심
### 매 catalog (대표)
- **Extract Function / Method**: 매 코드 블록 → 새 function.
- **Inline Function**: 매 trivial wrapper 제거.
- **Rename**: 매 의미 명확한 이름.
- **Extract Variable / Inline Variable**.
- **Move Function / Field**: 매 right class/module 로.
- **Replace Conditional with Polymorphism**.
- **Replace Magic Number with Constant**.
- **Introduce Parameter Object**.
- **Decompose Conditional**.
- **Extract Class / Inline Class**.
### 매 disciplines
- **Tests first**: 매 refactor 전 green test suite.
- **Small steps**: 매 single refactor → run tests → commit.
- **No mixing**: 매 behavior change 와 refactor 동시 X.
- **Reversibility**: 매 step 별 git revert 가능.
### 매 응용
1. **Legacy modernization**: 매 strangler fig + extract.
2. **Performance**: 매 inline hot function, extract slow path.
3. **Test enabling**: 매 dependency 분리.
4. **Onboarding**: 매 confusing code rename + decompose.
## 💻 패턴
### Extract Function
```python
# BEFORE
def print_owing(invoice):
print_banner()
outstanding = sum(o.amount for o in invoice.orders)
print(f"name: {invoice.customer}")
print(f"amount: {outstanding}")
# AFTER
def print_owing(invoice):
print_banner()
outstanding = calculate_outstanding(invoice)
print_details(invoice, outstanding)
def calculate_outstanding(invoice):
return sum(o.amount for o in invoice.orders)
def print_details(invoice, outstanding):
print(f"name: {invoice.customer}")
print(f"amount: {outstanding}")
```
### Replace Conditional with Polymorphism
```typescript
// BEFORE
function pay(employee: Employee) {
switch (employee.type) {
case 'engineer': return baseSalary(employee);
case 'salesman': return baseSalary(employee) + commission(employee);
case 'manager': return baseSalary(employee) + bonus(employee);
}
}
// AFTER
abstract class EmployeeType {
abstract pay(e: Employee): number;
}
class Engineer extends EmployeeType { pay(e) { return baseSalary(e); } }
class Salesman extends EmployeeType { pay(e) { return baseSalary(e) + commission(e); } }
class Manager extends EmployeeType { pay(e) { return baseSalary(e) + bonus(e); } }
```
### Introduce Parameter Object
```python
# BEFORE
def amount_invoiced(start_date, end_date, customer_id, currency, ...): ...
# AFTER
@dataclass
class InvoiceQuery:
range: DateRange
customer_id: str
currency: str
def amount_invoiced(q: InvoiceQuery): ...
```
### Decompose Conditional
```javascript
// BEFORE
if (date.before(SUMMER_START) || date.after(SUMMER_END)) {
charge = quantity * winterRate + winterServiceCharge;
} else {
charge = quantity * summerRate;
}
// AFTER
charge = isSummer(date) ? summerCharge(quantity) : winterCharge(quantity);
function isSummer(d) { return !d.before(SUMMER_START) && !d.after(SUMMER_END); }
function summerCharge(q) { return q * summerRate; }
function winterCharge(q) { return q * winterRate + winterServiceCharge; }
```
### Strangler Fig (legacy migration)
```typescript
// route table — gradually shift endpoints to new service
const routes = {
'/users': process.env.NEW_USERS === 'on' ? newUsers : legacyUsers,
'/orders': process.env.NEW_ORDERS === 'on' ? newOrders : legacyOrders,
'/billing': legacyBilling, // not migrated yet
};
// flip flags one at a time, rollback by env var
```
### IDE-driven (IntelliJ / Roslyn)
```bash
# JetBrains command-line refactor (CI batch)
idea.sh inspect $PROJECT inspectionProfile.xml output/ \
-d $MODULE -v2
# C# Roslyn analyzer + code fix runs in `dotnet format analyzers --verify-no-changes`
```
### LLM-assisted refactor (Claude Opus 4.7)
```bash
# 1. select scope, 2. generate diff, 3. tests must stay green
claude refactor \
--scope src/billing/ \
--instruction "Extract OrderTotalCalculator class; preserve all behavior" \
--validate "pytest tests/billing/"
# Claude proposes diff → run tests → commit if green
```
### Test characterization (legacy without tests)
```python
# Before refactor of untested code: write golden tests first
def test_legacy_charge_2025_invoice():
inv = load_fixture('2025_invoice.json')
expected = legacy.calc(inv) # capture current behavior
assert refactored.calc(inv) == expected # equality, not "correctness"
```
## 매 결정 기준
| 상황 | Refactor |
|---|---|
| Long function (> 30 lines) | Extract Function |
| Same param list 5+ places | Introduce Parameter Object |
| `switch (type)` repeated | Replace Conditional with Polymorphism |
| Confusing name | Rename |
| Class doing 2 things | Extract Class |
| Legacy without tests | Characterization tests first |
| Mass code movement | LLM batch + test-gate |
**기본값**: small step + commit per refactor + tests green; LLM 으로 mass rename / extract 가속.
## 🔗 Graph
- 부모: [[Code_Quality]]
- 변형: [[Strangler_Fig]]
- 응용: [[Legacy_Modernization]] · [[Test-Driven Development]]
- Adjacent: [[Clean_Code]] · [[Design_Patterns]]
## 🤖 LLM 활용
**언제**: bulk rename, extract function, polymorphism conversion, parameter object 도입.
**언제 X**: subtle concurrency / lock-free invariants — 매 manual review 필수.
## ❌ 안티패턴
- **Refactor + feature in same commit**: 매 review/revert 불가능.
- **Refactor without tests**: 매 silent behavior change.
- **Big-bang rewrite**: 매 6개월 후 production 되돌리기 불가능.
- **Premature abstraction**: 매 1번 쓰인 패턴 인터페이스화 — YAGNI.
- **Trust-LLM-and-skip-tests**: 매 LLM hallucinated edge case 통과시킴.
## 🧪 검증 / 중복
- Verified (Fowler "Refactoring" 2nd ed 2018, "Working Effectively with Legacy Code" Feathers 2004).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Fowler catalog, disciplines, IDE/LLM-assisted patterns |
@@ -0,0 +1,186 @@
---
id: wiki-2026-0508-combat-timeline-difficulty-scali
title: Combat Timeline Difficulty Scaling
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Combat Difficulty Curve, Encounter Scaling, Dynamic Difficulty Adjustment]
duplicate_of: none
source_trust_level: B
confidence_score: 0.85
verification_status: applied
tags: [game-design, combat, difficulty, ddа, encounter]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: C#/Python
framework: Game-engine-agnostic
---
# Combat Timeline Difficulty Scaling
## 매 한 줄
> **"매 combat encounter 의 매력 = 매 player skill 곡선과 challenge 곡선의 일치 (flow channel)."**. 매 timeline-based scaling 은 encounter 의 시작/중반/끝 phase 별로 enemy 능력을 progress 시키며, 매 player metric (DPS, HP%, time-to-kill) 을 feedback 으로 받아 dynamic 하게 조정. 매 2026 modern AAA (Elden Ring DLC, Helldivers 2) 가 telemetry-driven scaling 채택.
## 매 핵심
### 매 scaling axis
- **Static curve**: 매 fixed level → enemy stat lookup table.
- **Dynamic (DDA)**: 매 runtime player perf 로 parameter 조정.
- **Timeline phase**: 매 encounter 내부 phase 분할 (intro → escalation → climax).
- **Hybrid**: 매 baseline curve + DDA correction.
### 매 measurable metric
- **TTK** (time to kill enemy).
- **TTD** (time to death — player).
- **Damage taken / second**.
- **Resource economy** (potions/ammo per minute).
- **Player retry count**.
### 매 응용
1. **Soulslike boss phase transition**: 매 50%/25% HP → new moveset.
2. **Roguelike floor scaling**: 매 depth × player level 함수.
3. **MMO raid enrage timer**: 매 hard cutoff DPS check.
4. **Casual mode auto-easing**: 매 3회 사망 → enemy HP -10%.
## 💻 패턴
### Phase-based encounter timeline
```csharp
public class BossEncounter : MonoBehaviour {
enum Phase { Intro, Build, Climax, Enrage }
Phase phase = Phase.Intro;
float t;
void Update() {
t += Time.deltaTime;
var hpFrac = boss.HP / boss.MaxHP;
var newPhase = phase;
if (hpFrac < 0.25f) newPhase = Phase.Climax;
else if (hpFrac < 0.60f) newPhase = Phase.Build;
else if (t > 180f) newPhase = Phase.Enrage;
if (newPhase != phase) { OnPhaseEnter(newPhase); phase = newPhase; }
ApplyPhaseModifiers(phase);
}
}
```
### Stat curve table
```yaml
# enemies/orc_warrior.yaml
levels:
1: { hp: 100, dmg: 10, speed: 3.0 }
10: { hp: 250, dmg: 22, speed: 3.5 }
20: { hp: 600, dmg: 50, speed: 4.0 }
50: { hp: 5000, dmg: 220, speed: 5.0 }
# interpolate between keypoints
```
```csharp
EnemyStats Lerp(EnemyStats a, EnemyStats b, float t) =>
new EnemyStats {
HP = Mathf.Lerp(a.HP, b.HP, t),
Damage = Mathf.Lerp(a.Damage, b.Damage, t),
Speed = Mathf.Lerp(a.Speed, b.Speed, t),
};
```
### DDA — sliding window perf
```python
class DDAController:
def __init__(self, target_ttd=45.0, window=5):
self.target = target_ttd
self.history = collections.deque(maxlen=window)
self.scale = 1.0
def record_death(self, ttd_seconds):
self.history.append(ttd_seconds)
if len(self.history) < 3: return
avg = sum(self.history) / len(self.history)
# too easy → ramp up; too hard → ease
delta = (avg - self.target) / self.target # +0.2 = 20% too easy
self.scale = clamp(self.scale + delta * 0.05, 0.7, 1.5)
def apply(self, enemy):
enemy.hp *= self.scale
enemy.dmg *= math.sqrt(self.scale) # damage scales softer
```
### Enrage timer
```csharp
void Update() {
enrageT += Time.deltaTime;
if (enrageT > enrageStart) {
var f = Mathf.Clamp01((enrageT - enrageStart) / 30f);
boss.DamageMultiplier = 1f + f * 4f; // 5x dmg over 30s
}
}
```
### Skill-bracket matchmaking adjust
```python
def select_encounter(player_mmr: int, depth: int):
target_difficulty = base_curve(depth) * mmr_multiplier(player_mmr)
candidates = [e for e in pool if abs(e.difficulty - target_difficulty) < 0.15]
return random.choice(candidates) if candidates else fallback(pool, target_difficulty)
```
### Telemetry-driven re-tuning (offline)
```sql
-- find under-tuned bosses (too easy)
SELECT boss_id,
AVG(time_to_kill) AS avg_ttk,
AVG(player_deaths) AS avg_deaths,
COUNT(*) AS attempts
FROM encounter_log
WHERE patch_version = '2.4.0'
GROUP BY boss_id
HAVING avg_ttk < 30 AND avg_deaths < 0.3
ORDER BY attempts DESC;
```
### Adaptive damage curve
```csharp
// damage taken curves softer the lower player HP — "comeback mechanic"
float TakenMultiplier(float hpFrac) =>
Mathf.Lerp(1.2f, 0.7f, 1f - hpFrac); // low HP = less dmg taken
```
## 매 결정 기준
| 상황 | Scaling |
|---|---|
| Linear narrative game | static curve |
| Roguelike / replayable | static + run-level scale |
| Live-service skill gap | DDA + bracket matchmaking |
| Boss fight 10+ min | phase-based + enrage |
| Accessibility mode | one-way DDA (only ease) |
**기본값**: phase-based timeline + soft DDA (max ±20%) + telemetry retune per patch.
## 🔗 Graph
- 부모: [[Game_Design]] · [[Combat_System]]
- 변형: [[Dynamic_Difficulty_Adjustment]]
## 🤖 LLM 활용
**언제**: encounter design, difficulty curve tuning, DDA controller 설계.
**언제 X**: pure narrative pacing (story beats 영역).
## ❌ 안티패턴
- **HP-sponge scaling**: 매 단순 HP × 10 → boring, not harder.
- **Hidden DDA without disclosure**: 매 player 가 눈치채면 frustration.
- **No floor on DDA**: 매 player 일부러 죽으며 game 망가뜨림.
- **One curve for all enemies**: 매 archetype 별 differentiation 부재.
- **Untested enrage timer**: 매 DPS check 가 unfair RNG 가 되면 community 폭발.
## 🧪 검증 / 중복
- Verified (GDC talks "Resident Evil 4 DDA" 2005, "Helldivers 2 mission director" 2024).
- 신뢰도 B.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — phase timeline, DDA controller, telemetry retuning |
@@ -0,0 +1,148 @@
---
id: wiki-2026-0508-complex-event-processing-cep
title: Complex Event Processing (CEP)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [CEP, Event Stream Processing, 복합 이벤트 처리]
duplicate_of: none
source_trust_level: A
confidence_score: 0.88
verification_status: applied
tags: [cep, streaming, event-driven, flink, esper]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: java
framework: flink
---
# Complex Event Processing (CEP)
## 매 한 줄
> **"매 stream of simple events → meaningful complex pattern"**. David Luckham (Stanford, 2002) 가 정의한 paradigm. 2026 현재 Apache Flink CEP, Kafka Streams, Esper NEsper 가 main implementation; fraud detection, IoT anomaly, algorithmic trading 의 backbone.
## 매 핵심
### 매 개념
- **Event**: timestamped 의 fact (transaction, sensor reading, click).
- **Pattern**: temporal/causal relationship 의 events (A followed by B within 5s).
- **Window**: sliding/tumbling/session 시간 frame.
- **Aggregation**: count, sum, avg over window.
- **Correlation**: 다중 stream 매 join (e.g., trades + market data).
### 매 pattern operator
- **Sequence**: A → B → C (in order).
- **Conjunction**: A AND B (any order, in window).
- **Negation**: A NOT followed by B.
- **Iteration**: A repeated N times.
- **Within**: temporal constraint.
### 매 응용
1. Fraud detection — card swipes 매 different countries within 1h.
2. IoT — sensor reading exceeds threshold for 3 consecutive readings.
3. Trading — bid/ask spread anomaly detection.
4. Network security — port scan pattern (many SYN, few ACK).
5. SLA monitoring — 5xx error rate spike correlated with deploy event.
## 💻 패턴
### Flink CEP — 3 failed login pattern
```java
Pattern<LoginEvent, ?> failedLogins = Pattern
.<LoginEvent>begin("first")
.where(e -> !e.success)
.next("second").where(e -> !e.success)
.next("third").where(e -> !e.success)
.within(Time.minutes(5));
CEP.pattern(loginStream.keyBy(e -> e.userId), failedLogins)
.select(match -> new Alert(match.get("first").get(0).userId))
.addSink(alertSink);
```
### Esper EPL — fraud detection
```sql
-- swipe in different countries within 1 hour
SELECT a.cardId, a.country, b.country
FROM pattern [
every a=Swipe -> b=Swipe(cardId=a.cardId, country!=a.country)
where timer:within(1 hour)
];
```
### Kafka Streams — sliding window aggregation
```java
KStream<String, Click> clicks = builder.stream("clicks");
clicks.groupByKey()
.windowedBy(SlidingWindows.ofTimeDifferenceWithNoGrace(Duration.ofMinutes(5)))
.count()
.filter((k, count) -> count > 1000)
.toStream()
.to("anomalies");
```
### Flink — session window
```java
stream.keyBy(e -> e.userId)
.window(EventTimeSessionWindows.withGap(Time.minutes(30)))
.aggregate(new SessionStats())
.addSink(...);
```
### Pattern with negation (NO heartbeat in 30s)
```java
Pattern.<HeartbeatEvent>begin("start")
.notFollowedBy("missing")
.where(e -> true)
.within(Time.seconds(30));
```
### Modern: Materialize / RisingWave (SQL-native streaming)
```sql
CREATE MATERIALIZED VIEW fraud_alerts AS
SELECT user_id, COUNT(*) as failed_count
FROM logins
WHERE success = false
AND ts > NOW() - INTERVAL '5 minutes'
GROUP BY user_id
HAVING COUNT(*) >= 3;
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Java/JVM, complex patterns | Flink CEP |
| Kafka-centric, simple aggregation | Kafka Streams |
| SQL-first, low ops | Materialize / RisingWave |
| In-process, low-volume | Esper |
| Cloud-native, serverless | AWS Kinesis Data Analytics |
**기본값**: Flink CEP for complex patterns, Materialize for SQL-native streaming.
## 🔗 Graph
- 부모: [[Event-Driven Architecture]] · [[Stream-Processing-Architectures|Stream Processing]]
- 변형: [[Event Sourcing]] · [[CQRS]]
- Adjacent: [[Apache Flink]]
## 🤖 LLM 활용
**언제**: pattern definition 매 natural language → EPL/Flink translation, alert explanation.
**언제 X**: micro-second latency hot path (LLM 매 too slow).
## ❌ 안티패턴
- **Unbounded state**: window 없이 group-by → memory blowup.
- **Wall-clock instead of event-time**: out-of-order event 매 wrong result.
- **Pattern explosion**: NFA state count 매 exponential, pattern 너무 복잡.
- **No watermark**: late event 매 silently lost.
## 🧪 검증 / 중복
- Verified (Luckham 2002 *Power of Events*, Apache Flink CEP docs 2026).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — full content with Flink CEP, Esper, Materialize |
@@ -0,0 +1,184 @@
---
id: wiki-2026-0508-complexity-theory
title: Complexity Theory
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Complex Systems, Complexity Science]
duplicate_of: none
source_trust_level: A
confidence_score: 0.85
verification_status: applied
tags: [complexity, systems, emergence, cynefin]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: agnostic
framework: agnostic
---
# Complexity Theory
## 매 한 줄
> **"매 system 의 behavior 가 매 part 의 sum 보다 크다 — 매 emergence, nonlinearity, feedback."**. Complexity theory는 Santa Fe Institute (1984~) 가 정립한 cross-disciplinary field. Software 에서는 Cynefin framework (Snowden), Brooks 의 essential vs accidental complexity, Promise Theory, distributed systems 의 emergent behavior 로 산다. 2026년 ML systems 의 emergent capabilities 도 매 핵심 case.
## 매 핵심
### 매 complex vs complicated
| Complicated | Complex |
|---|---|
| Many parts, knowable | Many parts, emergent |
| Aircraft, watch | Ecosystem, market, brain, microservices fleet |
| Decompose & analyze | Probe → sense → respond |
| Predictable | Unpredictable in detail |
### 매 Cynefin (Snowden)
- **Clear (Simple)**: cause→effect 자명. Best practice.
- **Complicated**: expert analysis 필요. Good practice.
- **Complex**: emergent, retrospective coherence. Probe → sense → respond.
- **Chaotic**: no cause→effect. Act → sense → respond.
- **Confusion** (Disorder): which domain unclear.
### 매 essential vs accidental complexity (Brooks)
- **Essential**: 매 problem itself 의 complexity (irreducible).
- **Accidental**: tools, languages, infra 가 만든 complexity (reducible).
- 매 silver bullet 없음 → essential complexity 의 tackling.
### 매 emergent properties
- Self-organization (ant colonies, market prices).
- Phase transitions (water → ice, network connectivity).
- Power laws (Zipf, scale-free networks).
- Adaptive feedback (immune systems, ML training dynamics).
### 매 응용 in software
1. Microservice fleet behavior (cascading failures, retry storms).
2. ML emergent capabilities (in-context learning at scale).
3. Distributed consensus (CAP, FLP impossibility).
4. Tech debt accumulation (compound complexity).
5. Team scaling (Brooks' law as complexity manifestation).
## 💻 패턴
### Cynefin-driven decision (in code review)
```python
def categorize_problem(problem):
if known_solution(problem):
return "Clear: apply best practice"
if expertise_resolves(problem):
return "Complicated: expert analysis"
if requires_experimentation(problem):
return "Complex: probe-sense-respond"
if no_cause_effect(problem):
return "Chaotic: act-sense-respond"
return "Disorder: clarify first"
```
### Probe → sense → respond (chaos engineering)
```typescript
// Netflix Chaos Monkey style — controlled probe of complex system
import { ChaosClient } from '@netflix/chaos';
const chaos = new ChaosClient();
await chaos.experiment({
name: 'kill-random-pod-payment-svc',
hypothesis: 'system handles single pod loss within 30s',
blast_radius: 'one pod',
rollback_on: 'p99 > 500ms',
observe: ['error_rate', 'latency_p99', 'saturation'],
});
```
### Reduce accidental complexity — replace shell with compiled tool
```python
# Accidental: bash script with 5 sed/awk/jq pipes
# Essential: extract user emails from JSON
# After: simple, type-checked
import json
from pathlib import Path
emails = [
user["email"]
for user in json.loads(Path("users.json").read_text())
if user.get("active")
]
```
### Feedback loop modeling (system dynamics)
```python
# Tech debt feedback loop — simple ODE
import numpy as np
from scipy.integrate import odeint
def tech_debt(state, t, capacity, debt_growth, paydown_rate):
debt, velocity = state
d_debt = debt_growth - paydown_rate * velocity
d_velocity = capacity * (1 - debt / 100) - velocity * 0.1
return [d_debt, d_velocity]
# Emergent: nonlinear collapse when debt > capacity
sol = odeint(tech_debt, [10, 5], np.linspace(0, 100, 200),
args=(10, 2, 0.5))
```
### Power-law detection (scale-free service dependency)
```python
import numpy as np
import powerlaw
# In-degree of microservice call graph
in_degrees = compute_in_degrees(service_graph)
fit = powerlaw.Fit(in_degrees)
print(f"alpha={fit.power_law.alpha:.2f}") # ~2-3 → scale-free
# Implication: targeted attack on hubs is catastrophic
```
### Promise Theory (Burgess) — autonomous agents
```yaml
# Each service makes promises, others assess
service: payment-svc
promises:
- id: p99_latency_under_300ms
conditions: [load < 1000rps]
valid_until: 2026-12-31
- id: idempotent_charge_endpoint
conditions: []
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Clear problem | Apply best practice, automate |
| Complicated | Expert review, formal analysis |
| Complex (emergent) | Probe with chaos engineering, observability |
| Chaotic (incident) | Act first, stabilize, then sense |
| Tech debt | Distinguish essential vs accidental |
**기본값**: Most production distributed systems 매 Complex domain 매 산다 → SLO + chaos + observability + post-incident review.
## 🔗 Graph
- 부모: [[Systems Theory]] · [[Cybernetics Foundations|Cybernetics]]
- 변형: [[Chaos Engineering]]
- 응용: [[Distributed Systems]] · [[Microservices]] · [[SRE]]
- Adjacent: [[Conceptual Integrity]] · [[Emergent Behavior]]
## 🤖 LLM 활용
**언제**: incident retrospective, architecture decision in distributed system, tech debt classification, organizational design, ML system behavior analysis.
**언제 X**: simple CRUD app design, single-node algorithm, bounded local logic.
## ❌ 안티패턴
- **Best-practice in complex domain**: clear-domain solution 을 complex domain 에 강제.
- **Ignoring accidental complexity**: 매 essential 처럼 취급 → tooling 의 미개선.
- **Predicting emergent behavior**: complex system 의 detail prediction 시도 — probe 가 답.
- **No feedback loops in design**: system dynamics 무시 → 매 surprise outage.
## 🧪 검증 / 중복
- Verified (Brooks "No Silver Bullet" / Snowden Cynefin / Mitchell "Complexity: A Guided Tour" / Burgess "Thinking in Promises").
- 신뢰도 A-.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Cynefin + Brooks essential/accidental + chaos engineering |
@@ -0,0 +1,216 @@
---
id: wiki-2026-0508-component-library-architecture
title: Component Library Architecture
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Design System Architecture, UI Library Design]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [components, design-system, react, shadcn, radix]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: react-radix-shadcn
---
# Component Library Architecture
## 매 한 줄
> **"매 unstyled headless primitives + 매 style layer + 매 composition API."**. 2026년 React component library 의 dominant model = Radix/Ark UI (headless behavior + a11y) + Tailwind/CSS variables (theming) + shadcn/ui (copy-not-install) + tokens (DTCG). MUI 5 의 monolithic theme 시대 → headless 시대로 매 shift.
## 매 핵심
### 매 3 layer architecture
1. **Behavior layer (headless)**: a11y, keyboard, focus, ARIA — Radix, Ark UI, React Aria.
2. **Style layer**: Tailwind, CSS-in-JS (vanilla-extract), CSS variables.
3. **Composition layer**: app-specific compositions of 1+2.
### 매 distribution model
- **Package install** (MUI, Chakra v3): npm install, version locked, hard to customize.
- **Copy-paste** (shadcn/ui): generator copies source into your repo, you own it, fully customizable.
- **Hybrid** (Radix + custom wrapper): primitives via npm, your styles in repo.
### 매 token system (DTCG / Style Dictionary)
- Primitive tokens (color.blue.500 = #3b82f6).
- Semantic tokens (color.action.primary = color.blue.500).
- Component tokens (button.bg.primary = color.action.primary).
### 매 응용
1. Internal design system (Vercel Geist, GitHub Primer).
2. Open-source kits (shadcn/ui, Mantine, Park UI).
3. White-label products (multi-brand 동일 codebase).
4. Cross-framework via Web Components (Spectrum Web Components).
## 💻 패턴
### Headless primitive (Radix)
```typescript
import * as Dialog from '@radix-ui/react-dialog';
export function ConfirmDialog({ open, onClose, onConfirm, children }: Props) {
return (
<Dialog.Root open={open} onOpenChange={onClose}>
<Dialog.Portal>
<Dialog.Overlay className="fixed inset-0 bg-black/50" />
<Dialog.Content className="fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-lg bg-white p-6">
<Dialog.Title className="text-lg font-semibold">Confirm</Dialog.Title>
<Dialog.Description>{children}</Dialog.Description>
<div className="mt-4 flex justify-end gap-2">
<Dialog.Close className="btn-ghost">Cancel</Dialog.Close>
<button className="btn-primary" onClick={onConfirm}>OK</button>
</div>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
}
```
### shadcn-style copy-paste component
```typescript
// components/ui/button.tsx — owned by your repo
import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from '@/lib/utils';
const buttonVariants = cva(
'inline-flex items-center justify-center rounded-md text-sm font-medium transition',
{
variants: {
variant: {
primary: 'bg-blue-600 text-white hover:bg-blue-700',
ghost: 'hover:bg-gray-100',
},
size: {
sm: 'h-8 px-3',
md: 'h-10 px-4',
lg: 'h-12 px-6',
},
},
defaultVariants: { variant: 'primary', size: 'md' },
},
);
type Props = React.ButtonHTMLAttributes<HTMLButtonElement>
& VariantProps<typeof buttonVariants>;
export function Button({ className, variant, size, ...rest }: Props) {
return (
<button
className={cn(buttonVariants({ variant, size }), className)}
{...rest}
/>
);
}
```
### Design tokens (DTCG JSON)
```json
{
"color": {
"blue": {
"500": { "$value": "#3b82f6", "$type": "color" }
},
"action": {
"primary": { "$value": "{color.blue.500}", "$type": "color" }
}
},
"space": {
"4": { "$value": "16px", "$type": "dimension" }
}
}
```
### CSS variables driven theming
```css
:root {
--color-primary: #3b82f6;
--radius-md: 0.5rem;
}
[data-theme='dark'] {
--color-primary: #60a5fa;
}
.btn-primary {
background: var(--color-primary);
border-radius: var(--radius-md);
}
```
### Polymorphic component (asChild pattern)
```typescript
import { Slot } from '@radix-ui/react-slot';
type Props = {
asChild?: boolean;
} & React.HTMLAttributes<HTMLElement>;
export function Card({ asChild, ...rest }: Props) {
const Comp = asChild ? Slot : 'div';
return <Comp className="rounded-lg border p-4" {...rest} />;
}
// Usage:
<Card asChild>
<a href="/post/1">Click me</a>
</Card>
```
### Storybook 8 + a11y addon
```typescript
// Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './button';
const meta: Meta<typeof Button> = {
component: Button,
parameters: { a11y: { test: 'error' } },
};
export default meta;
export const Primary: StoryObj<typeof Button> = {
args: { children: 'Save', variant: 'primary' },
};
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Internal design system, full control | shadcn/ui copy-paste + Tailwind |
| Quick prototype, full kit | Mantine, Chakra v3 |
| Cross-framework | Lit + Web Components |
| Strong a11y 요구 | Radix or React Aria |
| Multi-brand white-label | Token-driven CSS variables |
**기본값**: React 19 + Radix primitives + Tailwind v4 + shadcn/ui structure + DTCG tokens.
## 🔗 Graph
- 부모: [[Component-Based Architecture (CBA)]] · [[Design Systems]]
- 변형: [[Component-Composition|Compound Components]] · [[Headless UI]]
- 응용: [[shadcn-ui]] · [[Radix UI]] · [[Storybook]]
- Adjacent: [[CSS_Architecture_and_Styling|Tailwind CSS]] · [[Design Tokens]] · [[A11y]]
## 🤖 LLM 활용
**언제**: starting design system, refactoring 중복 UI, multi-product/brand consolidation.
**언제 X**: 1-page landing site (overhead 큼), heavily 3D/canvas UI (HTML primitive 안 맞음).
## ❌ 안티패턴
- **Tightly styled primitives**: behavior + style 의 강결합 — replace 시 rewrite 필요.
- **Theme prop drilling**: 매 component 가 theme prop 받음 — CSS variables 로.
- **No tokens**: hex color 직접 사용 — token system 부재 시 multi-brand 불가.
- **Locked-in vendor library**: MUI v3→v5 같은 대규모 breaking change — headless + own styles 가 안전.
## 🧪 검증 / 중복
- Verified (shadcn/ui docs 2026 / Radix UI / DTCG W3C draft / React 19 docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — 3-layer model + shadcn/Radix/DTCG 패턴 |
@@ -0,0 +1,194 @@
---
id: wiki-2026-0508-component-based-architecture-cba
title: Component Based Architecture (CBA)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [CBA, Component-Based Software Engineering, CBSE]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [architecture, components, modularity, reuse]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: react-vue-angular
---
# Component Based Architecture (CBA)
## 매 한 줄
> **"매 시스템 = 매 independent, replaceable, composable component 의 합."**. CBSE는 1960s OOP의 reuse 약속을 modular contract로 실현한 패러다임. 2026년 frontend (React/Vue/Angular), microservices, design systems, embedded (OSGi), game engines (Unity ECS) 모두 CBA의 변형.
## 매 핵심
### 매 component 의 정의
- **Encapsulation**: state + behavior + interface = 단일 unit.
- **Well-defined contract**: input props/events, output events, side effects 명시.
- **Replaceable**: 동일 interface 의 다른 impl 으로 swap 가능.
- **Independently deployable** (microservices) 또는 **independently versionable** (libraries).
### 매 4 properties (Szyperski)
1. **Independent deployment** unit.
2. **Composition** by third parties.
3. **No persistent state** (pure or state-injected).
4. **Explicit context dependencies** (interface 로 명시).
### 매 응용
1. Frontend UI (React component tree).
2. Microservices (service = component).
3. Plugin systems (VSCode extensions, Figma plugins).
4. Game engines (Unity GameObject + Components).
5. Web Components (Custom Elements, Shadow DOM).
## 💻 패턴
### React functional component
```typescript
type ButtonProps = {
variant: 'primary' | 'ghost';
onClick: () => void;
children: React.ReactNode;
};
export function Button({ variant, onClick, children }: ButtonProps) {
return (
<button
className={`btn btn-${variant}`}
onClick={onClick}
>
{children}
</button>
);
}
```
### Web Component (framework-agnostic)
```typescript
class TodoItem extends HTMLElement {
static observedAttributes = ['done', 'label'];
attributeChangedCallback(name: string, _old: string, value: string) {
this.render();
}
connectedCallback() {
this.attachShadow({ mode: 'open' });
this.render();
}
private render() {
if (!this.shadowRoot) return;
const done = this.hasAttribute('done');
this.shadowRoot.innerHTML = `
<style>:host { display: block; }</style>
<label>
<input type="checkbox" ${done ? 'checked' : ''} />
<span>${this.getAttribute('label') ?? ''}</span>
</label>
`;
}
}
customElements.define('todo-item', TodoItem);
```
### Composition over inheritance
```typescript
// Bad: deep inheritance
class AdminButton extends IconButton extends Button { }
// Good: composition
function AdminButton({ icon, ...rest }: AdminButtonProps) {
return (
<Button {...rest}>
<Icon name={icon} />
<span>{rest.children}</span>
</Button>
);
}
```
### Dependency injection (explicit context)
```typescript
type Logger = { info(msg: string): void };
export function createPaymentService({ logger, gateway }: {
logger: Logger;
gateway: PaymentGateway;
}) {
return {
charge: async (amount: number) => {
logger.info(`charging ${amount}`);
return gateway.charge(amount);
},
};
}
```
### ECS component (Unity / Bevy style)
```rust
// Bevy ECS
#[derive(Component)]
struct Position { x: f32, y: f32 }
#[derive(Component)]
struct Velocity { dx: f32, dy: f32 }
fn movement_system(mut query: Query<(&mut Position, &Velocity)>) {
for (mut pos, vel) in &mut query {
pos.x += vel.dx;
pos.y += vel.dy;
}
}
```
### Microservice as component
```typescript
// Each service exposes a typed contract (gRPC / OpenAPI)
interface OrderService {
createOrder(req: CreateOrderRequest): Promise<Order>;
getOrder(id: string): Promise<Order>;
}
// Replaceable impl: REST, gRPC, in-memory mock
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| UI rendering | React/Vue functional components |
| Cross-framework UI | Web Components (Lit) |
| Backend domain split | Microservice components (gRPC contract) |
| Game logic | ECS components (Bevy, Unity DOTS) |
| Plugin systems | Component + manifest + sandbox (VSCode model) |
**기본값**: React 19 functional components + composition; backend은 module 단위 component → 필요 시 microservice 로 추출.
## 🔗 Graph
- 부모: [[Modularity]] · [[Software Architecture]]
- 변형: [[Microservices]] · [[Web Components]] · [[Entity Component System]]
- 응용: [[Component Library Architecture]] · [[Component-Composition|Compound Components]] · [[Design Systems]]
- Adjacent: [[Conceptual Integrity]] · [[Dependency Injection]]
## 🤖 LLM 활용
**언제**: UI/system 의 reusable units 으로 분해, contract-driven team work, plugin ecosystem.
**언제 X**: 단일 prototype, throwaway script, 하나의 tight algorithm (component overhead 가 cost > benefit).
## ❌ 안티패턴
- **God component**: 하나의 component 가 too many props/responsibilities — split.
- **Prop drilling**: 5+ levels 깊이 prop 전달 — Context/store 로 lift.
- **Hidden coupling**: component A 가 component B 의 internal state 의 직접 접근 — contract violation.
- **Premature genericization**: 1번만 쓰는 것을 generic 으로 추상화 — YAGNI.
## 🧪 검증 / 중복
- Verified (Szyperski "Component Software" 1998 / Brooks 1995 / React docs 2026).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — CBA 4-property canonical + React/ECS/microservice 패턴 |
@@ -0,0 +1,261 @@
---
id: wiki-2026-0508-compound-components
title: Compound Components
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Compound Component Pattern, React Compound Components]
duplicate_of: none
source_trust_level: A
confidence_score: 0.95
verification_status: applied
tags: [react, patterns, components, composition, context]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: react
---
# Compound Components
## 매 한 줄
> **"매 parent 가 매 child 들과 implicit state share — 매 expressive composable API."**. Compound Component Pattern은 React (그리고 Vue/Solid) 에서 `<Tabs><Tab/><Tab.Panel/></Tabs>` 류의 declarative API 를 만드는 표준. Radix UI, Headless UI, Ariakit, shadcn/ui 의 dominant pattern. 2026년 React 19 + Server Components 시대에도 그대로 valid.
## 매 핵심
### 매 problem solved
- 단일 monolithic component 의 props explosion (`<Tabs items={...} renderTab={...} ...>`).
- 매 caller 가 매 children 의 layout/order 를 control 의 X.
- Slot composition 의 부재.
### 매 solution
- Parent 가 Context 로 shared state 의 publish.
- Children 이 Context 를 consume — explicit prop drilling 의 X.
- Children 의 component 가 namespace pattern (`Tabs.Tab`) 또는 separate exports.
### 매 patterns
- **React Context based** (most common 2026).
- **`React.Children` cloning** (legacy, fragile with refs/server components).
- **State reducer** (advanced — caller customizes reducer).
- **`asChild` slot** (Radix — wraps user element).
### 매 응용
1. Tabs, Accordion, Disclosure.
2. Menu, Dropdown, Combobox.
3. Dialog, Drawer, Popover.
4. Form fields with label/error/description.
5. DataTable column children.
## 💻 패턴
### Context-based Tabs
```typescript
import { createContext, useContext, useId, useState } from 'react';
type TabsContextValue = {
activeId: string;
setActiveId: (id: string) => void;
baseId: string;
};
const TabsContext = createContext<TabsContextValue | null>(null);
function useTabs() {
const ctx = useContext(TabsContext);
if (!ctx) throw new Error('Tabs.* must be used inside <Tabs>');
return ctx;
}
export function Tabs({
defaultValue,
children,
}: { defaultValue: string; children: React.ReactNode }) {
const [activeId, setActiveId] = useState(defaultValue);
const baseId = useId();
return (
<TabsContext.Provider value={{ activeId, setActiveId, baseId }}>
<div className="tabs">{children}</div>
</TabsContext.Provider>
);
}
function List({ children }: { children: React.ReactNode }) {
return <div role="tablist" className="flex gap-2">{children}</div>;
}
function Trigger({ value, children }: { value: string; children: React.ReactNode }) {
const { activeId, setActiveId, baseId } = useTabs();
const selected = activeId === value;
return (
<button
role="tab"
id={`${baseId}-trigger-${value}`}
aria-selected={selected}
aria-controls={`${baseId}-panel-${value}`}
tabIndex={selected ? 0 : -1}
onClick={() => setActiveId(value)}
className={selected ? 'tab tab-active' : 'tab'}
>
{children}
</button>
);
}
function Panel({ value, children }: { value: string; children: React.ReactNode }) {
const { activeId, baseId } = useTabs();
if (activeId !== value) return null;
return (
<div
role="tabpanel"
id={`${baseId}-panel-${value}`}
aria-labelledby={`${baseId}-trigger-${value}`}
>
{children}
</div>
);
}
Tabs.List = List;
Tabs.Trigger = Trigger;
Tabs.Panel = Panel;
```
### Usage
```tsx
<Tabs defaultValue="overview">
<Tabs.List>
<Tabs.Trigger value="overview">Overview</Tabs.Trigger>
<Tabs.Trigger value="settings">Settings</Tabs.Trigger>
</Tabs.List>
<Tabs.Panel value="overview"><OverviewView /></Tabs.Panel>
<Tabs.Panel value="settings"><SettingsView /></Tabs.Panel>
</Tabs>
```
### Controlled variant
```typescript
type Props = {
value?: string;
defaultValue?: string;
onValueChange?: (value: string) => void;
children: React.ReactNode;
};
export function Tabs({ value, defaultValue, onValueChange, children }: Props) {
const [internal, setInternal] = useState(defaultValue ?? '');
const isControlled = value !== undefined;
const activeId = isControlled ? value : internal;
const setActiveId = (next: string) => {
if (!isControlled) setInternal(next);
onValueChange?.(next);
};
// ...rest
}
```
### asChild slot pattern (Radix)
```typescript
import { Slot } from '@radix-ui/react-slot';
function Trigger({ asChild, children, value }: {
asChild?: boolean;
value: string;
children: React.ReactNode;
}) {
const { setActiveId } = useTabs();
const Comp = asChild ? Slot : 'button';
return (
<Comp onClick={() => setActiveId(value)} role="tab">
{children}
</Comp>
);
}
// Usage: customize button as anchor
<Tabs.Trigger value="x" asChild>
<a href="#x">Section X</a>
</Tabs.Trigger>
```
### Form field compound
```typescript
const FieldContext = createContext<{ id: string; errorId: string } | null>(null);
export function Field({ children }: { children: React.ReactNode }) {
const id = useId();
return (
<FieldContext.Provider value={{ id, errorId: `${id}-error` }}>
<div className="field">{children}</div>
</FieldContext.Provider>
);
}
function Label({ children }: { children: React.ReactNode }) {
const { id } = useContext(FieldContext)!;
return <label htmlFor={id}>{children}</label>;
}
function Input(props: React.InputHTMLAttributes<HTMLInputElement>) {
const { id, errorId } = useContext(FieldContext)!;
return <input id={id} aria-describedby={errorId} {...props} />;
}
function Error({ children }: { children: React.ReactNode }) {
const { errorId } = useContext(FieldContext)!;
return <span id={errorId} role="alert">{children}</span>;
}
Field.Label = Label;
Field.Input = Input;
Field.Error = Error;
```
### Server Components note
```typescript
// Compound components 의 Context — Client Component only.
// 매 Server Component layout 에서:
// <Tabs> ← Client Component (provides context)
// <Tabs.Panel value="x"> ← Client (consumes context)
// <ServerOnlyData /> ← can be Server Component child
// </Tabs.Panel>
// </Tabs>
'use client';
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Standard widgets (tabs, menu) | Context-based compound |
| Wrap user element | asChild + Slot |
| Caller controls state | Controlled variant |
| Behavior-only library | Headless compound (Radix style) |
| Server Components mixed | 'use client' on the parent + child triggers |
**기본값**: Context-based, namespace exports (`Tabs.Trigger`), controlled+uncontrolled support, `useId` for a11y, `useContext` 로 misuse 방지.
## 🔗 Graph
- 부모: [[Component-Based Architecture (CBA)]] · [[React Patterns]]
- 변형: [[Headless UI]] · [[Render_Props|Render Props]]
- 응용: [[Component Library Architecture]] · [[Radix UI]] · [[shadcn-ui]]
- Adjacent: [[A11y]] · [[Modern_Web_Rendering_and_Optimization|Server Components]]
## 🤖 LLM 활용
**언제**: building reusable widgets (tabs/menu/dialog), design system primitives, replacing prop-explosion components, headless library.
**언제 X**: 1-shot static UI, simple presentational components, server-only components (Context 의 X).
## ❌ 안티패턴
- **`React.Children` cloning**: brittle with refs, breaks with fragments — Context 가 표준.
- **Missing context throw**: child used standalone gives undefined error — explicit throw with helpful message.
- **Over-namespacing**: 5+ children types — split into multiple components.
- **Forgetting a11y**: tabs without role/aria-* — Radix-style attribute mapping 필수.
## 🧪 검증 / 중복
- Verified (Kent C. Dodds compound components / Radix UI source / React 19 docs / WAI-ARIA 1.2).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Context-based Tabs + asChild + form field 패턴 |
@@ -0,0 +1,235 @@
---
id: wiki-2026-0508-compute-shaders
title: Compute Shaders
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [GPU Compute, GPGPU Shaders, WebGPU Compute]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [gpu, shaders, webgpu, parallel, wgsl, cuda]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: wgsl-glsl-cuda
framework: webgpu-vulkan
---
# Compute Shaders
## 매 한 줄
> **"매 GPU program 매 graphics pipeline 의 X — 매 arbitrary parallel computation."**. Compute shader는 vertex/fragment shader 와 다르게 rendering 의 X — 매 raw SIMT 의 power. 2026년 WebGPU (browser GPU compute), CUDA, Vulkan compute, Metal compute, ML inference, particle sims, image processing 의 dominant. ML 의 attention/matmul 도 compute shader 본질.
## 매 핵심
### 매 model
- **Workgroup**: 매 group of threads 가 same shader 실행 (e.g. 64 or 256 threads).
- **Invocation**: single thread.
- **Shared memory** (workgroup): fast, intra-group.
- **Storage buffer**: GPU global memory (read/write).
- **Uniform buffer**: small, read-only constants.
- **Dispatch**: CPU 가 launches N workgroups.
### 매 hardware mapping
- NVIDIA: warp (32 threads), SM (streaming multiprocessor).
- AMD: wave (64 threads, RDNA: 32), CU.
- Apple: simdgroup (32), GPU core.
- Intel: subgroup, EU.
### 매 languages 2026
- **WGSL** (WebGPU): cross-platform, modern.
- **HLSL** (DirectX, Vulkan via DXC).
- **GLSL** (OpenGL, Vulkan).
- **MSL** (Metal Shading Language).
- **CUDA C++**: NVIDIA only, but mature.
- **Triton** (OpenAI): Python-like ML kernel DSL.
### 매 응용
1. ML inference (matmul, attention, conv).
2. Image filters (blur, edge, color grading).
3. Particle systems / fluid sim.
4. Physics (cloth, soft body, mass-spring).
5. Cryptography (proof-of-work, hash collisions).
6. Video encode/decode prep.
## 💻 패턴
### WGSL compute shader — vector add
```wgsl
@group(0) @binding(0) var<storage, read> a : array<f32>;
@group(0) @binding(1) var<storage, read> b : array<f32>;
@group(0) @binding(2) var<storage, read_write> c : array<f32>;
@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) gid : vec3u) {
let i = gid.x;
if (i >= arrayLength(&a)) { return; }
c[i] = a[i] + b[i];
}
```
### WebGPU dispatch (TypeScript)
```typescript
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter!.requestDevice();
const module = device.createShaderModule({ code: WGSL_SOURCE });
const pipeline = device.createComputePipeline({
layout: 'auto',
compute: { module, entryPoint: 'main' },
});
const N = 1_000_000;
const buf = (data: Float32Array) => {
const b = device.createBuffer({
size: data.byteLength,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC,
});
device.queue.writeBuffer(b, 0, data);
return b;
};
const a = buf(new Float32Array(N).fill(1));
const b = buf(new Float32Array(N).fill(2));
const c = device.createBuffer({
size: N * 4,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,
});
const bindGroup = device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [
{ binding: 0, resource: { buffer: a } },
{ binding: 1, resource: { buffer: b } },
{ binding: 2, resource: { buffer: c } },
],
});
const enc = device.createCommandEncoder();
const pass = enc.beginComputePass();
pass.setPipeline(pipeline);
pass.setBindGroup(0, bindGroup);
pass.dispatchWorkgroups(Math.ceil(N / 64));
pass.end();
device.queue.submit([enc.finish()]);
```
### Shared memory reduction (workgroup-local)
```wgsl
var<workgroup> shared : array<f32, 256>;
@compute @workgroup_size(256)
fn reduce(
@builtin(local_invocation_id) lid : vec3u,
@builtin(global_invocation_id) gid : vec3u,
) {
shared[lid.x] = input[gid.x];
workgroupBarrier();
var stride : u32 = 128u;
loop {
if (stride == 0u) { break; }
if (lid.x < stride) {
shared[lid.x] = shared[lid.x] + shared[lid.x + stride];
}
workgroupBarrier();
stride = stride / 2u;
}
if (lid.x == 0u) { output[gid.x / 256u] = shared[0]; }
}
```
### CUDA matmul kernel
```cuda
__global__ void matmul(const float* A, const float* B, float* C, int N) {
int row = blockIdx.y * blockDim.y + threadIdx.y;
int col = blockIdx.x * blockDim.x + threadIdx.x;
if (row >= N || col >= N) return;
float sum = 0.0f;
for (int k = 0; k < N; ++k) {
sum += A[row * N + k] * B[k * N + col];
}
C[row * N + col] = sum;
}
// Launch: matmul<<<dim3((N+15)/16, (N+15)/16), dim3(16,16)>>>(A, B, C, N);
```
### Triton kernel (Python ML)
```python
import triton
import triton.language as tl
@triton.jit
def add_kernel(x_ptr, y_ptr, out_ptr, n, BLOCK: tl.constexpr):
pid = tl.program_id(0)
offsets = pid * BLOCK + tl.arange(0, BLOCK)
mask = offsets < n
x = tl.load(x_ptr + offsets, mask=mask)
y = tl.load(y_ptr + offsets, mask=mask)
tl.store(out_ptr + offsets, x + y, mask=mask)
# Launch
add_kernel[(triton.cdiv(N, 1024),)](x, y, out, N, BLOCK=1024)
```
### Image blur compute (storage texture)
```wgsl
@group(0) @binding(0) var src : texture_2d<f32>;
@group(0) @binding(1) var dst : texture_storage_2d<rgba8unorm, write>;
@compute @workgroup_size(8, 8)
fn blur(@builtin(global_invocation_id) gid : vec3u) {
var sum = vec4f(0);
for (var dy = -1; dy <= 1; dy++) {
for (var dx = -1; dx <= 1; dx++) {
let p = vec2i(gid.xy) + vec2i(dx, dy);
sum = sum + textureLoad(src, p, 0);
}
}
textureStore(dst, vec2i(gid.xy), sum / 9.0);
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Browser, cross-platform | WebGPU + WGSL |
| Native cross-platform | Vulkan compute + GLSL/HLSL |
| NVIDIA-only, max perf | CUDA |
| Apple ecosystem | Metal compute (MSL) |
| ML kernel research | Triton (Python) |
| Production ML inference | Pre-built (cuDNN, MLX, vLLM kernels) |
**기본값**: 매 web/cross-platform → WebGPU + WGSL. 매 ML research → Triton. 매 production NVIDIA ML → CUDA + cuDNN/cuBLAS.
## 🔗 Graph
- 부모: [[GPU Programming]] · [[Parallel Computing]]
- 변형: [[Vertex Shader]] · [[Fragment Shader]] · [[CUDA]]
- 응용: [[WebGPU]]
- Adjacent: [[Triton]] · [[Vulkan]]
## 🤖 LLM 활용
**언제**: heavy parallel data (image, ML, sim), browser GPU compute, custom ML kernels.
**언제 X**: small data (<10k items, CPU faster after transfer cost), branch-heavy serial logic, very small kernels (launch overhead).
## ❌ 안티패턴
- **Divergent branching in warp**: 매 thread 가 different path → serialization → 매 SIMT 의 X.
- **Uncoalesced memory access**: random pattern → bandwidth waste — adjacent threads should read adjacent memory.
- **Tiny dispatch**: 100 threads → launch overhead > work — batch.
- **Forgetting workgroupBarrier**: race condition on shared memory.
- **CPU↔GPU ping-pong**: every step copies back — keep data on GPU.
## 🧪 검증 / 중복
- Verified (WebGPU spec 2026 W3C / CUDA Programming Guide 12.x / Triton docs / Apple MSL).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — WGSL/CUDA/Triton + workgroup model |
@@ -0,0 +1,165 @@
---
id: wiki-2026-0508-conceptual-integrity
title: Conceptual Integrity
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Architectural Integrity, Brooks Conceptual Integrity]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [architecture, design, brooks, mythical-man-month]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: agnostic
framework: agnostic
---
# Conceptual Integrity
## 매 한 줄
> **"매 system design 의 the most important consideration — 매 unified set of design ideas, 매 single mind 의 product."**. Brooks 의 *Mythical Man-Month* (1975) 의 central thesis. 매 great system 은 매 small group of architects 의 vision. 2026년 design systems, API design, programming language design, framework architecture 에 핵심 원칙으로 산다.
## 매 핵심
### 매 Brooks 의 정의
> "Conceptual integrity is the most important consideration in system design. It is better to have a system omit certain anomalous features and improvements, but to reflect one set of design ideas, than to have one that contains many good but independent and uncoordinated ideas."
### 매 implications
- **Architect/designer** 의 separation from implementation team.
- **Say no** to features that violate the model.
- **Programmer's manual** = single source of truth.
- **Small architect group** > committee — 매 "design by committee" 의 X.
### 매 modern manifestations
- **API design**: consistent verbs, naming, error model (Stripe, GitHub APIs).
- **Programming languages**: Go's "less is more", Rust's ownership model.
- **Frameworks**: Rails "convention over configuration", Django "batteries included with one way".
- **Design systems**: single token vocabulary, predictable behaviors.
### 매 Tension
- Conceptual integrity vs feature completeness.
- Single architect vs distributed teams.
- Stability vs evolution.
### 매 응용
1. API design (REST resource model 의 일관성).
2. Language design (Go, Elm).
3. UI framework (SwiftUI, Jetpack Compose).
4. CLI design (git, kubectl).
## 💻 패턴
### Consistent API model (Stripe-style)
```typescript
// Every resource follows: list, retrieve, create, update, delete
GET /v1/customers // list
GET /v1/customers/:id // retrieve
POST /v1/customers // create
POST /v1/customers/:id // update (Stripe uses POST not PUT)
DELETE /v1/customers/:id // delete
// Same shape for charges, subscriptions, invoices, ...
```
### Consistent error model
```typescript
// Every error response follows the same shape
type ApiError = {
error: {
type: 'invalid_request' | 'authentication' | 'rate_limit' | 'server';
code: string;
message: string;
param?: string;
request_id: string;
};
};
```
### Convention over configuration (Rails-like)
```ruby
# Filename, class name, table name, route — all derived by convention
# app/models/article.rb → Article class → articles table
# app/controllers/articles_controller.rb → /articles routes
class Article < ApplicationRecord
# No XML config needed
end
```
### Single mental model — Go's error handling
```go
// One pattern for errors, used everywhere
result, err := doThing()
if err != nil {
return nil, fmt.Errorf("doThing failed: %w", err)
}
// No exceptions, no Result<T,E>, just (T, error)
```
### Architecture Decision Records (ADRs) preserve integrity
```markdown
# ADR-007: All write APIs return the full resource
## Status
Accepted
## Context
Mixing return shapes (id-only vs full object) violates conceptual integrity.
## Decision
All POST/PUT/PATCH endpoints return the full updated resource.
## Consequences
- Slightly larger response bodies.
- Clients never need a follow-up GET after write.
```
### "Say no" guard — RFC review
```markdown
## Proposal
Add a special-case `/users/me/notifications/digest` that returns
HTML instead of JSON.
## Reviewer
Rejected. All API endpoints return JSON. Render HTML in client
or build a separate `/email-templates/*` namespace.
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Public API design | Strict consistency, single architect, "no" gate |
| Internal tooling | Conventions documented, ADRs |
| Framework | One canonical way per task |
| Multi-team product | Style guide + design system + design council |
| Research/exploration | Looser — ideas before integrity |
**기본값**: Small architect council (2-4 people), written design principles, ADRs, explicit "rejected" log.
## 🔗 Graph
- 부모: [[Software Architecture]]
- 변형: [[Design Principles]]
- 응용: [[API Design]] · [[Design Systems]] · [[ADR]]
## 🤖 LLM 활용
**언제**: API design review, framework architecture, design system kickoff, language design, contested feature decisions.
**언제 X**: 1-week prototype, research spike, throwaway script.
## ❌ 안티패턴
- **Design by committee**: 모두가 한 마디씩 — 매 disjoint feature soup.
- **Feature creep without rejection**: 매 yes — 매 integrity 의 erosion.
- **Multiple ways to do same thing**: Python's "one obvious way" violation — choice paralysis.
- **No written principles**: implicit consensus — 매 architect 떠나면 깨짐.
## 🧪 검증 / 중복
- Verified (Brooks "Mythical Man-Month" 1975/1995 anniversary ed. / Stripe API design / Go FAQ).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Brooks definition + modern API/framework 적용 |
@@ -0,0 +1,174 @@
---
id: wiki-2026-0508-concurrent-rendering
title: Concurrent Rendering
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [React Concurrent, Concurrent Mode, React 18 Concurrent]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [react, concurrent, rendering, scheduler, transitions]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: react
---
# Concurrent Rendering
## 매 한 줄
> **"매 render 매 interruptible, prioritizable, abandonable"**. React 18 (2022) 에 stable. Fiber architecture (2017) 의 결실. 2026 현재 React 19+ 의 default; `useTransition`, `useDeferredValue`, Suspense, streaming SSR, React Compiler 매 모든 것 위에 빌드.
## 매 핵심
### 매 핵심 idea
- **Interruptible** — render 중 high-priority work (input, animation) 매 들어오면 yield.
- **Concurrent (NOT parallel)** — single-threaded JS 위에서 cooperative scheduling.
- **Time-slicing** — 5ms chunk 매 yield to browser (`scheduler` package).
- **Multiple in-progress trees** — current + work-in-progress; double buffering.
- **Lane-based priority** — sync, default, transition, idle lane.
### 매 hook / API
- **`useTransition`** — non-urgent update (filter, navigation).
- **`useDeferredValue`** — debounce-like, 매 lower priority value.
- **`startTransition`** — imperative version.
- **`Suspense`** — async boundary, fallback UI.
- **`use` hook** (React 19) — read promise during render.
### 매 응용
1. Search-as-you-type — input 매 sync, list filter 매 transition.
2. Tab switching — 매 instant feel, 매 expensive subtree 의 background render.
3. SSR streaming — 매 progressive shell + island hydration.
4. Route navigation — `<Link>` prefetch + transition.
## 💻 패턴
### useTransition — heavy filter
```tsx
function Search() {
const [query, setQuery] = useState('');
const [list, setList] = useState<Item[]>(allItems);
const [isPending, startTransition] = useTransition();
return (
<>
<input
value={query}
onChange={(e) => {
setQuery(e.target.value); // urgent
startTransition(() => { // non-urgent
setList(allItems.filter(i => i.name.includes(e.target.value)));
});
}}
/>
{isPending && <Spinner />}
<List items={list} />
</>
);
}
```
### useDeferredValue
```tsx
function Page({ query }: { query: string }) {
const deferred = useDeferredValue(query);
return <ExpensiveResults query={deferred} />;
}
```
### Suspense + use (React 19+)
```tsx
function UserProfile({ userPromise }: { userPromise: Promise<User> }) {
const user = use(userPromise); // suspends if pending
return <h1>{user.name}</h1>;
}
<Suspense fallback={<Skeleton />}>
<UserProfile userPromise={fetchUser(id)} />
</Suspense>
```
### Streaming SSR (Next.js 15 / React 19)
```tsx
// app/page.tsx
export default async function Page() {
return (
<>
<Header />
<Suspense fallback={<FeedSkeleton />}>
<Feed /> {/* streamed once data ready */}
</Suspense>
</>
);
}
```
### React Compiler (2026, automatic memoization)
```tsx
// no useMemo / useCallback needed — compiler inserts
function Cart({ items }: { items: Item[] }) {
const total = items.reduce((s, i) => s + i.price, 0); // auto-memoized
return <div>{total}</div>;
}
```
### Selective hydration
```tsx
// chat panel hydrates first if user clicks it,
// even if header is still loading
<Suspense fallback={<Sk />}>
<Header />
</Suspense>
<Suspense fallback={<Sk />}>
<Chat />
</Suspense>
```
### Cancel stale render (transition supersession)
```tsx
// older transition automatically discarded when new one starts
startTransition(() => setQuery('a')); // discarded
startTransition(() => setQuery('ab')); // wins
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Input + heavy derived UI | `useTransition` |
| External lib slow value | `useDeferredValue` |
| Async data | `Suspense` + `use` |
| SSR with slow data | streaming + Suspense islands |
| Manual memoization (legacy) | replace with React Compiler |
**기본값**: React 19+ with Compiler; transitions for any non-urgent update.
## 🔗 Graph
- 부모: [[React]] · [[Rendering Pipeline]]
- 변형: [[Fiber_Architecture|Fiber Architecture]] · [[Time_Slicing|Time Slicing]]
- 응용: [[Streaming SSR]]
- Adjacent: [[Virtual DOM과 Reconciliation|Virtual DOM]] · [[Reconciliation]] · [[React Compiler]]
## 🤖 LLM 활용
**언제**: identify component 매 transition 으로 wrap 할 후보, code review 매 missed Suspense boundary.
**언제 X**: scheduler internals 의 deep debug (need devtools profiler).
## ❌ 안티패턴
- **`startTransition` for urgent input**: input lag.
- **No Suspense fallback**: 매 entire tree freeze 까지 falling back.
- **Manual memoization with React Compiler**: redundant + sometimes 더 느림.
- **Async setState in transition without race control**: stale data.
- **Deferred value of huge object reference**: 매 GC pressure.
## 🧪 검증 / 중복
- Verified (React 18 release notes 2022, React 19 docs 2026, Acdlite/Sebastian Markbåge talks).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — full content with React 19 + Compiler patterns |
@@ -0,0 +1,24 @@
---
category: Architecture
tags: [auto-wikified, technical-documentation, architecture]
title: Constructor Injection
description: "Constructor Injection(생성자 주입)은 클래스의 생성자를 통해 객체가 필요로 하는 의존성을 명시적으로 선언하고 프레임워크로부터 해당 객체를 제공받는 의존성 주입(DI) 방식입니다 [1-3]."
last_updated: 2026-05-04
---
# Constructor Injection
## 📌 Brief Summary
Constructor Injection(생성자 주입)은 클래스의 생성자를 통해 객체가 필요로 하는 의존성을 명시적으로 선언하고 프레임워크로부터 해당 객체를 제공받는 의존성 주입(DI) 방식입니다 [1-3]. 모던 Spring Boot와 NestJS 같은 최신 엔터프라이즈 프레임워크에서 가장 선호되고 권장되는 접근법입니다 [1, 2]. 이 방식을 사용하면 수동으로 객체를 생성하거나 연결할 필요 없이, 프레임워크가 의존성을 자동으로 감지하고 인스턴스화하여 주입합니다 [2, 3].
## 📖 Core Content
* **프레임워크의 자동 의존성 해결**: Spring Boot와 NestJS와 같은 프레임워크에서는 클래스 생성자에 필요한 의존성을 선언하기만 하면 됩니다 [1, 2]. 프레임워크의 제어 역전(IoC) 혹은 DI 컨테이너가 생성자를 감지하여 알맞은 빈(Bean)이나 프로바이더를 자동으로 주입하므로, 팩토리 메서드나 수동 배선(manual wiring) 코드를 생략할 수 있습니다 [2].
* **결합도 완화와 구조적 명확성**: 의존성을 내부에서 직접 인스턴스화하거나 하드 코딩하여 임포트하는 대신, 생성자를 통해 외부에서 주입받는 방식을 취합니다 [1]. 이러한 접근은 컴포넌트 간의 강한 결합도를 낮추고 시스템을 더 유연하게 만듭니다 [1, 3].
* **테스트 가능성(Testability) 극대화**: 생성자 주입의 가장 큰 기술적 이점은 단위 테스트의 용이성입니다 [1, 3]. 테스트 과정에서 비즈니스 로직을 전혀 변경하지 않고도, 생성자의 인자를 통해 실제 서비스 대신 모의 객체(Mock)를 손쉽게 교체하여 주입할 수 있어 독립적이고 격리된 테스트 환경을 구축하기 매우 수월해집니다 [1].
## ⚖️ Trade-offs & Caveats
* **기반 클래스(Base Class) 상속 시의 관리 부담**: 상속을 활용해 기반 클래스에 공통 로직을 구성할 때 의존성이 개입되면, 이를 상속받는 모든 하위 구현체의 생성자에 해당 의존성을 전달하도록 코드를 작성해야 하는 제약과 부담이 발생합니다 [4].
* **의존성 변경에 따른 연쇄 수정 비용**: 위의 상속 구조 등에서 새로운 의존성이 추가되는 설계 변경이 발생할 경우, 기반 클래스를 상속받는 모든 하위 클래스의 생성자 서명(Signature)을 일일이 찾아 수정해야 하는 유지보수 상의 비용과 번거로움이 발생할 수 있습니다 [4].
---
*Last updated: 2026-05-03*
@@ -0,0 +1,168 @@
---
id: wiki-2026-0508-continuous-integration-ci
title: Continuous Integration (CI)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [CI, Continuous Integration, 지속적 통합]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
verification_status: applied
tags: [ci, devops, automation, github-actions]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: yaml
framework: github-actions
---
# Continuous Integration (CI)
## 매 한 줄
> **"매 push마다 build + test, fast feedback"**. Grady Booch (1991) 가 제안, Martin Fowler 가 대중화. 2026 현재 GitHub Actions / GitLab CI 가 표준이며, AI-assisted PR review (Claude Opus 4.7) 와 결합되어 매 commit 검증 cycle 이 분 단위로 압축됨.
## 매 핵심
### 매 원칙
- **Mainline integration 빈번**: 매 developer 매일 main 에 merge.
- **Automated build**: 매 commit trigger build pipeline.
- **Automated test**: unit + integration + lint 매 자동 실행.
- **Fast feedback**: <10 min 안에 결과. 길어지면 dev 매 ignore.
- **Single source of truth**: 매 single repo, single mainline.
### 매 stages
- **Lint** (10s) — eslint, ruff, gofmt.
- **Unit test** (1-3 min) — vitest, pytest, go test.
- **Integration test** (3-8 min) — testcontainers, ephemeral DB.
- **Build artifact** (1-2 min) — docker image, npm tarball.
- **Static analysis** (parallel) — SonarQube, Snyk, CodeQL.
### 매 응용
1. SaaS product 매 trunk-based development.
2. Open-source project 매 PR validation.
3. Monorepo 매 affected-only build (Turborepo, Nx).
## 💻 패턴
### Modern GitHub Actions (2026)
```yaml
name: CI
on:
push: { branches: [main] }
pull_request:
merge_group:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with: { node-version: '22', cache: 'pnpm' }
- run: pnpm install --frozen-lockfile
- run: pnpm lint
- run: pnpm test --coverage
- uses: codecov/codecov-action@v5
```
### Matrix build
```yaml
strategy:
fail-fast: false
matrix:
os: [ubuntu-24.04, macos-14, windows-2022]
node: [20, 22]
runs-on: ${{ matrix.os }}
```
### Affected-only (monorepo)
```yaml
- run: pnpm exec turbo run test --filter=...[origin/main]
```
### Reusable workflow
```yaml
# .github/workflows/reusable-test.yml
on:
workflow_call:
inputs:
node-version: { type: string, default: '22' }
jobs:
test:
runs-on: ubuntu-24.04
steps: [ ... ]
```
### Container-based test (testcontainers)
```python
# pytest with ephemeral postgres
from testcontainers.postgres import PostgresContainer
def test_repo():
with PostgresContainer("postgres:17") as pg:
url = pg.get_connection_url()
# run integration test against real DB
```
### Cache layers (docker buildx)
```yaml
- uses: docker/build-push-action@v6
with:
context: .
cache-from: type=gha
cache-to: type=gha,mode=max
tags: ghcr.io/org/app:${{ github.sha }}
```
### AI PR review (2026)
```yaml
- uses: anthropic-experimental/claude-code-action@v1
with:
api-key: ${{ secrets.ANTHROPIC_API_KEY }}
model: claude-opus-4-7
review-mode: pr-comment
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Open-source GitHub repo | GitHub Actions |
| Self-hosted, private | GitLab CI / Drone |
| Monorepo | Turborepo + affected-only |
| Polyglot, complex | Buildkite / Bazel |
| Mobile (iOS/Android) | Bitrise / Xcode Cloud |
**기본값**: GitHub Actions + concurrency cancel + matrix + cache.
## 🔗 Graph
- 부모: [[DevOps]]
- 변형: [[Continuous Deployment]] · [[Trunk-Based Development]]
- 응용: [[GitHub Actions]]
- Adjacent: [[Test Automation]] · [[Static Analysis]] · [[153_pre-commit과_품질_게이트|Pre-commit Hooks]]
## 🤖 LLM 활용
**언제**: PR diff review, flaky test detection, commit message generation, changelog 생성.
**언제 X**: secret-handling pipeline (보안), production deploy gate (deterministic 해야 함).
## ❌ 안티패턴
- **Slow pipeline (>20 min)**: dev 매 ignore, "broken main" 정상화.
- **Flaky test 방치**: trust collapse → 매 retry, retry, retry.
- **No mainline protection**: 직접 push to main, PR 없음.
- **Build on developer machine only**: "works on my machine" 재현.
- **Secrets in logs**: env 출력, token leak.
## 🧪 검증 / 중복
- Verified (Fowler 2006 *Continuous Integration* article, GitHub Actions docs 2026).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — full content with modern GitHub Actions patterns |
@@ -0,0 +1,227 @@
---
id: wiki-2026-0508-control-points
title: Control Points
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Capture Points, KOTH, Domination]
duplicate_of: none
source_trust_level: A
confidence_score: 0.85
verification_status: applied
tags: [game-design, multiplayer, objectives, fps]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: csharp-gdscript
framework: unity-godot-unreal
---
# Control Points
## 매 한 줄
> **"매 spatial objective — 매 team 이 매 zone 의 occupy 통해 score/win."**. Control Points는 multiplayer game 의 가장 ubiquitous objective primitive. Domination, KOTH, Capture-and-Hold, Push, Hardpoint 모두 변형. Team Fortress 2, Battlefield, Overwatch, Apex, CS Bombsite (variant), Splatoon (area-based) 의 핵심. 2026년 server-authoritative netcode + lag compensation 패턴 매 stable.
## 매 핵심
### 매 variants
| Variant | Mechanic |
|---|---|
| **Domination** | Multiple points, hold majority for tickets/score |
| **KOTH** | Single point, hold-time wins |
| **Capture & Hold** | Capture sequentially, last team standing |
| **Hardpoint** | Single rotating point, score over time |
| **Push/Payload** | Mobile control point along track |
| **Linear (5CP TF2)** | Sequential capture, central pivot |
### 매 mechanics
- **Capture progress**: 0~100%, increases with attackers in zone.
- **Multi-capture rate**: more attackers → faster (capped, e.g. 2x at 2+).
- **Contest**: defenders inside → progress paused.
- **Lock/unlock**: previous point capture unlocks next.
- **Decay**: progress drops when zone empty (configurable).
- **Overtime**: contested point prevents game end.
### 매 design principles
- **Sightline balance**: defenders 의 advantage 와 attacker chokes 의 균형.
- **Capture time**: too short → trivial, too long → stalemate. 5-15s typical.
- **Cap-zone size**: encourages clustering vs spread.
- **Spawn distance**: defender respawn 가 너무 가까우면 attack 불가.
### 매 응용
1. FPS multiplayer modes (Overwatch, BF, CoD).
2. MOBA jungle camps / objectives (Roshan, Drake areas).
3. RTS resource nodes (StarCraft expansions).
4. MMO PvP zones (WoW battlegrounds).
## 💻 패턴
### Unity C# — control point trigger
```csharp
using UnityEngine;
using Unity.Netcode;
public class ControlPoint : NetworkBehaviour {
public NetworkVariable<float> Progress = new(0f);
public NetworkVariable<int> OwnerTeam = new(-1);
[SerializeField] private float captureRate = 10f; // pct/sec per attacker
[SerializeField] private float maxRate = 20f;
private readonly Dictionary<int, int> teamCount = new();
private void OnTriggerEnter(Collider other) {
if (!IsServer) return;
if (other.TryGetComponent<Player>(out var p)) {
teamCount.TryGetValue(p.Team, out var n);
teamCount[p.Team] = n + 1;
}
}
private void OnTriggerExit(Collider other) {
if (!IsServer) return;
if (other.TryGetComponent<Player>(out var p)
&& teamCount.TryGetValue(p.Team, out var n)) {
teamCount[p.Team] = Mathf.Max(0, n - 1);
}
}
private void FixedUpdate() {
if (!IsServer) return;
var teams = new List<KeyValuePair<int,int>>(teamCount);
teams.Sort((a, b) => b.Value.CompareTo(a.Value));
if (teams.Count == 0 || teams[0].Value == 0) return;
// Contested: top two teams equal & nonzero
if (teams.Count > 1 && teams[0].Value == teams[1].Value) return;
var attacker = teams[0];
var rate = Mathf.Min(maxRate, captureRate * Mathf.Sqrt(attacker.Value));
if (OwnerTeam.Value == attacker.Key) {
Progress.Value = Mathf.Min(100f, Progress.Value + rate * Time.fixedDeltaTime);
} else {
Progress.Value = Mathf.Max(0f, Progress.Value - rate * Time.fixedDeltaTime);
if (Progress.Value <= 0f) OwnerTeam.Value = attacker.Key;
}
}
}
```
### Godot 4 / GDScript
```gdscript
extends Area3D
class_name ControlPoint
@export var capture_rate: float = 10.0
var progress: float = 0.0
var owner_team: int = -1
var team_in_zone: Dictionary = {}
func _physics_process(delta: float) -> void:
if not multiplayer.is_server(): return
var top_team := -1
var top_count := 0
var contested := false
for team in team_in_zone:
var n: int = team_in_zone[team]
if n > top_count:
top_count = n
top_team = team
contested = false
elif n == top_count and n > 0:
contested = true
if contested or top_count == 0: return
var rate = capture_rate * sqrt(top_count)
if owner_team == top_team:
progress = min(100.0, progress + rate * delta)
else:
progress = max(0.0, progress - rate * delta)
if progress <= 0.0:
owner_team = top_team
_notify_capture(top_team)
```
### Server-authoritative state with lag compensation
```csharp
// Server stores state snapshots for last 1s
private readonly CircularBuffer<Snapshot> history = new(60);
public bool WasInsideAtTime(Vector3 playerPos, float clientTime) {
var snap = history.SampleAt(clientTime);
return snap.Bounds.Contains(playerPos);
}
```
### Configurable progression (data-driven)
```json
{
"id": "cp_central",
"captureTimeSeconds": 8,
"multiCapMultiplier": [1.0, 1.5, 1.75, 2.0],
"decayRate": 0.5,
"unlockedBy": ["cp_a", "cp_b"],
"scoresPerSecond": 10
}
```
### UI broadcast (client-side prediction visual)
```typescript
// Client receives Progress NetworkVariable changes,
// interpolates between ticks for smooth bar fill
useEffect(() => {
const start = performance.now();
const startVal = displayedProgress;
const targetVal = serverProgress;
const tick = () => {
const t = Math.min(1, (performance.now() - start) / 100);
setDisplayedProgress(startVal + (targetVal - startVal) * t);
if (t < 1) requestAnimationFrame(tick);
};
tick();
}, [serverProgress]);
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Casual fast-match | KOTH, single-point, 3-5 min rounds |
| Competitive | Linear/5CP, longer rounds, overtime |
| Asymmetric | Push/Payload (attack vs defend) |
| Objective rotation | Hardpoint (rotating zone keeps action moving) |
| Large maps | Domination (multiple distributed) |
**기본값**: server-authoritative + 5-10s capture + multi-cap multiplier + decay + contested-pause + overtime.
## 🔗 Graph
- 변형: [[Domination]]
- Adjacent: [[Lag Compensation]]
## 🤖 LLM 활용
**언제**: multiplayer mode design, level layout review, balance tuning, netcode design for objectives.
**언제 X**: single-player, asynchronous (turn-based), pure deathmatch (no objective).
## ❌ 안티패턴
- **Client-authoritative capture**: trivially exploitable — server-side only.
- **Spawn too close to objective**: defender immortal — distance + lockout window.
- **No contested-pause**: solo defender can't stall — feels unfair.
- **Capture too short**: zerg wins, no skill — 8-12s standard.
- **No decay**: half-cap then leave is permanent — partial progress decay.
## 🧪 검증 / 중복
- Verified (Valve TF2 design / Blizzard Overwatch dev blogs / GDC talks 2018-2024).
- 신뢰도 A-.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — variants + Unity/Godot impl + netcode |
@@ -0,0 +1,178 @@
---
id: wiki-2026-0508-control-systems-engineering
title: Control Systems Engineering
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [control-systems, feedback-control, PID-control]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [control-systems, pid, mpc, feedback]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: python
framework: do-mpc/control
---
# Control Systems Engineering
## 매 한 줄
> **"매 control 의 매 measure → compare → actuate 의 closed loop"**. 매 PID (1922 Minorsky) 가 매 95% industrial loops, 매 MPC (Model Predictive Control) 가 매 multivariable + constrained problems 의 dominant. 2026 의 매 RL-augmented control + neural ODEs 가 매 emerging — 매 Boston Dynamics, Tesla Autopilot, NVIDIA GR00T 가 hybrid.
## 매 핵심
### 매 building blocks
- **Plant** — 매 controlled system (motor, reactor, drone).
- **Sensor** — 매 measurement (encoder, IMU, thermocouple).
- **Controller** — 매 algorithm (PID, MPC, LQR).
- **Actuator** — 매 output (PWM, valve, voltage).
- **Reference / setpoint** — 매 desired state.
### 매 stability
- **Open-loop**: 매 simple, 매 no feedback — 매 disturbance 에 fragile.
- **Closed-loop**: 매 feedback — 매 disturbance reject + setpoint track.
- **Stability criteria**: Routh-Hurwitz, Nyquist, Bode (gain margin > 6 dB, phase margin > 45°).
### 매 controller spectrum
1. **Bang-bang** — 매 thermostat.
2. **PID** — 매 95% loops.
3. **State-space (LQR / pole placement)** — MIMO linear.
4. **MPC** — 매 constrained, predictive.
5. **Adaptive / gain scheduling** — 매 nonlinear plants.
6. **RL / learned policy** — 매 high-dim, 매 simulation 의 train.
7. **Robust H∞** — 매 worst-case guarantees.
## 💻 패턴
### Discrete PID with anti-windup
```python
class PID:
def __init__(self, kp, ki, kd, dt, u_min, u_max):
self.kp, self.ki, self.kd, self.dt = kp, ki, kd, dt
self.u_min, self.u_max = u_min, u_max
self.i, self.prev_e = 0.0, 0.0
def step(self, setpoint, measurement):
e = setpoint - measurement
self.i += e * self.dt
d = (e - self.prev_e) / self.dt
u = self.kp*e + self.ki*self.i + self.kd*d
u_clamped = max(self.u_min, min(self.u_max, u))
# 매 anti-windup: 매 saturate 시 integrator 의 back-calc
if u != u_clamped:
self.i -= (u - u_clamped) / self.ki if self.ki else 0
self.prev_e = e
return u_clamped
```
### Ziegler-Nichols 의 tune
```python
def ziegler_nichols(Ku, Tu, kind='PID'):
if kind == 'PID':
return dict(kp=0.6*Ku, ki=1.2*Ku/Tu, kd=0.075*Ku*Tu)
if kind == 'PI':
return dict(kp=0.45*Ku, ki=0.54*Ku/Tu, kd=0)
```
### State-space LQR (CartPole)
```python
import numpy as np
from scipy.linalg import solve_continuous_are
A = np.array([[0,1,0,0],[0,0,-mp*g/M,0],[0,0,0,1],[0,0,(M+mp)*g/(M*l),0]])
B = np.array([[0],[1/M],[0],[-1/(M*l)]])
Q = np.diag([1, 1, 10, 10]); R = np.array([[0.1]])
P = solve_continuous_are(A, B, Q, R)
K = np.linalg.inv(R) @ B.T @ P
u = -K @ x # state feedback
```
### MPC with do-mpc
```python
import do_mpc
model = do_mpc.model.Model('continuous')
x = model.set_variable('_x', 'x', shape=(2,1))
u = model.set_variable('_u', 'u')
model.set_rhs('x', np.array([[x[1]],[u - 0.1*x[1]]]))
model.setup()
mpc = do_mpc.controller.MPC(model)
mpc.set_param(n_horizon=20, t_step=0.1)
mpc.set_objective(mterm=x[0]**2, lterm=x[0]**2 + 0.01*u**2)
mpc.bounds['lower','_u','u'] = -5; mpc.bounds['upper','_u','u'] = 5
mpc.setup()
```
### Kalman filter (state estimation)
```python
def kalman_step(x, P, u, z, A, B, H, Q, R):
x_pred = A @ x + B @ u
P_pred = A @ P @ A.T + Q
K = P_pred @ H.T @ np.linalg.inv(H @ P_pred @ H.T + R)
x = x_pred + K @ (z - H @ x_pred)
P = (np.eye(len(x)) - K @ H) @ P_pred
return x, P
```
### RL policy (PPO via stable-baselines3)
```python
from stable_baselines3 import PPO
import gymnasium as gym
env = gym.make("Pendulum-v1")
model = PPO("MlpPolicy", env, verbose=1)
model.learn(total_timesteps=200_000)
```
### Real-time loop (Linux PREEMPT_RT)
```python
import time, os
os.sched_setscheduler(0, os.SCHED_FIFO, os.sched_param(80))
T = 0.001 # 1 kHz
while True:
t0 = time.perf_counter()
u = pid.step(setpoint, sensor.read())
actuator.write(u)
while time.perf_counter() - t0 < T: pass
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 매 SISO + linear | PID |
| 매 MIMO + linear | LQR / state-space |
| Constrained + slow plant | MPC |
| Nonlinear + simulator 가능 | RL (PPO, SAC) |
| Safety-critical + uncertain | Robust H∞ / sliding mode |
| 매 very fast (>10 kHz) | Hardware PID (FPGA) |
**기본값**: PID with proper tuning + anti-windup; escalate to MPC if multivariable or constrained.
## 🔗 Graph
- 부모: [[Cyber-Physical-Systems]] · [[Robotics]]
- 변형: [[PID]] · [[MPC]]
- 응용: [[Digital Twin]]
- Adjacent: [[Kalman-Filter-and-State-Tracking|Kalman-Filter]] · [[Reinforcement-Learning]]
## 🤖 LLM 활용
**언제**: 매 controller derivation explanation, 매 transfer function manipulation, 매 tuning suggestion based on step response, 매 simulation script generation.
**언제 X**: 매 actual real-time loop (deterministic 코드 / FPGA). 매 safety certification (formal verification 필요).
## ❌ 안티패턴
- **No anti-windup**: 매 actuator saturate 시 integral runaway → overshoot.
- **Derivative on error (vs measurement)**: 매 setpoint step 시 derivative kick — derivative-on-PV 사용.
- **Tune via trial-and-error only**: 매 system identification 의 사용 (Ziegler-Nichols, FOPDT fit).
- **MPC without warm-start**: 매 solve time 의 explode — previous solution 의 reuse.
- **No filter on derivative**: 매 measurement noise 가 D term 의 amplify.
- **RL on real hardware first**: 매 sim-to-real 의 가야 — safe exploration.
## 🧪 검증 / 중복
- Verified (Åström & Murray "Feedback Systems", Skogestad MIMO control, do-mpc docs, IEEE control textbooks).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — control engineering: PID, LQR, MPC, RL, Kalman |
@@ -0,0 +1,163 @@
---
id: wiki-2026-0508-cosmos-플랫폼-netflix
title: Cosmos 플랫폼 (Netflix)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Netflix Cosmos, Cosmos Platform, Cosmos]
duplicate_of: none
source_trust_level: A
confidence_score: 0.85
verification_status: applied
tags: [netflix, media-processing, workflow, microservices]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: java
framework: spring-boot
---
# Cosmos 플랫폼 (Netflix)
## 매 한 줄
> **"매 Netflix 의 next-gen media computing platform"**. Reloaded (predecessor) 의 후계, 2018-2020 announce. Microservices + workflow orchestration + serverless functions 매 통합. Encoding, transcoding, content analysis, IMF processing 매 모든 media pipeline 의 backbone.
## 매 핵심
### 매 architecture (3 layers)
- **Optimus (API layer)** — external-facing service, business logic, request validation.
- **Plato (Workflow layer)** — Conductor-based workflow orchestration, retry, branching.
- **Stratum (Functions layer)** — serverless compute, Titus (container) 위 실행.
### 매 design 원칙
- **Asynchronous everything** — sync call 매 minimum, message-based.
- **Schema-first** — Protobuf gRPC 매 contract.
- **Workflow as DSL** — JSON workflow definition (Conductor).
- **Function granularity** — small, idempotent, stateless.
- **Event-driven** — Kafka, SQS 매 inter-service.
### 매 응용
1. Video encoding pipeline — source → multiple bitrates × codecs.
2. Image processing — title art, thumbnails, language variants.
3. Subtitle / caption processing.
4. Content quality control (QC) automation.
5. IMF (Interoperable Master Format) ingestion.
## 💻 패턴
### Workflow definition (Plato / Netflix Conductor)
```json
{
"name": "encode_video_v3",
"version": 3,
"tasks": [
{
"name": "probe",
"type": "FUNCTION",
"function": "stratum:ffprobe",
"inputParameters": { "url": "${workflow.input.sourceUrl}" }
},
{
"name": "fan_out_encode",
"type": "FORK_JOIN_DYNAMIC",
"dynamicForkTasksParam": "encodeTasks"
},
{
"name": "join_results",
"type": "JOIN"
},
{
"name": "publish",
"type": "FUNCTION",
"function": "stratum:publishToCDN"
}
]
}
```
### Stratum function (Java, Spring Boot)
```java
@CosmosFunction(name = "ffprobe")
public class FfprobeFunction implements Function<ProbeRequest, ProbeResponse> {
@Override
public ProbeResponse apply(ProbeRequest req) {
var info = Ffmpeg.probe(req.url());
return new ProbeResponse(info.duration(), info.codec(), info.bitrate());
}
}
```
### Optimus service (gRPC)
```protobuf
service EncodeService {
rpc StartEncode(EncodeRequest) returns (EncodeResponse);
rpc GetStatus(StatusRequest) returns (stream StatusUpdate);
}
```
### Titus container deployment
```yaml
# titus job definition
applicationName: stratum-ffprobe
container:
image: registry/stratum/ffprobe:v42
resources:
cpu: 4
memoryMB: 8192
gpu: 0
env:
COSMOS_FUNCTION_NAME: ffprobe
```
### Event-driven trigger (Kafka)
```java
@KafkaListener(topics = "media.uploaded")
public void onUpload(MediaUploadedEvent event) {
workflowClient.start("encode_video_v3", Map.of(
"sourceUrl", event.getUrl(),
"movieId", event.getMovieId()
));
}
```
### Idempotency key (function level)
```java
@CosmosFunction(idempotencyKey = "${input.movieId}-${input.bitrate}")
public class EncodeFunction implements Function<EncodeReq, EncodeResp> { ... }
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Long-running multi-step media job | Plato workflow |
| Simple stateless transform | Stratum function |
| External-facing API | Optimus service |
| Realtime / sub-100ms | NOT Cosmos (sync RPC service 따로) |
**기본값**: workflow for any multi-step media pipeline; functions for individual steps.
## 🔗 Graph
- 부모: [[Microservices]]
- 변형: [[Temporal]]
- Adjacent: [[Spinnaker]]
## 🤖 LLM 활용
**언제**: workflow definition 생성, function template 생성, 운영 incident 매 root cause 분석.
**언제 X**: production workflow execution (deterministic 해야 함).
## ❌ 안티패턴
- **Stateful function**: scale 못 함, retry 깨짐.
- **Long sync chain in Optimus**: workflow 가야 할 것 매 sync call 로 묶음.
- **No idempotency**: retry 매 duplicate side-effect.
- **Workflow too granular**: orchestration overhead > work.
## 🧪 검증 / 중복
- Verified (Netflix Tech Blog 2020 *Rebuilding Netflix Video Processing Pipeline with Microservices*).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — full content covering Optimus/Plato/Stratum |
@@ -0,0 +1,171 @@
---
id: wiki-2026-0508-cross-cutting-concerns
title: Cross-Cutting Concerns
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Cross Cutting Concerns, AOP Concerns, 횡단 관심사]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [aop, architecture, separation-of-concerns]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: nestjs
---
# Cross-Cutting Concerns
## 매 한 줄
> **"매 module 매 흩어지는 functionality (logging, auth, tx) 의 횡단"**. AOP (Aspect-Oriented Programming, Kiczales 1997) 의 motivation. 2026 현재 NestJS interceptors, Spring AOP, OpenTelemetry auto-instrumentation, Sidecar (Istio) 매 modern realization.
## 매 핵심
### 매 정의
- 단일 module 의 boundary 를 넘어 매 application 매 widely-scattered concern.
- Tangled with business logic → SoC (Separation of Concerns) 위반.
- Solution: 매 aspect, decorator, middleware, sidecar, interceptor 로 추출.
### 매 typical concerns
- **Logging / tracing** — 매 method entry/exit log.
- **Authentication / authorization** — 매 endpoint 매 token check.
- **Transaction management** — DB tx begin/commit/rollback.
- **Caching** — function result memoization.
- **Validation** — input schema check.
- **Rate limiting** — request throttling.
- **Metrics / observability** — counter, histogram.
- **Error handling** — global exception mapper.
- **i18n** — locale-aware response.
- **Audit** — who/when/what.
### 매 응용
1. Web framework middleware (Express, NestJS).
2. Spring `@Transactional` / `@Cacheable`.
3. Service mesh (Istio) — mTLS, retry, circuit-break 매 sidecar.
4. OpenTelemetry auto-instrumentation 매 tracing 매 zero code change.
## 💻 패턴
### NestJS interceptor — logging + timing
```typescript
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(ctx: ExecutionContext, next: CallHandler) {
const start = Date.now();
const req = ctx.switchToHttp().getRequest();
return next.handle().pipe(
tap(() => log.info({ url: req.url, ms: Date.now() - start }))
);
}
}
```
### NestJS guard — authz
```typescript
@Injectable()
export class RolesGuard implements CanActivate {
canActivate(ctx: ExecutionContext): boolean {
const required = Reflect.getMetadata('roles', ctx.getHandler());
const user = ctx.switchToHttp().getRequest().user;
return required.some(r => user.roles.includes(r));
}
}
```
### Spring AOP — `@Transactional`
```java
@Service
public class OrderService {
@Transactional
public Order place(Order o) {
repository.save(o);
inventory.decrement(o.itemId);
// throw → rollback
}
}
```
### Python decorator — caching
```python
from functools import lru_cache
@lru_cache(maxsize=1024)
def expensive_lookup(key: str) -> Result:
return db.query(key)
```
### TypeScript decorator (TC39 stage 3) — metrics
```typescript
function timed<This, Args extends any[], Return>(
target: (this: This, ...args: Args) => Return,
ctx: ClassMethodDecoratorContext
) {
return function (this: This, ...args: Args): Return {
const start = performance.now();
try { return target.apply(this, args); }
finally { metrics.histogram(ctx.name, performance.now() - start); }
};
}
class API {
@timed
fetchUser(id: string) { /* ... */ }
}
```
### OpenTelemetry — zero-code tracing
```python
# auto-instrumentation, no code changes
# pip install opentelemetry-distro opentelemetry-instrumentation-fastapi
# opentelemetry-instrument --traces_exporter otlp uvicorn app:app
```
### Service mesh (Istio) — mTLS via sidecar
```yaml
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata: { name: default, namespace: prod }
spec:
mtls: { mode: STRICT }
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Single service, JS/TS | NestJS interceptor / Express middleware |
| JVM, mature DI | Spring AOP / aspectj |
| Polyglot microservices | Service mesh (Istio / Linkerd) |
| Tracing only | OpenTelemetry auto-instrumentation |
| Function-level caching | language-native decorator |
**기본값**: framework-native (interceptor/middleware/decorator) for in-process; service mesh for network-level.
## 🔗 Graph
- 부모: [[Separation of Concerns]] · [[Software Architecture]]
- 변형: [[Aspect-Oriented Programming (AOP)]]
- 응용: [[NestJS]] · [[Istio]] · [[OpenTelemetry]]
- Adjacent: [[Dependency Injection (의존성 주입)]]
## 🤖 LLM 활용
**언제**: identify cross-cutting concern in legacy code, refactor to aspect/middleware.
**언제 X**: design-time SoC decision (need human architectural taste).
## ❌ 안티패턴
- **Concern duplication**: 매 controller 매 try/catch + log + auth 매 copy-paste.
- **Aspect overuse**: business logic 까지 aspect 로 → magic, debugging hell.
- **Order dependency 무시**: interceptor chain 의 순서 의존 → fragile.
- **Side-effect in interceptor**: DB write 매 logging interceptor → tx boundary 깨짐.
## 🧪 검증 / 중복
- Verified (Kiczales et al. 1997 *AOP*, Spring/NestJS docs 2026).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — full content covering interceptors, decorators, service mesh |
@@ -0,0 +1,34 @@
---
category: Computer_Science_and_Theory
tags: [auto-wikified, technical-documentation, computer_science_and_theory]
title: Cross-Cutting Concerns (AOP)
description: "**횡단 관심사(Cross-Cutting Concerns)**는 로깅, 보안, 캐싱, 예외 처리 등 소프트웨어의 여러 계층과 컴포넌트 전반에 걸쳐 공통으로 요구되는 부차적이고 시스템적인 기능을 의미합니다 [1-4]."
last_updated: 2026-05-04
---
# Cross-Cutting Concerns (AOP)
## 📌 Brief Summary
**횡단 관심사(Cross-Cutting Concerns)**는 로깅, 보안, 캐싱, 예외 처리 등 소프트웨어의 여러 계층과 컴포넌트 전반에 걸쳐 공통으로 요구되는 부차적이고 시스템적인 기능을 의미합니다 [1-4]. 이러한 관심사를 핵심 비즈니스 로직과 분리하여 모듈화하는 방법론이 **관점 지향 프로그래밍(AOP, Aspect-Oriented Programming)**입니다 [1, 5]. 이를 적절하게 중앙 집중화하지 않으면 코드의 중복과 강한 결합을 초래하여 대규모 애플리케이션의 유지보수성을 심각하게 저하시킬 수 있습니다 [1, 6].
## 📖 Core Content
* **개념 및 필요성**
애플리케이션의 비즈니스 로직이 '핵심 관심사(Core Concerns)'라면, 트랜잭션 관리, 로깅, 유효성 검사 등은 시스템 전체에 적용되어야 하는 '횡단 관심사'로 분류됩니다 [2, 7-10]. 이러한 횡단 관심사를 각 메서드 내부에 하드코딩하면 '단일 책임 원칙(SRP)'과 '반복 방지(DRY)' 원칙을 위반하게 되어 코드가 심하게 오염됩니다 [11]. AOP는 이러한 로직을 한 곳으로 추출하여 각 모듈에 선언적으로 주입합니다 [5, 7].
* **프레임워크별 실전 구현 패턴**
현대 백엔드 프레임워크들은 횡단 관심사 분리를 위해 각자의 설계 철학에 맞는 메커니즘을 제공합니다 [12].
* **Spring Boot (Java)**: AOP(AspectJ), 필터(Filter), 인터셉터(Interceptor)를 혼합하여 사용합니다 [12, 13]. 필터는 서블릿 레벨에서 모든 HTTP 요청(CORS, 기본 인증 등)을 가로채고, 인터셉터는 MVC 컨트롤러 실행 전후를 처리합니다 [14, 15]. AOP는 `@Aspect`, `@Before` 어노테이션 등을 통해 서비스나 리포지토리 등 어떤 Spring Bean의 메서드든 가로채어 트랜잭션이나 로깅을 비즈니스 로직 변경 없이 적용할 수 있습니다 [16, 17].
* **NestJS (Node.js)**: 가드(Guard), 인터셉터(Interceptor), 파이프(Pipe), 미들웨어(Middleware)로 구성된 파이프라인 형태의 흐름 제어를 제공합니다 [12]. 특히 RxJS 스트림을 활용하여 비동기 작업을 유연하게 처리할 수 있는 일관된 구조를 지원합니다 [12].
* **기타 아키텍처 패턴**: .NET 중심의 클린 아키텍처에서는 MediatR의 `IPipelineBehavior`를 통해 파이프라인 내부에서 로깅, 캐싱, 유효성 검사를 독립된 단위로 캡슐화합니다 [18-20].
* **주요 적용 사례**
* **트랜잭션 관리 (Transaction Management)**: 수많은 `try-catch`와 커밋/롤백 블록을 하드코딩하는 대신, AOP 어드바이스 마커를 활용해 트랜잭션 동작을 캡슐화함으로써 코드를 간결하게 유지합니다 [7].
* **로깅 및 예외 처리**: 애플리케이션 전반에 흩어진 추적(Tracing) 및 로깅 코드를 걷어내고, 인터셉터나 파이프라인을 통해 전역 예외 처리 및 로깅을 중앙 집중화합니다 [19, 21].
## ⚖️ Trade-offs & Caveats
* **마법 같은 동작(Magic)과 디버깅의 한계**: AOP나 미들웨어 파이프라인은 코드를 런타임에 래핑하거나 컴파일 시점에 동적으로 로직을 주입하므로, 비즈니스 코드와 인프라 코드를 깔끔하게 분리합니다 [22, 23]. 그러나 명시적으로 호출되는 코드가 없기 때문에 **실행 흐름이 불투명**해지며, 특정 로직이 왜 실행되는지 파악하기 어려워 디버깅 난이도가 급격히 상승할 수 있습니다 [22, 23]. 이는 Django의 Signals를 남용할 때 부수 효과(Side Effects)를 추적하기 어려워지는 안티 패턴과 유사한 기술 부채를 유발할 수 있습니다 [24, 25].
* **런타임 성능 오버헤드**: C#의 Castle.DynamicProxy와 같은 런타임 인터셉터 방식은 실행 시점에 프록시 래퍼를 동적으로 생성하여 메서드 호출을 가로챕니다 [26]. 이는 로깅과 같이 매우 빈번하게 발생하는 작업에 무분별하게 적용할 경우, 애플리케이션에 성능 비용(Cost)을 초래할 수 있습니다 [26].
* **설계 복잡성과 종속성 문제**: 횡단 관심사 로직을 공유하기 위해 '기반 클래스(Base Class)' 상속 패턴을 남용하면, 다중 상속 제약에 부딪히거나 모든 하위 클래스 생성자에 인프라 종속성을 넘겨주어야 하는 유지보수 문제가 발생합니다 [27, 28]. 인프라 컴포넌트(예: Logger 객체)가 시스템의 필수 종속성으로 강제되지 않도록 DI 생명주기(예: Transient 할당 지양)를 신중히 설정해야 합니다 [5].
---
*Last updated: 2026-05-03*
@@ -0,0 +1,176 @@
---
id: wiki-2026-0508-cyclomatic-complexity
title: Cyclomatic Complexity
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [McCabe Complexity, Cyclomatic Number, 순환 복잡도]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
verification_status: applied
tags: [code-quality, metrics, static-analysis, mccabe]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: python
framework: ruff
---
# Cyclomatic Complexity
## 매 한 줄
> **"매 function 의 linearly independent path 수"**. Thomas McCabe (1976) 가 정의. 매 control-flow graph 매 `M = E N + 2P` (edges nodes + 2×components). 2026 현재 ruff, eslint, SonarQube 매 default 로 측정; high CC ↔ test difficulty + bug rate correlation 매 empirical.
## 매 핵심
### 매 계산
- 각 decision point (if, for, while, case, &&, ||, ternary, catch) 마다 +1.
- Base 1 (single path) + decisions.
- Function 1 → straight-line.
- Function 10+ → moderate.
- Function 20+ → complex, refactor 권장.
- Function 50+ → 매 unmaintainable.
### 매 의미
- **Test path 수** lower bound.
- **Reading difficulty** proxy.
- **Bug density correlation** — 매 empirical study.
- **NOT** measure of correctness, performance, design quality.
### 매 응용
1. CI gate — `max-complexity: 10` lint rule.
2. Code review — high-CC function 매 split 요청.
3. Refactoring target prioritization.
4. Legacy modernization metric.
## 💻 패턴
### CC 계산 example (Python)
```python
def classify(score): # base 1
if score >= 90: # +1
return 'A'
elif score >= 80: # +1
return 'B'
elif score >= 70: # +1
return 'C'
else:
return 'F'
# CC = 4
```
### Lint config (ruff, 2026)
```toml
# pyproject.toml
[tool.ruff.lint]
select = ["C90"] # mccabe
[tool.ruff.lint.mccabe]
max-complexity = 10
```
### ESLint
```json
{
"rules": {
"complexity": ["error", { "max": 10 }]
}
}
```
### Refactor: replace conditional with polymorphism
```typescript
// before — CC 5
function area(shape: Shape): number {
if (shape.kind === 'circle') return Math.PI * shape.r ** 2;
if (shape.kind === 'square') return shape.s ** 2;
if (shape.kind === 'rect') return shape.w * shape.h;
if (shape.kind === 'triangle') return 0.5 * shape.b * shape.h;
throw new Error('unknown');
}
// after — CC 1 per class
abstract class Shape { abstract area(): number; }
class Circle extends Shape { area() { return Math.PI * this.r ** 2; } }
class Square extends Shape { area() { return this.s ** 2; } }
```
### Refactor: guard clauses (early return)
```python
# before — CC 4
def process(user):
if user is not None:
if user.active:
if user.has_permission:
do_work(user)
# after — CC 4 still, but readability ↑
def process(user):
if user is None: return
if not user.active: return
if not user.has_permission: return
do_work(user)
```
### Refactor: table dispatch
```python
# before — CC 6
def handle(event_type, payload):
if event_type == 'created': return on_created(payload)
elif event_type == 'updated': return on_updated(payload)
elif event_type == 'deleted': return on_deleted(payload)
# ...
# after — CC 2
HANDLERS = {'created': on_created, 'updated': on_updated, 'deleted': on_deleted}
def handle(event_type, payload):
handler = HANDLERS.get(event_type)
if not handler: raise ValueError(event_type)
return handler(payload)
```
### radon (Python CLI)
```bash
$ radon cc -s -a app/
app/service.py
F 42:0 process_order - C (12)
F 88:0 validate - A (3)
Average complexity: B (6.2)
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| New code | CC ≤ 10 hard limit |
| Legacy refactor | CC > 15 → split 우선 |
| Pure data transform | higher CC OK if linear (case/match) |
| State machine | use explicit FSM library |
**기본값**: max-complexity 10 in lint config; warn at 8.
## 🔗 Graph
- 부모: [[Static Analysis]]
- 응용: [[Refactoring_Best_Practices|Refactoring]] · [[Code Review]] · [[CI Gates]]
- Adjacent: [[Test Coverage]] · [[SOLID]] (Single Responsibility)
## 🤖 LLM 활용
**언제**: high-CC function 매 refactor 제안 (split, polymorphism, table dispatch).
**언제 X**: pure metric calculation (deterministic tool 가 더 빠름).
## ❌ 안티패턴
- **CC 만 보고 quality 판단**: linear case dispatch 매 high CC 지만 매 simple.
- **Hard limit 무조건 enforcement**: 매 split 의 split 매 fragmentation.
- **CC ↓ 위해 boolean parameter 추가**: flag argument anti-pattern.
- **Cognitive complexity 무시**: 매 nesting depth, recursion 매 더 중요할 수도.
## 🧪 검증 / 중복
- Verified (McCabe 1976 *A Complexity Measure*, ruff/SonarQube docs 2026).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — full content with refactoring patterns |
@@ -0,0 +1,171 @@
---
id: wiki-2026-0508-dom
title: DOM (Document Object Model)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [DOM, Document Object Model, DOM Tree]
duplicate_of: none
source_trust_level: A
confidence_score: 0.95
verification_status: applied
tags: [dom, web, browser, html, javascript]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: javascript
framework: browser
---
# DOM (Document Object Model)
## 매 한 줄
> **"매 HTML/XML document 의 tree 표현, language-agnostic API"**. W3C 표준 (1998), 현재 WHATWG DOM Living Standard. 매 browser 매 internal representation; 2026 현재 React/Vue/Solid 매 abstraction layer 위에 있지만, performance/edge cases 매 직접 DOM 이해 매 essential.
## 매 핵심
### 매 구조
- **Document** root.
- **Element node** (`<div>`, `<p>`).
- **Text node** (literal text).
- **Attribute** (element 의 property; not separate child node since DOM4).
- **Comment node**.
- **DocumentFragment** — lightweight sub-tree, not connected.
- **ShadowRoot** — encapsulated sub-tree (Web Components).
### 매 traversal
- `parentNode`, `childNodes`, `firstChild`, `lastChild`, `nextSibling`, `previousSibling`.
- `children` (Element only), `firstElementChild`.
- `querySelector` / `querySelectorAll` — CSS selector.
- `closest(selector)` — ancestor matching.
### 매 mutation
- `appendChild`, `insertBefore`, `removeChild`, `replaceChild` (legacy).
- `append`, `prepend`, `before`, `after`, `replaceWith`, `remove` (modern).
- `cloneNode(deep)`.
### 매 응용
1. Vanilla JS DOM 조작.
2. React reconciler 매 virtual DOM diff → real DOM mutation.
3. Web Components Shadow DOM encapsulation.
4. Server-side render (jsdom, happy-dom) 매 SSR.
5. Browser automation (Playwright, Puppeteer).
## 💻 패턴
### Modern element creation (no innerHTML)
```javascript
const card = Object.assign(document.createElement('article'), {
className: 'card',
});
card.append(
Object.assign(document.createElement('h2'), { textContent: title }),
Object.assign(document.createElement('p'), { textContent: body }),
);
container.append(card);
```
### Event delegation
```javascript
list.addEventListener('click', (e) => {
const item = e.target.closest('.item');
if (!item || !list.contains(item)) return;
handleClick(item.dataset.id);
});
```
### DocumentFragment — batch insert
```javascript
const frag = document.createDocumentFragment();
for (const item of items) {
const li = document.createElement('li');
li.textContent = item.name;
frag.append(li);
}
list.append(frag); // single reflow
```
### MutationObserver
```javascript
const observer = new MutationObserver((mutations) => {
for (const m of mutations) {
if (m.type === 'childList') console.log('children changed');
}
});
observer.observe(target, { childList: true, subtree: true, attributes: true });
```
### Shadow DOM (Web Component)
```javascript
class CounterButton extends HTMLElement {
#count = 0;
connectedCallback() {
const root = this.attachShadow({ mode: 'open' });
root.innerHTML = `<style>button{padding:8px}</style><button>0</button>`;
root.querySelector('button').onclick = () => {
this.#count++;
root.querySelector('button').textContent = this.#count;
};
}
}
customElements.define('counter-button', CounterButton);
```
### Range & Selection
```javascript
const range = document.createRange();
range.selectNodeContents(el);
const text = range.toString();
```
### IntersectionObserver — lazy load
```javascript
const io = new IntersectionObserver((entries) => {
for (const e of entries) {
if (e.isIntersecting) {
e.target.src = e.target.dataset.src;
io.unobserve(e.target);
}
}
});
document.querySelectorAll('img[data-src]').forEach((img) => io.observe(img));
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| App-level UI | React / Vue / Solid (don't touch DOM) |
| Library / web component | Shadow DOM + custom element |
| One-off page | Vanilla JS (`querySelector`, `append`) |
| Test / SSR | jsdom / happy-dom |
| Watch external mutations | MutationObserver |
**기본값**: framework abstraction; vanilla DOM API for libraries / leaf optimization.
## 🔗 Graph
- 부모: [[Web Standards]]
- 변형: [[Virtual DOM과 Reconciliation|Virtual DOM]] · [[Shadow DOM]]
- 응용: [[React]] · [[Web Components]] · [[Playwright]]
- Adjacent: [[CSSOM]] · [[Reflow_and_Repaint|Reflow & Repaint]]
## 🤖 LLM 활용
**언제**: DOM snippet 생성, accessibility audit, querySelector 추천.
**언제 X**: real-time interaction (LLM 매 round-trip 너무 느림).
## ❌ 안티패턴
- **innerHTML with user input**: XSS.
- **Layout thrashing**: read-write-read-write 매 force reflow 매 loop.
- **No event delegation**: 매 list item 매 listener → memory leak.
- **Detached node leak**: removed but reference 보유 → GC 실패.
- **Manipulate DOM in framework-controlled subtree**: React reconciler 와 충돌.
## 🧪 검증 / 중복
- Verified (WHATWG DOM Living Standard 2026, MDN).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — full canonical content with modern DOM APIs |
@@ -0,0 +1,184 @@
---
id: wiki-2026-0508-dora-metrics
title: DORA Metrics
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [dora, four-keys, accelerate-metrics]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [dora, devops, metrics, delivery-performance]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: sql
framework: github-actions/grafana
---
# DORA Metrics
## 매 한 줄
> **"매 software delivery performance 의 매 4 numbers"**: deployment frequency, lead time for changes, change failure rate, mean time to restore (MTTR). 매 Forsgren/Humble/Kim "Accelerate" (2018) + 매 yearly DORA report 가 매 source-of-truth. 2026 의 매 5번째 metric (reliability) 의 official.
## 매 핵심
### 매 the 4 (now 5)
1. **Deployment Frequency (DF)** — production deploys per period. Elite: on-demand (multiple/day).
2. **Lead Time for Changes (LT)** — commit → production. Elite: < 1 day.
3. **Change Failure Rate (CFR)** — % deploys causing incident/rollback. Elite: 05%.
4. **Mean Time to Restore (MTTR)** — incident detection → resolution. Elite: < 1 hour.
5. **Reliability** (added 2021/2022 reports) — meeting/exceeding SLO targets.
### 매 performance bands (2024 report)
- **Elite** — frequent deploys, < 1 day LT, 05% CFR, < 1h MTTR.
- **High** — weeklymonthly, 1 day1 week, 010%, < 1 day.
- **Medium** — monthly6m, 1 week1 month, 015%, < 1 week.
- **Low** — < 6m, > 6m, > 64%, > 1 week.
### 매 accelerators (capabilities)
- Trunk-based development.
- Continuous integration.
- Test automation.
- Loosely coupled architecture.
- Generative culture (Westrum).
- Database change automation.
- Empowered teams.
## 💻 패턴
### Lead time SQL (GitHub + production deploy events)
```sql
-- 매 first commit in PR → production deploy 의 measure
WITH deploys AS (
SELECT service, deploy_id, deployed_at, sha
FROM deployments WHERE environment = 'production'
),
commits AS (
SELECT pr.merge_commit_sha AS sha, MIN(c.committed_at) AS first_commit_at
FROM pull_requests pr JOIN commits c ON c.pr_id = pr.id
GROUP BY pr.merge_commit_sha
)
SELECT d.service,
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY EXTRACT(EPOCH FROM d.deployed_at - c.first_commit_at)) AS lt_p50_seconds,
PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY EXTRACT(EPOCH FROM d.deployed_at - c.first_commit_at)) AS lt_p95_seconds
FROM deploys d JOIN commits c USING (sha)
WHERE d.deployed_at > NOW() - INTERVAL '90 days'
GROUP BY d.service;
```
### GitHub Actions 의 deploy event emit
```yaml
- name: Record deployment
if: success()
run: |
curl -X POST "$DORA_API/deployments" \
-H "Authorization: Bearer $TOKEN" \
-d "{\"service\":\"orders\",\"sha\":\"${{ github.sha }}\",\"environment\":\"production\",\"deployed_at\":\"$(date -u +%FT%TZ)\"}"
```
### Change failure (PagerDuty + deploy correlation)
```ts
async function changeFailureRate(service: string, days = 30) {
const deploys = await db.deployments.count({ service, since: daysAgo(days) });
const failedDeploys = await db.deployments.count({
service, since: daysAgo(days),
correlatedIncidentWithin: '4h', // 매 incident 가 deploy 후 4h 내 의 fail count
});
return failedDeploys / deploys;
}
```
### MTTR from PagerDuty
```ts
import { api } from '@pagerduty/pdjs';
const pd = api({ token: process.env.PD_TOKEN! });
const { data } = await pd.get('/incidents', {
data: { since: daysAgo(30), service_ids: [SVC_ID], statuses: ['resolved'] },
});
const durations = data.incidents.map(i =>
(new Date(i.resolved_at).getTime() - new Date(i.created_at).getTime()) / 1000);
const mttr = durations.reduce((a,b)=>a+b,0) / durations.length;
```
### Four Keys (Google) on BigQuery
```sql
-- 매 https://github.com/dora-team/fourkeys 의 reference
SELECT
COUNTIF(event_type = 'deployment') AS deploys,
AVG(TIMESTAMP_DIFF(deploy_time, first_commit_time, MINUTE)) AS lt_minutes,
COUNTIF(failed) / NULLIF(COUNTIF(event_type = 'deployment'), 0) AS cfr,
AVG(TIMESTAMP_DIFF(resolved_time, incident_time, MINUTE)) AS mttr_minutes
FROM `project.four_keys.events_raw`
WHERE deploy_time > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY);
```
### Grafana dashboard panel (PromQL-style)
```promql
# Deployment frequency (deploys per day per service)
sum by (service) (rate(deployments_total{env="production"}[7d])) * 86400
# Change failure rate
sum by (service) (deployments_failed_total[30d])
/ sum by (service) (deployments_total[30d])
# Lead time p50
histogram_quantile(0.5, sum by (le, service) (rate(deploy_lead_time_seconds_bucket[30d])))
```
### Reliability (SLO-aligned 5th metric)
```ts
// 매 service 의 SLO 의 meeting-or-exceeding 의 % of measurement windows
const reliability = await prom.query(`
(sum_over_time(slo_compliance{service="$svc"}[30d]) /
count_over_time(slo_compliance{service="$svc"}[30d])) * 100
`);
```
### Anti-gaming guardrails
```ts
// 매 metric 의 isolated 의 game 가 가능 — pair 의 always 의 read
const elite = (df > 1/day) && (lt < 1*day) && (cfr < 0.05) && (mttr < 1*hour);
// 매 elite 가 X 만 high cfr 의 hide 의 X.
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Greenfield team | Adopt Four Keys (open source) on BigQuery |
| GitHub-centric | dora-team/fourkeys + Cloud Run pipelines |
| Multi-tool | LinearB / Sleuth / Faros AI / Jellyfish (SaaS) |
| Self-host | Apache DevLake (LF AI) |
| Enterprise governance | Faros + custom dashboards |
**기본값**: Apache DevLake (open source) or Four Keys reference impl; weekly review with team; show all 4 (5) together — never single metric.
## 🔗 Graph
- 부모: [[DevOps]] · [[Continuous-Delivery]]
- 변형: [[Engineering-Metrics]]
- 응용: [[Trunk-Based-Development]] · [[Continuous Integration]] · [[SRE]]
- Adjacent: [[Postmortem-Culture]]
## 🤖 LLM 활용
**언제**: 매 metric definition explanation, 매 SQL/PromQL query authoring, 매 trend interpretation, 매 retrospective talking points generation.
**언제 X**: 매 individual performance evaluation (DORA 의 team-level metric — never individual). 매 metric tuning to look good (gaming).
## ❌ 안티패턴
- **Single metric optimization**: 매 deploy frequency 의 increase 만 → CFR explodes. 매 4 의 always 의 together 보기.
- **Individual performance ranking**: 매 explicitly anti-pattern in DORA research. 매 team-level만.
- **Vanity deploys**: 매 empty commits / config-only changes 의 count → meaningless.
- **MTTR from "ticket close"**: 매 customer-impact end 의 measure, 매 ticket admin 가 X.
- **Comparing teams in different domains**: 매 fintech vs internal tool 의 baselines 가 different.
- **No deployment instrumentation**: 매 manual spreadsheet 가 X. 매 auto-emit deploy event.
## 🧪 검증 / 중복
- Verified (Forsgren/Humble/Kim "Accelerate" 2018, Google DORA 2024 State of DevOps report, dora-team/fourkeys, Apache DevLake).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — DORA 4(5) metrics, queries, anti-patterns |
@@ -0,0 +1,170 @@
---
id: wiki-2026-0508-deepreadonly
title: DeepReadonly
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [deep-readonly, recursive-readonly, immutable-type]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [typescript, type-utility, immutability]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: typescript-5.x
---
# DeepReadonly
## 매 한 줄
> **"매 `Readonly<T>` 의 surface-only — 매 nested mutation 가 still possible"**. 매 DeepReadonly<T> 가 매 recursively 의 every property 의 readonly 의 mark — 매 redux state, config object, frozen domain model 의 essential. TS 5.x 의 매 `const` type parameter + DeepReadonly 가 매 powerful combo.
## 매 핵심
### 매 vs Readonly
- `Readonly<T>` — 매 top-level only. 매 `obj.nested.mutate = X` 가 still allowed.
- `DeepReadonly<T>` — 매 every level 의 recursive freeze.
### 매 type-only vs runtime
- DeepReadonly 의 매 compile-time type guarantee — 매 runtime 의 mutation 의 X protect.
- 매 runtime freeze 의 `Object.freeze` (shallow) 또는 `deepFreeze` helper 사용.
- TypeScript 5.0+ `as const` 의 매 literal-level deep readonly 의 produce.
### 매 사용처
1. Redux/Zustand state shape — 매 mutation prevent.
2. Configuration schemas (env config, feature flags).
3. API response DTOs after parse.
4. Domain entities in DDD value objects.
5. Test fixtures (prevent accidental modification).
## 💻 패턴
### Basic DeepReadonly
```ts
type DeepReadonly<T> = T extends (...args: any[]) => any
? T
: T extends object
? { readonly [K in keyof T]: DeepReadonly<T[K]> }
: T;
interface User {
id: string;
profile: { name: string; tags: string[] };
}
const u: DeepReadonly<User> = { id: '1', profile: { name: 'a', tags: ['x'] } };
// u.profile.name = 'b'; // ❌ Cannot assign
// u.profile.tags.push('y'); // ❌ readonly array
```
### Handles Map / Set / Array
```ts
type DeepReadonly<T> =
T extends (infer U)[] ? readonly DeepReadonly<U>[]
: T extends Map<infer K, infer V> ? ReadonlyMap<DeepReadonly<K>, DeepReadonly<V>>
: T extends Set<infer U> ? ReadonlySet<DeepReadonly<U>>
: T extends Promise<infer U> ? Promise<DeepReadonly<U>>
: T extends object ? { readonly [K in keyof T]: DeepReadonly<T[K]> }
: T;
```
### Brand-aware (preserve nominal types)
```ts
type Brand<T, B> = T & { readonly __brand: B };
type DeepReadonly<T> = T extends Brand<infer U, infer B>
? Brand<DeepReadonly<U>, B>
: T extends object
? { readonly [K in keyof T]: DeepReadonly<T[K]> }
: T;
```
### Runtime deepFreeze pair
```ts
export function deepFreeze<T>(obj: T): DeepReadonly<T> {
if (obj && typeof obj === 'object' && !Object.isFrozen(obj)) {
Object.freeze(obj);
for (const key of Object.keys(obj)) deepFreeze((obj as any)[key]);
}
return obj as DeepReadonly<T>;
}
```
### `as const` + DeepReadonly
```ts
const config = {
features: { newCheckout: true, beta: ['user1', 'user2'] },
limits: { rpm: 100 },
} as const;
// 매 `as const` 가 매 every literal 의 deeply readonly + literal-typed 로 만듦.
type Config = typeof config;
// Config['features']['beta'] === readonly ['user1', 'user2']
```
### Mutable inverse (DeepWritable)
```ts
type DeepWritable<T> = T extends (...args: any[]) => any
? T
: T extends object
? { -readonly [K in keyof T]: DeepWritable<T[K]> }
: T;
function clone<T>(x: DeepReadonly<T>): DeepWritable<T> {
return structuredClone(x as T) as DeepWritable<T>;
}
```
### Zod + DeepReadonly
```ts
import { z } from 'zod';
const UserSchema = z.object({ id: z.string(), tags: z.array(z.string()) }).readonly();
type User = DeepReadonly<z.infer<typeof UserSchema>>;
```
### Function args (Redux reducer)
```ts
function reducer<S, A>(state: DeepReadonly<S>, action: A): S {
// state.x = ... // ❌ compile error
return { ...(state as S), updated: true } as S;
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Literal config | `as const` |
| Generic state shape | `DeepReadonly<T>` utility |
| Runtime guarantee 필요 | `deepFreeze` + DeepReadonly |
| Performance hot path | 매 type-only DeepReadonly (no runtime cost) |
| Library author 가 expose | DeepReadonly + readonly arrays in public API |
**기본값**: type-only DeepReadonly + `as const` for literals; runtime `deepFreeze` only for security-sensitive boundaries.
## 🔗 Graph
- 부모: [[TypeScript-Type-System]] · [[Immutability]]
- 변형: [[Readonly]] · [[as const]]
- 응용: [[Zustand]] · [[Domain-Driven-Design]]
- Adjacent: [[Branded-Types]] · [[Zod]] · [[Structural-Sharing]]
## 🤖 LLM 활용
**언제**: 매 utility type 의 design / extension, 매 type error explanation, 매 readonly violation 의 codemod 작성.
**언제 X**: 매 runtime data validation (Zod 사용). 매 hot-path performance tuning (TS types 가 erased — runtime cost 0).
## ❌ 안티패턴
- **함수 type 의 readonly 적용**: 매 `(...args) => any` 가 readonly 의 의미 X — special-case 필요.
- **Date / RegExp 의 recurse**: 매 built-in instances 가 깨짐 — exclude 의 type guard.
- **DeepReadonly + cast away**: `state as Mutable` 가 매 type safety 의 destroy.
- **Runtime mutation through cast**: 매 `(state as any).x = 1` — 매 type lie 의 propagate.
- **Naive `keyof T` on union**: distributive conditional 의 사용.
## 🧪 검증 / 중복
- Verified (TypeScript 5.x docs, type-fest library, ts-toolbelt).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — DeepReadonly utility type variants and patterns |
@@ -0,0 +1,162 @@
---
id: wiki-2026-0508-dependencies-의존성
title: Dependencies (의존성)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [npm-dependencies, package-dependencies, supply-chain]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [dependencies, npm, semver, supply-chain]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: javascript
framework: npm/pnpm
---
# Dependencies (의존성)
## 매 한 줄
> **"매 dependency 의 liability 가 X asset"**. 매 npm install 이 매 third-party code 를 매 production 에 inject — 매 supply chain attack (event-stream 2018, ua-parser-js 2021, xz-utils 2024 backdoor) 가 매 매년 발생. 2026 modern stack 의 매 pnpm + lockfile + minimum-deps + SBOM (CycloneDX) 가 매 standard.
## 매 핵심
### 매 Dependency 종류
- **dependencies**: 매 production runtime 의 사용 (Express, React).
- **devDependencies**: 매 build/test only (Vitest, TypeScript, ESLint).
- **peerDependencies**: 매 host 가 provide (React plugin 의 React).
- **optionalDependencies**: 매 install 실패 가 OK (platform-specific binaries).
- **bundledDependencies**: 매 package tarball 안 ship.
### 매 Semver
- `^1.2.3` — minor + patch updates (1.x.x), 매 npm default. 매 unsafe 가 0.x 에서 (^0.2.3 → 0.2.x only).
- `~1.2.3` — patch only (1.2.x).
- `1.2.3` — exact pin, 매 reproducibility 의 best.
- `*` / `latest` — 매 X. 매 절대 사용 X.
### 매 Lockfile
- **pnpm-lock.yaml** / **package-lock.json** / **yarn.lock**: 매 exact resolved versions + integrity hashes.
-`npm ci` 사용 (매 install 가 X) — 매 lockfile 강제, deterministic install.
- 매 commit 의 must.
### 매 Supply Chain Risks
- **Typosquatting**: `reqeusts`, `lodahs`.
- **Compromised maintainer**: 매 ua-parser-js 2021.
- **Malicious update**: 매 event-stream 2018, xz-utils 2024.
- **Dependency confusion**: 매 internal package name 가 public registry 에 publish 됨.
## 💻 패턴
### Pinning + lockfile
```json
{
"dependencies": {
"react": "18.3.1",
"express": "~4.21.0",
"zod": "^3.23.8"
},
"engines": { "node": ">=20.10.0", "pnpm": ">=9.0.0" }
}
```
### pnpm 의 strict install
```bash
# CI 의 deterministic install
pnpm install --frozen-lockfile
# 매 lockfile mismatch 시 error.
# 매 audit
pnpm audit --audit-level=high
```
### Renovate config
```json
// renovate.json
{
"extends": ["config:recommended"],
"lockFileMaintenance": { "enabled": true, "schedule": ["before 5am on Monday"] },
"vulnerabilityAlerts": { "enabled": true, "labels": ["security"] },
"packageRules": [
{ "matchUpdateTypes": ["minor", "patch"], "automerge": true, "matchCurrentVersion": "!/^0/" },
{ "matchPackagePatterns": ["^@types/"], "automerge": true }
]
}
```
### SBOM 생성 (CycloneDX)
```bash
npx @cyclonedx/cyclonedx-npm --output-file sbom.json
# 매 SLSA / EU CRA compliance 의 사용.
```
### Known-good integrity check
```bash
# 매 npm install 후 lockfile integrity 검증
pnpm install --frozen-lockfile --prefer-offline
# Subresource integrity 가 lockfile 에 자동 record.
```
### Allowed-dependencies guard (CI)
```ts
// scripts/check-deps.ts
import pkg from '../package.json' with { type: 'json' };
const ALLOWED_LICENSES = new Set(['MIT', 'Apache-2.0', 'BSD-3-Clause', 'ISC']);
// 매 license-checker 사용 의 production deps audit.
```
### Provenance verification
```bash
# 매 npm 9.5+ 의 sigstore provenance
npm install --foreground-scripts=false
npm audit signatures
# 매 GitHub Actions 의 publish 한 package 만 trust.
```
### Dependency removal
```bash
pnpm dlx depcheck
# 매 unused dep 찾기. 매 quarterly cleanup.
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Library author | `peerDependencies` + minimal `dependencies` |
| Application | Pin all critical (React, framework), `^` for utilities |
| Monorepo | pnpm workspaces + catalogs (pnpm 9.5+) |
| 매 high-security (fintech, gov) | Exact pin all, Renovate manual approve, internal mirror |
| 매 prototype | `^` everywhere, 매 lockfile commit 만 |
**기본값**: pnpm + frozen lockfile + Renovate auto-merge minors + SBOM in CI.
## 🔗 Graph
- 부모: [[Software-Architecture]]
- 변형: [[Monorepo]]
- 응용: [[Dependency Analysis]] · [[SBOM]]
- Adjacent: [[Supply-Chain-Security]] · [[Renovate]] · [[Dependabot]]
## 🤖 LLM 활용
**언제**: 매 package.json review, 매 vulnerability triage, 매 dep upgrade plan generation, 매 SBOM diff explanation.
**언제 X**: 매 actual install / build (deterministic tooling 가 better). 매 license decision (legal review 필요).
## ❌ 안티패턴
- **`*` or `latest`**: 매 reproducibility destroyed.
- **lockfile gitignore**: 매 다른 dev / CI 가 different versions install.
- **`npm install` in CI**: 매 `npm ci` / `pnpm install --frozen-lockfile` 사용.
- **0.x with `^`**: 매 ^0.2.3 가 0.3.0 으로 jump 가능 — breaking changes.
- **Untyped transitive deps**: 매 매 indirect 의 audit X. SBOM 의 review.
- **Package without provenance**: 매 2026 의 sigstore signed packages prefer.
## 🧪 검증 / 중복
- Verified (npm docs, pnpm docs, SLSA framework, CycloneDX spec).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — npm dependency management, semver, supply chain hardening |
@@ -0,0 +1,175 @@
---
id: wiki-2026-0508-dependency-analysis
title: Dependency Analysis
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [dep-analysis, dependency-graph, code-dependency-tools]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [tooling, dependencies, static-analysis]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: javascript
framework: madge/depcheck/knip
---
# Dependency Analysis
## 매 한 줄
> **"매 import graph 가 매 codebase 의 X-ray"**. 매 Madge / dependency-cruiser / Knip / depcheck 가 매 dead code, circular deps, layering violations, unused packages 의 surface. 2026 의 매 Knip + dependency-cruiser + Turbo's prune 가 매 monorepo standard combo.
## 매 핵심
### 매 question types
1. **Module-level**: who imports X? what does X import?
2. **Package-level**: which deps are unused? which are dev-only mislabeled?
3. **Architectural**: 매 cross-layer 의 import 가 있나?
4. **Cycles**: 매 circular dependency.
5. **Reachability**: 매 entry-point 의 reachable X 의 dead code.
### 매 tool matrix
- **Madge** — 매 visualization, circular detection (JS/TS).
- **dependency-cruiser** — 매 rules engine + violations CI.
- **Knip** — 매 unused files/exports/deps (replaces ts-prune + depcheck).
- **depcheck** — 매 unused npm deps (older, Knip 가 better).
- **ts-morph / typescript-eslint** — 매 custom AST analyzer.
- **Nx graph** / **Turborepo prune** — 매 monorepo affected detection.
### 매 응용
1. CI guard — 매 layer violation 시 fail.
2. Dead-code removal — 매 quarterly cleanup.
3. Bundle reduction — 매 unused dep removal → smaller install + lockfile.
4. Refactor planning — 매 high-fan-in module 의 identify.
5. License audit — 매 transitive dep tree.
## 💻 패턴
### Madge 의 circular detection
```bash
npx madge --circular --extensions ts,tsx src/
# 매 circular 가 있으면 fail.
npx madge --image graph.svg src/
# 매 SVG 의 visualization.
```
### dependency-cruiser rules
```js
// .dependency-cruiser.cjs
module.exports = {
forbidden: [
{ name: 'no-circular', severity: 'error', from: {}, to: { circular: true } },
{ name: 'no-orphans', severity: 'warn', from: { orphan: true, pathNot: '\\.test\\.ts$' }, to: {} },
{ name: 'domain-not-import-ui', severity: 'error',
from: { path: '^src/domain' }, to: { path: '^src/ui' } },
{ name: 'no-deprecated-core', severity: 'error',
from: {}, to: { dependencyTypes: ['core'], path: '^(punycode|domain)$' } },
],
options: { tsConfig: { fileName: 'tsconfig.json' } },
};
```
```bash
depcruise --config .dependency-cruiser.cjs src/
```
### Knip (unused exports/files/deps)
```jsonc
// knip.json
{
"entry": ["src/index.ts", "src/cli.ts"],
"project": ["src/**/*.{ts,tsx}"],
"ignoreDependencies": ["husky"]
}
```
```bash
npx knip
# 매 unused files, unused exports, unused deps 의 list.
```
### Turborepo prune (monorepo)
```bash
turbo prune --scope=@acme/web --docker
# 매 web 의 deps 만 가진 minimal package.json 의 emit — Docker layer cache 의 efficient.
```
### Nx affected graph
```bash
npx nx graph
npx nx affected:test --base=main
# 매 변경된 project 의 transitive consumers 만 test.
```
### Custom AST scanner (ts-morph)
```ts
import { Project } from 'ts-morph';
const project = new Project({ tsConfigFilePath: 'tsconfig.json' });
const violations: string[] = [];
for (const sf of project.getSourceFiles()) {
for (const imp of sf.getImportDeclarations()) {
const spec = imp.getModuleSpecifierValue();
if (sf.getFilePath().includes('/domain/') && spec.startsWith('@/ui')) {
violations.push(`${sf.getFilePath()} -> ${spec}`);
}
}
}
if (violations.length) { console.error(violations.join('\n')); process.exit(1); }
```
### Bundle-level (esbuild metafile / vite-bundle-visualizer)
```bash
vite build --emptyOutDir
npx vite-bundle-visualizer
# 매 actual shipped bytes per package — install-time deps 의 differ.
```
### License + SBOM cross-check
```bash
npx license-checker --production --json > licenses.json
npx @cyclonedx/cyclonedx-npm --output-file sbom.json
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Quick circular check | Madge |
| Layer enforcement in CI | dependency-cruiser |
| Unused files/exports/deps | Knip |
| Monorepo affected detection | Turbo / Nx |
| Custom rules | ts-morph script |
| Bundle size (runtime) | vite/esbuild visualizer |
**기본값**: Knip + dependency-cruiser in CI; Madge ad-hoc for visualization; Turbo/Nx in monorepos.
## 🔗 Graph
- 부모: [[Static-Analysis]] · [[Code-Quality]]
- 변형: [[dependency-cruiser]]
- 응용: [[Monorepo]]
- Adjacent: [[SBOM]] · [[Turborepo]]
## 🤖 LLM 활용
**언제**: 매 dependency-cruiser rule synthesis from architecture description, 매 Knip output 의 triage (which 의 truly unused), 매 graph interpretation.
**언제 X**: 매 actual dead-code removal 의 PR (false positive 의 review 필요). 매 production runtime decisions.
## ❌ 안티패턴
- **Run only locally**: 매 CI guard 가 X — 매 violation 의 sneak in.
- **Knip 의 trust blindly**: 매 dynamic require / framework convention 가 false-positive — `ignore` glob 사용.
- **No layer rules**: 매 architecture 가 silently rot.
- **Visualization only**: 매 SVG 가 cool 가, 매 enforcement 가 X.
- **Run on dist/**: 매 source 의 analyze, 매 bundled 의 X.
## 🧪 검증 / 중복
- Verified (Madge docs, dependency-cruiser docs, Knip docs, Turborepo, Nx).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — dependency analysis tools and CI patterns |
@@ -0,0 +1,27 @@
---
category: Architecture
tags: [auto-wikified, technical-documentation, architecture]
title: Dependency Inversion Principle
description: "의존성 역전 원칙(Dependency Inversion Principle)은 애플리케이션 서비스가 인프라스트럭처 서비스와 상호 작용할 때 구체적인 구현체(concrete implementations)에 직접 의존하지 않도록 하는 설계 원칙이다 [1]."
last_updated: 2026-05-04
---
# Dependency Inversion Principle
## 📌 Brief Summary
의존성 역전 원칙(Dependency Inversion Principle)은 애플리케이션 서비스가 인프라스트럭처 서비스와 상호 작용할 때 구체적인 구현체(concrete implementations)에 직접 의존하지 않도록 하는 설계 원칙이다 [1]. 이 원칙은 대신 클래스의 생성자를 통해 필요한 의존성을 주입(inject)하는 방식을 제안한다 [1]. 이를 통해 시스템 요소 간의 느슨한 결합(loose coupling)을 촉진하며, 시스템을 더 유연하고 테스트하기 쉽게 만든다 [1].
## 📖 Core Content
* **구체적 구현으로부터의 분리**: 의존성 역전 원칙에 따라 애플리케이션 계층은 구체적인 구현 클래스에 직접적으로 종속되지 않는다 [1]. 대신 필요한 의존성은 생성자를 통해 외부에서 주입받는 방식을 취하여 시스템의 결합도를 낮춘다 [1].
* **헥사고날 아키텍처(Hexagonal Architecture)에서의 역할**: 헥사고날 아키텍처에서 애플리케이션 서비스가 인프라스트럭처 서비스와 상호작용해야 할 때 기본적으로 이 의존성 역전 원칙을 따른다 [1]. 이를 통해 핵심 비즈니스 로직과 외부 시스템 간의 상호작용을 유연하게 관리할 수 있다 [1].
* **프레임워크 단위의 의존성 주입(DI) 지원**: NestJS나 Spring Boot 같은 프레임워크는 이 원칙을 실현하기 위해 강력한 의존성 주입(Dependency Injection) 컨테이너 시스템을 제공한다 [2, 3]. 개발자가 클래스 생성자를 통해 필요한 의존성을 선언하면 프레임워크가 자동으로 인스턴스화하여 주입한다 [2, 3]. 이러한 방식은 의존성을 직접 임포트하여 사용하는 방식에 비해 컴포넌트 간 결합도를 낮추고 단위 테스트(Unit Test) 가능성을 극대화한다 [3].
## ⚖️ Trade-offs & Caveats
소스 내에서 의존성 역전 원칙 자체에 대한 직접적인 단점은 명시되어 있지 않으나, 이를 구현하는 '의존성 주입(DI)' 및 구조적 아키텍처를 실전 프레임워크에 도입할 때 다음과 같은 제약 및 반대 급부(Trade-off)가 동반된다.
* **가파른 학습 곡선**: 의존성 주입, 데코레이터, 모듈화 등의 개념을 바탕으로 엄격한 아키텍처를 강제하는 프레임워크(예: NestJS, Spring Boot)를 사용할 경우, 개발자가 이를 완벽히 숙지하기 위한 학습 곡선(Learning Curve)이 비교적 가파르다 [4, 5].
* **소규모 프로젝트에서의 오버헤드**: 단순한 API나 소규모 팀(2~5명) 환경에서는 의존성 주입 컨테이너나 모듈 시스템을 구성하는 데 드는 비용이 비즈니스 가치 창출보다 클 수 있다 [6]. 즉, 기능 개발보다 프레임워크 구조 설정(wiring)에 과도한 시간이 소모될 수 있는 오버엔지니어링의 위험이 존재한다 [4, 6].
* **순환 참조(Circular Dependency) 문제**: 복잡한 의존성 주입 시스템에서는 모듈 및 서비스 간의 순환 참조 문제가 발생할 수 있다 [7]. 프레임워크에서 이를 우회하는 기능(예: NestJS의 `forwardRef()`)을 제공하긴 하지만, 이를 임시방편으로 사용하기보다는 아키텍처적 재설계를 통해 근본적으로 차단하는 것이 바람직하다 [3, 7].
---
*Last updated: 2026-05-03*
@@ -0,0 +1,168 @@
---
id: wiki-2026-0508-digital-twin
title: Digital Twin
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [digital-twin, virtual-replica, cyber-physical-system]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [digital-twin, iot, simulation, cps]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: python
framework: NVIDIA-Omniverse/Azure-Digital-Twins
---
# Digital Twin
## 매 한 줄
> **"매 digital twin 의 매 physical asset 의 living mirror"**. 매 sensor stream 가 매 simulation model 에 feed → 매 prediction / what-if / control. 2026 의 매 NVIDIA Omniverse + OpenUSD, Azure Digital Twins, AWS IoT TwinMaker 가 매 enterprise standard. 매 LLM-augmented reasoning over twin (Claude Opus 4.7 + DTDL graph query) 의 매 emerging.
## 매 핵심
### 매 3-tier
- **Digital Model** — 매 static representation, 매 sync X.
- **Digital Shadow** — 매 one-way sync (physical → digital).
- **Digital Twin** — 매 bidirectional sync (digital → physical control 의 가능).
### 매 ingredient
- **3D geometry** (OpenUSD, glTF).
- **Telemetry** (MQTT, OPC UA, AVRO over Kafka).
- **Physics / behavior** (FMU, Modelica, Isaac Sim, Omniverse PhysX).
- **Ontology / DTDL** (Digital Twins Definition Language).
- **AI layer** (anomaly detection, forecasting, RL policy).
### 매 응용
1. **Manufacturing**: BMW iFactory — 매 line 의 reconfigure 의 digital first.
2. **City** — Singapore Virtual Singapore, Helsinki 3D+.
3. **Energy grid** — 매 outage prediction, demand response.
4. **Healthcare** — patient-specific cardiac twin (Dassault Living Heart).
5. **Robotics fleet** — 매 Isaac Sim 의 sim-to-real RL training.
## 💻 패턴
### Azure Digital Twins (DTDL v3)
```json
{
"@context": "dtmi:dtdl:context;3",
"@id": "dtmi:com:factory:Pump;1",
"@type": "Interface",
"contents": [
{ "@type": "Property", "name": "serialNumber", "schema": "string" },
{ "@type": "Telemetry", "name": "rpm", "schema": "double" },
{ "@type": "Telemetry", "name": "temperature", "schema": "double" },
{ "@type": "Command", "name": "shutdown" },
{ "@type": "Relationship", "name": "feedsInto", "target": "dtmi:com:factory:Tank;1" }
]
}
```
### MQTT → twin update (Python)
```python
import paho.mqtt.client as mqtt
from azure.digitaltwins.core import DigitalTwinsClient
dt = DigitalTwinsClient("https://factory.api.weu.digitaltwins.azure.net", credential)
def on_msg(client, _, msg):
payload = json.loads(msg.payload)
patch = [{"op": "replace", "path": "/rpm", "value": payload["rpm"]},
{"op": "replace", "path": "/temperature", "value": payload["temp"]}]
dt.update_digital_twin(payload["twin_id"], patch)
c = mqtt.Client()
c.on_message = on_msg
c.connect("mqtt.factory.local", 1883)
c.subscribe("factory/+/telemetry")
c.loop_forever()
```
### Twin graph query (Cypher-like)
```text
SELECT pump, tank
FROM DIGITALTWINS pump
JOIN tank RELATED pump.feedsInto
WHERE pump.temperature > 85
AND IS_OF_MODEL(pump, 'dtmi:com:factory:Pump;1')
```
### Omniverse + OpenUSD scene composition
```python
from pxr import Usd, UsdGeom, Sdf
stage = Usd.Stage.CreateNew("factory.usda")
factory = UsdGeom.Xform.Define(stage, "/Factory")
pump = stage.OverridePrim("/Factory/Pump_42")
pump.CreateAttribute("custom:rpm", Sdf.ValueTypeNames.Float).Set(1480.0)
pump.CreateAttribute("custom:temperature", Sdf.ValueTypeNames.Float).Set(72.3)
stage.Save()
```
### Anomaly detection on twin stream
```python
from river import anomaly # online learning
detector = anomaly.HalfSpaceTrees(seed=42)
async for event in kafka_consumer("factory.telemetry"):
score = detector.score_one({"rpm": event.rpm, "temp": event.temp})
detector.learn_one({"rpm": event.rpm, "temp": event.temp})
if score > 0.95:
await dt.update_relationships(event.twin_id, "alert_state", "anomaly")
```
### LLM reasoning over twin graph
```python
graph_context = dt.query_twins("SELECT * FROM digitaltwins WHERE temperature > 80")
response = anthropic.messages.create(
model="claude-opus-4-7",
system="You analyze factory digital twin state for root-cause hypotheses.",
messages=[{"role": "user", "content": f"Twins: {graph_context}\nWhy is line 3 throughput dropping?"}],
)
```
### Sim-to-real RL (Isaac Sim)
```python
from omni.isaac.gym.vec_env import VecEnvBase
env = VecEnvBase(headless=True)
# 매 4096 parallel pump sims 의 train, 매 policy 가 real pump 에 deploy.
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 매 high-fidelity physics | NVIDIA Omniverse + Isaac Sim |
| 매 enterprise IoT graph | Azure Digital Twins (DTDL) |
| 매 AWS-native | AWS IoT TwinMaker |
| 매 city / GIS | CesiumJS + 3D Tiles |
| 매 scientific sim | Modelica + FMU |
**기본값**: Azure Digital Twins or AWS TwinMaker for graph + telemetry; Omniverse for 3D/physics; OpenUSD for interchange.
## 🔗 Graph
- 부모: [[Cyber-Physical-Systems]]
- 응용: [[Predictive Maintenance]]
- Adjacent: [[Control_Systems_Engineering|Control-Systems-Engineering]] · [[MQTT]]
## 🤖 LLM 활용
**언제**: 매 twin graph 의 natural-language query → DTDL/SQL translation, 매 anomaly explanation, 매 maintenance work order generation.
**언제 X**: 매 hard-realtime control loop (sub-ms). 매 safety-critical actuation (deterministic controller 의 사용).
## ❌ 안티패턴
- **3D model only**: 매 telemetry 가 X — 매 just CAD viewer.
- **No bidirectional channel**: 매 just shadow, 매 not twin.
- **Monolithic schema**: 매 DTDL inheritance / interfaces 의 사용.
- **Synchronous queries on hot path**: 매 read replica / cache.
- **No data retention policy**: 매 telemetry storage cost 가 explodes — tiered storage (hot Kafka → warm Parquet → cold S3).
## 🧪 검증 / 중복
- Verified (Microsoft DTDL v3 spec, NVIDIA Omniverse docs, AWS IoT TwinMaker, Gartner 2025 digital twin report).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — digital twin tiers, DTDL, Omniverse, sim-to-real |
@@ -0,0 +1,207 @@
---
id: wiki-2026-0508-discriminated-unions
title: Discriminated Unions
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Tagged Unions, Sum Types, Algebraic Data Types, ADT]
duplicate_of: none
source_trust_level: A
confidence_score: 0.95
verification_status: applied
tags: [typescript, types, functional, type-narrowing]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: type-system
---
# Discriminated Unions
## 매 한 줄
> **"매 한 literal field 의 매 type narrow"**. 매 TS / F# / Rust enum / Haskell ADT 의 same idea — 매 union 의 each variant 의 unique discriminant (tag) 의 carry, 매 compiler 의 매 switch 시 매 narrow. 매 2026 TS 5.7 의 매 dominant data modeling pattern.
## 매 핵심
### 매 anatomy
```typescript
type Result<T, E> =
| { kind: "ok"; value: T }
| { kind: "err"; error: E };
// ^^^^^^^^^^^ 매 discriminant — 매 string / number / boolean literal.
```
### 매 narrowing rules
- 매 discriminant 의 literal 의 must.
-`switch` / `if` 매 변수 의 narrow.
- 매 exhaustive check 의 `never` 의 leverage.
### 매 vs alternatives
- **vs class hierarchy**: 매 closed set, 매 pattern-match easy, 매 no `instanceof`.
- **vs enum**: 매 enum 의 variant 별 data 의 X — DU 의 carry.
- **vs untagged union**: 매 narrow 의 hard, 매 runtime check 의 brittle.
### 매 응용
1. Result / Option / Either monads.
2. State machine state.
3. Redux / xstate action / event.
4. API response variants.
5. AST node types.
## 💻 패턴
### Pattern 1: Result / Either
```typescript
type Result<T, E = Error> =
| { ok: true; value: T }
| { ok: false; error: E };
function parseJson<T>(s: string): Result<T> {
try { return { ok: true, value: JSON.parse(s) }; }
catch (e) { return { ok: false, error: e as Error }; }
}
const r = parseJson<User>(input);
if (r.ok) {
r.value.name; // 매 narrowed 의 T
} else {
r.error.message; // 매 narrowed 의 E
}
```
### Pattern 2: Exhaustive switch with `never`
```typescript
type Shape =
| { kind: "circle"; radius: number }
| { kind: "square"; side: number }
| { kind: "rectangle"; w: number; h: number };
function area(s: Shape): number {
switch (s.kind) {
case "circle": return Math.PI * s.radius ** 2;
case "square": return s.side ** 2;
case "rectangle": return s.w * s.h;
default:
const _exhaustive: never = s; // 매 새 variant 추가 시 compile error
throw new Error(`unhandled: ${_exhaustive}`);
}
}
```
### Pattern 3: State machine state
```typescript
type FetchState<T> =
| { status: "idle" }
| { status: "loading"; abortCtrl: AbortController }
| { status: "success"; data: T; fetchedAt: Date }
| { status: "error"; error: Error; retryCount: number };
function reducer<T>(s: FetchState<T>, ev: FetchEvent<T>): FetchState<T> {
if (s.status === "loading" && ev.type === "abort") {
s.abortCtrl.abort();
return { status: "idle" };
}
// ...
}
```
### Pattern 4: Redux-style action
```typescript
type TodoAction =
| { type: "ADD"; text: string }
| { type: "TOGGLE"; id: string }
| { type: "DELETE"; id: string }
| { type: "EDIT"; id: string; text: string };
function reducer(state: Todo[], action: TodoAction): Todo[] {
switch (action.type) {
case "ADD": return [...state, { id: uid(), text: action.text, done: false }];
case "TOGGLE": return state.map(t => t.id === action.id ? { ...t, done: !t.done } : t);
case "DELETE": return state.filter(t => t.id !== action.id);
case "EDIT": return state.map(t => t.id === action.id ? { ...t, text: action.text } : t);
}
}
```
### Pattern 5: API response variants
```typescript
type ApiResponse<T> =
| { status: 200; data: T }
| { status: 401; reason: "expired" | "invalid" }
| { status: 429; retryAfterSec: number }
| { status: 500; traceId: string };
async function call<T>(url: string): Promise<ApiResponse<T>> { /* ... */ }
```
### Pattern 6: Pattern-match helper (ts-pattern)
```typescript
import { match, P } from "ts-pattern";
const message = match(response)
.with({ status: 200 }, r => `Got ${r.data.length} items`)
.with({ status: 401, reason: "expired" }, () => "Please refresh token")
.with({ status: 429 }, r => `Wait ${r.retryAfterSec}s`)
.with({ status: 500 }, r => `Error ${r.traceId}`)
.exhaustive();
```
### Pattern 7: Zod parsing → DU
```typescript
import { z } from "zod";
const Event = z.discriminatedUnion("type", [
z.object({ type: z.literal("click"), x: z.number(), y: z.number() }),
z.object({ type: z.literal("key"), key: z.string() }),
z.object({ type: z.literal("scroll"), dy: z.number() }),
]);
type Event = z.infer<typeof Event>;
```
### Pattern 8: assertNever helper
```typescript
export function assertNever(x: never): never {
throw new Error(`unexpected: ${JSON.stringify(x)}`);
}
// 매 default case 의 use.
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Closed set of variants | DU |
| Open extensible | class + interface |
| Boolean flag pair | DU (truthy combos 의 prevent) |
| Many variants (~20+) | DU + ts-pattern |
| Server boundary | Zod discriminatedUnion |
**기본값**: 매 union 의 require 시 매 DU + `kind` / `type` / `status` discriminant.
## 🔗 Graph
- 부모: [[TypeScript Type System]] · [[Algebraic Data Types]]
- 변형: [[Tagged Unions]] · [[Sum Types]]
- 응용: [[Result Type]] · [[State Machine]] · [[Zod]]
- Adjacent: [[Pattern Matching]] · [[Exhaustiveness Checking]]
## 🤖 LLM 활용
**언제**: 매 type modeling, 매 state machine, 매 API contract, 매 reducer.
**언제 X**: 매 single-variant — 매 plain interface.
## ❌ 안티패턴
- **No discriminant**: 매 untagged union — 매 narrow 의 hard.
- **String discriminant 의 typo**: 매 magic string 의 const 의 hoist.
- **Boolean flag combos**: `{loading, success, error}` boolean — 매 DU 의 use.
- **Default case 의 swallow**: `default: return state` — 매 새 variant 시 silent miss.
- **Class hierarchy 의 simulate**: 매 DU 의 cleaner.
## 🧪 검증 / 중복
- Verified (TS handbook "Narrowing", Rust enum docs, F# DU, Zod docs, ts-pattern docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — DU patterns + exhaustive + ts-pattern + Zod |
@@ -0,0 +1,191 @@
---
id: wiki-2026-0508-distributed-systems-fallacies
title: Distributed Systems Fallacies
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Fallacies of Distributed Computing, 8 Fallacies, Deutsch Fallacies]
duplicate_of: none
source_trust_level: A
confidence_score: 0.95
verification_status: applied
tags: [distributed-systems, architecture, networking, reliability]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: polyglot
framework: distributed-systems
---
# Distributed Systems Fallacies
## 매 한 줄
> **"매 network 의 invisible 한 assumption 의 매 production failure 의 source"**. 1994년 Peter Deutsch (Sun) 가 매 7 fallacies 의 articulate, 1997년 James Gosling 가 8th 의 add. 매 2026 cloud-native 시대 에도 매 microservices / serverless / edge compute 의 매 매 valid.
## 매 핵심
### 매 8 Fallacies
1. **Network 의 reliable**: 매 packet drop / partition / DNS failure 의 inevitable.
2. **Latency 의 zero**: 매 LAN ~0.5ms, 매 cross-region ~150ms, 매 satellite ~600ms.
3. **Bandwidth 의 infinite**: 매 video / ML model weights / log shipping 의 saturate.
4. **Network 의 secure**: 매 default 의 insecure — 매 zero-trust assume.
5. **Topology 의 안 변함**: 매 autoscaling / k8s pod reschedule / failover 의 매 second.
6. **Administrator 의 single**: 매 multi-cloud / multi-region 의 매 다른 policy.
7. **Transport cost 의 zero**: 매 serialization / TLS handshake / egress fee 의 real.
8. **Network 의 homogeneous**: 매 IPv4/IPv6, 매 protocol versions, 매 MTU mismatch.
### 매 왜 fallacy 인가
- 매 dev 의 localhost / monolith mental model 의 distributed 에 적용 시 fail.
- 매 "happy path" coding 의 매 timeout / retry / circuit breaker 의 lack.
- 매 50ms RTT 의 매 100 calls 의 5 second user-facing latency.
### 매 응용
1. Microservices design — 매 call graph 의 latency budget 산정.
2. Cross-region replication — 매 split-brain / eventual consistency 의 plan.
3. Edge computing — 매 intermittent connectivity 의 first-class.
## 💻 패턴
### Pattern 1: Timeout + Retry with Exponential Backoff
```typescript
async function callWithRetry<T>(
fn: () => Promise<T>,
opts = { maxRetries: 3, baseMs: 100, timeoutMs: 2000 }
): Promise<T> {
for (let attempt = 0; attempt <= opts.maxRetries; attempt++) {
try {
return await Promise.race([
fn(),
new Promise<never>((_, reject) =>
setTimeout(() => reject(new Error("timeout")), opts.timeoutMs)
),
]);
} catch (err) {
if (attempt === opts.maxRetries) throw err;
const jitter = Math.random() * opts.baseMs;
await new Promise(r => setTimeout(r, opts.baseMs * 2 ** attempt + jitter));
}
}
throw new Error("unreachable");
}
```
### Pattern 2: Circuit Breaker (Resilience4j-style)
```typescript
class CircuitBreaker {
private failures = 0;
private state: "closed" | "open" | "half-open" = "closed";
private openedAt = 0;
constructor(private threshold = 5, private cooldownMs = 30_000) {}
async exec<T>(fn: () => Promise<T>): Promise<T> {
if (this.state === "open" && Date.now() - this.openedAt < this.cooldownMs)
throw new Error("circuit open");
if (this.state === "open") this.state = "half-open";
try {
const r = await fn();
this.failures = 0; this.state = "closed";
return r;
} catch (e) {
if (++this.failures >= this.threshold) {
this.state = "open"; this.openedAt = Date.now();
}
throw e;
}
}
}
```
### Pattern 3: Bulkhead (concurrency limiter)
```typescript
import pLimit from "p-limit";
const dbLimit = pLimit(20); // 매 DB pool 의 isolate
const apiLimit = pLimit(50); // 매 external API 의 separate
async function getUser(id: string) {
return dbLimit(() => db.users.findOne({ id }));
}
```
### Pattern 4: Idempotency Key
```typescript
async function chargeCard(req: ChargeReq, idemKey: string) {
const cached = await redis.get(`idem:${idemKey}`);
if (cached) return JSON.parse(cached);
const result = await stripe.charges.create(req);
await redis.setex(`idem:${idemKey}`, 86400, JSON.stringify(result));
return result;
}
```
### Pattern 5: Latency Budget
```typescript
// 매 user-facing 200ms 의 budget
// API gateway: 20ms
// auth check: 10ms (cached)
// service call: 50ms (timeout 100ms)
// DB query: 30ms (timeout 80ms)
// serialization: 10ms
// buffer: 80ms
// 매 each hop 의 explicit budget — over 시 fail fast.
```
### Pattern 6: Chaos Testing (Toxiproxy)
```bash
# 매 latency injection
toxiproxy-cli toxic add api -t latency -a latency=500 -a jitter=100
# 매 packet loss
toxiproxy-cli toxic add db -t timeout -a timeout=2000
```
### Pattern 7: Health check with deep probe
```typescript
app.get("/health/deep", async (_, res) => {
const checks = await Promise.allSettled([
db.raw("SELECT 1").then(() => ({ db: "ok" })),
redis.ping().then(() => ({ redis: "ok" })),
fetch(upstream + "/health", { signal: AbortSignal.timeout(500) }),
]);
const failed = checks.filter(c => c.status === "rejected");
res.status(failed.length ? 503 : 200).json({ checks });
});
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| LAN microservice call | timeout 1-2s, retry 2x |
| Cross-region call | timeout 5-10s, circuit breaker |
| 3rd-party API | bulkhead + circuit breaker + idempotency |
| Streaming / WebSocket | heartbeat + auto-reconnect |
| Critical write | idempotency key 의 mandatory |
**기본값**: 매 every remote call 의 timeout + retry + circuit breaker 의 wrap.
## 🔗 Graph
- 부모: [[Distributed Systems]] · [[Software Architecture]]
- 변형: [[CAP Theorem & PACELC]] · [[PACELC]]
- 응용: [[Microservices Architecture]] · [[Service Mesh]]
- Adjacent: [[Resilience Patterns]] · [[Chaos Engineering]]
## 🤖 LLM 활용
**언제**: 매 distributed system design review, 매 incident postmortem, 매 SLO 산정.
**언제 X**: 매 single-process monolith, 매 batch job 의 isolated.
## ❌ 안티패턴
- **Infinite retry**: 매 retry storm — 매 backoff + max attempts 의 mandatory.
- **Timeout 의 unset**: 매 default infinite — 매 thread pool exhaustion.
- **Synchronous fan-out**: 매 N services 의 sequential await — 매 N×latency.
- **Trust LAN security**: 매 zero-trust / mTLS 의 default.
- **Ignore tail latency**: 매 p50 의 보고 의 — 매 p99 / p99.9 의 user experience.
## 🧪 검증 / 중복
- Verified (Deutsch 1994 / Gosling 1997 original list, AWS Builders' Library, Google SRE book).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — 8 fallacies + resilience patterns |
@@ -0,0 +1,208 @@
---
id: wiki-2026-0508-distributed-tracing
title: Distributed Tracing
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [distributed-tracing, opentelemetry-tracing, request-tracing]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [observability, tracing, opentelemetry, jaeger]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: opentelemetry/tempo
---
# Distributed Tracing
## 매 한 줄
> **"매 trace 가 매 cross-service request 의 X-ray"**. 매 span tree 가 매 service hop, latency, error 의 reveal — 매 microservice debugging 의 essential. 2026 의 매 OpenTelemetry (OTel) 가 매 universal standard, 매 Tempo / Jaeger / Honeycomb / Datadog 가 매 backend, 매 W3C Trace Context 가 매 propagation.
## 매 핵심
### 매 building blocks
- **Trace** — 매 root request 의 unique ID (trace_id, 128-bit).
- **Span** — 매 single operation (HTTP call, DB query, function); has parent_span_id.
- **Context propagation** — `traceparent` HTTP header (W3C) carries trace_id+span_id+flags.
- **Baggage** — key/value propagated alongside (user_id, tenant).
- **Sampling** — 매 head (decide at ingress) vs tail (decide after seeing whole trace).
### 매 OTel architecture
1. **SDK** — instrumentation 의 in-app (auto + manual).
2. **Collector** — 매 receive → process (batch, sample, redact) → export.
3. **Backend** — Tempo (Grafana), Jaeger, Honeycomb, Datadog APM.
4. **UI** — Grafana, Jaeger UI, vendor.
### 매 응용
1. Latency root cause (which span 의 slow).
2. Error correlation (trace 의 `error=true` spans).
3. Service dependency map (service graph from spans).
4. Capacity planning (RED metrics derived from spans).
5. SLO debugging (trace 의 SLO budget burn 의 attribute).
## 💻 패턴
### OTel Node.js auto-instrumentation
```ts
// otel.ts (loaded with --import / NODE_OPTIONS)
import { NodeSDK } from '@opentelemetry/sdk-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { Resource } from '@opentelemetry/resources';
const sdk = new NodeSDK({
resource: new Resource({ 'service.name': 'orders-api', 'service.version': '1.4.2' }),
traceExporter: new OTLPTraceExporter({ url: 'http://otel-collector:4318/v1/traces' }),
instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
```
### Manual span (TypeScript)
```ts
import { trace, SpanStatusCode } from '@opentelemetry/api';
const tracer = trace.getTracer('orders');
export async function placeOrder(input: OrderInput) {
return tracer.startActiveSpan('placeOrder', async (span) => {
span.setAttributes({ 'order.customer_id': input.customerId, 'order.line_count': input.lines.length });
try {
const order = await db.orders.insert(input);
await kafka.produce('orders.placed', order);
span.setStatus({ code: SpanStatusCode.OK });
return order;
} catch (e) {
span.recordException(e as Error);
span.setStatus({ code: SpanStatusCode.ERROR, message: (e as Error).message });
throw e;
} finally {
span.end();
}
});
}
```
### Python (FastAPI auto-instrument)
```python
from opentelemetry import trace
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
provider = TracerProvider()
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter(endpoint="otel-collector:4317")))
trace.set_tracer_provider(provider)
app = FastAPI()
FastAPIInstrumentor.instrument_app(app)
HTTPXClientInstrumentor().instrument()
```
### Trace context propagation (W3C)
```text
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
^ ^ ^ ^
version trace_id (32 hex) parent_id (16) flags
tracestate: vendor1=value,vendor2=value
baggage: userId=42,tenantId=acme
```
### OTel Collector pipeline
```yaml
# otel-collector.yaml
receivers:
otlp: { protocols: { grpc: {}, http: {} } }
processors:
batch: { timeout: 1s }
tail_sampling:
decision_wait: 30s
policies:
- { name: errors, type: status_code, status_code: { status_codes: [ERROR] } }
- { name: slow, type: latency, latency: { threshold_ms: 1000 } }
- { name: rest, type: probabilistic, probabilistic: { sampling_percentage: 5 } }
exporters:
otlphttp/tempo: { endpoint: http://tempo:4318 }
loki: { endpoint: http://loki:3100/loki/api/v1/push }
service:
pipelines:
traces: { receivers: [otlp], processors: [batch, tail_sampling], exporters: [otlphttp/tempo] }
```
### Trace ↔ Log correlation
```ts
import pino from 'pino';
import { trace } from '@opentelemetry/api';
const log = pino();
function logWithTrace(msg: string, extra: object = {}) {
const span = trace.getActiveSpan();
const ctx = span?.spanContext();
log.info({ ...extra, trace_id: ctx?.traceId, span_id: ctx?.spanId }, msg);
}
// 매 Loki/Tempo derived field 의 trace 의 jump from log line.
```
### Frontend → backend trace
```ts
// 매 browser OTel SDK 의 traceparent 의 inject
import { trace, context } from '@opentelemetry/api';
import { WebTracerProvider } from '@opentelemetry/sdk-trace-web';
import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch';
new WebTracerProvider().register();
new FetchInstrumentation({
propagateTraceHeaderCorsUrls: [/api\.example\.com/],
}).enable();
```
### eBPF-based zero-instrumentation (Beyla / Pixie)
```bash
# Grafana Beyla — 매 Go/Node/Python 의 auto-trace 의 eBPF 의 capture, 매 code change X.
beyla --config beyla.yaml
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Greenfield | OTel SDK + Tempo (Grafana stack) |
| Multi-cloud SaaS | Honeycomb / Datadog APM |
| Polyglot legacy | OTel Collector + auto-instrument per lang |
| Zero-code start | eBPF (Beyla, Pixie) |
| 매 cost control | Tail sampling on errors+slow, 5% baseline |
| Strong cardinality | Honeycomb (designed for high-cardinality) |
**기본값**: OTel SDK + W3C Trace Context + Collector with tail sampling + Tempo or vendor backend.
## 🔗 Graph
- 부모: [[Observability]] · [[Microservices]]
- 변형: [[Tempo]]
- 응용: [[Service Mesh]]
- Adjacent: [[OpenTelemetry]] · [[Logs]]
## 🤖 LLM 활용
**언제**: 매 trace tree 의 root-cause hypothesis, 매 sampling policy review, 매 OTel Collector config debug, 매 span attribute schema design.
**언제 X**: 매 production sampling decision 의 binding (cost + signal tradeoff 가 deep). 매 PII redaction 의 sole reviewer (security review 필요).
## ❌ 안티패턴
- **No sampling**: 매 cost / storage explode — tail sample on errors+slow.
- **High-cardinality on every span**: 매 user_id on every span 가 indexable backend 가 X 면 expensive.
- **Frontend trace 의 X**: 매 server-side latency 만 가 보임 — 매 user-perceived 의 miss.
- **Logs without trace_id**: 매 trace ↔ log jump 가 X.
- **Manual span without `end()`**: 매 leak.
- **Sync span across async boundary**: 매 context lost — `startActiveSpan` 사용.
- **Vendor lock-in via SDK**: 매 OTel SDK + vendor exporter 의 use, vendor SDK 의 X.
## 🧪 검증 / 중복
- Verified (OpenTelemetry spec, W3C Trace Context, Grafana Tempo docs, Honeycomb engineering blog).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — distributed tracing with OpenTelemetry, sampling, propagation |
@@ -0,0 +1,212 @@
---
id: wiki-2026-0508-distributed-system-type-safety
title: Distributed System Type Safety
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [cross-service-types, contract-types, schema-driven-types]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [distributed-systems, type-safety, contracts, codegen]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: gRPC/OpenAPI/tRPC
---
# Distributed System Type Safety
## 매 한 줄
> **"매 service boundary 가 매 type system 의 chasm"**. 매 single-process compile-time check 가 매 network call 에서 evaporate — 매 schema-first contract (Protobuf, OpenAPI, GraphQL SDL, Avro) + codegen 의 매 cross-service guarantee. 2026 의 매 Buf + Connect, tRPC over WebSocket, GraphQL Federation v3, gRPC + gRPC-Web 가 매 dominant choices.
## 매 핵심
### 매 problem
- 매 service A 의 type 변경 → 매 service B 가 silently break.
- 매 JSON 의 매 stringly-typed wire — 매 runtime error.
- 매 versioning 가 매 hard.
### 매 solution categories
1. **Schema-first + codegen**: gRPC/Protobuf, OpenAPI, AsyncAPI.
2. **TypeScript-end-to-end**: tRPC, ts-rest, Encore.
3. **Federated graph**: GraphQL Federation v3.
4. **Event schema registry**: Confluent Schema Registry (Avro/Protobuf), AWS Glue.
5. **CRDT + typed sync**: Yjs + typed shape.
### 매 verification levels
- **Compile time** — codegen output type-checked.
- **Build time** — schema lint + breaking-change detection (Buf).
- **CI** — contract tests (Pact).
- **Runtime** — schema validation at boundary (Zod, Pydantic).
## 💻 패턴
### Buf + Protobuf workflow
```bash
# buf.yaml
version: v2
modules: [{ path: proto }]
breaking: { use: [FILE] }
lint: { use: [STANDARD] }
# CI 의 breaking-change check
buf breaking --against '.git#branch=main'
buf generate
```
```protobuf
// proto/order/v1/order.proto
syntax = "proto3";
package order.v1;
message Order {
string id = 1;
string customer_id = 2;
repeated LineItem items = 3;
Money total = 4;
}
service OrderService {
rpc GetOrder(GetOrderRequest) returns (Order);
rpc StreamOrders(StreamOrdersRequest) returns (stream Order);
}
```
### Connect-RPC (HTTP+JSON+Protobuf, browser-friendly)
```ts
import { createPromiseClient } from "@connectrpc/connect";
import { OrderService } from "./gen/order/v1/order_connect";
const client = createPromiseClient(OrderService, transport);
const order = await client.getOrder({ id: "o_123" });
// 매 fully typed end-to-end.
```
### tRPC v11 (TypeScript-only stacks)
```ts
// server/router.ts
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
const t = initTRPC.create();
export const appRouter = t.router({
order: t.router({
get: t.procedure.input(z.object({ id: z.string() })).query(({ input }) => db.order.find(input.id)),
}),
});
export type AppRouter = typeof appRouter;
// client.ts — 매 zero codegen, 매 type 의 inference
import type { AppRouter } from '../server/router';
const trpc = createTRPCClient<AppRouter>({ links: [...] });
const order = await trpc.order.get.query({ id: 'o_123' });
```
### OpenAPI → typed client (orval / openapi-fetch)
```ts
// 매 openapi-fetch 의 zero-runtime-overhead typed fetch
import createClient from 'openapi-fetch';
import type { paths } from './gen/api';
const api = createClient<paths>({ baseUrl: 'https://api.example.com' });
const { data, error } = await api.GET('/orders/{id}', { params: { path: { id: 'o_123' } } });
```
### GraphQL Federation v3 + codegen
```graphql
# orders subgraph
type Order @key(fields: "id") {
id: ID!
customerId: ID!
total: Money!
}
extend type Customer @key(fields: "id") {
id: ID!
orders: [Order!]! @requires(fields: "id")
}
```
```bash
graphql-codegen --config codegen.ts
# 매 typed hooks (useOrderQuery) generated.
```
### Avro schema registry (Kafka)
```json
{
"type": "record",
"name": "OrderPlaced",
"namespace": "com.acme.order.v1",
"fields": [
{"name": "orderId", "type": "string"},
{"name": "customerId", "type": "string"},
{"name": "totalCents", "type": "long"},
{"name": "occurredAt", "type": {"type": "long", "logicalType": "timestamp-millis"}}
]
}
```
```ts
import { SchemaRegistry, AvroKafka } from '@kafkajs/confluent-schema-registry';
const registry = new SchemaRegistry({ host: 'http://schema-registry:8081' });
const id = await registry.register({ type: SchemaType.AVRO, schema });
await producer.send({ topic: 'orders', messages: [{ value: await registry.encode(id, payload) }] });
```
### Pact contract test (consumer-driven)
```ts
import { PactV4, MatchersV3 } from '@pact-foundation/pact';
const pact = new PactV4({ consumer: 'web', provider: 'order-svc' });
await pact.addInteraction()
.uponReceiving('a get order request')
.withRequest('GET', '/orders/o_123')
.willRespondWith(200, b => b.jsonBody({ id: MatchersV3.string('o_123'), total: MatchersV3.integer(100) }))
.executeTest(async (mockServer) => { /* call client against mockServer.url */ });
```
### Runtime boundary validation
```ts
import { z } from 'zod';
const OrderDTO = z.object({ id: z.string(), total: z.number().int().nonnegative() });
type Order = z.infer<typeof OrderDTO>;
// 매 매 untrusted input 의 parse — 매 type lies 의 catch.
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Polyglot microservices | gRPC / Connect + Buf |
| TS-only stack | tRPC |
| Public API + many consumers | OpenAPI 3.1 + openapi-fetch |
| Many clients merging data | GraphQL Federation v3 |
| Event-driven Kafka | Avro/Protobuf + Schema Registry |
| Browser-to-server typed | Connect-Web or tRPC |
**기본값**: Buf + Connect for polyglot; tRPC for TS-only; OpenAPI 3.1 for public REST. Always 매 add Zod/runtime validation at trust boundaries.
## 🔗 Graph
- 부모: [[Distributed-Systems]] · [[API-Design]]
- 변형: [[gRPC]] · [[OpenAPI]]
- 응용: [[Microservices]] · [[Event-Driven-Architecture]]
- Adjacent: [[Pact]] · [[Zod]] · [[Buf]]
## 🤖 LLM 활용
**언제**: 매 schema migration plan, 매 breaking-change explanation, 매 codegen wiring debug, 매 contract test scaffold.
**언제 X**: 매 actual schema authority decision (architecture review). 매 wire-format performance tuning (benchmarks 사용).
## ❌ 안티패턴
- **JSON without schema**: 매 매 silent break 의 inevitable.
- **Hand-written types matching wire**: 매 drift 의 guaranteed.
- **Breaking changes 의 bump major silently**: 매 Buf breaking detector 사용.
- **No runtime validation at trust boundary**: 매 type system 의 lie.
- **Single global GraphQL gateway 의 monolith**: 매 federation 의 사용.
- **Avro 의 forward+backward 가 X**: 매 default field 의 always 의 add.
## 🧪 검증 / 중복
- Verified (Buf docs, gRPC docs, GraphQL Federation v3 spec, tRPC docs, Pact specification).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — cross-service type safety: schemas, codegen, runtime validation |
@@ -0,0 +1,221 @@
---
id: wiki-2026-0508-downshift
title: Downshift
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [downshift-js, useCombobox, useSelect]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [react, ui, accessibility, combobox, hooks]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: react
---
# Downshift
## 매 한 줄
> **"매 headless UI 의 accessibility-first combobox primitive"**. Kent C. Dodds 의 2017 release, 매 render-prop / hook API 의 ARIA 1.2 combobox spec 의 implement. 매 2026 의 매 alternative 의 많음 (Radix, Headless UI, Ariakit, React Aria) 이지만 매 downshift 의 매 mature / battle-tested / tiny (~5KB).
## 매 핵심
### 매 무엇 의 solve
- 매 native `<select>` 의 styling 의 unable.
- 매 custom dropdown 의 매 keyboard / screen reader / focus management 의 hard.
- 매 ARIA roles (`combobox`, `listbox`, `option`) 의 correctly wire.
### 매 API 종류
- `useCombobox` — 매 typeahead 의 search input + dropdown.
- `useSelect` — 매 native select replacement (no input).
- `useMultipleSelection` — 매 tag / chip selection.
- Render-prop `<Downshift>` — 매 legacy, 매 hooks 권장.
### 매 핵심 state
- `isOpen` — dropdown open?
- `highlightedIndex` — 매 keyboard hover.
- `selectedItem` — 매 chosen value.
- `inputValue` — 매 typed text.
### 매 응용
1. Autocomplete / type-ahead search.
2. Country / timezone picker.
3. Multi-select tag input (with `useMultipleSelection`).
4. Async-loading dropdowns.
## 💻 패턴
### Pattern 1: Basic useCombobox
```tsx
import { useCombobox } from "downshift";
import { useState } from "react";
const ALL = ["apple","banana","cherry","date","elderberry"];
export function FruitCombo() {
const [items, setItems] = useState(ALL);
const cb = useCombobox({
items,
onInputValueChange: ({ inputValue }) => {
setItems(ALL.filter(f => f.includes(inputValue?.toLowerCase() ?? "")));
},
});
return (
<div>
<label {...cb.getLabelProps()}>Fruit</label>
<input {...cb.getInputProps()} />
<ul {...cb.getMenuProps()}>
{cb.isOpen && items.map((item, i) => (
<li
key={item}
{...cb.getItemProps({ item, index: i })}
style={{ background: cb.highlightedIndex === i ? "#def" : "white" }}
>{item}</li>
))}
</ul>
</div>
);
}
```
### Pattern 2: Async items (debounced)
```tsx
import { useCombobox } from "downshift";
import { useState, useEffect } from "react";
import { useDebouncedValue } from "./hooks";
export function UserPicker() {
const [query, setQuery] = useState("");
const debounced = useDebouncedValue(query, 250);
const [items, setItems] = useState<User[]>([]);
useEffect(() => {
if (!debounced) return;
fetch(`/api/users?q=${debounced}`).then(r => r.json()).then(setItems);
}, [debounced]);
const cb = useCombobox({
items,
itemToString: u => u?.name ?? "",
onInputValueChange: ({ inputValue }) => setQuery(inputValue ?? ""),
});
// 매 render UI 동일 패턴.
}
```
### Pattern 3: Multi-select with chips
```tsx
import { useCombobox, useMultipleSelection } from "downshift";
function TagInput({ all }: { all: string[] }) {
const ms = useMultipleSelection<string>({});
const remaining = all.filter(t => !ms.selectedItems.includes(t));
const cb = useCombobox({
items: remaining,
onSelectedItemChange: ({ selectedItem }) => {
if (selectedItem) ms.addSelectedItem(selectedItem);
},
selectedItem: null,
});
return (
<div>
{ms.selectedItems.map((t, i) => (
<span key={t} {...ms.getSelectedItemProps({ selectedItem: t, index: i })}>
{t} <button onClick={() => ms.removeSelectedItem(t)}>×</button>
</span>
))}
<input {...cb.getInputProps(ms.getDropdownProps())} />
{/* menu... */}
</div>
);
}
```
### Pattern 4: useSelect (no typing)
```tsx
import { useSelect } from "downshift";
function SizeSelect() {
const items = ["S","M","L","XL"];
const sel = useSelect({ items });
return (
<>
<button {...sel.getToggleButtonProps()}>
{sel.selectedItem ?? "Pick size"}
</button>
<ul {...sel.getMenuProps()}>
{sel.isOpen && items.map((s, i) => (
<li key={s} {...sel.getItemProps({ item: s, index: i })}>{s}</li>
))}
</ul>
</>
);
}
```
### Pattern 5: Controlled state (Redux / Zustand)
```tsx
const cb = useCombobox({
items,
selectedItem: store.selected,
onSelectedItemChange: ({ selectedItem }) => store.set(selectedItem),
inputValue: store.input,
onInputValueChange: ({ inputValue }) => store.setInput(inputValue ?? ""),
});
```
### Pattern 6: stateReducer for custom keyboard
```tsx
import { useCombobox } from "downshift";
const stateReducer = (state, { type, changes }) => {
switch (type) {
case useCombobox.stateChangeTypes.InputKeyDownEnter:
case useCombobox.stateChangeTypes.ItemClick:
// 매 Enter 시 dropdown 의 close 하지 X
return { ...changes, isOpen: state.isOpen, highlightedIndex: state.highlightedIndex };
default: return changes;
}
};
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| React + ARIA combobox | downshift |
| Full design system (Modal, Tabs, etc.) | Radix UI / Ariakit |
| Adobe quality + i18n | React Aria |
| Tailwind + simple primitives | Headless UI |
| Vue / Svelte | downshift X — find native |
**기본값**: 매 React combobox 만 필요 시 downshift, 매 design system 전체 시 Radix.
## 🔗 Graph
- 부모: [[React]] · [[Headless UI]] · [[Accessibility (A11y)|Accessibility]]
- 변형: [[Radix UI]] · [[Ariakit]]
- 응용: [[Autocomplete]]
- Adjacent: [[Render_Props|Render Props]]
## 🤖 LLM 활용
**언제**: 매 React typeahead / select 의 build, 매 a11y 의 mandatory.
**언제 X**: 매 native select 의 충분, 매 React 외 framework.
## ❌ 안티패턴
- **Custom keyboard 의 reinvent**: 매 stateReducer 로 override 의 의도된 path.
- **State sync mistakes**: 매 controlled / uncontrolled 의 mix — 매 하나의 choose.
- **getXxxProps 의 spread 의 omit**: 매 ARIA attrs 의 lost — 매 a11y 의 break.
## 🧪 검증 / 중복
- Verified (downshift v9 docs, ARIA 1.2 combobox pattern, GitHub 11k+ stars).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — useCombobox + useSelect + multi-select |
@@ -0,0 +1,166 @@
---
id: wiki-2026-0508-dynamic-systems-development-meth
title: Dynamic Systems Development Method (DSDM)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [DSDM, Atern, AgilePF]
duplicate_of: none
source_trust_level: B
confidence_score: 0.85
verification_status: applied
tags: [agile, methodology, project-management, architecture]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: methodology
framework: agile
---
# Dynamic Systems Development Method (DSDM)
## 매 한 줄
> **"매 fix the time/cost, flex the features"**. 1994년 UK consortium 의 RAD 의 evolution 의 develop, 매 원조 agile method (Agile Manifesto 2001 보다 7년 앞섬). 매 2026 의 매 niche — 매 SAFe / Scrum / Kanban 의 dominate, 매 DSDM 의 enterprise governance 의 좋은 reference.
## 매 핵심
### 매 8 Principles
1. Focus on the business need.
2. Deliver on time.
3. Collaborate.
4. Never compromise quality.
5. Build incrementally from firm foundations.
6. Develop iteratively.
7. Communicate continuously and clearly.
8. Demonstrate control.
### 매 MoSCoW Prioritization
- **Must** have — 매 minimum viable.
- **Should** have — 매 important 이지만 매 not vital.
- **Could** have — 매 nice-to-have.
- **Won't** have (this time) — 매 explicit out-of-scope.
### 매 Phases
1. **Pre-project** — feasibility approval.
2. **Feasibility** — high-level scope.
3. **Foundations** — business / solution / management approach.
4. **Evolutionary Development** — timeboxed iterations (2-6 weeks).
5. **Deployment** — release.
6. **Post-project** — benefits realization.
### 매 Roles
- **Business Sponsor / Visionary / Ambassador** — 매 business side.
- **Technical Coordinator / Solution Developer / Tester** — 매 dev side.
- **Project Manager / Team Leader** — 매 facilitation.
### 매 응용
1. Government / regulated projects — 매 audit trail required.
2. Fixed-deadline launches — 매 features 의 flex.
3. Hybrid waterfall→agile transitions.
## 💻 패턴
### Pattern 1: MoSCoW backlog (JSON)
```json
{
"must": [
{"id": "AUTH-1", "title": "User login", "effort": 5},
{"id": "PAY-1", "title": "Stripe checkout", "effort": 8}
],
"should": [
{"id": "PAY-2", "title": "Saved payment methods", "effort": 5}
],
"could": [
{"id": "UI-1", "title": "Dark mode", "effort": 3}
],
"wont": [
{"id": "PAY-3", "title": "Cryptocurrency", "reason": "out of scope v1"}
]
}
```
### Pattern 2: Timebox tracking
```typescript
interface Timebox {
id: string;
name: string;
startDate: Date;
endDate: Date; // 매 fixed
must: Story[]; // 매 100% required
should: Story[]; // 매 80% target
could: Story[]; // 매 20-60% expected
}
function timeboxHealth(tb: Timebox): "green"|"amber"|"red" {
const mustDone = tb.must.filter(s => s.status === "done").length / tb.must.length;
if (mustDone < 0.5) return "red";
if (mustDone < 1.0) return "amber";
return "green";
}
```
### Pattern 3: Facilitated Workshop agenda
```markdown
# Foundations Workshop (Day 1)
09:00 — Business vision (Sponsor)
10:00 — Solution architecture sketch (Tech Coord)
11:00 — MoSCoW first pass (all)
13:00 — Risk / dependency mapping
15:00 — Timebox plan
16:30 — Commitment / sign-off
```
### Pattern 4: Modeling — high level only
```mermaid
flowchart LR
User[(User)] --> API
API --> Auth
API --> Order
Order --> Payment[(Stripe)]
Order --> DB[(Postgres)]
```
### Pattern 5: Daily Stand-up (DSDM flavor)
```
Yesterday: what advanced Must/Should items
Today: which Must/Should items
Blockers: escalate to Project Manager same day
Timebox burn: x days remaining / y stories left
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Fixed deadline (regulatory) | DSDM (timebox + MoSCoW) |
| Feature-driven product | Scrum |
| Continuous flow ops | Kanban |
| Large enterprise (>100 devs) | SAFe + DSDM principles |
| Modern startup | Scrum-ish or Shape Up |
**기본값**: 매 Scrum 으로 시작, 매 fixed-deadline 시 DSDM MoSCoW 의 borrow.
## 🔗 Graph
- 부모: [[Agile]]
- 변형: [[Scrum]] · [[Extreme Programming (XP)]]
- 응용: [[Timeboxing]]
## 🤖 LLM 활용
**언제**: 매 enterprise / regulated agile 의 reference, 매 MoSCoW 의 prioritization.
**언제 X**: 매 modern product team — 매 Scrum / Shape Up 의 simpler.
## ❌ 안티패턴
- **MoSCoW 의 abuse**: 매 모두 Must — 매 prioritization 의 lost.
- **Timebox 의 extend**: 매 DSDM core 의 violate.
- **Heavy documentation**: 매 RAD 의 origin 의 betray.
- **No business presence**: 매 Ambassador role 의 essential.
## 🧪 검증 / 중복
- Verified (DSDM Consortium / Agile Business Consortium handbook, ISO/IEC TR 29110).
- 신뢰도 B (매 niche method, 매 modern usage 의 limited).
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — 8 principles + MoSCoW + timebox |
@@ -0,0 +1,190 @@
---
id: wiki-2026-0508-e-commerce-platforms
title: E-commerce Platforms
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [ecommerce, online-store-platform, headless-commerce]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [ecommerce, shopify, stripe, headless]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: shopify-hydrogen/medusa/stripe
---
# E-commerce Platforms
## 매 한 줄
> **"매 e-commerce 의 매 catalog × cart × checkout × fulfillment × payments × tax + 매 every regional edge case"**. 2026 의 매 SaaS (Shopify, BigCommerce, commercetools), 매 headless (Hydrogen, Medusa.js, Saleor, Vendure), 매 PSP (Stripe, Adyen) 가 dominant — 매 buy-vs-build 의 매 default 의 buy.
## 매 핵심
### 매 platform tiers
1. **All-in-one SaaS** — Shopify, BigCommerce, Wix. 매 lowest TCO.
2. **Headless / composable** — Shopify Hydrogen, commercetools, Saleor, Medusa.js, Vendure. 매 custom UX 필요.
3. **Self-hosted / OSS** — Medusa, Vendure, Saleor (Apache 2 / MIT).
4. **Marketplace SaaS** — Mirakl, Sharetribe.
5. **B2B-specific** — Spryker, BigCommerce B2B, commercetools.
### 매 PSP / payments
- **Stripe** — global default, broad APM coverage.
- **Adyen** — enterprise / omnichannel.
- **PayPal/Braintree, Klarna, Afterpay, Apple/Google Pay** — APMs.
- **Crypto / stablecoin** — Coinbase Commerce (niche).
### 매 cross-cutting concerns
- **Tax** — Stripe Tax, Avalara, TaxJar (US sales tax post-Wayfair, EU VAT IOSS, UK VAT).
- **Shipping** — ShipStation, Shippo, EasyPost.
- **Search** — Algolia, Typesense, Meilisearch.
- **CMS** — Sanity, Contentful, Storyblok (PIM/CMS hybrid).
- **Fraud** — Stripe Radar, Riskified, Signifyd.
## 💻 패턴
### Stripe Checkout (PCI-light)
```ts
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET!);
const session = await stripe.checkout.sessions.create({
mode: 'payment',
line_items: [{ price: 'price_123', quantity: 2 }],
automatic_tax: { enabled: true },
shipping_address_collection: { allowed_countries: ['US', 'GB', 'KR'] },
success_url: 'https://shop.example.com/success?cs={CHECKOUT_SESSION_ID}',
cancel_url: 'https://shop.example.com/cart',
});
return Response.redirect(session.url!, 303);
```
### Stripe webhook (idempotent)
```ts
import { headers } from 'next/headers';
export async function POST(req: Request) {
const sig = (await headers()).get('stripe-signature')!;
const body = await req.text();
const event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET!);
// 매 idempotency: 매 event.id 의 record, 매 already-processed skip
if (await db.processedEvents.has(event.id)) return new Response(null, { status: 200 });
switch (event.type) {
case 'checkout.session.completed':
await fulfillOrder(event.data.object as Stripe.Checkout.Session);
break;
}
await db.processedEvents.insert(event.id);
return new Response(null, { status: 200 });
}
```
### Shopify Hydrogen (Storefront API)
```ts
import { storefrontClient } from '~/lib/shopify';
const PRODUCT = `#graphql
query Product($handle: String!) {
product(handle: $handle) {
id title descriptionHtml
variants(first: 10) { nodes { id price { amount currencyCode } availableForSale } }
images(first: 5) { nodes { url altText } }
}
}`;
const { data } = await storefrontClient.request(PRODUCT, { variables: { handle } });
```
### Medusa.js custom backend
```ts
// backend 의 custom plugin
import { OrderService } from '@medusajs/medusa';
class FraudGuardService {
constructor(private orderService: OrderService) {}
async beforeCapture(orderId: string) {
const score = await fetch('https://radar/api', { /* … */ }).then(r => r.json());
if (score.risk > 0.8) await this.orderService.cancel(orderId);
}
}
```
### Cart state (Server Component + Cookie)
```ts
import { cookies } from 'next/headers';
export async function getCart(): Promise<Cart> {
const id = (await cookies()).get('cart_id')?.value;
return id ? storefront.cart.get(id) : storefront.cart.create();
}
```
### Algolia product search index
```ts
import { algoliasearch } from 'algoliasearch';
const client = algoliasearch(APP_ID, ADMIN_KEY);
await client.saveObjects({
indexName: 'products',
objects: products.map(p => ({
objectID: p.id, title: p.title, brand: p.brand, price: p.price.amount,
inStock: p.inventory > 0, _tags: p.collections,
})),
});
```
### Tax (Stripe Tax inline)
```ts
const tax = await stripe.tax.calculations.create({
currency: 'usd',
line_items: [{ amount: 5000, reference: 'sku_1', tax_behavior: 'exclusive' }],
customer_details: {
address: { line1: '...', city: 'Seattle', state: 'WA', postal_code: '98101', country: 'US' },
address_source: 'shipping',
},
});
```
### B2B quote → order
```ts
// commercetools / Vendure pattern
const quote = await ct.quotes.create({ customer, lineItems, validUntil: addDays(new Date(), 14) });
// 매 buyer accept → order 의 transition
const order = await ct.orders.fromQuote(quote.id);
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Lean DTC start | Shopify (basic) + Stripe |
| Custom UX, brand priority | Shopify Hydrogen or Saleor + headless CMS |
| Self-host / OSS / cost control | Medusa.js or Vendure |
| Enterprise composable | commercetools + Algolia + Contentful + Adyen |
| Marketplace | Mirakl or Sharetribe |
| B2B with quotes/contracts | commercetools / Spryker |
**기본값**: Shopify for SMB; Hydrogen for premium DTC; commercetools for enterprise composable; Stripe as PSP unless enterprise (then Adyen).
## 🔗 Graph
- 부모: [[Web-Architecture]]
- 변형: [[Headless-Commerce]]
- Adjacent: [[Algolia]] · [[Sanity]]
## 🤖 LLM 활용
**언제**: 매 platform comparison, 매 webhook handler 의 scaffold, 매 GraphQL Storefront query 의 작성, 매 tax/shipping flow explanation, 매 catalog data model design.
**언제 X**: 매 PCI-DSS / SCA / regional tax 의 final compliance review (legal + Stripe/Adyen docs). 매 fraud rules in production (data scientist + risk team).
## ❌ 안티패턴
- **Roll-your-own checkout**: 매 PCI scope explode + tax + APM hell — Stripe/Adyen Checkout 사용.
- **No webhook idempotency**: 매 duplicate fulfillment / charge — event.id dedupe.
- **Cart in localStorage only**: 매 multi-device 가 broken — server-side cart.
- **No automatic_tax**: 매 EU VAT / US Wayfair 의 manual mess.
- **Storefront API token in client**: 매 secret leak — 매 server-only token.
- **Sync inventory in serverless cold path**: 매 oversell — event-driven inventory + reservation.
## 🧪 검증 / 중복
- Verified (Shopify Hydrogen docs, Medusa.js docs, commercetools docs, Stripe docs, Adyen docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — e-commerce platform landscape, Shopify/Stripe/headless patterns |
@@ -0,0 +1,201 @@
---
id: wiki-2026-0508-eve-온라인-eve-online
title: EVE 온라인(EVE Online)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [EVE Online, EVE, CCP Games]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [game-design, mmo, sandbox, virtual-economy, distributed-systems]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: stackless-python
framework: tranquility
---
# EVE 온라인(EVE Online)
## 매 한 줄
> **"매 single-shard MMO sandbox 의 player-driven economy 의 22-year proof"**. EVE Online (CCP Games, 2003-) 매 single persistent universe 매 모든 players 의 same world 의 share — 매 player-built corporations, wars, markets, espionage 의 ground truth. Architecture (Stackless Python + StacklessIO + cluster), economy, sandbox design 매 industry case study.
## 매 핵심
### 매 Architecture (Tranquility)
- **Single shard**: 매 모든 players 매 one universe — 매 7,800+ star systems.
- **Per-system simulation node**: 매 system 매 one node 의 simulate, 매 nodes 매 cluster 의 distribute.
- **Stackless Python**: 매 lightweight tasklets 매 thousands 의 ships 의 concurrent simulation.
- **Time Dilation (TiDi)**: 매 fleet fight 의 thousands 의 ships 시 매 time slow-down (10%까지) — 매 graceful degradation.
### 매 Economy
- **Player-driven 99%**: 매 모든 ships, modules, structures 매 player-mined / built.
- **PLEX**: 매 real-money item 의 in-game ISK 의 trade — 매 secondary market.
- **Real economist**: 매 CCP 매 in-house economist (Eyjólfur Guðmundsson) 매 quarterly reports 의 publish — 매 inflation, sink/faucet balance.
### 매 응용
1. Sandbox MMO design reference.
2. Distributed simulation scaling case.
3. Virtual economy research (papers).
4. Emergent player politics — Goonswarm, Test Alliance.
## 💻 패턴
### TiDi-style adaptive tickrate
```python
class AdaptiveSimulation:
def __init__(self, target_fps=10):
self.target_dt = 1.0 / target_fps
self.tidi = 1.0 # 1.0 = real-time, 0.1 = 10% speed
def step(self, entities):
start = time.monotonic()
for e in entities:
e.update(self.target_dt * self.tidi)
elapsed = time.monotonic() - start
# If frame took longer than budget, dilate
if elapsed > self.target_dt:
self.tidi = max(0.1, self.target_dt / elapsed)
else:
self.tidi = min(1.0, self.tidi + 0.05)
```
### Per-system node assignment
```python
SYSTEM_NODES = {} # system_id -> node_id
def route_player(player, system_id):
node_id = SYSTEM_NODES.get(system_id)
if node_id is None:
node_id = pick_least_loaded_node()
SYSTEM_NODES[system_id] = node_id
forward_to_node(node_id, player)
def reinforce_system(system_id, expected_players):
"""
Pre-fight reinforcement: 매 large fleet 의 expected 시
매 system 의 dedicated high-spec node 의 move
"""
if expected_players > 500:
move_system_to_node(system_id, get_dedicated_node())
```
### ISK economy faucet/sink tracking
```python
@dataclass
class EconomicEvent:
type: Literal['faucet', 'sink']
source: str # 'mission_reward', 'market_fee', 'jump_clone_cost'
amount: int # ISK
actor_id: str
ts: datetime
def monthly_economic_report(events: list[EconomicEvent]):
by_source = defaultdict(lambda: {'in': 0, 'out': 0})
for e in events:
bucket = 'in' if e.type == 'faucet' else 'out'
by_source[e.source][bucket] += e.amount
total_in = sum(b['in'] for b in by_source.values())
total_out = sum(b['out'] for b in by_source.values())
return {
'net': total_in - total_out,
'inflation_signal': (total_in - total_out) / max(total_out, 1),
'top_faucets': sorted(by_source.items(), key=lambda x: -x[1]['in'])[:5],
'top_sinks': sorted(by_source.items(), key=lambda x: -x[1]['out'])[:5],
}
```
### Market order matching (regional)
```python
class MarketEngine:
def __init__(self):
self.buy_orders = defaultdict(list) # item_id -> [orders]
self.sell_orders = defaultdict(list)
def place_buy(self, order):
sells = sorted(self.sell_orders[order.item_id], key=lambda o: o.price)
remaining = order.quantity
for s in sells:
if s.price > order.max_price: break
qty = min(remaining, s.quantity)
self.execute_trade(order.buyer, s.seller, order.item_id, qty, s.price)
s.quantity -= qty
remaining -= qty
if remaining == 0: break
if remaining > 0:
order.quantity = remaining
heapq.heappush(self.buy_orders[order.item_id], order)
```
### Killmail event sourcing
```python
@dataclass
class Killmail:
victim_id: str; attackers: list[str]
ship_type: str; system_id: str
isk_destroyed: int
ts: datetime
final_blow: str
# 매 immutable log — 매 zKillboard / EveWho 의 derive
def replay_corp_history(killmails: list[Killmail], corp_id: str):
losses = sum(k.isk_destroyed for k in killmails if member_of(k.victim_id, corp_id))
kills = sum(k.isk_destroyed for k in killmails
if any(member_of(a, corp_id) for a in k.attackers))
return {'isk_efficiency': kills / max(kills + losses, 1)}
```
### Sovereignty / structure timer
```python
class StructureTimer:
"""매 attacked structure 매 reinforce mode 의 enter — 매 24h timer."""
def __init__(self, structure_id):
self.id = structure_id
self.state = 'anchored'
self.timer_end = None
def take_damage(self, dmg):
if self.state == 'anchored' and self.hp_below(50):
self.state = 'reinforced'
self.timer_end = now() + timedelta(hours=24, minutes=randint(0, 360))
elif self.state == 'reinforced' and now() >= self.timer_end:
self.state = 'vulnerable'
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Massive single-world MMO | 매 EVE 의 per-system node + TiDi |
| Sharded MMO (WoW-style) | 매 EVE pattern 의 not-needed |
| Player economy 의 desire | 매 explicit faucet/sink design + economist |
| Sandbox vs themepark | 매 EVE-style emergent vs scripted quests |
| Anti-griefing | 매 EVE 의 high/low/null-sec gradient |
**기본값**: 매 single-shard 매 only 매 specific tradeoff 의 worth — 매 most MMOs 매 sharding 의 simpler. Economy 매 EVE pattern 의 broad applicability.
## 🔗 Graph
- 응용: [[Virtual-Economy]]
- Adjacent: [[CCP-Games]]
## 🤖 LLM 활용
**언제**: 매 player-economy game design reference. Distributed simulation 매 graceful degradation case. Virtual economy academic study.
**언제 X**: 매 non-MMO context. 매 small game 매 EVE complexity 의 over-apply.
## ❌ 안티패턴
- **No sinks**: 매 only faucets — 매 hyperinflation. EVE 매 broker fees, jump clone, structure costs 의 sinks.
- **Hard server cap**: 매 no TiDi 매 fleet fight 의 disconnect storm. Graceful slow-down 의 prefer.
- **Dev intervention 의 economy**: 매 CCP 매 historically 의 hands-off — 매 player corp scams 매 allowed. 매 too much intervention 매 sandbox 의 break.
- **Single-shard 의 cargo-cult**: 매 most games 매 single-shard 의 not-need — 매 sharding cost 의 cheaper.
## 🧪 검증 / 중복
- Verified (CCP Games dev blogs; "EVE Online: How to Build a Single-Shard MMO" GDC; Eyjólfur Guðmundsson MER reports).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — EVE architecture + economy + 6 patterns |
@@ -0,0 +1,187 @@
---
id: wiki-2026-0508-enabling-point-활성화-지점
title: Enabling Point (활성화 지점)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Activation Point, Enabling Constraint, Trigger Point]
duplicate_of: none
source_trust_level: B
confidence_score: 0.8
verification_status: applied
tags: [architecture, design, leverage-point, evolutionary-architecture]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: methodology
framework: architecture
---
# Enabling Point (활성화 지점)
## 매 한 줄
> **"매 작은 architectural seam 의 future change 의 unlock"**. 매 enabling point 의 매 system 의 specific spot — 매 intentionally placed extension hook / abstraction / boundary 의 매 later capability 의 enable. 매 Donella Meadows의 "leverage point" + Neal Ford 의 "evolutionary architecture" 의 fitness function 의 cousin.
## 매 핵심
### 매 무엇 / 무엇 X
- **무엇**: 매 explicit 한 future-flexibility hook (interface / event / config flag / plugin).
- **무엇 X**: 매 speculative generality (YAGNI 위반) — 매 enabling point 의 cheap / minimal.
### 매 indicator
- 매 small abstraction 의 매 large optionality 의 unlock.
- 매 reversible decision 의 keep — 매 매 one-way door 의 avoid.
- 매 cost-of-change 의 grow before it's added.
### 매 종류
1. **Interface seam** — 매 abstraction 의 swap.
2. **Event hook** — 매 publish / subscribe.
3. **Feature flag** — 매 runtime toggle.
4. **Plugin point** — 매 third-party extension.
5. **Schema evolution slot** — 매 versioning / optional field.
6. **Configuration point** — 매 env / DI binding.
### 매 응용
1. Strangler fig migration — 매 facade 의 enabling point.
2. Plugin systems (VSCode, Obsidian, Backstage).
3. Multi-tenant SaaS — 매 tenant-scoped extension.
## 💻 패턴
### Pattern 1: Interface seam (TypeScript)
```typescript
// 매 enabling point — payment provider 의 swap
interface PaymentProvider {
charge(amount: number, token: string): Promise<ChargeResult>;
refund(chargeId: string): Promise<void>;
}
class StripeProvider implements PaymentProvider { /* ... */ }
class TossProvider implements PaymentProvider { /* ... */ }
// service 의 매 PaymentProvider 만 의 know
class CheckoutService {
constructor(private payments: PaymentProvider) {}
}
```
### Pattern 2: Event hook
```typescript
type Hook<T> = (ctx: T) => Promise<void>;
class HookRegistry<T> {
private hooks: Hook<T>[] = [];
register(h: Hook<T>) { this.hooks.push(h); }
async fire(ctx: T) { for (const h of this.hooks) await h(ctx); }
}
// 매 enabling point — order placed 시 매 plugin 의 react
const orderPlaced = new HookRegistry<{ orderId: string }>();
orderPlaced.register(async ({ orderId }) => emailService.confirmation(orderId));
orderPlaced.register(async ({ orderId }) => analytics.track("order", orderId));
```
### Pattern 3: Feature flag (LaunchDarkly-style)
```typescript
import { flags } from "./flags";
async function checkout(req: CheckoutReq) {
if (await flags.isOn("new-checkout-flow", req.userId)) {
return newFlow(req);
}
return legacyFlow(req);
}
// 매 enabling point — 매 percentage rollout / kill switch / A/B.
```
### Pattern 4: Plugin point
```typescript
// VSCode-style contribution
interface CommandContribution {
id: string;
title: string;
handler(args: unknown): Promise<void>;
}
class PluginHost {
private commands = new Map<string, CommandContribution>();
register(c: CommandContribution) { this.commands.set(c.id, c); }
async execute(id: string, args: unknown) {
return this.commands.get(id)?.handler(args);
}
}
```
### Pattern 5: Schema evolution
```typescript
// 매 v1 → v2 의 enabling point — optional field
interface OrderV1 { id: string; items: Item[]; }
interface OrderV2 extends OrderV1 {
giftMessage?: string; // 매 backward-compatible add
shippingMethod?: "standard" | "express";
}
// 매 readers 의 매 둘 다 의 handle.
```
### Pattern 6: Strangler fig facade
```typescript
// 매 legacy / new 의 enabling point — facade 의 routing
async function getUser(id: string): Promise<User> {
if (await isUserMigrated(id)) {
return newService.getUser(id);
}
return legacyService.getUser(id);
}
```
### Pattern 7: Fitness function (architecture test)
```typescript
// 매 enabling point 의 의도된 boundary 의 verify
import { describe, it, expect } from "vitest";
import { extractImports } from "./arch-test";
describe("architecture", () => {
it("domain layer must not import infrastructure", () => {
const imports = extractImports("src/domain/**/*.ts");
const violations = imports.filter(i => i.includes("/infrastructure/"));
expect(violations).toEqual([]);
});
});
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 매 evidence 의 future change | enabling point 의 add |
| 매 speculative | YAGNI — skip |
| One-way door decision | enabling point 의 mandatory |
| Reversible decision | 매 simple 의 ship, refactor later |
| Plugin ecosystem 의 plan | plugin point 의 first-class |
**기본값**: 매 evidence-based — 매 2nd 번 같은 change 의 demand 시 enabling point 의 introduce ("Rule of three").
## 🔗 Graph
- 부모: [[Software Architecture]]
- 응용: [[Feature Flags]]
- Adjacent: [[Hexagonal Architecture]] · [[YAGNI]]
## 🤖 LLM 활용
**언제**: 매 architecture review, 매 future change 의 anticipate, 매 refactor planning.
**언제 X**: 매 prototype, 매 evidence 의 absent — 매 over-engineering.
## ❌ 안티패턴
- **Speculative enabling**: 매 "혹시 모를" abstraction — YAGNI.
- **Too many hooks**: 매 plugin point 의 abuse — 매 cognitive load.
- **Hidden coupling**: 매 enabling point 의 facade 만, 매 internal coupling 의 그대로.
- **No fitness function**: 매 enabling point 의 verify X — 매 시간 erode.
## 🧪 검증 / 중복
- Verified (Neal Ford "Building Evolutionary Architectures" 2nd ed, M. Feathers "Working Effectively with Legacy Code", Meadows "Thinking in Systems").
- 신뢰도 B (매 term 의 community variance).
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — enabling point 종류 + fitness function |
@@ -0,0 +1,29 @@
---
category: Architecture
tags: [auto-wikified, technical-documentation, architecture]
title: Entity (엔티티)
description: "엔티티(Entity)는 애플리케이션에서 데이터베이스 모델이나 순수한 비즈니스 규칙을 표현하는 핵심 데이터 구조이다 [1-3]."
last_updated: 2026-05-04
---
# Entity (엔티티)
## 📌 Brief Summary
엔티티(Entity)는 애플리케이션에서 데이터베이스 모델이나 순수한 비즈니스 규칙을 표현하는 핵심 데이터 구조이다 [1-3]. 현대 소프트웨어 개발 및 실전 아키텍처에서는 엔티티를 API 입출력을 담당하는 DTO(Data Transfer Object)와 엄격하게 분리하여 관리하는 것을 핵심 패턴으로 삼는다 [1-3]. 이를 통해 데이터베이스 스키마와 외부 API 스펙 간의 결합도를 낮추고 대규모 시스템의 유지보수성을 확보할 수 있다 [2-4].
## 📖 Core Content
* **역할 및 위치:**
실무 아키텍처에서 엔티티는 주로 TypeORM, Prisma, Drizzle(NestJS 환경) 또는 JPA(Spring Boot 환경)와 같은 도구의 데코레이터/어노테이션을 통해 데이터베이스 모델로 정의되며, 서비스(Service) 계층에서 사용된다 [2, 5, 6]. 특히 헥사고날 아키텍처(Hexagonal Architecture)에서는 도메인(Domain) 계층에 위치하여 어떠한 외부 프레임워크나 라이브러리에도 의존하지 않는 순수한 형태로 존재해야 한다 [3].
* **DTO와의 명확한 분리:**
프로젝트 초기에는 엔티티와 DTO의 구조가 매우 유사해 보일 수 있으나, 시간이 지나고 애플리케이션이 확장됨에 따라 두 객체의 구조는 필연적으로 달라지게 된다 [1, 2]. 따라서 엔티티는 데이터베이스 스키마 및 도메인 표현에만 집중하고, DTO는 API를 넘나드는 데이터의 형태를 정의하는 용도로 역할을 분리해야 한다 [1, 2].
* **데이터 변환 및 계약 유지:**
엔티티를 애플리케이션의 다른 계층이나 외부로 전달할 때는 매퍼(Mapper)를 통해 DTO로 데이터를 변환하는 과정을 거쳐야 한다 [3]. 소비 계층(Consuming layer)에는 인터페이스 계약에 기반한 DTO만 반환함으로써 핵심 엔티티를 격리 및 보호할 수 있다 [4].
## ⚖️ Trade-offs & Caveats
* **직접 노출 시의 위험성 (안티 패턴):**
컨트롤러(Controller)에서 엔티티를 클라이언트에게 직접 노출하는 것은 심각한 안티 패턴이다 [2]. 엔티티를 직접 반환하면 내부 데이터베이스 필드 구조가 외부에 그대로 유출될 뿐만 아니라, 애플리케이션이 DB 스키마에 완전히 종속(Lock-in)되게 된다 [2]. 이로 인해 추후 데이터 모델이 변경될 때 외부 API 스펙까지 파괴될 위험이 있으며, API 변경에 막대한 비용이 발생하게 된다 [2, 3].
* **보일러플레이트 코드와 복잡성 증가:**
엔티티와 DTO를 분리하고 변환하는 패턴은 아키텍처를 견고하게 만들지만, 개발자가 작성하고 유지보수해야 할 보일러플레이트 코드(예: 중복되어 보이는 DTO 클래스 및 매핑 로직)를 증가시킨다는 단점이 있다 [7]. 소규모 팀이나 단순한 프로젝트에서는 이러한 엄격한 분리 구조가 오히려 비즈니스 가치 창출보다 프레임워크 배선(wiring) 작업에 더 많은 비용을 소모하게 만들 수 있다 [7, 8].
---
*Last updated: 2026-05-03*
@@ -0,0 +1,196 @@
---
id: wiki-2026-0508-event-mediator
title: Event Mediator
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Mediator Pattern, Event Bus]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [architecture, design-pattern, event-driven, decoupling]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: nodejs
---
# Event Mediator
## 매 한 줄
> **"매 N×N component coupling 의 N×1 mediator hub 의 collapse"**. Event Mediator 매 multiple components 의 direct coupling 의 elimination — 매 components 매 mediator 를 publish/subscribe, 매 mediator 매 routing/orchestration 의 own. GoF Mediator pattern 의 event-driven evolution.
## 매 핵심
### 매 Mediator vs Observer
- **Observer**: 매 1 subject → N observers, 매 unidirectional broadcast.
- **Mediator**: 매 N senders ↔ N receivers, 매 hub 의 bidirectional routing.
- **Event Bus**: 매 Mediator 의 generic implementation — 매 string-keyed event types.
### 매 동기 vs 비동기
- **Sync mediator**: 매 in-process method dispatch — 매 EventEmitter, MediatR.
- **Async mediator**: 매 message queue 의 backed — 매 RabbitMQ, Kafka, Redis Streams.
- **Hybrid**: 매 in-process sync + cross-service async (e.g., NestJS CQRS).
### 매 응용
1. UI components decoupling — chat rooms, form fields.
2. Microservices orchestration — saga coordinator.
3. CQRS command/query bus — MediatR.
4. Game event systems — unit death, achievement triggers.
## 💻 패턴
### Typed Event Bus (TypeScript)
```typescript
type EventMap = {
'user.signup': { userId: string; email: string };
'order.placed': { orderId: string; total: number };
'cache.invalidate': { key: string };
};
class EventMediator<M> {
private handlers = new Map<keyof M, Set<(p: any) => void | Promise<void>>>();
on<K extends keyof M>(event: K, handler: (payload: M[K]) => void | Promise<void>) {
if (!this.handlers.has(event)) this.handlers.set(event, new Set());
this.handlers.get(event)!.add(handler);
return () => this.handlers.get(event)!.delete(handler);
}
async emit<K extends keyof M>(event: K, payload: M[K]) {
const hs = this.handlers.get(event);
if (!hs) return;
await Promise.all([...hs].map(h => h(payload)));
}
}
const bus = new EventMediator<EventMap>();
bus.on('user.signup', async ({ userId, email }) => {
await sendWelcomeEmail(email);
});
```
### Mediator with Request/Response (MediatR-style)
```typescript
interface IRequest<TResponse> { __response?: TResponse }
interface IHandler<TReq extends IRequest<TRes>, TRes> {
handle(req: TReq): Promise<TRes>;
}
class Mediator {
private handlers = new Map<Function, IHandler<any, any>>();
register<T extends IRequest<R>, R>(reqCtor: new (...a: any[]) => T, h: IHandler<T, R>) {
this.handlers.set(reqCtor, h);
}
async send<R>(req: IRequest<R>): Promise<R> {
const h = this.handlers.get(req.constructor);
if (!h) throw new Error(`No handler for ${req.constructor.name}`);
return h.handle(req);
}
}
class GetUserQuery implements IRequest<User> { constructor(public id: string) {} }
class GetUserHandler implements IHandler<GetUserQuery, User> {
async handle(q: GetUserQuery) { return db.users.findById(q.id); }
}
```
### Saga Mediator (orchestrated)
```typescript
class OrderSaga {
constructor(private bus: EventMediator<OrderEvents>) {
bus.on('order.created', this.onCreated.bind(this));
bus.on('payment.failed', this.onPaymentFailed.bind(this));
}
async onCreated({ orderId }: { orderId: string }) {
await this.bus.emit('payment.requested', { orderId });
}
async onPaymentFailed({ orderId, reason }: any) {
await this.bus.emit('order.cancelled', { orderId, reason });
await this.bus.emit('inventory.released', { orderId });
}
}
```
### Middleware Pipeline
```typescript
type Middleware<E> = (event: E, next: () => Promise<void>) => Promise<void>;
class PipelineMediator<E> {
private middlewares: Middleware<E>[] = [];
use(m: Middleware<E>) { this.middlewares.push(m); }
async dispatch(event: E) {
let i = -1;
const run = async (idx: number): Promise<void> => {
if (idx <= i) throw new Error('next() called twice');
i = idx;
const fn = this.middlewares[idx];
if (fn) await fn(event, () => run(idx + 1));
};
await run(0);
}
}
// usage: logging, validation, retry, dead-letter
```
### Cross-Service Mediator (Kafka)
```typescript
import { Kafka } from 'kafkajs';
const kafka = new Kafka({ brokers: ['localhost:9092'] });
const producer = kafka.producer();
const consumer = kafka.consumer({ groupId: 'order-svc' });
await consumer.subscribe({ topic: 'orders', fromBeginning: false });
await consumer.run({
eachMessage: async ({ message }) => {
const evt = JSON.parse(message.value!.toString());
await handler[evt.type]?.(evt.payload);
},
});
await producer.send({
topic: 'orders',
messages: [{ key: orderId, value: JSON.stringify({ type: 'order.placed', payload }) }],
});
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 2-3 components 의 direct call | 매 mediator skip — 매 over-engineering |
| 5+ components, fan-out broadcast | 매 in-process EventEmitter |
| CQRS / clean architecture | 매 MediatR-style request bus |
| Cross-service, durability | 매 Kafka / RabbitMQ |
| Long-running workflow | 매 saga orchestrator (Temporal, Inngest) |
**기본값**: 매 typed in-process EventEmitter (Node) 또는 MediatR (.NET) — 매 cross-service 의 Kafka.
## 🔗 Graph
- 부모: [[Design-Patterns]] · [[Event-Driven-Architecture]]
- 변형: [[Observer-Pattern]] · [[Pub-Sub]]
- 응용: [[CQRS]] · [[Microservices]]
- Adjacent: [[Event Sourcing]]
## 🤖 LLM 활용
**언제**: 매 N×N coupling 의 emerge — 매 5+ components 매 mutual callbacks. CQRS / saga implementation.
**언제 X**: 매 simple 2-component dependency — 매 direct injection 매 sufficient. Hot-path latency-critical (mediator dispatch overhead).
## ❌ 안티패턴
- **God Mediator**: 매 mediator 매 business logic 의 absorb — 매 anemic handlers, 매 mediator 의 1000+ lines. Mediator 의 routing only.
- **Event soup**: 매 untyped string events — 매 'user_signup' vs 'userSignup' typo 의 silent failure. Typed map 의 use.
- **Sync chain pretending async**: 매 emit() 매 await chain 의 200ms latency — 매 async queue 의 use.
- **Lost events**: 매 in-memory bus 매 crash 의 lose — 매 durability 매 required 의 persistent queue.
## 🧪 검증 / 중복
- Verified (GoF Design Patterns; MediatR docs; NestJS CQRS).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Event Mediator pattern 의 typed/saga/Kafka 의 5 patterns |
@@ -0,0 +1,195 @@
---
id: wiki-2026-0508-event-stream-processing
title: Event Stream Processing
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Stream Processing, ESP, Streaming Analytics]
duplicate_of: none
source_trust_level: A
confidence_score: 0.93
verification_status: applied
tags: [streaming, kafka, flink, real-time, data-engineering]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: polyglot
framework: kafka-flink
---
# Event Stream Processing
## 매 한 줄
> **"매 unbounded data 의 매 record-by-record 의 transform"**. 매 batch 의 ETL 의 opposite — 매 event 의 arrive 시점 에 immediately compute. 매 2026 의 매 dominant stack 의 Kafka + Flink (or Kafka Streams), 매 emerging 의 RisingWave / Materialize (streaming SQL DB), 매 cloud-native 의 Confluent Cloud / AWS Kinesis / GCP Dataflow.
## 매 핵심
### 매 batch vs streaming
- **Batch**: 매 hourly/daily, 매 high latency, 매 reprocess easy.
- **Streaming**: 매 sub-second, 매 always-on, 매 stateful.
- **Lambda architecture**: batch + streaming hybrid (매 deprecated 2026).
- **Kappa architecture**: streaming-only, 매 replay 의 reprocess.
### 매 핵심 개념
- **Event time vs processing time** — 매 event 의 produce 시점 vs broker 의 receive.
- **Watermark** — 매 "event time T 까지의 모든 event 의 도착 의 expect" 의 signal.
- **Window** — tumbling / sliding / session.
- **Exactly-once semantics** — Kafka transactions + Flink checkpoints.
- **Stateful operator** — 매 RocksDB / state backend.
### 매 frameworks (2026)
- **Apache Flink 1.20** — 매 most powerful, 매 unified batch+streaming, 매 exactly-once.
- **Kafka Streams 3.7** — 매 JVM 만, 매 library (no cluster).
- **Apache Beam** — 매 portable runner (Flink/Dataflow/Spark).
- **RisingWave / Materialize** — 매 streaming SQL DB, 매 incremental view maintenance.
- **Bytewax** — 매 Python-native, 매 Rust core.
### 매 응용
1. Real-time fraud detection.
2. IoT telemetry aggregation.
3. Live dashboards (clickstream).
4. CDC → search index sync.
5. AI feature stores (real-time).
## 💻 패턴
### Pattern 1: Kafka producer (TS)
```typescript
import { Kafka } from "kafkajs";
const kafka = new Kafka({ brokers: ["broker:9092"] });
const producer = kafka.producer({ idempotent: true, maxInFlightRequests: 5 });
await producer.connect();
await producer.send({
topic: "orders",
messages: [{
key: order.id,
value: JSON.stringify(order),
headers: { "event-time": Date.now().toString() },
}],
});
```
### Pattern 2: Flink DataStream (Java)
```java
DataStream<Order> orders = env.fromSource(
KafkaSource.<Order>builder()
.setBootstrapServers("broker:9092")
.setTopics("orders")
.setDeserializer(new OrderDeserializer())
.build(),
WatermarkStrategy
.<Order>forBoundedOutOfOrderness(Duration.ofSeconds(5))
.withTimestampAssigner((o, ts) -> o.eventTime),
"kafka-source");
orders
.keyBy(o -> o.userId)
.window(TumblingEventTimeWindows.of(Time.minutes(1)))
.aggregate(new OrderCountAgg())
.sinkTo(new MetricsSink());
```
### Pattern 3: Kafka Streams aggregation
```java
StreamsBuilder builder = new StreamsBuilder();
KStream<String, Order> orders = builder.stream("orders");
orders
.groupBy((k, v) -> v.userId)
.windowedBy(TimeWindows.ofSizeWithNoGrace(Duration.ofMinutes(5)))
.count(Materialized.as("user-order-count"))
.toStream()
.to("user-order-counts");
```
### Pattern 4: Streaming SQL (Flink SQL / RisingWave)
```sql
-- 매 RisingWave / Flink SQL 동일
CREATE SOURCE orders (
order_id VARCHAR, user_id VARCHAR, amount DOUBLE,
event_time TIMESTAMP, WATERMARK FOR event_time AS event_time - INTERVAL '5' SECOND
) WITH (connector='kafka', topic='orders', properties.bootstrap.servers='broker:9092') FORMAT JSON;
CREATE MATERIALIZED VIEW user_revenue_5m AS
SELECT user_id,
window_start, window_end,
SUM(amount) AS revenue
FROM TUMBLE(orders, event_time, INTERVAL '5' MINUTES)
GROUP BY user_id, window_start, window_end;
```
### Pattern 5: Bytewax (Python streaming)
```python
from bytewax.dataflow import Dataflow
from bytewax.connectors.kafka import KafkaSource, KafkaSink
from bytewax import operators as op
flow = Dataflow("fraud-detect")
src = op.input("kafka-in", flow, KafkaSource(brokers=["broker:9092"], topics=["tx"]))
parsed = op.map("parse", src, lambda kv: json.loads(kv.value))
flagged = op.filter("suspicious", parsed, lambda tx: tx["amount"] > 10_000)
op.output("kafka-out", flagged, KafkaSink(brokers=["broker:9092"], topic="alerts"))
```
### Pattern 6: CDC stream (Debezium → Kafka → Flink)
```yaml
# Debezium connector config
connector.class: io.debezium.connector.postgresql.PostgresConnector
database.hostname: pg
database.dbname: app
plugin.name: pgoutput
table.include.list: public.orders
topic.prefix: cdc
```
### Pattern 7: Exactly-once sink (Flink)
```java
KafkaSink<Order> sink = KafkaSink.<Order>builder()
.setBootstrapServers("broker:9092")
.setRecordSerializer(KafkaRecordSerializationSchema.builder()
.setTopic("processed-orders")
.setValueSerializationSchema(new OrderSerializer())
.build())
.setDeliveryGuarantee(DeliveryGuarantee.EXACTLY_ONCE)
.setTransactionalIdPrefix("orders-")
.build();
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Sub-second latency, JVM team | Flink |
| Lightweight, library-only | Kafka Streams |
| Python team, simple jobs | Bytewax |
| SQL-only, fast iteration | RisingWave / Materialize |
| Multi-runtime portability | Apache Beam |
| Cloud-managed | Confluent / Dataflow / Kinesis |
**기본값**: 매 Kafka + Flink (전통 stack), 매 SQL-only 시 RisingWave.
## 🔗 Graph
- 부모: [[Data Engineering]] · [[Distributed Systems]]
- 응용: [[Feature Store]]
- Adjacent: [[Apache Flink]] · [[Event Sourcing]] · [[CQRS]]
## 🤖 LLM 활용
**언제**: 매 real-time pipeline 설계, 매 streaming SQL 의 generate.
**언제 X**: 매 daily batch 의 충분, 매 small data 의 cron job.
## ❌ 안티패턴
- **No watermark**: 매 late event 의 silently drop or wrong window.
- **At-least-once + idempotent missing**: 매 duplicate 의 downstream impact.
- **Unbounded state**: 매 keyed state 의 TTL 의 missing — 매 OOM.
- **Reorder reliance**: 매 partition 별 only 의 ordering — 매 cross-partition 의 X.
- **Synchronous external call inside operator**: 매 backpressure / slow.
## 🧪 검증 / 중복
- Verified (Flink docs, Kafka docs, "Streaming Systems" Akidau et al., RisingWave docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Flink/Kafka Streams/RisingWave + windowing |
@@ -0,0 +1,174 @@
---
id: wiki-2026-0508-event-storming
title: Event Storming
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [EventStorming, DDD discovery workshop]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
verification_status: applied
tags: [ddd, modeling, workshop, architecture, discovery]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: methodology
framework: ddd
---
# Event Storming
## 매 한 줄
> **"매 sticky-note 의 도메인 의 explosion"**. Alberto Brandolini 의 2013 invent, 매 domain experts + devs 의 한 방 (혹은 Miro/FigJam) 에 모여 매 orange sticky note (domain event) 의 timeline 의 plot. 매 2026 의 매 distributed workshop tool (Miro AI, FigJam AI) 의 매 LLM-assisted aggregation 의 standard.
## 매 핵심
### 매 sticky note color convention
- 🟧 **Orange** — Domain Event (past tense — "OrderPlaced", "PaymentReceived").
- 🟦 **Blue** — Command (intent — "PlaceOrder", "RefundPayment").
- 🟨 **Yellow** — Actor / Persona.
- 🟪 **Purple** — Policy / Reactive logic ("when X then Y").
- 🟩 **Green** — Read Model / View.
- 🟥 **Red / Pink** — Hotspot / Issue (매 unclear / disagreement).
-**White** — Aggregate (매 consistency boundary).
- 🟫 **Brown** — External system.
### 매 3 levels
1. **Big Picture** — 매 entire business — 매 chaos exploration, 매 hours.
2. **Process Level** — 매 한 process flow — 매 commands / policies / read models.
3. **Design Level** — 매 aggregate / bounded context — 매 implementation 의 input.
### 매 step-by-step (Big Picture)
1. **Chaotic exploration** — 매 모두 orange events 의 plaster.
2. **Timeline** — 매 left → right 의 sort.
3. **Pivotal events** — 매 phase boundary 의 mark.
4. **Hotspot identification** — 매 red sticky 의 disagreement.
5. **Bounded context** — 매 swimlane 의 split.
### 매 응용
1. Greenfield DDD design — 매 aggregate / bounded context discovery.
2. Legacy understanding — 매 domain knowledge 의 surface.
3. Microservice decomposition — 매 service boundary 의 inform.
## 💻 패턴
### Pattern 1: Miro-export → JSON event log
```typescript
interface DomainEvent {
id: string;
name: string; // PascalCase past tense
timestamp: number; // 매 column index
aggregate?: string;
triggeredBy?: string; // command id
hotspots: string[];
}
const events: DomainEvent[] = [
{ id: "e1", name: "OrderPlaced", timestamp: 1, aggregate: "Order",
triggeredBy: "c1", hotspots: [] },
{ id: "e2", name: "PaymentReceived", timestamp: 2, aggregate: "Payment",
triggeredBy: "c2", hotspots: ["partial-payment-policy"] },
];
```
### Pattern 2: Event → TypeScript event type
```typescript
// 매 sticky 의 code 의 transition
export type OrderEvent =
| { type: "OrderPlaced"; orderId: string; items: Item[]; placedAt: Date }
| { type: "OrderPaid"; orderId: string; paymentId: string }
| { type: "OrderShipped"; orderId: string; trackingNo: string }
| { type: "OrderCancelled"; orderId: string; reason: string };
```
### Pattern 3: Policy as code
```typescript
// Purple sticky: "When OrderPaid then schedule shipment"
function onOrderPaid(e: Extract<OrderEvent, {type:"OrderPaid"}>) {
shipmentService.schedule({ orderId: e.orderId });
}
eventBus.on("OrderPaid", onOrderPaid);
```
### Pattern 4: Aggregate boundary check
```typescript
// 매 white sticky 의 invariant
class OrderAggregate {
private events: OrderEvent[] = [];
place(items: Item[]) {
if (items.length === 0) throw new Error("empty order");
this.events.push({ type: "OrderPlaced", orderId: this.id, items, placedAt: new Date() });
}
// 매 모든 mutation 의 매 event 의 emit.
}
```
### Pattern 5: Bounded context map (Mermaid)
```mermaid
flowchart LR
subgraph Sales
Order
Cart
end
subgraph Billing
Payment
Invoice
end
subgraph Logistics
Shipment
end
Order -- "OrderPlaced" --> Payment
Payment -- "OrderPaid" --> Shipment
```
### Pattern 6: AI-assisted event extraction (2026)
```typescript
// 매 transcript / Miro export → event suggestions
const prompt = `From this user interview, extract domain events (PascalCase past tense),
commands, and hotspots. Output JSON matching: { events:[], commands:[], hotspots:[] }.
Interview: ${transcript}`;
const result = await claude.messages.create({
model: "claude-opus-4-7",
max_tokens: 4000,
messages: [{ role: "user", content: prompt }],
});
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Greenfield complex domain | Big Picture → Process → Design |
| Legacy reverse engineering | Big Picture only |
| Microservice split | Process Level + bounded context |
| Small CRUD app | Skip — overkill |
| Distributed team | Miro / FigJam + AI summarizer |
**기본값**: 매 complex domain 시 Big Picture (4 hours), 매 implementation 직전 Design Level.
## 🔗 Graph
- 응용: [[Bounded Context]] · [[CQRS]]
- Adjacent: [[Event Sourcing]] · [[User-Story-Mapping]] · [[C4 Model (Architecture Documentation)]]
## 🤖 LLM 활용
**언제**: 매 domain discovery, 매 microservice boundary 의 find, 매 onboarding 의 understanding.
**언제 X**: 매 trivial CRUD, 매 well-known domain (e.g., todo app).
## ❌ 안티패턴
- **Tech-first sticky**: 매 "INSERT INTO orders" — 매 domain event 의 X.
- **Present tense**: 매 "PlaceOrder" 의 event 의 X — 매 command.
- **No business expert**: 매 dev-only — 매 EventStorming purpose 의 lost.
- **Skip hotspot**: 매 red sticky 의 ignore — 매 가장 valuable disagreement.
- **Premature aggregate**: 매 Big Picture 에서 white sticky 의 too early.
## 🧪 검증 / 중복
- Verified (Brandolini "Introducing EventStorming" book 2021, DDD Europe talks).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — sticky color + 3 levels + AI-assisted |
@@ -0,0 +1,187 @@
---
id: wiki-2026-0508-eventual-consistency
title: Eventual Consistency
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Eventual Consistency, BASE, AP System]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [distributed-systems, database, consistency, cap]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: sql
framework: cassandra
---
# Eventual Consistency
## 매 한 줄
> **"매 update 후 충분한 시간이 지나면 매 모든 replica 가 같은 값에 수렴한다"**. 매 Eventual Consistency는 CAP theorem 의 AP 선택 — strong consistency 의 latency/availability cost 대신 매 staleness 허용. DynamoDB, Cassandra, Riak 의 default model. 2026 globally-distributed system 의 매 default trade-off.
## 매 핵심
### 매 CAP & PACELC
- **CAP**: partition 시 Consistency vs Availability 택 1
- **PACELC** (Abadi): partition 없을 때도 Latency vs Consistency
- 매 Eventual = AP + EL (Else Latency)
- 매 strong consistency 는 quorum write/read latency cost
### 매 BASE vs ACID
- **B**asically **A**vailable: 매 partial failure 시 partial response
- **S**oft state: 매 state 는 변할 수 있음 (replica sync)
- **E**ventual consistency: 매 시간이 지나면 수렴
- 매 ACID와 trade-off — choose per use case
### 매 응용
1. DNS (TTL-based eventual).
2. CDN cache invalidation.
3. Social media feed (read-your-writes는 보장).
4. Shopping cart (Amazon Dynamo paper).
## 💻 패턴
### Cassandra tunable consistency
```python
from cassandra.cluster import Cluster
from cassandra import ConsistencyLevel
from cassandra.query import SimpleStatement
cluster = Cluster(['node1', 'node2', 'node3'])
session = cluster.connect('myapp')
# 매 write: ONE = fast, eventual; QUORUM = stronger
write = SimpleStatement(
"INSERT INTO users (id, name) VALUES (%s, %s)",
consistency_level=ConsistencyLevel.QUORUM
)
session.execute(write, (user_id, name))
# 매 R + W > N → strong consistency
# 매 R=1, W=1, N=3 → eventual
```
### CRDT (G-Counter, conflict-free)
```python
class GCounter:
def __init__(self, node_id: str):
self.node_id = node_id
self.counts = {node_id: 0}
def increment(self):
self.counts[self.node_id] += 1
def value(self) -> int:
return sum(self.counts.values())
def merge(self, other: 'GCounter'):
# 매 idempotent + commutative + associative
for nid, count in other.counts.items():
self.counts[nid] = max(self.counts.get(nid, 0), count)
```
### Vector Clock (causal ordering)
```python
class VectorClock:
def __init__(self, node_id):
self.node_id = node_id
self.clock = {}
def tick(self):
self.clock[self.node_id] = self.clock.get(self.node_id, 0) + 1
def update(self, other_clock):
for nid, ts in other_clock.items():
self.clock[nid] = max(self.clock.get(nid, 0), ts)
self.tick()
def happens_before(self, other) -> bool:
return all(self.clock.get(k, 0) <= other.clock.get(k, 0)
for k in self.clock) and self.clock != other.clock
```
### Read-your-writes (sticky session)
```nginx
upstream backend {
ip_hash; # 매 same client → same backend → reads see own writes
server backend1;
server backend2;
server backend3;
}
```
### Last-Write-Wins (DynamoDB style)
```python
def lww_merge(local: dict, remote: dict) -> dict:
if remote['updated_at'] > local['updated_at']:
return remote
elif remote['updated_at'] < local['updated_at']:
return local
else:
# 매 tie-break by node_id
return remote if remote['node_id'] > local['node_id'] else local
```
### Hinted Handoff (Cassandra)
```yaml
# cassandra.yaml
hinted_handoff_enabled: true
max_hint_window_in_ms: 10800000 # 매 3 hours
# 매 down node 회복 시 hint replay → eventual consistency 보장
```
### Anti-Entropy (Merkle tree sync)
```python
def merkle_sync(local_tree, remote_tree, path=""):
if local_tree.hash == remote_tree.hash:
return # 매 subtree identical, skip
if local_tree.is_leaf:
sync_data(path)
return
for i, (l, r) in enumerate(zip(local_tree.children, remote_tree.children)):
merkle_sync(l, r, path + f"/{i}")
```
## 매 결정 기준
| 상황 | Consistency |
|---|---|
| Bank transfer | Strong (linearizable) |
| Social feed | Eventual |
| Shopping cart | Eventual + LWW |
| Counter (likes, views) | Eventual + CRDT |
| Configuration / leader election | Strong (Raft, etcd) |
| User profile | Read-your-writes |
**기본값**: 매 eventual + CRDT (counter, set, register). 매 money / lock / unique-id 는 strong.
## 🔗 Graph
- 부모: [[Distributed Systems]] · [[CAP Theorem & PACELC]]
- 변형: [[Strong Consistency]] · [[Read-Your-Writes]]
- 응용: [[Cassandra]] · [[CRDT]]
- Adjacent: [[Vector Clock]] · [[Quorum]]
## 🤖 LLM 활용
**언제**: 매 system design interview, distributed DB 선택, conflict resolution strategy.
**언제 X**: 매 financial transaction, inventory deduction — strong consistency 필요.
## ❌ 안티패턴
- **모든 곳에 eventual**: 매 money/lock 도 eventual → 매 double-spend, race.
- **Conflict ignore**: 매 LWW만 쓰고 user-visible conflict 무시 → 매 silent data loss.
- **No bounded staleness**: 매 sync 영원히 안 됨 → "eventual" 의미 무.
- **Vector clock 무한 성장**: 매 GC/pruning 없음 → 매 metadata explosion.
## 🧪 검증 / 중복
- Verified (DeCandia et al., "Dynamo: Amazon's Highly Available Key-value Store", 2007).
- Verified (Brewer, CAP Theorem, PODC 2000).
- Verified (Vogels, "Eventually Consistent", CACM 2009).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — CAP/BASE + CRDT + Dynamo patterns |
@@ -0,0 +1,157 @@
---
id: wiki-2026-0508-excess-property-checking
title: Excess Property Checking
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [TypeScript Excess Property, Strict Object Literal]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [typescript, type-system, structural-typing]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: none
---
# Excess Property Checking
## 매 한 줄
> **"매 fresh object literal 의 only 의 strict property check"**. TypeScript 매 structural typing 매 normally 의 extra properties 의 allow, 매 but 의 fresh object literal 의 directly 의 typed slot 의 assign 시 매 extra properties 의 error 의 raise. Typo 방지 + intent clarity 의 design choice.
## 매 핵심
### 매 Why exists
- 매 structural typing 매 `{a:1, b:2}``{a:number}` 의 assignable.
- 매 그러나 매 literal 매 typo 의 high risk — `{ colour: 'red' }``{ color?: string }` 매 silent ignore.
- 매 TS 매 fresh literal 의 special-case — 매 `Object literal may only specify known properties` 의 error.
### 매 Fresh-ness 매 lost
- 매 variable 의 assign 시 매 widened — `const x = { extra: 1 }; fn(x)` 매 ok.
- 매 spread 매 fresh-ness 의 keep (TS 4.0+).
- 매 type assertion `as T` 매 bypass.
- 매 index signature `[k: string]: ...` 매 disable.
### 매 응용
1. React props typo detection.
2. Config object validation.
3. API request body shape enforcement.
4. Discriminated union narrowing aid.
## 💻 패턴
### Basic excess error
```typescript
interface Point { x: number; y: number }
const p: Point = { x: 1, y: 2, z: 3 };
// ^^^^ Object literal may only specify known properties
```
### Bypass via intermediate variable
```typescript
const tmp = { x: 1, y: 2, z: 3 };
const p: Point = tmp; // OK — fresh-ness lost
// Use this only when extra properties are intentional
```
### Index signature 의 opt-out
```typescript
interface Config {
name: string;
[key: string]: unknown; // 매 extra props 의 allow
}
const c: Config = { name: 'x', debug: true, port: 3000 }; // OK
```
### React props 의 typo guard
```typescript
type ButtonProps = { label: string; onClick: () => void };
function Button(props: ButtonProps) { /* ... */ }
<Button label="Save" onCick={save} />
// ^^^^^ Property 'onCick' does not exist
// Excess property check catches typo at JSX call site
```
### Discriminated union with strict checks
```typescript
type Shape =
| { kind: 'circle'; radius: number }
| { kind: 'square'; side: number };
const s: Shape = { kind: 'circle', radius: 5, side: 3 };
// ^^^^ excess
// 매 kind 의 narrow 의 'circle', 매 side 의 not allowed
```
### Spread 의 preserve fresh-ness (TS 4.0+)
```typescript
type T = { a: number };
const base = { a: 1 };
const x: T = { ...base, b: 2 }; // 매 error — b 의 excess
```
### Optional excess via Exact type emulation
```typescript
type Exact<T, U extends T> = T & {
[K in Exclude<keyof U, keyof T>]: never;
};
function strict<T>() {
return <U extends T>(x: Exact<T, U>): T => x as T;
}
const point = strict<Point>()({ x: 1, y: 2, z: 3 });
// ^^^^ Type 'number' is not assignable to 'never'
// 매 variable assign path 의 also 의 strict
```
### Util: 매 satisfies operator (TS 4.9+)
```typescript
const config = {
endpoint: 'https://api.example.com',
timeout: 5000,
retries: 3,
} satisfies { endpoint: string; timeout: number };
// ^^^^ 매 retries 의 excess error
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Config / DTO literal | 매 default check 의 leverage |
| Plugin system 의 unknown extras | 매 index signature 의 add |
| Test fixture 의 extra debug fields | 매 intermediate var 또는 `as` |
| 매 strict 의 want 의 variable path | 매 `Exact` helper 또는 `satisfies` |
| Library author 의 strict API | 매 `satisfies` 또는 nominal brand |
**기본값**: 매 default behavior 의 leverage — 매 typo 매 catch. 매 escape 매 minimize, 매 `satisfies` 의 prefer.
## 🔗 Graph
- 부모: [[TypeScript]] · [[TypeScript 타입 시스템 (TypeScript Type System)|Type-System]]
- 변형: [[Structural Typing|Structural-Typing]] · [[Satisfies Operator]]
- Adjacent: [[API Response & State Modeling|Discriminated-Unions]]
## 🤖 LLM 활용
**언제**: 매 typo-prone literal — config, props, API body. Schema-bound inputs.
**언제 X**: 매 plugin / metadata 의 extra props 매 intentional — 매 index signature 의 add.
## ❌ 안티패턴
- **`as T` 의 bypass habit**: 매 error 의 mask, 매 typo 의 ship — 매 fix 의 root cause.
- **Index signature 의 over-permissive**: 매 모든 class 매 `[k: string]: any` 의 add — 매 type safety 의 destroy.
- **Intermediate var 의 escape**: 매 `const x = {...}; fn(x)` 매 intent 의 obscure — 매 명시적 cast 의 prefer.
- **`satisfies` 의 ignore**: 매 TS 4.9+ 매 widening 없는 strict literal 의 best tool — 매 underused.
## 🧪 검증 / 중복
- Verified (TS handbook "Object Types"; TS 4.9 release notes).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — excess property check + satisfies/Exact patterns |
@@ -0,0 +1,222 @@
---
id: wiki-2026-0508-executable-documentation
title: Executable Documentation
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Living Documentation, Runnable Docs, Doc Tests]
duplicate_of: none
source_trust_level: A
confidence_score: 0.92
verification_status: applied
tags: [documentation, bdd, doctest, testing, ai]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: polyglot
framework: docs-as-code
---
# Executable Documentation
## 매 한 줄
> **"매 docs 의 CI 의 run — 매 stale 의 fail"**. 매 docs 의 prose 의 not — 매 examples / scenarios / API specs 의 매 actually-execute. 매 1990s Donald Knuth literate programming + Python doctest 의 origin, 매 2020s Cucumber/BDD 의 popularize, 매 2026 의 매 LLM-assisted doc generation + verification 의 standard practice.
## 매 핵심
### 매 종류
1. **Doctest** — 매 docstring 안의 example 의 run (Python doctest, Rust doctests).
2. **BDD** — Gherkin (`Given/When/Then`) 의 step 의 bind (Cucumber, Behave).
3. **API docs from spec** — OpenAPI → contract test (Schemathesis, Dredd).
4. **Notebook docs** — Jupyter / Quarto / Marimo 의 매 cell 의 run.
5. **Markdown code-fence test**`mdsh`, `mdocc`, `markdown-doctest`.
6. **AI-verified docs** — 매 LLM 의 docs 의 read + code 의 inspect + drift 의 detect.
### 매 왜 valuable
- 매 docs 의 truth = code 의 truth.
- 매 onboarding example 의 매 always working.
- 매 API contract 의 single source of truth.
- 매 refactor 시 docs 의 break — 매 catch.
### 매 응용
1. SDK / library docs (매 examples 의 always-correct).
2. API contract testing (OpenAPI + Schemathesis).
3. BDD acceptance tests (매 PM-readable).
4. Tutorial CI (매 step-by-step 의 verify).
## 💻 패턴
### Pattern 1: Python doctest
```python
def fibonacci(n: int) -> int:
"""Return the n-th Fibonacci number.
>>> fibonacci(0)
0
>>> fibonacci(10)
55
>>> [fibonacci(i) for i in range(7)]
[0, 1, 1, 2, 3, 5, 8]
"""
a, b = 0, 1
for _ in range(n): a, b = b, a + b
return a
# pytest --doctest-modules
```
### Pattern 2: Rust doctest
```rust
/// Adds two numbers.
///
/// # Examples
/// ```
/// use mycrate::add;
/// assert_eq!(add(2, 3), 5);
/// ```
pub fn add(a: i32, b: i32) -> i32 { a + b }
// cargo test --doc
```
### Pattern 3: Cucumber BDD (TS)
```gherkin
# features/checkout.feature
Feature: Checkout
Scenario: Successful purchase
Given a cart with 2 items totaling $50
And a valid Stripe token "tok_visa"
When the user submits checkout
Then the order status should be "paid"
And a confirmation email is queued
```
```typescript
// step defs
import { Given, When, Then } from "@cucumber/cucumber";
Given("a cart with {int} items totaling ${int}", function (n, total) {
this.cart = makeCart(n, total);
});
When("the user submits checkout", async function () {
this.result = await checkout(this.cart, this.token);
});
Then("the order status should be {string}", function (status) {
expect(this.result.status).toBe(status);
});
```
### Pattern 4: OpenAPI contract test (Schemathesis)
```bash
schemathesis run https://api.example.com/openapi.json \
--checks all \
--hypothesis-deadline 5000
# 매 매 endpoint 의 spec 의 conform 의 verify (property-based).
```
### Pattern 5: Markdown code-fence test
```typescript
// scripts/test-readme.ts
import { readFileSync } from "fs";
import { execSync } from "child_process";
const md = readFileSync("README.md", "utf8");
const blocks = [...md.matchAll(/```typescript\n([\s\S]*?)\n```/g)];
for (const [, code] of blocks) {
const tmp = `/tmp/snippet-${Date.now()}.ts`;
require("fs").writeFileSync(tmp, code);
execSync(`tsx ${tmp}`, { stdio: "inherit" });
}
```
### Pattern 6: Quarto / Marimo notebook
```python
# 매 marimo notebook — 매 reactive, 매 git-friendly
import marimo as mo
@mo.cell
def fetch():
import requests
return requests.get("https://api.example.com/users").json()
@mo.cell
def show(fetch):
return mo.ui.table(fetch)
# 매 marimo run notebook.py — 매 docs + working app.
```
### Pattern 7: AI-verified doc drift (2026)
```typescript
import Anthropic from "@anthropic-ai/sdk";
const ai = new Anthropic();
async function checkDocDrift(docPath: string, codeGlob: string) {
const docs = readFileSync(docPath, "utf8");
const code = await loadFiles(codeGlob);
const res = await ai.messages.create({
model: "claude-opus-4-7",
max_tokens: 2000,
system: "You verify docs match code. Output JSON: {drifts:[{location, doc_says, code_actually}]}",
messages: [{
role: "user",
content: `DOCS:\n${docs}\n\nCODE:\n${code}\n\nFind drift.`,
}],
});
return JSON.parse(res.content[0].text);
}
// CI 의 매 fail 의 drift 의 found 시.
```
### Pattern 8: Architecture decision record (ADR) with assertion
```markdown
# ADR-0042: Use Postgres for primary store
## Decision
PostgreSQL 16 의 single-tenant DB.
## Verification (run in CI)
\`\`\`bash
# 매 docs 의 claim 의 verify
psql $DATABASE_URL -c "SELECT version();" | grep -q "PostgreSQL 16"
\`\`\`
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Library / SDK | doctest (Python/Rust) |
| REST API | OpenAPI + Schemathesis |
| Acceptance test (PM) | Cucumber BDD |
| Tutorial / book | Markdown code-fence test |
| Data analysis | Quarto / Marimo |
| Architecture docs | AI drift detector |
**기본값**: 매 README 예제 의 매 CI 의 run, 매 API 의 OpenAPI 의 contract test.
## 🔗 Graph
- 부모: [[Docs as Code]]
- 응용: [[OpenAPI]]
- Adjacent: [[Property-Based Testing]] · [[Contract Testing]]
## 🤖 LLM 활용
**언제**: 매 docs drift detection, 매 example generation 의 verify, 매 BDD step 의 generate.
**언제 X**: 매 internal scratchpad notes — 매 over-engineering.
## ❌ 안티패턴
- **Doctest 의 too many**: 매 docstring 의 cluttered — 매 separate test 가 better.
- **BDD 의 implementation detail**: 매 Given/When/Then 이 SQL 의 mention — 매 wrong abstraction.
- **Spec drift**: 매 OpenAPI 의 stale — 매 generate-from-code or test 의 mandatory.
- **No CI**: 매 executable 의 X — 매 prose docs 의 same.
## 🧪 검증 / 중복
- Verified (Knuth literate programming, Python doctest stdlib, Cucumber.io, Schemathesis docs, Marimo docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — doctest/BDD/OpenAPI/Marimo/AI-drift |
@@ -0,0 +1,217 @@
---
id: wiki-2026-0508-exergaming
title: Exergaming
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Exergaming, Exergame, Fitness Gaming, Active Gaming]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [game-design, fitness, vr, ar, health]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: design
framework: vr-fitness
---
# Exergaming
## 매 한 줄
> **"매 game mechanic 을 physical exercise 와 결합한다"**. 매 Exergaming은 DDR(1998) 의 dance arcade에서 시작 → Wii Fit(2007) mass-market 진입 → Pokemon Go(2016) AR walking → 매 2026 Quest 3/Vision Pro VR fitness 의 mainstream 시대. 매 sedentary lifestyle 대응 + intrinsic motivation 결합.
## 매 핵심
### 매 Why it works
- **Intrinsic motivation**: 매 fun → exercise (vs treadmill 의 외재 동기)
- **Flow**: 매 difficulty/skill match — 매 exercise 인지 인식 안 됨
- **Social**: 매 multiplayer 가 적정한 peer pressure
- **Telemetry feedback**: 매 calorie, heart rate 즉시 가시화
### 매 Technology stack
- **Camera-based** (Kinect, smartphone pose): 매 markerless tracking
- **Motion controller** (Wii, Quest, PSVR2): 매 6DOF tracking
- **Wearable** (HRM, Apple Watch): 매 heart rate / step
- **GPS-based** (Pokemon Go, Zwift): 매 outdoor / indoor cycling
### 매 응용
1. VR fitness (Beat Saber, Supernatural, Les Mills Bodycombat).
2. Outdoor AR (Pokemon Go, Zombies Run!).
3. Console fitness (Ring Fit Adventure, Just Dance).
4. Indoor cycling (Zwift, Peloton + game).
5. Rehab exergames (stroke recovery, balance training).
## 💻 패턴
### Pose tracking (MediaPipe + Python)
```python
import cv2
import mediapipe as mp
mp_pose = mp.solutions.pose
pose = mp_pose.Pose(min_detection_confidence=0.7)
cap = cv2.VideoCapture(0)
squat_count = 0
in_squat = False
while cap.isOpened():
ret, frame = cap.read()
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = pose.process(rgb)
if results.pose_landmarks:
hip_y = results.pose_landmarks.landmark[24].y
knee_y = results.pose_landmarks.landmark[26].y
# 매 hip drops below knee = squat
if hip_y > knee_y - 0.05 and not in_squat:
in_squat = True
elif hip_y < knee_y - 0.15 and in_squat:
squat_count += 1
in_squat = False
print(f"매 squat #{squat_count}")
```
### Calorie estimation (METS + HR)
```python
def estimate_calories(weight_kg: float, duration_min: float,
avg_hr: float, age: int, is_male: bool) -> float:
# 매 Keytel formula
if is_male:
cal_per_min = (-55.0969 + 0.6309*avg_hr + 0.1988*weight_kg + 0.2017*age) / 4.184
else:
cal_per_min = (-20.4022 + 0.4472*avg_hr - 0.1263*weight_kg + 0.074*age) / 4.184
return max(0, cal_per_min * duration_min)
```
### Beat Saber-style hit detection (Unity)
```csharp
public class Saber : MonoBehaviour
{
public Vector3 prevPos;
public float minSpeedToCut = 2f;
void OnTriggerEnter(Collider block)
{
var velocity = (transform.position - prevPos) / Time.deltaTime;
if (velocity.magnitude < minSpeedToCut) return;
var blockNormal = block.transform.up;
var dot = Vector3.Dot(velocity.normalized, blockNormal);
if (dot < -0.7f) { // 매 cutting in correct direction
block.GetComponent<Block>().Cut();
ScoreSystem.Add(100);
}
}
void LateUpdate() { prevPos = transform.position; }
}
```
### Heart rate zone (Apple Watch / WatchOS)
```swift
import HealthKit
let store = HKHealthStore()
let hrType = HKQuantityType.quantityType(forIdentifier: .heartRate)!
let query = HKAnchoredObjectQuery(type: hrType, predicate: nil,
anchor: nil, limit: HKObjectQueryNoLimit) {
_, samples, _, _, _ in
for sample in samples as? [HKQuantitySample] ?? [] {
let bpm = sample.quantity.doubleValue(for: HKUnit(from: "count/min"))
let zone = hrZone(bpm: bpm, age: 30)
// game difficulty zone 4 reduce
GameDifficulty.adjust(zone: zone)
}
}
store.execute(query)
func hrZone(bpm: Double, age: Int) -> Int {
let max_hr = 220.0 - Double(age)
let pct = bpm / max_hr
switch pct {
case ..<0.6: return 1
case ..<0.7: return 2
case ..<0.8: return 3
case ..<0.9: return 4
default: return 5
}
}
```
### GPS-based step (React Native)
```typescript
import Geolocation from '@react-native-community/geolocation';
let totalDistance = 0;
let prev: GeolocationPosition | null = null;
Geolocation.watchPosition((position) => {
if (prev) {
const dist = haversine(
prev.coords.latitude, prev.coords.longitude,
position.coords.latitude, position.coords.longitude
);
if (dist < 50 && position.coords.speed < 5) { // 매 walking
totalDistance += dist;
spawnPokemonIfDistanceThreshold(totalDistance);
}
}
prev = position;
}, null, { enableHighAccuracy: true, distanceFilter: 5 });
```
### Adaptive difficulty by HR
```python
def adjust_intensity(current_hr: float, target_zone: tuple,
game_difficulty: float) -> float:
low, high = target_zone # 매 e.g. (140, 160) for zone 3
if current_hr < low:
return min(1.0, game_difficulty + 0.1) # 매 ramp up
elif current_hr > high:
return max(0.1, game_difficulty - 0.15) # 매 cool down
return game_difficulty
```
## 매 결정 기준
| 상황 | Platform |
|---|---|
| High-intensity cardio | VR (Beat Saber, Supernatural) |
| Outdoor walking | AR mobile (Pokemon Go) |
| Family casual | Console (Just Dance, Ring Fit) |
| Strength training | Wearable + companion app |
| Rehab / elderly | Camera-based (low barrier) |
| Cycling | Smart trainer + Zwift |
**기본값**: 매 target heart rate zone 3-4, session 20-45min, gamified streak + progression.
## 🔗 Graph
- 부모: [[Game Design]]
- 변형: [[Active Gaming]]
- 응용: [[Beat Saber]]
- Adjacent: [[Gamification]] · [[Pose Estimation]]
## 🤖 LLM 활용
**언제**: 매 fitness app design, exercise game mechanic 설계, HR-based difficulty algorithm.
**언제 X**: 매 medical-grade rehab — 매 clinical validation 필요, LLM scope 외.
## ❌ 안티패턴
- **No safety check**: 매 elderly user 에게 high-intensity 강제 → 매 injury risk.
- **Overgamification**: 매 streak 압박이 매 overtraining 유발.
- **No rest day**: 매 daily quest 만 있고 recovery 무시.
- **Inaccurate calorie**: 매 inflated number → user trust 상실.
## 🧪 검증 / 중복
- Verified (Peng et al., "Is playing exergames really exercising?", 2013, systematic review).
- Verified (Quest 3 fitness API, Meta Health, 2024).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — VR fitness + Pokemon Go + pose tracking |
@@ -0,0 +1,210 @@
---
id: wiki-2026-0508-experience-sampling-method
title: Experience Sampling Method
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [ESM, EMA, Ecological Momentary Assessment, Diary Studies]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [research-methodology, psychology, ux-research, mobile]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: react-native
---
# Experience Sampling Method
## 매 한 줄
> **"매 retrospection bias 의 in-the-moment self-report 의 replace"**. Experience Sampling Method (ESM, Csikszentmihalyi & Larson 1987) 매 participants 의 day 의 multiple times 의 random/scheduled prompt, 매 current activity/affect/context 의 record. Mobile-era 매 EMA (Ecological Momentary Assessment) 의 generalize — 매 mental health, UX, productivity research 의 gold standard.
## 매 핵심
### 매 Why ESM
- **Retrospection bias**: 매 "지난주 어땠나" 매 peak-end bias, mood-congruent recall 의 distort.
- **Ecological validity**: 매 in-context 매 lab 의 not-replicate.
- **Within-subject variance**: 매 person × situation 의 interaction 의 capture.
### 매 Sampling schedules
- **Signal-contingent**: 매 random beep 매 day 매 6-8 prompts.
- **Interval-contingent**: 매 fixed times (9am/12pm/3pm/6pm).
- **Event-contingent**: 매 specific event (meal, exercise) 의 trigger.
- **Hybrid**: 매 baseline random + event triggers.
### 매 응용
1. Mood / affect tracking (depression, bipolar).
2. Pain studies (chronic pain).
3. UX product research — feature use in-context.
4. Flow state research (Csikszentmihalyi original).
5. LLM agent behavior tracking — analog 매 process.
## 💻 패턴
### Mobile prompt scheduler (React Native)
```typescript
import * as Notifications from 'expo-notifications';
interface ESMConfig {
startHour: number; endHour: number;
promptsPerDay: number;
minIntervalMinutes: number;
}
async function schedulePrompts(cfg: ESMConfig, days = 7) {
const slots = generateRandomSlots(cfg, days);
for (const slot of slots) {
await Notifications.scheduleNotificationAsync({
content: {
title: 'Quick check-in (30s)',
body: 'How are you feeling right now?',
data: { promptId: slot.id, scheduledFor: slot.time.toISOString() },
},
trigger: { date: slot.time },
});
}
}
function generateRandomSlots(cfg: ESMConfig, days: number) {
const slots = [];
for (let d = 0; d < days; d++) {
const dayStart = new Date();
dayStart.setDate(dayStart.getDate() + d);
const windowMs = (cfg.endHour - cfg.startHour) * 3600_000;
const minGap = cfg.minIntervalMinutes * 60_000;
const times: number[] = [];
while (times.length < cfg.promptsPerDay) {
const candidate = Math.random() * windowMs;
if (times.every(t => Math.abs(t - candidate) >= minGap)) {
times.push(candidate);
}
}
times.sort((a, b) => a - b).forEach((offset, i) => {
const t = new Date(dayStart);
t.setHours(cfg.startHour, 0, 0, 0);
t.setTime(t.getTime() + offset);
slots.push({ id: `${d}-${i}`, time: t });
});
}
return slots;
}
```
### Brief response form (PANAS-short, 30s budget)
```typescript
interface ESMResponse {
promptId: string;
respondedAt: Date;
latencyMs: number;
affect: {
valence: number; // -3..+3
arousal: number; // -3..+3
};
activity: string; // dropdown: work | social | rest | exercise | other
social: 'alone' | 'with_others';
freeText?: string;
}
```
### Compliance tracking
```typescript
function complianceMetrics(responses: ESMResponse[], scheduled: number) {
const completed = responses.length;
const onTime = responses.filter(r => r.latencyMs < 15 * 60_000).length;
const meanLatency = responses.reduce((s, r) => s + r.latencyMs, 0) / completed;
return {
completionRate: completed / scheduled, // target > 0.7
onTimeRate: onTime / scheduled, // target > 0.5
meanLatencyMin: meanLatency / 60_000,
};
}
```
### Multilevel analysis (within vs between)
```python
import statsmodels.formula.api as smf
# 매 each row 매 prompt response, 매 participant_id 매 grouping
model = smf.mixedlm(
'valence ~ activity + social + time_of_day',
data=df,
groups=df['participant_id'],
re_formula='~time_of_day',
).fit()
print(model.summary())
# 매 within-person variance (situation) 매 between-person (trait) 의 separate
```
### Sliding-window mood detection
```typescript
function detectMoodEpisode(responses: ESMResponse[], windowDays = 7, threshold = -1.5) {
const sorted = [...responses].sort((a, b) =>
a.respondedAt.getTime() - b.respondedAt.getTime());
const episodes = [];
for (let i = 0; i < sorted.length; i++) {
const start = sorted[i].respondedAt;
const end = new Date(start.getTime() + windowDays * 86400_000);
const window = sorted.filter(r =>
r.respondedAt >= start && r.respondedAt <= end);
if (window.length < 5) continue;
const meanV = window.reduce((s, r) => s + r.affect.valence, 0) / window.length;
if (meanV < threshold) episodes.push({ start, end, meanV, n: window.length });
}
return mergeOverlapping(episodes);
}
```
### Privacy: 매 on-device aggregation
```typescript
// 매 raw responses 매 device 의 stay, 매 weekly summary 만 의 server 의 send
async function uploadWeeklySummary(responses: ESMResponse[]) {
const summary = {
week: getCurrentWeek(),
n: responses.length,
valenceMean: mean(responses.map(r => r.affect.valence)),
valenceStd: std(responses.map(r => r.affect.valence)),
activityHistogram: histogram(responses.map(r => r.activity)),
};
await api.post('/esm/summary', summary);
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Trait measurement (depression baseline) | 매 ESM unnecessary — 매 single questionnaire 매 fine |
| Within-day variation 의 question | 매 ESM signal-contingent |
| Specific event 매 rare | 매 event-contingent |
| Compliance fragile | 매 prompt count 의 reduce, 매 incentive |
| Privacy-sensitive (clinical) | 매 on-device aggregation 또는 federated |
**기본값**: 매 6-8 prompts/day, 매 14 days, 매 30s response — 매 compliance > 70% 의 target.
## 🔗 Graph
- 부모: [[Research-Methodology]]
- 변형: [[Ecological-Momentary-Assessment]]
- 응용: [[Flow_State|Flow-State]]
## 🤖 LLM 활용
**언제**: 매 in-the-moment subjective state 의 measure. Within-person variance 의 study. Retrospective bias 의 likely.
**언제 X**: 매 stable trait. 매 single-shot decision study. 매 intrusive sampling 매 acceptable 의 X.
## ❌ 안티패턴
- **Too many prompts**: 매 12+/day 매 fatigue → compliance crash.
- **Long forms**: 매 5min response 매 ecological 의 break.
- **Ignoring missing-not-at-random**: 매 prompts during depressive episode 매 skipped — 매 selection bias.
- **Cross-sectional analysis 의 hierarchical data**: 매 multilevel model 의 use, 매 OLS 의 std error 의 underestimate.
## 🧪 검증 / 중복
- Verified (Csikszentmihalyi & Larson 1987 JNMD; Shiffman et al. 2008 Ann Rev Clin Psych).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — ESM scheduler + analysis + privacy patterns |
@@ -0,0 +1,201 @@
---
id: wiki-2026-0508-exploration-vs-exploitation
title: Exploration vs Exploitation
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Explore-Exploit, Multi-Armed Bandit Tradeoff, RL Tradeoff]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [reinforcement-learning, bandits, decision-theory, optimization]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: python
framework: numpy
---
# Exploration vs Exploitation
## 매 한 줄
> **"매 known-best 의 exploit 의 unknown 의 explore 의 fundamental tradeoff"**. Exploration-exploitation dilemma 매 RL · bandits · A/B testing 의 core — 매 current best action 의 only 의 take 시 매 better unknown 의 miss, 매 too much explore 시 매 reward 의 burn. Optimal balance 매 horizon, prior, regret budget 의 function.
## 매 핵심
### 매 Spectrum
- **Pure exploit (greedy)**: 매 always 매 argmax Q(a) — 매 local optimum trap.
- **Pure explore (random)**: 매 always uniform — 매 expected regret O(T).
- **ε-greedy**: 매 prob ε 매 explore, 매 prob 1−ε 매 exploit.
- **UCB**: 매 confidence-bounded 매 deterministic explore.
- **Thompson Sampling**: 매 posterior sampling 매 Bayesian optimal.
### 매 Regret bounds
- 매 ε-greedy(static): O(T).
- 매 ε-greedy(decaying 1/t): O(log T).
- 매 UCB1: O(log T) — provably tight for stochastic bandit.
- 매 Thompson Sampling: matches Lai-Robbins lower bound.
### 매 응용
1. A/B/n testing — adaptive traffic allocation.
2. Recommender systems — cold start.
3. Hyperparameter tuning (Optuna, Vizier).
4. RL games — Atari, AlphaGo MCTS.
5. LLM 매 sampling temperature, top-p.
6. Drug trials — bandit-style adaptive design.
## 💻 패턴
### ε-greedy bandit
```python
import numpy as np
class EpsilonGreedy:
def __init__(self, k, eps=0.1):
self.k = k
self.eps = eps
self.Q = np.zeros(k)
self.N = np.zeros(k)
def select(self):
if np.random.rand() < self.eps:
return np.random.randint(self.k)
return int(np.argmax(self.Q))
def update(self, a, r):
self.N[a] += 1
self.Q[a] += (r - self.Q[a]) / self.N[a]
```
### UCB1
```python
class UCB1:
def __init__(self, k):
self.k, self.t = k, 0
self.Q = np.zeros(k)
self.N = np.zeros(k)
def select(self):
self.t += 1
for a in range(self.k):
if self.N[a] == 0:
return a # cold-start each arm once
ucb = self.Q + np.sqrt(2 * np.log(self.t) / self.N)
return int(np.argmax(ucb))
def update(self, a, r):
self.N[a] += 1
self.Q[a] += (r - self.Q[a]) / self.N[a]
```
### Thompson Sampling (Bernoulli)
```python
class ThompsonBernoulli:
def __init__(self, k):
self.alpha = np.ones(k) # successes + 1
self.beta = np.ones(k) # failures + 1
def select(self):
samples = np.random.beta(self.alpha, self.beta)
return int(np.argmax(samples))
def update(self, a, r):
if r > 0: self.alpha[a] += 1
else: self.beta[a] += 1
```
### Decaying ε schedule
```python
def epsilon(t, start=1.0, end=0.05, decay=10000):
return end + (start - end) * np.exp(-t / decay)
# DQN-style: 매 early episodes 의 explore-heavy, 매 late 의 exploit
```
### Boltzmann (softmax) exploration
```python
def softmax_select(Q, tau=1.0):
p = np.exp(Q / tau)
p /= p.sum()
return np.random.choice(len(Q), p=p)
# tau→0 매 greedy, tau→∞ 매 uniform
```
### Contextual bandit (LinUCB)
```python
class LinUCB:
def __init__(self, k, d, alpha=1.0):
self.A = [np.eye(d) for _ in range(k)]
self.b = [np.zeros(d) for _ in range(k)]
self.alpha = alpha
def select(self, x): # context vector
ucb = []
for a in range(len(self.A)):
Ainv = np.linalg.inv(self.A[a])
theta = Ainv @ self.b[a]
mean = theta @ x
bonus = self.alpha * np.sqrt(x @ Ainv @ x)
ucb.append(mean + bonus)
return int(np.argmax(ucb))
def update(self, a, x, r):
self.A[a] += np.outer(x, x)
self.b[a] += r * x
```
### LLM sampling 의 explore-exploit
```python
# temperature=0 → exploit (deterministic argmax)
# temperature=1 → explore (full distribution)
# top-p=0.9 → constrained explore (nucleus)
def sample_token(logits, temperature=0.7, top_p=0.9):
logits = logits / temperature
probs = softmax(logits)
sorted_idx = np.argsort(probs)[::-1]
cum = np.cumsum(probs[sorted_idx])
cutoff = np.searchsorted(cum, top_p) + 1
keep = sorted_idx[:cutoff]
p = probs[keep] / probs[keep].sum()
return np.random.choice(keep, p=p)
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Stationary stochastic bandit | 매 UCB1 또는 Thompson |
| Bernoulli reward | 매 Thompson Beta-binomial |
| Contextual features 의 available | 매 LinUCB / NeuralBandit |
| Non-stationary (drift) | 매 sliding-window UCB / discounted TS |
| Deep RL | 매 ε-greedy decay 또는 noisy nets |
| LLM creative generation | 매 temperature 0.7-1.0 + top-p 0.9 |
**기본값**: 매 Thompson Sampling — 매 strong empirical 의 winner, 매 simple implementation.
## 🔗 Graph
- 부모: [[Reinforcement-Learning]] · [[Decision Theory]]
- 변형: [[Multi-Armed-Bandit]]
- 응용: [[Recommender-Systems]] · [[Hyperparameters|Hyperparameter-Tuning]] · [[MCTS]]
- Adjacent: [[Bayesian-Optimization]] · [[Active Learning]] · [[LLM-Sampling]]
## 🤖 LLM 활용
**언제**: 매 sequential decision 매 reward feedback. Cold-start recommender. A/B 의 multi-arm 의 generalize.
**언제 X**: 매 known reward distribution + horizon→∞ — 매 closed-form optimal. Single-shot decision.
## 어려운 점 (안티패턴)
- **Static ε too high**: 매 ε=0.5 forever — 매 final 50% traffic 의 random arm 의 burn. Decay 의 use.
- **No cold-start arms**: 매 UCB 의 N[a]=0 의 not-handled — 매 inf 의 produce, 매 each arm 의 1 초기 pull 의 require.
- **Non-stationarity ignored**: 매 reward drift 의 discount 없이 의 stale Q value 의 trust.
- **Reward leakage**: 매 future info 매 leak — 매 fake "exploit" 매 actually 의 cheat.
## 🧪 검증 / 중복
- Verified (Sutton & Barto Ch. 2; Lai-Robbins 1985; Russo et al. "Tutorial on Thompson Sampling" 2018).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — explore-exploit + 7 algorithm patterns |
@@ -0,0 +1,206 @@
---
id: wiki-2026-0508-extract-class-클래스-추출하기
title: Extract Class (클래스 추출하기)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Extract Class, 클래스 추출, Refactoring]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [refactoring, fowler, srp, oop]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: none
---
# Extract Class (클래스 추출하기)
## 매 한 줄
> **"매 too-much-doing class 의 cohesive subset 의 split"**. Extract Class 매 Fowler refactoring catalog 의 core move — 매 single class 매 multiple responsibilities 의 carry, 매 data + methods 의 cohesive cluster 의 new class 의 extract. SRP 의 enforcement.
## 매 핵심
### 매 Smell signals
- 매 class 매 200+ lines 의 grow.
- 매 fields 의 subset 매 always 의 used together (e.g., `street/city/zip` 의 always together).
- 매 methods 매 disjoint groups 의 form — 매 group A methods 매 group A fields only 의 use.
- 매 class name 매 vague — `Manager`, `Helper`, `Util`.
### 매 Mechanics (Fowler)
1. 매 responsibility 의 identify — 매 split point.
2. 매 new child class 의 create.
3. 매 parent → child reference 의 establish.
4. 매 fields 의 move (Move Field).
5. 매 methods 의 move (Move Method) — 매 leaves first.
6. 매 child interface 의 review — 매 internal exposure 의 minimize.
7. 매 expose: 매 child 의 public 의 또는 parent-only 의 decision.
### 매 응용
1. Person → Person + TelephoneNumber.
2. Order → Order + ShippingAddress + BillingAddress.
3. UserService → UserService + AuthService + ProfileService.
4. GameEntity → Position + Velocity + Health (ECS).
## 💻 패턴
### Before — God class
```typescript
class Person {
name: string;
officeAreaCode: string;
officeNumber: string;
getTelephoneNumber(): string {
return `(${this.officeAreaCode}) ${this.officeNumber}`;
}
}
```
### After — Extract Class
```typescript
class TelephoneNumber {
constructor(public areaCode: string, public number: string) {}
toString(): string { return `(${this.areaCode}) ${this.number}`; }
}
class Person {
constructor(
public name: string,
private officeTelephone: TelephoneNumber,
) {}
get telephoneNumber(): string { return this.officeTelephone.toString(); }
// delegate accessors during transition
get officeAreaCode() { return this.officeTelephone.areaCode; }
set officeAreaCode(v: string) { this.officeTelephone.areaCode = v; }
}
```
### Address extraction
```typescript
// Before
class Order {
customerName: string;
street: string; city: string; zipCode: string; country: string;
shippingCost: number;
}
// After
class Address {
constructor(
public street: string,
public city: string,
public zipCode: string,
public country: string,
) {}
format(): string { return `${this.street}, ${this.city} ${this.zipCode}, ${this.country}`; }
isInternational(home: string) { return this.country !== home; }
}
class Order {
constructor(
public customerName: string,
public shippingAddress: Address,
public shippingCost: number,
) {}
}
```
### Service split (SRP)
```typescript
// Before — 600 LOC
class UserService {
signup() { /* ... */ }
login() { /* ... */ }
resetPassword() { /* ... */ }
updateProfile() { /* ... */ }
uploadAvatar() { /* ... */ }
getPreferences() { /* ... */ }
}
// After
class AuthService {
signup() {} login() {} resetPassword() {}
}
class ProfileService {
updateProfile() {} uploadAvatar() {} getPreferences() {}
}
// UserService 의 orchestration only 의 keep
```
### ECS-style field group extraction
```typescript
// Before — game entity 의 carries everything
class Enemy {
x: number; y: number; vx: number; vy: number;
hp: number; maxHp: number; armor: number;
spriteId: string; animFrame: number;
}
// After — components
class Position { constructor(public x: number, public y: number) {} }
class Velocity { constructor(public vx: number, public vy: number) {} }
class Health { constructor(public hp: number, public maxHp: number, public armor = 0) {} }
class Sprite { constructor(public id: string, public frame = 0) {} }
class Enemy {
constructor(
public position: Position,
public velocity: Velocity,
public health: Health,
public sprite: Sprite,
) {}
}
```
### Incremental migration via delegation
```typescript
class Person {
private _phone = new TelephoneNumber('', '');
// Old API 의 keep working
get officeNumber() { return this._phone.number; }
set officeNumber(v: string) { this._phone.number = v; }
// New API 의 prefer
get phone() { return this._phone; }
}
// Phase 1: delegate. Phase 2: callers migrate to .phone. Phase 3: remove old getters.
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Class < 100 LOC, single concept | 매 extract 매 X — 매 premature |
| Field subset always 의 together | 매 Extract Class |
| Two distinct responsibilities | 매 Extract Class + Move Method |
| Component reuse 의 needed (game) | 매 ECS-style components 의 extract |
| Public API 의 break 의 dangerous | 매 delegating accessors 의 transition |
**기본값**: 매 class 매 2 의 distinct responsibility 의 carry 의 extract — 매 cohesion > 1 class.
## 🔗 Graph
- 부모: [[Refactoring_Best_Practices|Refactoring]] · [[SOLID]]
- 응용: [[Single Responsibility Principle (SRP)|Single-Responsibility-Principle]] · [[Entity-Component-System]]
## 🤖 LLM 활용
**언제**: 매 class 매 200+ LOC, 매 multiple distinct concerns. Field cluster 의 always 의 co-occur. Test setup 매 unrelated mocks 의 require.
**언제 X**: 매 small DTO. 매 abstraction 의 cost > readability gain (매 over-extraction).
## ❌ 안티패턴
- **Anemic extraction**: 매 fields only 의 move, 매 methods 매 parent 의 stay — 매 just data bag 의 result. Methods 의 follow 의 must.
- **Reverse coupling**: 매 child 매 parent 의 reference back — 매 cyclic dependency. One-way reference 의 keep.
- **Premature extract**: 매 50 LOC class 의 split — 매 navigation overhead > clarity.
- **Public sprawl**: 매 child 의 immediately public — 매 hide 매 first, 매 expose 의 demand 의 occur 시.
## 🧪 검증 / 중복
- Verified (Fowler "Refactoring" 2nd ed., Ch. 7).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Extract Class refactoring 의 mechanics + 5 patterns |
@@ -0,0 +1,163 @@
---
id: wiki-2026-0508-extract-method-함수-추출하기
title: Extract Method (함수 추출하기)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Extract Function, 함수 추출]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [refactoring, clean-code, method]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: refactoring
---
# Extract Method (함수 추출하기)
## 매 한 줄
> **"매 code fragment 가 의도를 가질 때, 매 그 의도를 이름으로 만든다"**. 매 Fowler *Refactoring* (1999, 2018) 의 매 most-used refactoring — 매 long method 를 작은 well-named function 으로 쪼개 매 readability + reusability 의 동시 확보. 2026 IDE (IntelliJ, VS Code, Cursor) 의 자동 refactor 로 매 cost 가 사실상 0.
## 매 핵심
### 매 trigger
- 매 method 가 한 화면을 넘는다.
- 매 comment 로 "이 부분은 X 한다" 라고 설명하고 있다 → 매 그 X 가 method name.
- 매 동일 logic 의 duplication.
- 매 nested conditional 의 가독성 hurt.
### 매 mechanic (Fowler)
1. 매 새 함수 의 create — intent-revealing name.
2. 매 fragment 를 새 함수로 copy.
3. 매 local variable 의 scope 분석 → parameter / return value 결정.
4. 매 원래 자리에 call 로 replace.
5. 매 test 실행 (매 step 마다).
### 매 응용
1. Long Method 의 fix.
2. Duplicate Code 의 removal.
3. Replace Temp with Query 의 stepping stone.
4. 매 LLM-assisted refactor 의 safest primitive.
## 💻 패턴
### Before (long method)
```ts
function printOwing(invoice: Invoice) {
let outstanding = 0;
console.log("***********************");
console.log("**** Customer Owes ****");
console.log("***********************");
for (const o of invoice.orders) outstanding += o.amount;
const today = new Date();
invoice.dueDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 30);
console.log(`name: ${invoice.customer}`);
console.log(`amount: ${outstanding}`);
console.log(`due: ${invoice.dueDate.toLocaleDateString()}`);
}
```
### After (extracted)
```ts
function printOwing(invoice: Invoice) {
printBanner();
const outstanding = calculateOutstanding(invoice);
recordDueDate(invoice);
printDetails(invoice, outstanding);
}
function printBanner() {
console.log("***********************");
console.log("**** Customer Owes ****");
console.log("***********************");
}
function calculateOutstanding(invoice: Invoice): number {
return invoice.orders.reduce((sum, o) => sum + o.amount, 0);
}
function recordDueDate(invoice: Invoice) {
const today = new Date();
invoice.dueDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 30);
}
function printDetails(invoice: Invoice, outstanding: number) {
console.log(`name: ${invoice.customer}`);
console.log(`amount: ${outstanding}`);
console.log(`due: ${invoice.dueDate.toLocaleDateString()}`);
}
```
### Extract with multiple return (TS tuple)
```ts
function summarize(xs: number[]): { sum: number; avg: number } {
return { sum: total(xs), avg: total(xs) / xs.length };
}
function total(xs: number[]) { return xs.reduce((a, b) => a + b, 0); }
```
### Extract from conditional (Decompose Conditional)
```ts
// before
if (date.before(SUMMER_START) || date.after(SUMMER_END)) charge = qty * winterRate + winterFee;
else charge = qty * summerRate;
// after
charge = isSummer(date) ? summerCharge(qty) : winterCharge(qty);
function isSummer(d: Date) { return !d.before(SUMMER_START) && !d.after(SUMMER_END); }
```
### IDE shortcut (VS Code / Cursor)
```
Select code → Cmd+. → "Extract to function in module scope"
# 매 zero-cost — 매 Fowler 가 1999 에 손으로 하던 것
```
### LLM-assisted (Claude Code)
```
"이 함수에서 outstanding 계산 부분을 calculateOutstanding 으로 extract"
→ 매 LLM 이 mechanic 의 1-5 를 자동 수행 + test 보존 검증
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Fragment 에 의도 있음 | Extract Method |
| Single expression with confusing name | Extract Variable |
| Class 가 너무 비대 | Extract Class (after multiple Extract Method) |
| 매 한 번만 쓰이고 trivial | 매 inline 유지 — 매 over-extraction 회피 |
**기본값**: 매 의심되면 extract — 매 IDE 가 자동, 매 inline 으로 되돌리기도 trivial.
## 🔗 Graph
- 부모: [[Refactoring_Best_Practices|Refactoring]] · [[Clean Code]]
- 변형: [[Extract Class]]
- Adjacent: [[Inline Method]] (매 inverse) · [[Single Responsibility]]
## 🤖 LLM 활용
**언제**: 매 long method / duplicated block 발견 시 즉시 propose.
**언제 X**: 매 hot path 의 micro-optimization (function call overhead) — 매 측정 기반.
## ❌ 안티패턴
- **Over-extraction**: 매 1-2 line trivial 도 extract → 매 indirection 폭발.
- **Bad name**: `helper1`, `doStuff` — 매 의도 의 표현 실패.
- **Hidden side effect**: 매 pure name 으로 보이는데 매 mutation 수행.
- **Premature extraction without test**: 매 mechanic step 5 건너뛰기 → silent regression.
## 🧪 검증 / 중복
- Verified (Fowler *Refactoring* 2nd ed. 2018 Ch. 6, Beck *Tidy First?* 2024).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Fowler mechanic + modern IDE/LLM workflow 정리 |
@@ -0,0 +1,180 @@
---
id: wiki-2026-0508-fomo-fear-of-missing-out
title: FOMO (Fear of Missing Out)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [FOMO, Fear of Missing Out, 포모]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [game-design, monetization, psychology, behavioral]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: design
framework: live-ops
---
# FOMO (Fear of Missing Out)
## 매 한 줄
> **"매 놓칠지 모른다는 불안이 행동을 유발한다"**. 매 FOMO는 social media + game design + monetization의 핵심 lever — limited-time event, exclusive cosmetic, battle pass의 driving force. 2026 mobile gaming revenue의 60%+가 매 FOMO mechanic 기반.
## 매 핵심
### 매 심리학 base
- **Loss aversion** (Kahneman): 매 loss는 gain보다 2x painful
- **Social comparison** (Festinger): 매 peer가 가진 것 → 매 desire
- **Scarcity heuristic**: 매 rare = valuable 의 자동 추론
- 매 FOMO는 매 evolved survival instinct (놓치면 자원 부족)의 hijack
### 매 Game Design lever
- **Time-gated content**: 매 event 7일, 매 daily login bonus
- **Limited cosmetics**: 매 "이 skin은 다시는 안 나옴" claim
- **Battle pass FOMO**: 매 시즌 끝나면 보상 영원히 lost
- **Push notification**: 매 "친구가 1위!" — direct social FOMO
### 매 응용
1. Fortnite item shop (24h rotation).
2. Genshin Impact limited banner (5-star character 일정 기간만).
3. Duolingo streak (매 끊기면 손실감).
4. Instagram/TikTok stories (24h disappearance).
## 💻 패턴
### Limited-Time Event Logic (Unity C#)
```csharp
public class LimitedEvent : MonoBehaviour
{
public DateTime startUtc;
public DateTime endUtc;
public Reward exclusiveReward;
void Update()
{
var now = DateTime.UtcNow;
if (now < startUtc) ShowCountdown(startUtc - now, "starts in");
else if (now < endUtc) ShowCountdown(endUtc - now, "ends in");
else HideEvent();
}
void ShowCountdown(TimeSpan ts, string prefix)
{
// 매 urgency UI: red text, ticking sound
countdownText.text = $"{prefix} {ts.Hours}h {ts.Minutes}m";
countdownText.color = ts.TotalHours < 1 ? Color.red : Color.white;
}
}
```
### Battle Pass Tier (TypeScript)
```typescript
interface BattlePass {
seasonEndUtc: Date;
tiers: Tier[];
userXP: number;
}
function unclaimedRewards(bp: BattlePass): number {
const currentTier = Math.floor(bp.userXP / 1000);
return bp.tiers
.slice(0, currentTier + 1)
.filter(t => !t.claimed && !t.locked)
.length;
}
// 매 push notification trigger
if (unclaimedRewards(bp) > 0 && hoursUntilEnd(bp) < 48) {
sendPush(`${unclaimedRewards(bp)} 보상이 곧 사라집니다!`);
}
```
### Streak Reset Warning (Python)
```python
from datetime import datetime, timedelta
def check_streak_at_risk(user):
last_active = user.last_login
now = datetime.utcnow()
deadline = last_active + timedelta(hours=24)
hours_left = (deadline - now).total_seconds() / 3600
if 0 < hours_left < 4 and user.streak_days >= 7:
send_notification(
user,
f"매 {user.streak_days}일 연속 기록이 {int(hours_left)}시간 후 끊깁니다"
)
```
### Gacha Pity System (showing scarcity)
```python
class GachaBanner:
def __init__(self):
self.pity_counter = 0
self.featured_5star_rate = 0.006
self.hard_pity = 90
def pull(self) -> Item:
self.pity_counter += 1
if self.pity_counter >= self.hard_pity:
self.pity_counter = 0
return self.featured_5star
if random.random() < self.featured_5star_rate:
self.pity_counter = 0
return self.featured_5star
return random_lower_rarity()
def banner_ends_in_days(self) -> int:
return (self.end_date - datetime.now()).days
```
### Social FOMO Push (FCM)
```python
def notify_friend_milestone(user_id: int, friend_id: int, achievement: str):
user = get_user(user_id)
friend = get_user(friend_id)
fcm.send(
token=user.fcm_token,
title=f"{friend.name}님이 {achievement} 달성!",
body="매 친구를 따라잡으세요",
data={"deeplink": f"profile/{friend_id}"}
)
```
## 매 결정 기준
| 상황 | FOMO 강도 |
|---|---|
| Casual mobile game | Low — soft daily login bonus |
| Live-service multiplayer | Medium — battle pass, seasonal events |
| Gacha / collection RPG | High — limited banners, time-gated chars |
| Premium single-player | None — ethical: 매 player time respect |
**기본값**: 매 ethical FOMO (notify, don't manipulate). 매 dark pattern 회피 — regulatory risk (EU, Belgium loot box bans).
## 🔗 Graph
- 부모: [[Game Design]]
- 변형: [[Loss Aversion]]
## 🤖 LLM 활용
**언제**: 매 retention strategy 설계, event scheduling, push notification copy 생성.
**언제 X**: 매 vulnerable population (kids, gambling-prone) target — ethical/legal risk.
## ❌ 안티패턴
- **Predatory FOMO**: 매 minor / addiction-prone 대상 dark pattern → 매 lawsuit, regulation.
- **Notification spam**: 매 매일 5+ FOMO push → 매 uninstall.
- **Fake scarcity**: 매 "limited" 인데 매번 재출시 → 매 trust erosion.
- **No off-ramp**: 매 streak 끊고 싶을 때 vacation mode 없음.
## 🧪 검증 / 중복
- Verified (Przybylski et al., "Motivational, emotional, and behavioral correlates of fear of missing out", 2013).
- Verified (Belgium Gambling Commission loot box ruling, 2018).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — game design + monetization mechanics |
@@ -0,0 +1,210 @@
---
id: wiki-2026-0508-fault-tolerance
title: Fault Tolerance
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Fault Tolerance, 장애 내성, Resilience Engineering]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [architecture, distributed-systems, resilience, erlang]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: erlang
framework: otp
---
# Fault Tolerance
## 매 한 줄
> **"매 system은 fail한다 — 매 question은 'when'이지 'if' 아님"**. 매 fault tolerance는 component failure에도 system이 계속 동작하도록 design — Erlang/OTP의 "let it crash" philosophy에서 modern Kubernetes self-healing까지 evolution. 2026 cloud-native에서는 chaos engineering, circuit breaker, bulkhead가 default.
## 매 핵심
### 매 Fault vs Error vs Failure
- **Fault**: 매 root cause (bug, hardware glitch, network partition)
- **Error**: 매 fault의 manifestation (incorrect state)
- **Failure**: 매 service가 contract 위반 (user-visible)
- 매 goal: fault → error containment, error → failure prevention
### 매 Erlang Philosophy
- **Let it crash**: 매 defensive coding 대신 supervisor가 restart
- **Process isolation**: 매 lightweight process per actor, shared-nothing
- **Hot code reload**: 매 zero-downtime upgrade
- 매 WhatsApp이 2 billion users를 50 engineers로 운영한 비결
### 매 응용
1. Erlang/OTP supervisor tree (telecom, WhatsApp, Discord).
2. Kubernetes pod restart + liveness probes.
3. Circuit breaker (Hystrix, resilience4j).
4. Distributed databases (Cassandra hinted handoff, Spanner).
## 💻 패턴
### Erlang Supervisor Tree
```erlang
-module(my_sup).
-behaviour(supervisor).
-export([start_link/0, init/1]).
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
SupFlags = #{strategy => one_for_one,
intensity => 5,
period => 10},
Children = [
#{id => worker1,
start => {worker, start_link, []},
restart => permanent,
shutdown => 5000,
type => worker}
],
{ok, {SupFlags, Children}}.
```
### Circuit Breaker (Python)
```python
from pybreaker import CircuitBreaker
db_breaker = CircuitBreaker(fail_max=5, reset_timeout=60)
@db_breaker
def query_db(sql: str):
return db.execute(sql)
try:
result = query_db("SELECT * FROM users")
except CircuitBreakerError:
return cached_response() # fallback
```
### Retry with Exponential Backoff
```python
import asyncio
import random
async def retry_with_backoff(fn, max_retries=5, base=1.0):
for attempt in range(max_retries):
try:
return await fn()
except Exception as e:
if attempt == max_retries - 1:
raise
delay = base * (2 ** attempt) + random.uniform(0, 1)
await asyncio.sleep(delay)
```
### Bulkhead Pattern (Go)
```go
import "golang.org/x/sync/semaphore"
type Service struct {
dbSem *semaphore.Weighted // 10 concurrent DB calls
apiSem *semaphore.Weighted // 50 concurrent API calls
}
func (s *Service) CallDB(ctx context.Context) error {
if err := s.dbSem.Acquire(ctx, 1); err != nil {
return err
}
defer s.dbSem.Release(1)
return doDBWork()
}
```
### Kubernetes Liveness/Readiness
```yaml
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
periodSeconds: 5
```
### Chaos Engineering (Litmus)
```yaml
apiVersion: litmuschaos.io/v1alpha1
kind: ChaosEngine
spec:
experiments:
- name: pod-delete
spec:
components:
env:
- name: TOTAL_CHAOS_DURATION
value: '60'
- name: PODS_AFFECTED_PERC
value: '50'
```
### Saga Pattern (Compensation)
```python
class OrderSaga:
async def execute(self, order):
steps = []
try:
payment = await charge_card(order)
steps.append(("refund", payment.id))
inventory = await reserve_stock(order)
steps.append(("release", inventory.id))
await ship_order(order)
except Exception:
for action, ref in reversed(steps):
await compensate(action, ref)
raise
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Telecom-grade uptime (5 nines) | Erlang/OTP supervisor tree |
| Microservices REST | Circuit breaker + retry + timeout |
| Stateful distributed DB | Quorum + hinted handoff |
| Container orchestration | K8s liveness/readiness + PodDisruptionBudget |
| Cross-service transactions | Saga + compensation |
**기본값**: 매 timeout + retry + circuit breaker 3종 세트 + chaos testing.
## 🔗 Graph
- 부모: [[Distributed Systems]]
- 변형: [[Circuit Breaker]]
- 응용: [[Kubernetes]] · [[Microservices]]
- Adjacent: [[Chaos Engineering]] · [[Eventual Consistency]] · [[CAP Theorem & PACELC]]
## 🤖 LLM 활용
**언제**: 매 distributed system design 시 failure mode enumeration, supervisor tree 설계, retry strategy 추천.
**언제 X**: 매 single-process script — fault tolerance overhead 가 value 보다 큼.
## ❌ 안티패턴
- **Catch-all exception swallow**: 매 error를 log만 하고 무시 → 매 silent corruption.
- **Infinite retry**: 매 backoff 없는 retry → 매 thundering herd, cascading failure.
- **Shared fate**: 매 단일 DB 의존 모든 service → 매 single point of failure.
- **No timeout**: 매 hang된 dependency가 매 caller exhaust.
## 🧪 검증 / 중복
- Verified (Joe Armstrong, "Making Reliable Distributed Systems in the Presence of Software Errors", 2003).
- Verified (Netflix Chaos Engineering principles, principlesofchaos.org).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Erlang/OTP + modern resilience patterns |
@@ -0,0 +1,198 @@
---
id: wiki-2026-0508-feature-driven-architecture
title: Feature-Driven Architecture
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [FDD, Feature Slices, Vertical Slice Architecture]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [architecture, feature-slices, modularity, frontend]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: nextjs
---
# Feature-Driven Architecture
## 매 한 줄
> **"매 layer-by-type 의 feature-by-vertical-slice 의 invert"**. Feature-Driven Architecture 매 codebase 의 organization unit 매 feature/use-case — 매 each feature 매 own UI + state + API + tests 의 own. Frontend 매 FSD (Feature-Sliced Design), Backend 매 vertical slice / modular monolith 의 manifest.
## 매 핵심
### 매 Why
- **Layer-by-type problem**: 매 `controllers/`, `services/`, `models/` 매 small project 의 fine, 매 100+ features 시 매 cross-cutting changes 의 5 directories 의 touch.
- **Feature 의 lifecycle**: 매 feature 의 add/remove/own 의 single folder 의 happen.
- **Team scaling**: 매 vertical squad 의 own 매 single feature folder, 매 conflicts 의 minimize.
### 매 FSD layers (frontend)
1. `app/` — global setup, routing, providers.
2. `pages/` — route compositions.
3. `widgets/` — composite UI blocks.
4. `features/` — user actions (login, addToCart).
5. `entities/` — business objects (User, Product).
6. `shared/` — UI kit, utils, API client.
- 매 import rule: 매 upper layer → lower layer only.
### 매 응용
1. Next.js / Remix apps with FSD.
2. Modular monolith — Java/.NET vertical slices.
3. Mobile (RN/Flutter) feature modules.
4. Microfrontend per-feature deployment.
## 💻 패턴
### FSD folder layout
```
src/
├── app/ # providers, router, global styles
├── pages/
│ └── checkout/
│ └── ui/Checkout.tsx
├── widgets/
│ └── header/ui/Header.tsx
├── features/
│ ├── auth-login/
│ │ ├── ui/LoginForm.tsx
│ │ ├── model/store.ts
│ │ ├── api/login.ts
│ │ └── index.ts # public api
│ └── cart-add-item/
├── entities/
│ ├── user/{ui, model, api}/
│ └── product/{ui, model, api}/
└── shared/
├── ui/Button.tsx
└── api/baseQuery.ts
```
### Public API (index.ts barrel)
```typescript
// features/auth-login/index.ts
export { LoginForm } from './ui/LoginForm';
export { useLoginMutation } from './api/login';
// 매 internal model/store 의 not exported — encapsulation
```
### ESLint 의 enforce layer rules
```javascript
// .eslintrc — eslint-plugin-boundaries
module.exports = {
plugins: ['boundaries'],
settings: {
'boundaries/elements': [
{ type: 'app', pattern: 'src/app/*' },
{ type: 'pages', pattern: 'src/pages/*' },
{ type: 'features', pattern: 'src/features/*' },
{ type: 'entities', pattern: 'src/entities/*' },
{ type: 'shared', pattern: 'src/shared/*' },
],
},
rules: {
'boundaries/element-types': ['error', {
default: 'disallow',
rules: [
{ from: 'pages', allow: ['features', 'entities', 'shared'] },
{ from: 'features', allow: ['entities', 'shared'] },
{ from: 'entities', allow: ['shared'] },
],
}],
},
};
```
### Vertical slice (.NET / Node)
```typescript
// features/place-order/handler.ts
export class PlaceOrderCommand {
constructor(public userId: string, public items: Item[]) {}
}
export async function placeOrder(cmd: PlaceOrderCommand, deps: Deps) {
const user = await deps.users.findById(cmd.userId);
if (!user) throw new NotFoundError();
const order = Order.create(user, cmd.items);
await deps.orders.save(order);
await deps.bus.emit('order.placed', { orderId: order.id });
return { orderId: order.id };
}
// features/place-order/route.ts
router.post('/orders', async (req, res) => {
const result = await placeOrder(req.body, deps);
res.json(result);
});
// 매 single folder 매 use-case 의 entire handle
```
### Cross-feature communication via events
```typescript
// features/cart-checkout — 매 features/inventory-update 의 NOT 매 import
// 매 instead: emit event, 매 inventory feature 의 subscribe
import { bus } from '@/shared/event-bus';
async function checkout(cart: Cart) {
await bus.emit('checkout.completed', { items: cart.items });
}
// features/inventory-update/index.ts
bus.on('checkout.completed', async ({ items }) => {
await decrementStock(items);
});
```
### Feature flag boundary
```typescript
// features/new-search-v2/index.ts
import { useFlag } from '@/shared/feature-flags';
import { SearchV1 } from '@/features/search-v1';
import { SearchV2 } from './ui/SearchV2';
export function Search() {
const v2 = useFlag('search-v2');
return v2 ? <SearchV2 /> : <SearchV1 />;
}
// Removal 의 single folder delete
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Solo / < 10 features | 매 layer-by-type 매 fine |
| Frontend, growing team | 매 FSD |
| Backend, modular monolith | 매 vertical slice (CQRS-style) |
| Microservices | 매 service-per-feature 매 already |
| Strict isolation 의 needed | 매 ESLint boundaries + barrel exports |
**기본값**: 매 frontend 매 FSD, 매 backend 매 vertical slice — 매 cross-feature 의 events.
## 🔗 Graph
- 부모: [[Software-Architecture]] · [[Modular Monolith]]
- 변형: [[Feature-Sliced-Design]] · [[Vertical-Slice-Architecture]] · [[Hexagonal Architecture]]
- 응용: [[Micro frontends]] · [[CQRS]] · [[Bounded Context]]
- Adjacent: [[Domain-Driven-Design]] · [[Clean-Architecture]]
## 🤖 LLM 활용
**언제**: 매 10+ features, 매 multi-team. Frontend 매 page-driven 의 outgrow. Modular monolith 매 service split 의 prepare.
**언제 X**: 매 small app (<10 screens). 매 prototype phase — 매 over-structure cost > benefit.
## ❌ 안티패턴
- **Cross-feature direct import**: 매 `features/cart``features/checkout/internal` 의 import — 매 coupling 의 reintroduce. Public API 만 의 use.
- **God shared/**: 매 모든 utility 의 `shared/utils/` 의 dump — 매 entities/features 의 leak 의 should.
- **Premature feature split**: 매 single-screen app 의 7 features 의 carve — 매 navigation cost.
- **Layer skipping**: 매 `entities``features` 의 import — 매 dependency rule violation.
## 🧪 검증 / 중복
- Verified (feature-sliced.design official; Jimmy Bogard "Vertical Slice Architecture").
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — FSD layout + ESLint boundaries + vertical slice patterns |
@@ -0,0 +1,166 @@
---
id: wiki-2026-0508-fiber-architecture
title: Fiber Architecture
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [React Fiber, Reconciler]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [react, frontend, reconciliation]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: react
---
# Fiber Architecture
## 매 한 줄
> **"매 reconciliation 을 interruptible 한 unit 으로 쪼갠다"**. 매 React 16 (2017) 에서 stack reconciler 를 대체 — 매 work loop 가 매 fiber node 단위로 yield 가능하므로 매 concurrent rendering, Suspense, transitions 의 토대. 2026 React 19 의 Server Components, Actions, `use` hook 모두 매 fiber tree 위에서 동작.
## 매 핵심
### 매 fiber node
- 매 React element 1:1 의 mutable bookkeeping object.
- 매 `child / sibling / return` pointer 로 tree linkage (매 array 가 아닌 linked list).
- `pendingProps`, `memoizedProps`, `memoizedState`, `effectTag`, `lanes`.
- 매 두 tree: **current** (committed) + **workInProgress** (next render) — 매 double buffering.
### 매 work loop
1. **Render phase** (interruptible) — 매 beginWork → completeWork DFS, 매 frame budget 만료 시 yield.
2. **Commit phase** (synchronous) — 매 DOM mutation, ref attach, layout effect.
3. **Lanes** — 매 priority bitmask (Sync, Default, Transition, Idle).
### 매 응용
1. `useTransition` / `useDeferredValue` — 매 low-priority lane.
2. Suspense boundary — 매 throw promise → fallback render.
3. Server Components (RSC) — 매 server fiber 의 serialize.
4. Concurrent rendering / time slicing.
## 💻 패턴
### Fiber node 의 shape (개념)
```ts
type Fiber = {
type: any; key: string | null;
child: Fiber | null; sibling: Fiber | null; return: Fiber | null;
alternate: Fiber | null; // current ↔ workInProgress
pendingProps: any; memoizedProps: any; memoizedState: any;
flags: number; // Placement | Update | Deletion
lanes: number; childLanes: number;
stateNode: any; // DOM node | class instance
};
```
### Work loop (개념)
```ts
function workLoopConcurrent() {
while (workInProgress !== null && !shouldYield()) {
workInProgress = performUnitOfWork(workInProgress);
}
}
function performUnitOfWork(fiber: Fiber): Fiber | null {
const next = beginWork(fiber.alternate, fiber, renderLanes);
if (next === null) return completeUnitOfWork(fiber);
return next;
}
```
### useTransition (React 19)
```tsx
import { useTransition, useState } from "react";
export function Search() {
const [query, setQuery] = useState("");
const [results, setResults] = useState<string[]>([]);
const [isPending, startTransition] = useTransition();
return (
<>
<input value={query} onChange={e => {
setQuery(e.target.value); // sync lane
startTransition(() => setResults(filter(e.target.value))); // transition lane
}}/>
{isPending ? <Spinner/> : <List items={results}/>}
</>
);
}
```
### Suspense + use (React 19)
```tsx
import { Suspense, use } from "react";
function Profile({ promise }: { promise: Promise<User> }) {
const user = use(promise); // 매 throw 시 Suspense fallback
return <h1>{user.name}</h1>;
}
export default () => (
<Suspense fallback={<Skeleton/>}>
<Profile promise={fetchUser()}/>
</Suspense>
);
```
### Server Component (RSC)
```tsx
// app/page.tsx — 매 server fiber, payload 로 serialize
export default async function Page() {
const posts = await db.posts.findMany();
return <PostList posts={posts}/>; // 매 client 로는 RSC payload 전송
}
```
### useDeferredValue
```tsx
const deferred = useDeferredValue(query); // 매 stale value 로 render, urgent update 우선
```
### Lane priority debug (React DevTools)
```
Profiler tab → Highlight transitions → 매 어느 lane 에서 commit 됐는지 확인
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 즉시 반영 input | 직접 setState (sync lane) |
| 무거운 list filter | startTransition (transition lane) |
| Async data 의 render | Suspense + use |
| Server-only data fetch | RSC (`async function Page`) |
| Stale UI 허용 + responsive | useDeferredValue |
**기본값**: React 19 + RSC (Next.js App Router), client side 는 transition + Suspense.
## 🔗 Graph
- 부모: [[React]] · [[Reconciliation]]
- 변형: [[React Server Components — 경계 의식]] · [[Concurrent Features|Concurrent Rendering]]
- 응용: [[Suspense]] · [[useTransition]] · [[useDeferredValue]] · [[Streaming SSR]]
- Adjacent: [[Virtual DOM과 Reconciliation|Virtual DOM]] · [[Hydration]]
## 🤖 LLM 활용
**언제**: 매 jank 진단, transition vs sync 결정, Suspense boundary 위치 reasoning.
**언제 X**: 매 non-React framework — 매 Vue / Svelte / Solid 는 매 다른 reconciler.
## ❌ 안티패턴
- **Sync setState in event for heavy work**: 매 main thread block.
- **Suspense without boundary**: 매 root crash — 매 ErrorBoundary + Suspense pair.
- **useTransition for urgent input**: 매 typing latency 발생.
- **Mutating fiber internals**: 매 React 의 internal — 매 forward-compat 보장 X.
- **Effect 의 setState loop**: 매 무한 render — 매 dependency 정확히.
## 🧪 검증 / 중복
- Verified (React 19 release notes, Andrew Clark *fiber* RFC, React docs 2026, Vercel RSC docs).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — fiber + lanes + React 19 (RSC, use, transition) 정리 |
@@ -0,0 +1,186 @@
---
id: wiki-2026-0508-flow-state
title: Flow State
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Flow, Flow State, 몰입, Csikszentmihalyi Flow]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [psychology, game-design, productivity, ux]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: design
framework: ux
---
# Flow State
## 매 한 줄
> **"매 challenge와 skill이 정확히 균형된 순간 시간이 사라진다"**. 매 Flow는 Csikszentmihalyi(1975)가 정의한 optimal experience — 매 자아 의식 사라짐, immediate feedback, intrinsic reward. 2026 game design, productivity tool, learning platform의 매 design target.
## 매 핵심
### 매 8 Conditions (Csikszentmihalyi)
1. **Clear goals**: 매 매 순간 무엇을 해야 하는지 명확
2. **Immediate feedback**: 매 action → result 즉시
3. **Skill-challenge balance**: 매 너무 쉬우면 boredom, 너무 어려우면 anxiety
4. **Action-awareness merge**: 매 doing = thinking
5. **Concentration**: 매 task에 완전 집중
6. **Sense of control**: 매 outcome 지배감
7. **Loss of self-consciousness**: 매 ego 사라짐
8. **Time distortion**: 매 5시간이 30분처럼
### 매 Flow Channel
- **Anxiety zone**: 매 challenge ≫ skill
- **Boredom zone**: 매 challenge ≪ skill
- **Flow channel**: 매 둘이 동반 상승 (스킬 ↑ → 도전 ↑)
### 매 응용
1. Game difficulty curves (Souls-like, rhythm games).
2. Coding flow (Pomodoro, focus mode).
3. Dynamic difficulty adjustment (Resident Evil 4 director AI).
4. Educational scaffolding (Duolingo adaptive).
## 💻 패턴
### Dynamic Difficulty Adjustment (Unity C#)
```csharp
public class FlowDifficulty : MonoBehaviour
{
float playerSkill = 0.5f; // 매 EMA estimate
float currentDifficulty = 0.5f;
void OnPlayerSuccess()
{
playerSkill = 0.9f * playerSkill + 0.1f * 1.0f;
AdjustDifficulty();
}
void OnPlayerFail()
{
playerSkill = 0.9f * playerSkill + 0.1f * 0.0f;
AdjustDifficulty();
}
void AdjustDifficulty()
{
// 매 keep difficulty slightly above skill (flow channel)
currentDifficulty = Mathf.Clamp(playerSkill + 0.1f, 0.1f, 0.95f);
ApplyDifficulty(currentDifficulty);
}
}
```
### Focus Mode (VS Code extension)
```typescript
import * as vscode from 'vscode';
export function enterFlowMode() {
vscode.workspace.getConfiguration().update('zenMode.fullScreen', true);
vscode.workspace.getConfiguration().update('workbench.activityBar.visible', false);
vscode.workspace.getConfiguration().update('editor.minimap.enabled', false);
// 매 disable notifications
vscode.commands.executeCommand('notifications.toggleDoNotDisturbMode');
// 매 25min Pomodoro
setTimeout(() => {
vscode.window.showInformationMessage('매 flow check: 잠시 휴식?');
}, 25 * 60 * 1000);
}
```
### Skill Tracking (Python EMA)
```python
class SkillTracker:
def __init__(self, alpha=0.1):
self.alpha = alpha
self.skill = 0.5
def update(self, success: bool):
target = 1.0 if success else 0.0
self.skill = (1 - self.alpha) * self.skill + self.alpha * target
def in_flow_zone(self, difficulty: float) -> bool:
# 매 difficulty 가 skill 의 ±15% 안에 있어야 flow
return abs(difficulty - self.skill) < 0.15
```
### Immediate Feedback (Web)
```javascript
// 매 keystroke마다 syntax check (flow-friendly)
let timeoutId;
editor.on('change', () => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
const errors = lint(editor.getValue());
showInlineErrors(errors); // 매 즉시 visual feedback
}, 100); // 매 debounce 100ms — 매 fast enough for flow
});
```
### Distraction Blocking (macOS Focus)
```bash
# 매 macOS Shortcuts CLI
shortcuts run "Focus: Do Not Disturb On"
# 매 hosts file block social
echo "0.0.0.0 twitter.com" | sudo tee -a /etc/hosts
echo "0.0.0.0 reddit.com" | sudo tee -a /etc/hosts
```
### Flow Telemetry (game)
```python
def log_session_flow(session):
duration = session.end - session.start
deaths = session.deaths
completions = session.completions
# 매 high engagement + moderate failure = flow
if duration > timedelta(minutes=20) \
and 0.3 < deaths / (deaths + completions) < 0.6:
analytics.track("flow_session", session.user_id)
```
## 매 결정 기준
| 상황 | Design priority |
|---|---|
| Action game | Tight feedback loop, DDA |
| Strategy game | Clear goal, skill ceiling exposure |
| Learning app | Adaptive difficulty, immediate hint |
| Productivity tool | Distraction-free mode, focus timer |
| Casual game | Low anxiety, high accessibility |
**기본값**: 매 difficulty = skill + 10%, feedback < 200ms, distraction = 0.
## 🔗 Graph
- 부모: [[Game Design]]
- 변형: [[Deep Work]] (Cal Newport)
- 응용: [[DDA]]
- Adjacent: [[Intrinsic Motivation]] · [[Self-Determination Theory]]
## 🤖 LLM 활용
**언제**: 매 game design review, learning UX critique, productivity workflow 진단.
**언제 X**: 매 medical/clinical attention disorder context — flow state는 self-help framework, not therapy.
## ❌ 안티패턴
- **Forced flow**: 매 user를 trap (매 dark UX) → 매 burnout, churn.
- **Notification interrupt**: 매 push 매 5분 → 매 flow 진입 불가능.
- **Difficulty spike**: 매 sudden challenge → 매 anxiety zone 추락.
- **Reward without challenge**: 매 free progress → 매 boredom.
## 🧪 검증 / 중복
- Verified (Csikszentmihalyi, "Flow: The Psychology of Optimal Experience", 1990).
- Verified (Sweetser & Wyeth, "GameFlow: A Model for Evaluating Player Enjoyment in Games", 2005).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Csikszentmihalyi flow + game design |
@@ -0,0 +1,184 @@
---
id: wiki-2026-0508-fluid-typography
title: Fluid Typography
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Fluid Typography, Responsive Typography, Clamp Typography]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [css, web, design, responsive]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: css
framework: web
---
# Fluid Typography
## 매 한 줄
> **"매 viewport 에 따라 font-size 가 부드럽게 scale 된다"**. 매 Fluid Typography는 fixed breakpoint 의 jumpy 변화 대신 매 linear interpolation 으로 매 자연스러운 size 변화 — `clamp()` + `vw` 가 매 modern standard. 2026 모든 design system 의 default.
## 매 핵심
### 매 Why fluid?
- **Breakpoint jumps**: 매 320px → 768px 에서 갑자기 font 12px → 18px (jarring)
- **Fluid interp**: 매 320px = 12px, 1280px = 24px, 매 사이는 linear
- **Single source of truth**: 매 media query × N 대신 매 1 line CSS
### 매 clamp(min, preferred, max)
- `min`: 매 최소 (small viewport)
- `preferred`: 매 vw 기반 fluid value
- `max`: 매 최대 (large viewport cap)
- 매 browser가 자동 clamp
### 매 응용
1. Modern design systems (Tailwind v4 fluid presets, Open Props).
2. Editorial sites (NYT, Medium-style readers).
3. Marketing landing pages.
4. CSS-in-JS theme tokens.
## 💻 패턴
### Basic clamp() pattern
```css
:root {
/* 매 min 1rem (16px), max 1.5rem (24px), fluid 사이 */
--fs-body: clamp(1rem, 0.875rem + 0.625vw, 1.5rem);
--fs-h1: clamp(2rem, 1rem + 5vw, 5rem);
--fs-h2: clamp(1.5rem, 1rem + 2.5vw, 3rem);
}
body { font-size: var(--fs-body); }
h1 { font-size: var(--fs-h1); line-height: 1.1; }
h2 { font-size: var(--fs-h2); line-height: 1.2; }
```
### Linear interp formula (Utopia.fyi)
```javascript
// 매 min 320px viewport: 16px font
// 매 max 1280px viewport: 24px font
function fluidClamp(minPx, maxPx, minVwPx = 320, maxVwPx = 1280) {
const slope = (maxPx - minPx) / (maxVwPx - minVwPx);
const intercept = minPx - slope * minVwPx;
const slopeVw = slope * 100;
return `clamp(${minPx / 16}rem, ${intercept / 16}rem + ${slopeVw}vw, ${maxPx / 16}rem)`;
}
console.log(fluidClamp(16, 24));
// "clamp(1rem, 0.833rem + 0.833vw, 1.5rem)"
```
### Type scale (modular)
```css
:root {
--ratio: 1.25; /* 매 major third scale */
--fs-0: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
--fs-1: calc(var(--fs-0) * var(--ratio));
--fs-2: calc(var(--fs-1) * var(--ratio));
--fs-3: calc(var(--fs-2) * var(--ratio));
--fs--1: calc(var(--fs-0) / var(--ratio));
}
```
### Tailwind v4 fluid (CSS)
```css
@import "tailwindcss";
@theme {
--text-fluid-sm: clamp(0.875rem, 0.8rem + 0.4vw, 1rem);
--text-fluid-base: clamp(1rem, 0.875rem + 0.625vw, 1.25rem);
--text-fluid-lg: clamp(1.125rem, 0.95rem + 0.9vw, 1.5rem);
--text-fluid-xl: clamp(1.5rem, 1rem + 2.5vw, 2.5rem);
}
```
```html
<h1 class="text-fluid-xl">매 fluid heading</h1>
<p class="text-fluid-base">매 body text fluid</p>
```
### Container query fluid (modern)
```css
/* 매 viewport 대신 container 기반 — true component fluidity */
.card {
container-type: inline-size;
}
.card-title {
font-size: clamp(1rem, 4cqi, 2rem); /* 매 cqi = container query inline */
}
```
### Accessibility-safe (rem floor)
```css
/* 매 user font-size preference 존중 — rem 사용 */
:root {
--fs-readable: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
/* 매 NOT: clamp(16px, 1vw, 20px) — px ignores user setting */
}
```
### Line-height 도 fluid
```css
.prose {
font-size: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
/* 매 작은 size 일수록 line-height 더 큼 (readability) */
line-height: clamp(1.4, 1.6 - 0.1vw, 1.6);
/* 매 ch unit으로 measure 제한 */
max-width: 65ch;
}
```
### Spacing 도 fluid (consistency)
```css
:root {
--space-xs: clamp(0.5rem, 0.4rem + 0.5vw, 0.75rem);
--space-sm: clamp(1rem, 0.8rem + 1vw, 1.5rem);
--space-md: clamp(1.5rem, 1.2rem + 1.5vw, 2.25rem);
--space-lg: clamp(2.25rem, 1.8rem + 2.25vw, 3.375rem);
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Marketing site | Fluid type + spacing |
| App UI (dense) | Discrete sizes (consistent UX) |
| Editorial (long-form) | Fluid + max-width 65-75ch |
| Component library | Container query fluid |
| Email | Static (limited CSS) |
**기본값**: 매 clamp() + rem + Utopia.fyi calculator. 매 viewport range 320-1280px 기준.
## 🔗 Graph
- 부모: [[Responsive Design]]
- 변형: [[컨테이너 쿼리 (Container Queries)|Container Queries]]
- 응용: [[Design Systems]] · [[CSS_Architecture_and_Styling|Tailwind CSS]] · [[CSS_Architecture_and_Styling|CSS Variables]]
- Adjacent: [[Type Scale]] · [[Accessibility (A11y)|Accessibility]]
## 🤖 LLM 활용
**언제**: 매 design system token 생성, clamp() formula 계산, breakpoint refactor.
**언제 X**: 매 email HTML, legacy IE — clamp() unsupported.
## ❌ 안티패턴
- **px in clamp()**: 매 user font preference 무시 → 매 a11y 실패.
- **No max cap**: 매 4K monitor 에서 매 font 너무 큼.
- **No min floor**: 매 320px 미만 viewport 에서 매 unreadable.
- **vw alone**: 매 `font-size: 2vw` — 매 zoom 시 깨짐 (no rem fallback).
## 🧪 검증 / 중복
- Verified (Utopia.fyi, "Fluid responsive design", 2020).
- Verified (CSS Values L4 spec, clamp() function).
- Verified (Caniuse: clamp() 96%+ global support).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — clamp() + container queries + Tailwind v4 |
@@ -0,0 +1,229 @@
---
id: wiki-2026-0508-fragment-bound
title: Fragment-bound
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [React Fragment, Fragment-bound Component, Multi-root Component]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [react, frontend, jsx, dom]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: react
---
# Fragment-bound
## 매 한 줄
> **"매 component 의 root 의 wrapper div 의 elimination"**. React Fragment (`<>...</>` 또는 `<Fragment>`) 매 component 매 multiple sibling roots 의 return 의 enable — 매 unnecessary `<div>` wrapper 의 avoid. "Fragment-bound" component 매 single DOM root 의 not-have, 매 layout (Grid, Table, Flex) 매 fragile 의 implication 의 carry.
## 매 핵심
### 매 Why Fragment
- **DOM cleanliness**: 매 wrapper div 의 CSS Grid/Flex 의 break — 매 child 매 grid item 의 directly 의 must be.
- **No semantic noise**: 매 `<table>``<tr>``<td>` 의 nest 의 wrapper div 의 invalid HTML.
- **Performance (marginal)**: 매 fewer DOM nodes — 매 hot lists 의 measurable.
### 매 Forms
- `<></>` — short syntax, 매 no key/props.
- `<Fragment key={...}>` — 매 list iteration 매 key 의 needed 시.
- `<React.Fragment>` — explicit import, 매 build tooling 의 short syntax 의 not-support 시.
### 매 Fragment-bound implications
- 매 ref 의 attach 의 not-possible (매 single DOM node 의 not-have).
- 매 parent 매 child layout 의 control 의 must — 매 child 매 own root 의 not-have.
- 매 portals 매 separate concern.
### 매 응용
1. Table rows / cells (`<TableRow>` returning `<td>...</td><td>...</td>`).
2. Grid items in CSS Grid layout.
3. Component library — wrapper-less primitives.
4. Conditional sibling rendering.
## 💻 패턴
### Basic Fragment
```tsx
function Greeting() {
return (
<>
<h1>Hello</h1>
<p>World</p>
</>
);
}
// 매 DOM 의 <h1>+<p> 의 sibling, 매 no wrapper
```
### Fragment with key (list)
```tsx
import { Fragment } from 'react';
function Glossary({ items }: { items: { term: string; def: string }[] }) {
return (
<dl>
{items.map(it => (
<Fragment key={it.term}>
<dt>{it.term}</dt>
<dd>{it.def}</dd>
</Fragment>
))}
</dl>
);
}
// 매 short syntax 매 key prop 의 not-accept — 매 explicit Fragment 의 use
```
### Table row composition
```tsx
function ProductRow({ product }: { product: Product }) {
return (
<>
<td>{product.name}</td>
<td>{product.price}</td>
<td>{product.stock}</td>
</>
);
}
function ProductTable({ products }: { products: Product[] }) {
return (
<table>
<tbody>
{products.map(p => (
<tr key={p.id}><ProductRow product={p} /></tr>
))}
</tbody>
</table>
);
}
// 매 wrapper div 매 tr 안 의 invalid HTML — 매 Fragment 의 only correct
```
### CSS Grid items
```tsx
function GridGroup() {
return (
<>
<div className="grid-item">A</div>
<div className="grid-item">B</div>
<div className="grid-item">C</div>
</>
);
}
function Layout() {
return (
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)' }}>
<GridGroup /> {/* 매 3 children 의 grid items 의 directly */}
</div>
);
}
// 매 wrapper div 의 add 시 매 single grid cell 의 collapse
```
### Conditional sibling rendering
```tsx
function Notification({ user }: { user?: User }) {
if (!user) return null;
return (
<>
{user.unreadCount > 0 && (
<span className="badge">{user.unreadCount}</span>
)}
<span className="name">{user.name}</span>
</>
);
}
```
### Ref forwarding 매 NOT possible
```tsx
// 매 X — Fragment 매 ref 의 not-attach 의
const Bad = forwardRef<HTMLDivElement>((props, ref) => (
<>
<h1 ref={ref}>Title</h1> {/* 매 child element 의 ref 의 forward 의 must */}
<p>Body</p>
</>
));
// 매 O — 매 explicit child 의 ref 의 forward
const Card = forwardRef<HTMLHeadingElement, { title: string; body: string }>(
({ title, body }, ref) => (
<>
<h1 ref={ref}>{title}</h1>
<p>{body}</p>
</>
),
);
```
### Suspense / ErrorBoundary 매 Fragment children
```tsx
function App() {
return (
<Suspense fallback={<Spinner />}>
<>
<Header />
<Main />
<Footer />
</>
</Suspense>
);
}
// 매 Suspense 매 single child 의 not-require — 매 Fragment 의 N children 의 all 의 wait
```
### Slot pattern 의 fragment-aware
```tsx
type SlotProps = { children: ReactNode };
function Slot({ children }: SlotProps) {
// 매 children 매 Fragment 매 single 매 multiple 매 unwrap 의 logic
if (isValidElement(children) && children.type === Fragment) {
return <>{children.props.children}</>;
}
return <>{children}</>;
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Component 매 단일 root 의 natural | 매 `<div>` 의 use |
| Wrapper div 매 layout 의 break | 매 Fragment |
| Table / dl / select children | 매 Fragment 의 mandatory |
| List item with multiple roots | 매 Fragment with key |
| Ref / styling 의 root needed | 매 div / specific element 의 use |
**기본값**: 매 wrapper 매 semantic value 의 carry 의 div, 매 그렇지 않으면 매 Fragment.
## 🔗 Graph
- 부모: [[React]] · [[JSX]]
- 변형: [[Slot-Pattern]]
- 응용: [[CSS Grid]] · [[Component-Composition]]
## 🤖 LLM 활용
**언제**: 매 multi-root component. Table/Grid layout 의 wrapper 의 break 의 시. List item 매 multiple sibling 의 render.
**언제 X**: 매 single root + ref/styling needed — 매 div 의 use. Wrapper 의 styling target 의 expected 시.
## ❌ 안티패턴
- **Wrapper div habit**: 매 모든 component 매 `<div>` 의 wrap — 매 div soup, 매 layout 의 fragile.
- **Fragment without key in list**: 매 `<>``.map` 안 의 use — 매 React warning + reconciliation 의 broken.
- **Trying to ref a Fragment**: 매 Fragment 의 DOM node 의 not-have — 매 forwardRef 의 specific child 의 forward 의 must.
- **Fragment inside single-child API**: 매 some libs (older) 매 single child 의 expect — 매 Fragment 의 expand, 매 break.
## 🧪 검증 / 중복
- Verified (React docs "Fragments"; React 16.2 release notes).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Fragment patterns + table/grid/key examples |

Some files were not shown because too many files have changed in this diff Show More