[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -1,131 +1,139 @@
|
||||
---
|
||||
id: wiki-2026-0508-2026년-3월-연구-드롭-march-2026-resear
|
||||
title: 2026년 3월 연구 드롭(March 2026 Research Drop)
|
||||
title: 2026년 3월 연구 드롭 (March 2026 Research Drop)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [March 2026 Research Drop, 2026-03 Drop, Spring 2026 Releases]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
source_trust_level: B
|
||||
confidence_score: 0.85
|
||||
verification_status: applied
|
||||
tags: [research, llm, releases, 2026, frontier-models]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: en
|
||||
framework: research
|
||||
---
|
||||
|
||||
# [[2026년 3월 연구 드롭(March 2026 Research Drop)|2026년 3월 연구 드롭(March 2026 Research Drop)]]
|
||||
# 2026년 3월 연구 드롭 (March 2026 Research Drop)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
2026년 3월 연구 드롭은 Descendants의 섹터 통제 시도를 물리친 후 발견된 데이터 볼트를 기반으로 한 기지 업그레이드 시스템입니다 [1]. 이 업그레이드는 '이리듐(Iridium)' 자원을 필요로 하며, 방어 플랫폼에 특정 무기 공격에 대한 50% 피해 저항력을 부여하여 게임의 전투 메타를 근본적으로 변화시켰습니다 [1-3]. 더불어 항공기를 교란하는 나이트워치 벙커(Nightwatch Bunker)와 체력이 높은 유닛을 카운터 치는 메트로노모스(Metronomos) 중포탑이 새롭게 도입되어 방어 체계의 전략적 깊이가 크게 심화되었습니다 [4-6].
|
||||
## 매 한 줄
|
||||
> **"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.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
2026년 3월 연구 업데이트는 디센던트(Descendants) 세력의 섹터 통제 시도를 격퇴한 후 발견된 데이터 볼트를 기반으로 도입된 핵심 기술 업데이트입니다 [1]. 이 업데이트는 새로운 자원인 '이리듐(Iridium)'을 도입하고, 방어 플랫폼의 피해 저항력을 전문화하며, 신규 벙커 및 중포탑을 추가하여 게임의 전반적인 전투 메타를 크게 변화시켰습니다 [1, 2]. 특히 단일 무기 유형에 의존하는 공격의 효율을 크게 감소시켜, 공격자에게 '제병협동(Combined Arms)' 형태의 혼합 소대 전술을 강제하는 데 목적이 있습니다 [2, 3].
|
||||
### 매 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 동반.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **연구 드롭 배경 및 필요 자원:** Corpus의 과학자들이 잔해 속에서 발견한 소형 데이터 볼트를 복구하면서 새로운 기지 방어 업그레이드 청사진이 해제되었습니다 [1]. 이 연구 레벨들을 진행하려면 '이리듐' 자원이 필요하지만, 동급의 다른 기술 연구에 비해 소요 시간이 짧은 이점이 있습니다 [1, 2].
|
||||
- **새로운 방어 구조물 도입 (Operation: Western Sun 상점):**
|
||||
- **나이트워치 벙커 (Nightwatch Bunker):** 10개의 새로운 레벨로 구성되며 최대 750의 수용량과 사거리 20% 증가 보너스를 제공합니다 [4]. 보병, 차량, 항공기에 대해 10%의 추가 피해를 입히며, 특히 반경 300 내의 적 항공기에 '난기류(Turbulence)'를 일으켜 이동 및 타겟팅을 교란하는 강력한 대공 전자전(electronic warfare) 능력을 보유하고 있습니다 [4, 6].
|
||||
- **메트로노모스 중포탑 (Metronomos Heavy Turret):** 15개의 새로운 레벨을 가지며, 버스트(BURST) 피해를 입히는 무기입니다 [5]. 발사 중 연사 속도가 점차 증가하다가 1발의 플럭스 버블(Flux Bubble) 탄환을 발사한 후 초기화되어, 지속 타격을 견디며 진입하는 체력이 높은 전차를 상대로 매우 효과적입니다 [5, 6].
|
||||
- **플랫폼 전문화 및 피해 저항 메커니즘:** 가장 핵심적인 변화로 기존 플랫폼들의 명칭이 '지원(Support)'과 '중(Heavy)' 플랫폼으로 재편되며 각각 5레벨씩 추가되었습니다 [5, 7, 8]. 업그레이드된 플랫폼들은 특정 피해 유형에 대해 50%의 피해 감소 또는 상태 이상 면역 효과를 제공합니다 [3].
|
||||
- *지원/중력(Graviton)*: 지상 유닛으로부터의 피해 -50% [3, 5, 8].
|
||||
- *지원/절연(Insulated)*: 광역(AREA) 피해 -50% [3, 5].
|
||||
- *지원/강화(Reinforced)*: 버스트(BURST) 피해 -50% [3, 5].
|
||||
- *지원/장갑(Armored)*: 지속(SUSTAIN) 피해 -50% [3, 7].
|
||||
- *지원/중 항공제트(Aerojet)*: 항공 유닛으로부터의 피해 -50% [3, 7, 8].
|
||||
- *지원/중 저항(Resistor)*: 모든 상태 이상 효과(Status Effects)에 면역 [3, 7, 8].
|
||||
- *지원/중 방벽(Bulwark)*: 고정 수치 피해 감소 (Flat Damage Reduction) [3, 7, 8].
|
||||
- **전투 메타 및 전술의 진화:** 방어 플랫폼의 세분화 및 전문화로 인해, 공격자가 단일 무기 프로파일(예: 지속 피해 보병 대규모 투입 등)에만 의존할 경우 방어자의 플랫폼 세팅에 따라 화력이 반감될 위험이 커졌습니다 [3, 9]. 이에 따라 공격자는 적의 특정 방어 시스템 구성에 구애받지 않고 안정적인 타격을 입히기 위해, 다수의 피해 유형을 포함한 `[[혼합 소대(Mixed Platoons)|혼합 소대(Mixed Platoons)]]`를 구성하는 `[[제병협동 (Combined Arms)|제병 협동(Combined Arms)]]` 전술을 필수로 채택해야만 합니다 [2, 9].
|
||||
- **기타 구조물 및 무기 밸런스 조정:** 기지 운영 측면에서 딥 리액터(Deep Reactor)와 퓨전 타워(Fusion Tower)의 최대 전력 한도가 각각 250, 450으로 증가했습니다 [10]. 무기 체계에서도 데드아이(Deadeye)는 광역 범위가 줄어든 대신 피해량이 커졌고, 애시드 레인(Acid Rain)과 워프 랜스(Warp Lance)는 피해를 더욱 안정적이고 예측 가능하게 주기 위해 스플릿 거리 및 공격 패턴이 변경되었습니다 [4, 10].
|
||||
### 매 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.
|
||||
|
||||
* **신규 자원 '이리듐(Iridium)' 도입**: Corpus 과학자 Matt가 복구한 이 연구 청사진들은 기지 업그레이드에 기존 자원 대신 '이리듐'을 요구합니다 [1]. 이리듐을 사용하는 연구는 동급의 일반 연구에 비해 소요 시간이 짧습니다 [1].
|
||||
* **방어 플랫폼의 전문화 및 명칭 변경**: 지원(Support) 및 중형(Heavy) 플랫폼에 각각 5개의 신규 레벨이 추가되었으며, 각 플랫폼은 특정 공격 유형에 대해 50%의 피해 감소 또는 면역 효과를 제공하도록 전면 개편되었습니다 [4-7].
|
||||
* *Support Graviton* (구 Airborne Platform): 지상 유닛 공격 50% 감소 [4, 7].
|
||||
* *Support Insulated* (구 Insulated Platform): 범위(AREA) 피해 50% 감소 [4, 7].
|
||||
* *Support Reinforced* (구 Reinforced Platform): 폭발(BURST) 피해 50% 감소 [4, 7].
|
||||
* *Support Armored* (구 Armored Platform): 지속(SUSTAIN) 피해 50% 감소 [5, 7].
|
||||
* *Support Aerojet* (구 Flying Platform): 공중 유닛 공격 50% 감소 [5, 7].
|
||||
* *Support Resistor* (구 Resistor Platform): 모든 상태 이상(Status Effects) 면역 [5, 7].
|
||||
* *Support Bulwark* (구 Plated Platform): 고정 피해 감소 (Flat Damage Reduction) [5, 7].
|
||||
* Heavy 계열의 플랫폼(Aerojet, Resistor, Bulwark, Graviton, Clandestine) 역시 이와 유사한 저항 효과를 갖도록 조정되었습니다 [6, 8].
|
||||
* **신규 방어 구조물 (오퍼레이션: 웨스턴 선 상점)**:
|
||||
* **나이트워치(Nightwatch) 벙커**: 최대 수용량 750, 내부 유닛의 사거리 20% 증가 효과와 함께 보병, 차량, 항공기 대상 피해량이 각각 10%씩 증가합니다 [9]. 가장 큰 특징은 반경 300 내의 적 항공기에 '난기류(Turbulence)'를 일으켜 적의 공습 이동과 타겟팅을 방해하는 전자전 역할을 수행한다는 점입니다 [9, 10].
|
||||
* **메트로노모스(Metronomos) 중포탑**: 15개의 신규 레벨이 추가된 이 포탑은 폭발(BURST) 피해를 주며, 강력한 '플럭스 버블(Flux Bubble)' 탄환을 쏠 때까지 발사 속도가 지속적으로 증가하다가 초기화되는 특성을 가집니다 [4, 10]. 이는 높은 체력을 가진 탱킹 유닛을 카운터 하는 데 이상적입니다 [10].
|
||||
* **전술적 영향력 (Tactical Impact)**: 이러한 방어 플랫폼의 극단적인 전문화로 인해 지속(Sustain) 피해 보병 러시와 같은 단일 유닛 위주의 공격은 상대가 방어구(Armored) 플랫폼을 사용 중일 때 효율이 절반으로 떨어집니다 [3, 7]. 공격 지휘관은 방어자의 플랫폼 세팅과 무관하게 안정적인 화력을 투사하기 위해 다양한 피해 프로필이 혼합된 소대(Mixed Platoons)를 구성해야만 합니다 [3].
|
||||
* **기타 주요 기술 업그레이드**: Deep Reactor (최대 전력 250), Fusion Tower (최대 전력 450)를 통해 기지 전력 한도가 증가했습니다 [8]. 또한 Warp Lance (패턴 변경 및 AREA 피해로 전환), Deadeye (스플래시 감소 및 피해량 증가), Acid Rain (분열 거리 변경으로 신뢰성 증가) 등 다수의 무기 체계에 5개의 신규 레벨이 부여되었습니다 [8, 9].
|
||||
## 💻 패턴
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
No trade-offs available.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** `방어 플랫폼(Defense Platform)`, `이리듐(Iridium)`, `[[혼합 소대(Mixed Platoons)|혼합 소대(Mixed Platoons)]]`
|
||||
- **Projects/Contexts:** `[[Operation- Western Sun|Operation: Western Sun]]`, `[[제병협동 전술 (Combined Arms)|제병 협동 전술(Combined Arms)]]`
|
||||
- **Contradictions/Notes:** 소스 간의 정보 충돌은 없으며, 모든 자료가 2026년 3월 연구 드롭으로 인해 전투 시스템의 수비적 다각화 및 그에 따른 공격 전술(다기종 혼합 편성)의 변화가 발생했음을 일관되게 보여줍니다.
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-27*
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** [[방어 플랫폼(Defense Platforms)|방어 플랫폼(Defense Platforms)]], 이리듐(Iridium), 나이트워치 벙커(Nightwatch Bunker), 메트로노모스 중포탑(Metronomos Heavy Turret), 제병협동 전술(Combined Arms Tactics), [[피해 유형(Damage Types)|피해 유형(Damage Types)]]
|
||||
- **Projects/Contexts:** 오퍼레이션: 웨스턴 선(Operation: Western Sun)
|
||||
- **Contradictions/Notes:** 소스에 따르면 기존 방어 플랫폼의 명칭(예: Airborne Platform -> Support Graviton)과 저항 기능이 완전히 재설계되었기 때문에, 이 업데이트 이후로 단일 속성에 기반한 단순 화력전 전술은 더 이상 유효하지 않게 되었습니다.
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-27*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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}]
|
||||
)
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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"}]
|
||||
)
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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"}'
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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))
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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
|
||||
}
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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)
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 매 결정 기준
|
||||
| 상황 | 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
|
||||
- 부모: [[AI Research Timeline]] · [[Frontier Models]]
|
||||
- 변형: [[Claude Opus 4.7]] · [[GPT-5]] · [[DeepSeek V4]]
|
||||
- 응용: [[1M Context Patterns]] · [[Disaggregated Serving]]
|
||||
- Adjacent: [[vLLM]] · [[MLX]] · [[Blackwell Ultra]]
|
||||
|
||||
## 🤖 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) |
|
||||
|
||||
@@ -2,95 +2,127 @@
|
||||
id: wiki-2026-0508-3의-법칙-rule-of-three
|
||||
title: 3의 법칙 (Rule of Three)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [Rule of Three, WET, Three Strikes Refactor]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [uncategorized]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [refactoring, dry, code-smell, abstraction]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: python
|
||||
framework: general
|
||||
---
|
||||
|
||||
# [[3의 법칙 (Rule of Three)]]
|
||||
# 3의 법칙 (Rule of Three)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
3의 법칙(Rule of Three)은 돈 로버츠(Don Roberts)가 제안하고 마틴 파울러(Martin Fowler)가 대중화한 소프트웨어 리팩토링의 핵심 경험 법칙(Rule of Thumb)이다 [1, 2]. 이 법칙은 유사한 형태의 코드가 세 번 반복해서 사용될 때 비로소 중복을 피하기 위해 리팩토링을 수행해야 한다고 명시한다 [1, 3]. 이는 무분별한 리팩토링으로 인한 오버 엔지니어링과 기술 부채 사이의 균형을 맞추고, 실용적인 설계 조정을 권장하는 가이드라인이다 [3].
|
||||
## 매 한 줄
|
||||
> **"매 두 번까지는 복사, 세 번째 등장하면 추출."** Don Roberts 가 *Refactoring* (Fowler, 1999) 에 정식화한 휴리스틱. 매 premature abstraction 을 피하면서 매 진짜 duplication 만 제거하는 trade-off rule. 2026 LLM 기반 codegen 시대에도 매 the cheapest signal — 매 abstraction 의 timing 을 결정.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **3단계 진행 방식 (Three strikes and you refactor)**:
|
||||
1. 첫 번째로 무언가를 구현할 때는 단순히 기능을 완성하는 데 집중하여 일단 진행한다 [4-6].
|
||||
2. 두 번째로 비슷한 작업을 수행할 때는 코드 중복으로 인해 다소 꺼림칙하거나 불편함을 느끼더라도, 같은 방식으로 중복을 허용하여 코드를 작성한다 [2, 4, 6].
|
||||
3. 세 번째로 동일한 형태의 작업이 반복되는 시점이 오면, 그때 비로소 리팩토링을 시작하여 중복된 코드를 새로운 프로시저나 클래스로 추출 및 공통화한다 [1, 2, 4, 5].
|
||||
* **패턴 발견과 정확한 추상화 유도**: 단 두 번의 사례만으로는 코드의 공통점을 명확히 찾기 어려울 수 있다. 하지만 중복이 세 번 이상 발생할 경우, 공통점과 차이점의 패턴을 훨씬 쉽게 파악할 수 있어 더 정확하고 올바른 추상화 수준을 결정하는 데 도움이 된다 [2, 7, 8].
|
||||
* **경제성 관점**: 코드의 중복은 코드를 유지보수하기 어렵게 만들지만, 3의 법칙은 세 개의 복사본이 존재하게 될 때 발생하는 유지보수 비용이 리팩토링을 수행하는 비용 및 잠재적인 나쁜 설계의 위험성을 확실히 초과하게 된다는 것을 내포하고 있다 [1, 9].
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
* **성급한 추상화(Premature Refactoring)의 위험성**: 세 번의 중복이 나타나기 전에 너무 일찍 리팩토링을 시도하면 잘못된 추상화를 선택할 위험이 커진다 [2, 8]. 잘못된 추상화 모델이 시스템에 고착되면, 새로운 요구사항(유스케이스)을 처리하기 위해 부자연스러운 매개변수나 if 문 등을 억지로 추가해야 하므로 코드 유연성이 저하된다 [2, 10]. 결론적으로 잘못된 추상화보다 차라리 코드의 중복을 남겨두는 것이 유지보수 비용 측면에서 훨씬 저렴하다 [11].
|
||||
* **도그마화(Dogmatic)에 대한 경계**: 3의 법칙은 반드시 100% 지켜야 하는 엄격한 교리가 아니라 지침으로 활용해야 한다 [12, 13]. 세 번의 중복이 발견되었더라도 올바른 추상화 방법을 찾기 어렵거나 새로운 개념에 명확한 이름을 붙일 수 없다면, 억지로 추상화(over-abstraction)를 강요해서는 안 된다 [12]. 이런 경우에는 상황에 대한 더 많은 컨텍스트를 얻고 추가적인 중복 사례가 나타날 때까지 리팩토링을 유보하고 기다리는 것이 더 안전하다 [10].
|
||||
### 매 왜 "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 가 적용되지 않음.
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-03*
|
||||
### 매 응용
|
||||
1. Helper function 추출 timing 결정.
|
||||
2. Component / Module 추출 timing 결정.
|
||||
3. Configuration parameter 도입 timing 결정.
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
## 💻 패턴
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
### 1) 2회까지는 inline (resist abstraction)
|
||||
```python
|
||||
# Occurrence 1
|
||||
user_email = data["user"]["email"].strip().lower()
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
|
||||
- **Parent:** [[10_Wiki/Topics]]
|
||||
- **Related:** *(TODO: 최소 2개)*
|
||||
- **Opposite / Trade-off:** *(TODO)*
|
||||
- **Raw Source:** 직접 입력
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
# Occurrence 2 — DO NOT extract yet
|
||||
admin_email = data["admin"]["email"].strip().lower()
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 2) 3회째에 추출 — invariant 가 분명해진 시점
|
||||
```python
|
||||
def normalize_email(raw: str) -> str:
|
||||
return raw.strip().lower()
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
user_email = normalize_email(data["user"]["email"])
|
||||
admin_email = normalize_email(data["admin"]["email"])
|
||||
support_email = normalize_email(data["support"]["email"]) # ← trigger
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 5) 매 LLM-assisted refactoring 의 trigger
|
||||
```python
|
||||
# Claude / Cursor 에게 "extract this duplication" 을 매 3회 occurrence 부터 요청.
|
||||
# 2회 occurrence 에서는 "leave inline" 을 명시.
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]] · [[DRY]]
|
||||
- 변형: [[AHA Principle]] · [[YAGNI]]
|
||||
- 응용: [[AI-Assisted Refactoring]] · [[Code Smell]]
|
||||
- Adjacent: [[Premature Abstraction]] · [[Wrong Abstraction]]
|
||||
|
||||
## 🤖 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 정리 |
|
||||
|
||||
@@ -1,100 +1,175 @@
|
||||
---
|
||||
id: wiki-2026-0508-a2a
|
||||
title: A2A
|
||||
title: A2A (Agent-to-Agent Protocol)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [b3c4d5e6-f7a8-4b9c-0d1e-2f3a4b5c6d7e]
|
||||
aliases: [Agent-to-Agent, A2A Protocol, Agent2Agent]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.97
|
||||
tags: [a2a, agent, protocol, multi-agent, communication, infrastructure]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [agents, protocol, interop, anthropic, mcp]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-01
|
||||
github_commit: wikification-a2a
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: python
|
||||
framework: anthropic-sdk
|
||||
---
|
||||
|
||||
# Agent-to-Agent (A2A)
|
||||
# A2A (Agent-to-Agent Protocol)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> A2A는 서로 다른 하네스나 원격지에 위치한 에이전트들이 작업을 위임하고 상태를 공유하며 협업할 수 있도록 돕는 상호운용성 네트워크 표준 프로토콜이다.
|
||||
## 매 한 줄
|
||||
> **"매 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*.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
### 1. A2A의 정의 및 목적
|
||||
- **에이전트 간 통신망**: 단일 하네스를 넘어 분산된 에이전트 생태계를 연결한다.
|
||||
- **작업 위임(Delegation)**: 상위 오케스트레이터 에이전트가 특정 도메인 전문가 에이전트에게 하위 작업을 맡기고 결과를 회수하는 과정을 규격화한다.
|
||||
## 매 핵심
|
||||
|
||||
### 2. 주요 메커니즘
|
||||
- **메시지 라우팅**: 요청-응답(Request-Response) 및 이벤트 발행-구독(Pub-Sub) 모델을 통해 에이전트 간 정보를 교환한다.
|
||||
- **컨텍스트 전파**: 작업을 위임할 때 필요한 최소한의 문맥(Context)과 권한(Authorization)을 안전하게 전달한다.
|
||||
- **역할 정의**: 송신자(Requester)와 수신자(Worker) 간의 인터페이스 및 책임 범위를 명시한다.
|
||||
### 매 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 모두 지원.
|
||||
|
||||
### 3. MCP와의 관계
|
||||
- **수평적/수직적 확장**: MCP가 '에이전트-도구' 간의 수직적 통합을 담당한다면, A2A는 '에이전트-에이전트' 간의 수평적 협업을 담당하여 완전한 통신 스택을 형성한다.
|
||||
### 매 핵심 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 전송.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **보안 경계**: 원격 에이전트 호출 시 신뢰할 수 없는 데이터가 주입될 위험이 있으며, 교차 인증 및 데이터 검증 계층이 필수적이다.
|
||||
- **오케스트레이션 복잡성**: 에이전트가 많아질수록 통신 지연과 상태 불일치 문제가 발생하며, 이를 관리하기 위한 분산 시스템 수준의 설계가 요구된다.
|
||||
### 매 응용
|
||||
1. Cross-vendor agent orchestration (Claude → Gemini → in-house).
|
||||
2. Specialist agent dispatch (legal, finance, code-review).
|
||||
3. Marketplace 의 agent invocation.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Parent**: 10_Wiki/Topics/AI
|
||||
- **Related**: [[Agent Harness|Agent Harness]], [[Model Context Protocol (MCP)|Model Context Protocol (MCP)]], [[Agentic_Software_Engineering|Agentic Software Engineering]]
|
||||
- **Raw Source**: 00_Raw/Agent-to-Agent (A2A)
|
||||
## 💻 패턴
|
||||
|
||||
## 💻 GitHub 동기화 자동화 워크플로우
|
||||
1. Stage: git add .
|
||||
2. Commit: `git commit -m "[P-Reinforce] Wikify Agent-to-Agent (A2A) Protocol"`
|
||||
3. Push: `git push origin main`
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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"]}
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 2) Task 제출 (client agent)
|
||||
```python
|
||||
import httpx, uuid
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
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"]
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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"])
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 5) Server-side handler (FastAPI 예)
|
||||
```python
|
||||
from fastapi import FastAPI
|
||||
app = FastAPI()
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
@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
|
||||
- 부모: [[Agent Protocols]] · [[JSON-RPC]]
|
||||
- 변형: [[MCP (Model Context Protocol)]] · [[OpenAI Agents SDK]]
|
||||
- 응용: [[Multi-Agent Orchestration]] · [[Agent Marketplace]]
|
||||
- Adjacent: [[OAuth 2.1]] · [[SSE Streaming]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -2,134 +2,144 @@
|
||||
id: wiki-2026-0508-acid-transactions
|
||||
title: ACID Transactions
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-3FC2171D]
|
||||
aliases: [ACID, Database Transactions, Atomicity Consistency Isolation Durability]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [acid-transactions, microservices-architecture, eventual-consistency, saga-pattern, base, architecture-principles]
|
||||
verification_status: applied
|
||||
tags: [database, transactions, consistency, postgres]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-02
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: sql
|
||||
framework: postgres-17
|
||||
---
|
||||
|
||||
# [[ACID Transactions]]
|
||||
# ACID Transactions
|
||||
|
||||
## 📌 Brief 소스에 관련 정보가 부족합니다.
|
||||
ACID 트랜잭션은 작업의 구현을 더 쉽게 만들어주는 전통적인 데이터베이스 트랜잭션 관리 방식입니다 [1]. 그러나 각 서비스가 자체 데이터베이스를 가져야 하는 마이크로서비스 아키텍처(분산 시스템)에서는 도입이 매우 어려워, 시스템 설계 시 최종 일관성(Eventual Consistency) 모델이나 BASE, Saga 패턴 등으로 대체되는 특성을 지닙니다 [2, 3]. 소스에 ACID의 구체적인 원리나 4가지 속성(Atomicity, Consistency, Isolation, Durability)에 대한 상세한 정의 등 관련 정보가 부족합니다.
|
||||
## 매 한 줄
|
||||
> **"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 를 보장.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
소스에 관련 정보가 부족합니다. 다만, 제공된 소스에서 파악할 수 있는 ACID 트랜잭션의 아키텍처적 맥락은 다음과 같습니다:
|
||||
## 매 핵심
|
||||
|
||||
* **구현의 용이성 우위:** 일반적으로 최종 일관성(Eventual Consistency)을 가지는 Saga 패턴이나 BASE 모델을 구현하는 것보다, 전통적인 ACID 트랜잭션으로 작업을 구현하는 것이 훨씬 더 쉽고 직관적입니다 [1].
|
||||
* **분산 아키텍처에서의 적용 한계:** 마이크로서비스 아키텍처는 느슨한 결합(Loose coupling)을 달성하기 위해 '서비스당 데이터베이스(Database per service)' 패턴을 따라야 합니다 [2]. 이로 인해 여러 서비스의 데이터베이스에 걸친 비즈니스 트랜잭션을 중앙에서 관리해야 할 때, 기존의 ACID 트랜잭션을 그대로 적용하는 것은 불가능에 가깝거나 매우 어렵습니다 [2, 3].
|
||||
* **비-ACID(non-ACID) 모델로의 전환:** 여러 서비스에 걸친 복잡한 트랜잭션을 관리하기 위해 현대 분산 아키텍처에서는 ACID 트랜잭션을 포기하는 대신, 결국에는 상태가 동기화됨을 보장하는 비-ACID 방식인 최종 일관성 관리(예: Saga 패턴)를 대안으로 도입하게 됩니다 [2, 3].
|
||||
### 매 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).
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
소스에 ACID 트랜잭션 자체의 원리적 한계에 대한 정보는 부족하나, 아키텍처 선택 관점에서의 반대 급부는 다음과 같습니다:
|
||||
### 매 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 큼.
|
||||
|
||||
* **느슨한 결합(Loose Coupling)과의 충돌:** 애플리케이션의 유연성과 확장성을 위해 마이크로서비스 아키텍처를 도입할 경우, ACID 트랜잭션이 보장하는 강력한 데이터 일관성을 포기해야 하는 구조적 제약이 발생합니다 [2, 3].
|
||||
* **대안 선택 시의 복잡성 증가:** ACID 트랜잭션을 유지할 수 없는 분산 환경에서 최종 일관성 모델(Saga 패턴 등)을 도입하면, 트랜잭션 처리와 관련된 구현 및 테스트 난이도가 급격히 상승하는 반대 급부가 따릅니다 [3]. 비즈니스 로직에 실패 시 롤백을 처리하는 복잡한 보상 트랜잭션(Compensating transaction) 등을 추가로 구현해야 하는 부담이 생깁니다 [4].
|
||||
### 매 응용
|
||||
1. 매 financial / inventory 의 multi-row update.
|
||||
2. 매 idempotent worker — 매 transaction + unique key.
|
||||
3. 매 saga compensation 의 단위.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
(소스에 관련 정보가 부족하여 분산 시스템에서의 트랜잭션 관리 맥락을 중심으로 연결합니다.)
|
||||
## 💻 패턴
|
||||
|
||||
#### [아키텍처/기반 기술]
|
||||
- [[Microservices Architecture]]
|
||||
- 연결 이유: 각 서비스가 개별 데이터베이스를 가지는 특성으로 인해 ACID 트랜잭션 적용이 어렵다는 맥락의 배경이 됩니다 [2].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 단일 모놀리식 아키텍처에서 쉽게 보장되던 ACID 속성이 시스템이 분산됨에 따라 왜 깨지게 되는지 근본적인 아키텍처 원리를 이해할 수 있습니다 [2, 3].
|
||||
|
||||
#### [구현/활용 도구]
|
||||
- [[Eventual Consistency]]
|
||||
- 연결 이유: 분산 시스템 환경에서 ACID 트랜잭션의 강력한 일관성을 대체하기 위해 채택되는 데이터 일관성 모델입니다 [1-3].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 아키텍처가 ACID를 포기할 때, 시스템이 데이터를 동기화하고 최종적으로 상태를 일치시키는 메커니즘을 파악할 수 있습니다 [2, 3].
|
||||
- [[Saga Pattern]]
|
||||
- 연결 이유: 여러 마이크로서비스에 걸친 트랜잭션을 관리하기 위해 ACID 트랜잭션 대신 구체적으로 도입되는 구현 패턴입니다 [3].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 비-ACID(non-ACID) 환경에서 분산 트랜잭션의 순서와 롤백 과정을 어떻게 설계해야 하는지 배울 수 있습니다 [2, 3].
|
||||
- [[BASE]]
|
||||
- 연결 이유: 마이크로서비스 설계 시 전통적인 ACID 트랜잭션 모델과 대조되는 개념으로 언급됩니다 [1].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: ACID 방식이 불가능한 분산 시스템 환경에서 적용하는 데이터베이스 트랜잭션 철학을 이해할 수 있습니다 [1].
|
||||
|
||||
### Deeper Research Questions
|
||||
(소스에 관련 정보가 부족하여 ACID 트랜잭션의 깊이 있는 탐구를 위해 추가 외부 조사가 필요한 질문들입니다.)
|
||||
|
||||
- 분산 아키텍처에서도 ACID 트랜잭션을 보장하기 위해 2PC(Two-Phase Commit) 등의 프로토콜을 사용할 경우 발생하는 성능 및 가용성 저하의 구체적인 원리는 무엇인가?
|
||||
- ACID의 핵심 속성(원자성, 일관성, 고립성, 지속성) 중 분산 환경에서 가장 달성하기 어렵고 성능 병목을 일으키는 속성은 무엇이며 그 이유는 무엇인가?
|
||||
- 금융 시스템과 같이 강한 데이터 일관성(ACID)이 절대적으로 필요한 도메인에서 마이크로서비스를 도입할 때, 일관성과 가용성 사이의 트레이드오프를 해결하는 현대적인 하이브리드 아키텍처 전략은 무엇인가?
|
||||
- 이벤트 기반 아키텍처(EDA)와 이벤트 소싱(Event Sourcing) 환경에서 전통적인 ACID 트랜잭션과 같은 데이터 무결성을 검증하는 방법론은 어떻게 구성되는가?
|
||||
- 마이크로서비스의 Saga 패턴 내에서 일시적인 데이터 불일치(Eventual Consistency)가 발생하는 시간(Window) 동안 사용자에게 발생할 수 있는 이상 현상(Anomalies)을 UI/UX 측면에서 어떻게 방어해야 하는가?
|
||||
|
||||
### Practical Application Contexts
|
||||
|
||||
- **Implementation:** 모놀리식 시스템의 경우 단일 데이터베이스 구조이므로 ACID 트랜잭션을 활용한 쉽고 안전한 데이터 작업 구현이 가능하지만, 향후 마이크로서비스로 전환할 때는 이 구현 방식을 Saga 등으로 전면 수정해야 합니다 [1-3].
|
||||
- **System Design:** 소프트웨어 설계 시, 시스템이 반드시 강한 데이터 일관성(ACID)을 요구하는지, 아니면 최종 일관성만으로도 충분한지를 비즈니스 도메인에 맞춰 분석하고 그에 따라 데이터베이스 분리 여부를 결정해야 합니다 [2, 3].
|
||||
- **Operation / Maintenance:** 단일 시스템의 ACID 환경과 달리 최종 일관성 모델 도입 시 트랜잭션 실패 추적 및 디버깅이 매우 복잡해집니다. 따라서 분산 추적(Distributed Tracing) 및 로그 집계와 같은 강력한 관측성(Observability) 확보 계획이 운영 맥락에서 필수적입니다 [3].
|
||||
- **Learning Path:** 단일 데이터베이스에서의 전통적 ACID 속성(외부 지식 필요) 이해 ➔ 마이크로서비스 분산 환경의 제약사항(Database per Service) 인식 ➔ CAP 정리 및 BASE 모델 학습 ➔ 비-ACID 환경 극복을 위한 분산 트랜잭션 및 Saga 패턴 설계 단계로 아키텍처 학습을 확장할 수 있습니다.
|
||||
- **My Project Relevance:** 현재 대규모 시스템을 작은 서비스 단위로 분해하려는 프로젝트(예: 모놀리스에서 MSA로의 마이그레이션)를 계획 중이라면, 기존에 의존하던 ACID 트랜잭션 보장이 불가능해진다는 점을 사전에 식별하고, 데이터 무결성 보장을 위한 대안 설계를 프로젝트 초기부터 준비하는 데 직결됩니다.
|
||||
|
||||
### Adjacent Topics
|
||||
|
||||
- [[Database per Service Pattern]]
|
||||
- 확장 방향: 마이크로서비스 구조에서 각 서비스의 독립성을 보장하기 위해 데이터가 어떻게 격리되는지 살펴보고, 이 패턴이 분산 트랜잭션 관리와 ACID 트랜잭션 포기에 미치는 직접적인 영향을 연구할 수 있습니다.
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
|
||||
> *(TODO: 한 문장으로 핵심 통찰을 작성. "X는 Y 조건에서 Z 효과를 낸다" 구조 권장.)*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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;
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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 필요
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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;
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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
|
||||
- 부모: [[Database]] · [[Transactions]]
|
||||
- 변형: [[BASE]] · [[Snapshot Isolation]] · [[Serializable Snapshot Isolation (SSI)]]
|
||||
- 응용: [[Outbox Pattern]] · [[Saga Pattern]] · [[Idempotency]]
|
||||
- Adjacent: [[CAP Theorem]] · [[WAL (Write-Ahead Log)]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -2,204 +2,32 @@
|
||||
id: wiki-2026-0508-adr-architecture-decision-record
|
||||
title: ADR (Architecture Decision Record)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
canonical_id: self
|
||||
status: duplicate
|
||||
canonical_id: wiki-2026-0508-adr-architecture-decision-record
|
||||
duplicate_of: "[[ADR_(Architecture_Decision_Records)]]"
|
||||
aliases: []
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, architecture, adr]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
---
|
||||
|
||||
# [[ADR (Architecture Decision Record)]]
|
||||
# ADR (Architecture Decision Record)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
ADR(Architecture Decision Record)은 소프트웨어 프로젝트에서 내려진 아키텍처 결정과 그에 대한 기술적 및 비즈니스적 근거를 기록하는 단일 문서입니다 [1]. 이 문서는 시스템과 팀이 진화함에 따라 과거의 결정 배경이 잊혀지거나 오해받는 것을 방지합니다 [1, 2]. 접근 가능한 저장소에 관리되는 ADR은 의사결정의 이력을 투명하게 유지하여 아키텍처가 이해 가능하고 검증 가능하며 미래의 변화에 대비할 수 있도록 하는 핵심 자산입니다 [3, 4].
|
||||
> **이 문서는 [[ADR_(Architecture_Decision_Records)]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
---
|
||||
## 핵심 요약
|
||||
- 매 singular vs plural title 의 차이만 있음 — 매 동일 concept (Michael Nygard 2011, MADR).
|
||||
- 매 Nygard original blog 는 매 "Documenting Architecture Decisions" 으로 매 plural 사용.
|
||||
- 매 canonical 문서에서 매 template + workflow + LLM 활용 모두 다룸.
|
||||
|
||||
ADR(Architecture Decision Record)은 소프트웨어 아키텍처 결정 사항과 그 근거를 명확하고 투명하게 기록하는 문서화 도구이다 [1, 2]. 이 기록은 아키텍처 결정의 초기 맥락, 채택된 결정, 그 이유, 기각된 대안, 그리고 예상되는 위험과 결과를 상세히 명시한다 [3, 4]. 이를 통해 미래의 팀원, 감사자, 이해관계자들이 시스템의 발전 과정을 이해하고 진화시키는 데 필수적인 지식 관리 자산으로 기능한다 [3, 4].
|
||||
## 🔗 Graph
|
||||
- 부모: [[ADR_(Architecture_Decision_Records)]] (canonical)
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **ADR의 목적과 가치**
|
||||
아키텍처 결정은 한 번 내려지면 되돌리기 어렵고, 시간이 흐를수록 그 배경과 이유가 잊혀지기 쉽습니다 [2]. 결정을 문서화하지 않으면 동일한 논의가 해결 없이 반복되는 안티패턴(anti-pattern)이 발생할 수 있습니다 [1]. ADR은 이러한 지식 증발을 막고, 새로운 팀원, 감사자, 이해관계자 및 미래 시스템의 진화를 위해 이해하기 쉬운 근거와 맥락을 제공하는 중요한 역할을 수행합니다 [2, 3].
|
||||
|
||||
* **표준 구성 요소**
|
||||
ADR은 결정을 내린 과정을 포괄적으로 담고 있으며 일반적으로 다음 항목들로 구성됩니다 [2, 3]:
|
||||
* **Context (맥락):** 결정이 내려지게 된 초기 상황 및 기술적 배경.
|
||||
* **Decision (결정):** 실제로 무엇이 결정되고 선택되었는가.
|
||||
* **Reason/Justification (이유/근거):** 이 선택을 한 기술적 및 비즈니스적(비용, 출시 시간, 사용자 만족도 등) 이유 [1, 3].
|
||||
* **Alternatives (대안):** 검토 후 거절된 옵션들과 그 거절 사유.
|
||||
* **Risks and consequences (위험과 결과):** 이 결정이 단기 및 장기적으로 시스템에 미치는 의미와 위험 요소.
|
||||
|
||||
* **유지 및 관리 프로세스**
|
||||
ADR은 분산된 이메일 소통을 피하고, 위키(wiki)와 같이 중앙 집중화된 접근 가능한 저장소에 유지되어 단일 진실 공급원(single source of truth) 역할을 해야 합니다 [1]. 또한, 아키텍처는 고정된 것이 아니라 사용자 행동, 트래픽 부하, 팀 구조 등 컨텍스트가 변화함에 따라 함께 적응해야 합니다 [3, 5]. 이러한 변화가 발생할 때마다 아키텍처를 검토하고 그 경로를 단계별로 ADR에 갱신하거나 새롭게 기록해야 합니다 [3, 6].
|
||||
|
||||
---
|
||||
|
||||
* **ADR의 핵심 구성 요소**:
|
||||
ADR은 일관된 의사결정 추적을 위해 일반적으로 다음과 같은 구조를 갖는다 [3].
|
||||
* 맥락(Context): 결정을 내려야 했던 초기 상황이나 문제
|
||||
* 결정(Decision): 무엇을 결정했는가
|
||||
* 이유(Reason): 왜 이 선택을 했는가
|
||||
* 대안(Alternatives): 어떤 대안들을 검토했으며 왜 기각되었는가
|
||||
* 위험과 결과(Risks and consequences): 이 결정이 단기 및 장기적으로 시스템에 미치는 의미는 무엇인가
|
||||
|
||||
* **지속적인 문서화의 필요성**:
|
||||
아키텍처 결정은 한 번 내려지면 되돌리기 매우 어려우며, 이메일 등으로 소통할 경우 시간이 지나면 결정의 배경과 맥락이 잊혀져 반복적인 논쟁을 유발하는 안티패턴(Anti-pattern)이 발생할 수 있다 [1, 4]. ADR은 팀 내의 접근 가능한 위키(Wiki) 등에 저장되어 단일 업데이트 소스(Single Source of Truth) 역할을 수행하며 이러한 지식 증발을 방지한다 [1, 4].
|
||||
|
||||
* **적응과 진화의 추적**:
|
||||
사용자 행동 변화, 트래픽 증가, 팀 상황의 변경 등 시스템의 맥락이 변하면 아키텍처도 그에 맞게 적응해야 한다 [3, 5]. ADR은 시스템이 진화하는 경로를 단계별로 문서화하여 이러한 변화의 당위성을 입증한다 [3].
|
||||
|
||||
* **비즈니스 가치와의 정렬**:
|
||||
ADR은 단순히 기술적 선택만 기록하는 것이 아니라, 비용, 사용자 만족도, 시장 출시 시간(Time to market) 등 비즈니스적 타당성도 함께 제공한다 [1]. 따라서 ADR을 통해 이 아키텍처 결정이 실질적인 비즈니스 가치를 지니는지, 혹은 이해관계자의 목표와 일치하는지 객관적으로 검증할 수 있다 [1].
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
소스에 ADR 자체의 구조적인 제약 사항이나 부작용에 대한 상세한 정보가 부족합니다. 다만, 소스에서 확인되는 의사결정 및 문서화 과정에서의 한계와 관리적 책임(Trade-off)은 다음과 같습니다.
|
||||
|
||||
* **지속적인 유지보수 책임:** 아키텍처와 ADR은 한 번 작성되고 끝나는 것이 아닙니다. 요구사항, 부하, 팀의 운영 현실 등 컨텍스트가 변경되면 아키텍처 역시 변경되어야 하며, 이에 맞춰 ADR 문서도 반드시 지속적으로 업데이트되어야 하는 관리 비용이 발생합니다 [5, 6].
|
||||
* **비즈니스 가치 불일치 위험:** ADR에 기록된 아키텍처 결정이 가시적인 비즈니스 가치를 제공하지 못하거나, 이해관계자의 비즈니스 목표와 어긋난 채로 확정되어 문서화될 경우, 시스템 구현에 악영향을 미치므로 해당 결정을 다시 전면적으로 재고해야 하는 리스크가 있습니다 [1].
|
||||
|
||||
---
|
||||
|
||||
소스에 관련 정보가 부족합니다.
|
||||
(단, ADR과 같은 문서화 과정 자체에 대한 명시적인 단점은 소스에 서술되어 있지 않으나, 아키텍처를 둘러싼 컨텍스트가 변경될 때마다 시스템과 함께 ADR도 지속적으로 재검토하고 업데이트해야 하는 관리적 책임이 수반된다는 점이 제약 사항으로 언급되어 있습니다 [5]. 또한, ADR에 기록된 내용이 실질적인 비즈니스 가치를 제공하지 못하거나 비즈니스 이해관계자와 어긋나는 것으로 판명될 경우, 해당 아키텍처 결정을 즉각적으로 재고(reconsidered)해야 합니다 [1].)
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
|
||||
#### [의사결정 및 평가 방법론]
|
||||
* [[ATAM (Architecture Tradeoff Analysis Method)]]
|
||||
* 연결 이유: 특정 아키텍처가 비즈니스 목표를 얼마나 잘 지원하는지 평가하고 트레이드오프와 위험 요소를 식별하는 방법론으로, 이 분석의 최종 선택 결과가 ADR에 문서화됩니다 [2, 7, 8].
|
||||
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: 아키텍처 결정 과정에서 추상적인 목표 대신 구체적인 시나리오를 바탕으로 어떻게 타협점(Trade-off)을 찾고, 그 근거를 ADR의 '대안' 및 '위험' 항목에 객관적으로 채워 넣는지 이해할 수 있습니다.
|
||||
* [[Architecture Anti-patterns]]
|
||||
* 연결 이유: 아키텍처 결정을 미루거나 문서화하지 않아 반복적인 논의만 발생하는 현상으로, ADR의 도입이 이 안티패턴을 해결하는 핵심 해결책입니다 [1].
|
||||
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: 의사결정 기록의 부재가 프로젝트 개발 속도를 늦추고 분석 마비(analysis paralysis)를 일으키는 과정을 이해할 수 있습니다.
|
||||
|
||||
#### [시스템 유지보수 및 진화]
|
||||
* [[Software Architecture Erosion (소프트웨어 아키텍처 침식)]]
|
||||
* 연결 이유: 시스템이 노후화되고 지식 증발(knowledge vaporization)이 발생하여 의도한 아키텍처와 실제 구현 사이에 격차가 생기는 현상이며, ADR은 이를 예방하는 수단이 됩니다 [2, 9, 10].
|
||||
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: 문서화 누락이 장기적으로 시스템 성능 저하와 기술 부채(technical debt) 축적으로 이어지는 공학적 원리를 배울 수 있습니다.
|
||||
|
||||
### Deeper Research Questions
|
||||
* 컨텍스트(사용자 부하, 비즈니스 요구사항 등)가 변경되어 시스템 아키텍처를 수정해야 할 때, 기존 ADR을 폐기하고 새로 작성해야 하는가, 아니면 기존 ADR을 버전 관리하여 업데이트해야 하는가?
|
||||
* ATAM을 통한 시나리오 기반 분석 결과는 ADR의 '대안(Alternatives)' 및 '위험(Risks)' 섹션에 정량적으로 어떻게 기술되어야 하는가?
|
||||
* 단순한 소프트웨어 설계(Design) 결정과 아키텍처(Architecture) 결정을 구분하여 ADR에 필수적으로 기록해야 하는 기준점이나 규모는 어떻게 정해지는가?
|
||||
* 애자일(Agile) 환경에서 "마지막 책임 순간(last responsible moment)"에 결정을 내리는 전략과 ADR의 즉각적인 문서화 프로세스를 어떻게 마찰 없이 통합할 수 있는가?
|
||||
* 분산된 마이크로서비스 아키텍처 환경에서 여러 팀이 각기 다른 서비스의 ADR을 작성할 때, 전체 시스템 관점에서의 무결성을 어떻게 유지할 수 있는가?
|
||||
|
||||
### Practical Application Contexts
|
||||
* **Implementation:** 이메일이나 파편화된 메신저가 아닌 위키(Wiki) 등 중앙 집중화된 접근 가능한 저장소에 단일 진실 공급원(Single source of truth)으로 문서를 구축하고 관리해야 합니다 [1].
|
||||
* **System Design:** 품질 요구사항(확장성, 성능 등)에 기반하여 여러 아키텍처 패턴을 비교 평가한 뒤, 최종적으로 선택한 패턴의 근거와 감수한 타협점(Trade-off)을 ADR에 명시하여 설계의 타당성을 조직 내에 입증합니다 [2, 8, 11].
|
||||
* **Operation / Maintenance:** 시스템 운영 중 특정 장애에 대처하거나 리팩토링을 진행할 때, 과거에 특정 기술이나 제약 사항을 왜 수용했는지 감사자(Auditors)와 운영팀이 쉽게 추적하고 이해할 수 있도록 돕습니다 [3].
|
||||
* **Learning Path:** 팀에 새로 합류한 인원(New team members)이 시스템 구조가 현재와 같이 발전하게 된 역사적 맥락과 과거의 결정들을 빠르게 학습하기 위한 필수 온보딩 자료로 활용됩니다 [2, 3].
|
||||
* **My Project Relevance:** 프로젝트 중 유행하는 기술(Hype)이나 개인적 선호가 아닌, 측정 가능한 우선순위에 입각해 기술 결정을 내리도록 강제하고, 끝없는 논쟁을 방지하기 위한 핵심 규칙으로 적용할 수 있습니다 [1, 2, 12].
|
||||
|
||||
### Adjacent Topics
|
||||
* [[Software Architecture Knowledge Management (소프트웨어 아키텍처 지식 관리)]]
|
||||
* 확장 방향: 아키텍처 설계 과정에서 이해관계자의 머릿속에만 머물기 쉬운 암묵적 지식(tacit knowledge)을 발굴하고 소통하며 체계적으로 보존하는 포괄적인 관리 체계를 연구합니다 [13].
|
||||
* [[Agile Software Development (애자일 소프트웨어 개발)]]
|
||||
* 확장 방향: 아키텍처의 초기 선행 설계(Big design up front)를 지양하면서도, 지속적으로 변화하는 요구사항 속에서 필수적인 기반 구조를 마련하고 의사결정을 적응시키는 방법을 탐구합니다 [14].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
---
|
||||
|
||||
### Related Concepts
|
||||
|
||||
#### [아키텍처 평가 및 분석 방법]
|
||||
- [[ATAM (Architecture Tradeoff Analysis Method)]]
|
||||
- 연결 이유: 시스템의 아키텍처를 평가할 때 품질 속성 간의 타협점(Trade-offs)을 식별하고 구체적인 시나리오를 통해 분석하는 방법론으로, ADR에 기록될 결정의 근거와 위험성을 도출하는 핵심적인 선행 단계이다 [4, 6].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 아키텍처 결정 과정에서 성능, 보안, 유연성 등 충돌하는 요구사항들이 어떻게 정량적이고 객관적으로 분석되어 문서화(ADR)로 이어지는지 파악할 수 있다 [4, 6].
|
||||
|
||||
#### [아키텍처 설계 및 관리 원칙]
|
||||
- [[Architecture Anti-patterns (아키텍처 안티패턴)]]
|
||||
- 연결 이유: 잘못된 선택에 대한 두려움으로 결정을 미루거나, 이메일로 파편화된 소통을 하여 결정 사항을 잊어버리는 등의 문제 현상을 지칭하며, ADR은 이를 예방하고 극복하기 위해 사용되는 직접적인 도구이다 [1].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: ADR과 같은 중앙화된 아키텍처 결정 기록이 없을 때, 시스템 설계 과정과 팀 내 의사소통이 어떻게 붕괴될 수 있는지 그 근본 원인을 이해할 수 있다 [1].
|
||||
|
||||
- [[Software Architecture Erosion (소프트웨어 아키텍처 침식)]]
|
||||
- 연결 이유: 시간이 지남에 따라 의도한 초기 아키텍처와 실제 구현 사이에 격차가 벌어지는 현상을 말하며, 아키텍처 지식의 증발(Knowledge Vaporization)과 결정 사항의 문서화(ADR) 부재가 그 주요 원인이다 [7].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: ADR을 활용한 지식 보존이 장기적으로 시스템의 아키텍처 침식을 방지하고 기술 부채의 축적을 막는 예방적 조치로서 어떤 역할을 하는지 통찰할 수 있다 [7, 8].
|
||||
|
||||
### Deeper Research Questions
|
||||
|
||||
- 이해관계자 간의 요구사항 충돌이 있을 때, ADR의 '대안(Alternatives)' 섹션은 합의 및 기각 과정을 구체적으로 어떻게 기록해야 협업 효율성을 높일 수 있는가?
|
||||
- 애자일(Agile)과 같이 변경이 잦고 빠른 개발 환경에서 ADR 문서를 지속적으로 최신 상태로 유지하고 코드와 동기화하기 위한 가장 효율적인 전략은 무엇인가?
|
||||
- ADR에 기록된 비즈니스 타당성(비용, 출시 시간 등)을 사후에 정량적으로 측정하여 기존 아키텍처 결정의 유효성을 재평가하는 프로세스는 어떻게 설계되는가?
|
||||
- 마이크로서비스 아키텍처처럼 각기 독립된 개발 팀이 다수 존재하는 분산 환경에서, 전사적으로 일관된 형태의 ADR 저장소를 구축하고 거버넌스를 유지하는 방법은 무엇인가?
|
||||
- 아키텍처 침식(Architecture Erosion)을 효과적으로 방지하기 위해 ADR 기반의 문서화 체계를 정적 코드 분석 도구 등 자동화된 예방 수단과 어떻게 연계할 수 있는가?
|
||||
|
||||
### Practical Application Contexts
|
||||
|
||||
- **Implementation:** 아키텍처 설계와 구현을 시작하기 전, 채택된 아키텍처 패턴과 기술 스택의 결정 사유, 기각된 기술적 대안, 수반되는 위험을 양식에 맞춰 작성하여 개발 팀과 공유한다 [3, 4].
|
||||
- **System Design:** 단일 장애점(SPOF) 방지나 성능 확장성을 위해 내린 설계적 결단(예: 분산 시스템 도입 등)과 그에 따른 트레이드오프(ATAM 평가 결과 등)를 접근 가능한 단일 진실 공급원(Single Source of Truth)으로 문서화한다 [1, 6].
|
||||
- **Operation / Maintenance:** 운영 중 장애가 발생하거나 시스템 업데이트, 신규 팀원의 온보딩 시, 과거에 특정 아키텍처 구조가 왜 채택되었는지를 추적하여 시스템 진화의 근거 자산으로 활용한다 [3, 4].
|
||||
- **Learning Path:** 소프트웨어 엔지니어 및 아키텍트가 아키텍처 설계 실무를 학습할 때, 이메일 중심의 파편화된 소통을 지양하고 올바른 지식 관리(Knowledge Management)와 합리적인 의사결정 과정을 내재화하는 핵심 도구로 다룬다 [1, 9].
|
||||
- **My Project Relevance:** 복잡성이 높은 프로젝트를 수행할 때 아키텍처 결정이 개인의 기억에만 의존하거나 증발되는 것을 방지하기 위해, 위키(Wiki)나 저장소를 활용해 지속 가능하고 추적 가능한 프로젝트 기록 문화를 수립하는 데 직결된다 [1, 3].
|
||||
|
||||
### Adjacent Topics
|
||||
|
||||
- [[ISO/IEC 25010 (Quality Model)]]
|
||||
- 확장 방향: ADR 작성의 객관적인 기준점이 되는 시스템 품질 속성(성능 효율성, 보안, 유지보수성, 호환성 등)의 분류 및 평가를 위한 국제 표준화 체계 탐구 [10, 11].
|
||||
- [[Prototyping / Proof of Concept (PoC)]]
|
||||
- 확장 방향: 아키텍처 결정을 ADR로 확정하기에 앞서, 핵심적인 기술 리스크를 조기에 식별하고 성능 및 부하 처리의 타당성을 검증하기 위한 실무적인 기술 검증 기법 조사 [12, 13].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
|
||||
@@ -2,260 +2,184 @@
|
||||
id: wiki-2026-0508-adr-architecture-decision-record
|
||||
title: ADR (Architecture Decision Records)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [ADR, Architecture Decision Record, Decision Log, Lightweight ADR]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.95
|
||||
verification_status: applied
|
||||
tags: [architecture, documentation, decisions, governance]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: markdown
|
||||
framework: madr
|
||||
---
|
||||
|
||||
# [[ADR (Architecture Decision Records)]]
|
||||
# ADR (Architecture Decision Records)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
ADR(Architecture Decision Records)은 아키텍처 결정 사항과 그 근거를 이해하기 쉽고 검증 가능하게 문서화하는 도구입니다 [1-3]. 시스템의 맥락, 결정 내용, 합리적 근거, 고려된 대안, 그리고 단/장기적 위험과 결과를 기록함으로써 시간이 지나도 과거의 결정 배경을 추적할 수 있게 합니다 [3, 4]. 이를 통해 새로운 팀원, 감사자, 기타 이해관계자들이 시스템을 깊이 이해하고 진화시키는 데 필요한 핵심 자산으로 활용됩니다 [3, 4].
|
||||
## 매 한 줄
|
||||
> **"매 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 로 유지.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
Architecture Decision Records(ADR)는 소프트웨어 아키텍처와 관련된 중요한 기술적 결정 사항과 그 맥락, 대안, 근거 및 잠재적 위험을 명확히 기록하는 문서화 체계입니다 [1, 2]. 한 번 내려지면 변경하기 어려운 아키텍처 결정의 배경이 시간이 지나면서 잊혀지는 것을 방지하기 위해 단일 진실 공급원(Single Source of Truth)으로 유지됩니다 [2, 3]. 이는 신규 팀원이나 이해관계자, 감사자에게 시스템 진화 과정을 이해시키는 가장 중요한 자산으로 활용됩니다 [1, 2].
|
||||
### 매 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.
|
||||
|
||||
아키텍처 결정 기록(ADR)은 소프트웨어 아키텍처에 대한 결정 사항과 그 기술적 배경, 검토된 대안, 그리고 예상되는 결과 및 위험을 체계적으로 문서화한 기록입니다 [1, 2]. 이는 시간이 지나면서 아키텍처 설계의 맥락이 잊혀지는 것을 방지하고, 관련 이해관계자들을 위한 **단일 진실 공급원(Single source of truth)** 역할을 수행하여 시스템의 지속적인 진화를 지원합니다 [2, 3].
|
||||
### 매 응용
|
||||
1. 매 framework / DB / cloud provider 선택.
|
||||
2. 매 API style (REST vs gRPC vs GraphQL).
|
||||
3. 매 auth, observability, deploy strategy.
|
||||
4. 매 LLM model / provider 선택.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **문서화의 전략적 가치:** 소프트웨어 아키텍처 결정은 한 번 내려지면 되돌리기 어렵고, 시간이 흐를수록 그 배경과 맥락이 쉽게 잊혀집니다 [3]. 따라서 어떤 기술적 배경에서 결정이 이루어졌는지 체계적인 이력 관리를 하기 위해 ADR의 작성이 필수적으로 요구됩니다 [3].
|
||||
* **ADR의 핵심 구성 요소:** ADR은 객관적인 결정을 담보하기 위해 보통 다음과 같은 구체적인 항목들을 포함하여 작성됩니다 [3, 4].
|
||||
* **맥락(Context):** 결정이 내려지게 된 초기 상황과 기술적 배경은 무엇인가?
|
||||
* **결정(Decision):** 구체적으로 무엇을 선택하고 결정했는가?
|
||||
* **근거(Reason/Justification):** 이 선택을 하게 된 객관적이고 합리적인 이유는 무엇인가?
|
||||
* **대안(Alternatives):** 어떠한 대안들을 검토했으며, 해당 대안들은 왜 거절되었는가?
|
||||
* **위험 및 결과(Risks and consequences):** 이 결정이 단기 및 장기적으로 어떤 결과와 기술적 위험을 초래할 수 있는가?
|
||||
* **아키텍처 진화의 이력 관리:** 훌륭한 아키텍처는 고정된 것이 아니라, 트래픽(부하)의 변화나 새로운 통합 요구사항, 팀의 스킬셋 변화 등 운영 컨텍스트가 변화함에 따라 지속적으로 진화해야 합니다 [3, 5]. 컨텍스트가 변화하여 아키텍처를 수정할 때마다 ADR을 정기적으로 검토하고 함께 업데이트함으로써, 시스템이 거쳐온 진화의 궤적을 명확하게 문서화합니다 [5].
|
||||
## 💻 패턴
|
||||
|
||||
---
|
||||
### 1) Nygard ADR template
|
||||
```markdown
|
||||
# 0007. Use Postgres for OLTP
|
||||
|
||||
* **ADR의 필수 구성 요소**
|
||||
ADR은 후일에도 누구나 의사결정 과정을 이해할 수 있도록 다음과 같은 핵심 항목을 포함하여 작성됩니다 [1].
|
||||
* **컨텍스트(Context):** 의사결정을 내릴 당시의 초기 상황이나 배경은 무엇이었는가?
|
||||
* **결정(Decision):** 최종적으로 무엇이 결정되었는가?
|
||||
* **이유(Reason):** 왜 이 선택을 하게 되었는가 (비즈니스 및 기술적 타당성)?
|
||||
* **대안(Alternatives):** 어떠한 다른 옵션들이 기각되었으며, 그 이유는 무엇인가?
|
||||
* **위험 및 결과(Risks and consequences):** 이 결정이 단기 및 장기적으로 시스템에 어떤 의미(위험성 등)를 가지는가?
|
||||
Date: 2026-05-10
|
||||
Status: Accepted
|
||||
|
||||
* **안티패턴(Anti-patterns) 극복 도구**
|
||||
아키텍처 결정이 이메일 등을 통해 파편화되어 소통되거나, 전혀 문서화되지 않으면 반복적인 논의만 발생하고 결론이 나지 않는 안티패턴에 빠지기 쉽습니다 [2, 3]. 건축가(Architect)는 기술적 정당성과 비즈니스적 근거(비용, 사용자 만족도, 시장 출시 시간 등)를 결합하여 단일 ADR에 기록하고 위키와 같은 접근 가능한 저장소에 보관함으로써 이러한 위험을 효과적으로 방지할 수 있습니다 [3].
|
||||
## Context
|
||||
We need an OLTP store with strong ACID, JSON support, and managed offerings
|
||||
across AWS/GCP/Azure. Team size 12. Expected QPS 5k.
|
||||
|
||||
* **시스템 진화에 따른 문서화 유지**
|
||||
아키텍처는 고정된 유물이 아니라 시스템의 성장과 환경 변화에 따라 진화합니다 [2]. 사용자 수의 증가, 새로운 통합 요구사항, 팀 상황 등의 컨텍스트(Context)가 변화하면 아키텍처 또한 그에 맞게 적응해야 하며, 이때 ADR 역시 반드시 함께 업데이트되고 리뷰되어야 합니다 [4-6].
|
||||
## Decision
|
||||
Adopt Postgres 17 (RDS / Aurora / Cloud SQL / Neon).
|
||||
|
||||
---
|
||||
|
||||
* **ADR의 핵심 구성 요소**
|
||||
전형적인 ADR은 아키텍처 결정을 명확히 하기 위해 다음 항목들을 포함해야 합니다 [1, 2, 4].
|
||||
* **Context (컨텍스트):** 결정이 내려지게 된 초기 상황과 기술적 배경
|
||||
* **Decision (결정 사항):** 궁극적으로 어떤 선택을 내렸는지에 대한 명시
|
||||
* **Reason (이유 및 근거):** 이 특정한 선택을 내리게 된 논리적 기반과 정당성
|
||||
* **Alternatives (대안):** 거절된 다른 옵션들은 무엇이며, 왜 기각되었는지에 대한 설명
|
||||
* **Risks and consequences (위험과 결과):** 이 결정이 단기 및 장기적으로 시스템에 미치는 영향과 내재된 리스크
|
||||
|
||||
* **아키텍처 안티패턴(Anti-pattern) 방지**
|
||||
아키텍처 결정을 이메일 등으로 임시로 소통하거나 문서화하지 않으면, 결정 사항이 잊혀지거나 오해를 낳아 문제 해결 없이 반복적인 논의만 이어지는 안티패턴이 발생할 수 있습니다 [3]. ADR은 이러한 문제를 해결하기 위해 고안되었으며, 위키(wiki)와 같이 접근 가능한 저장소에 유지하여 조직 내 **단일 진실 공급원**을 확립하는 데 사용됩니다 [3].
|
||||
|
||||
* **시스템 진화와 의사소통을 위한 전략적 자산**
|
||||
아키텍처 결정은 한 번 내려지면 변경 비용이 매우 높기 때문에 그 배경을 문서화하는 것이 필수적입니다 [2, 5]. 기록된 ADR은 새로운 팀원의 온보딩, 감사(Auditors), 이해관계자와의 소통, 그리고 미래의 시스템 개발 방향을 결정하는 데 가장 중요한 자산이 됩니다 [1, 2]. 시스템 부하, 사용자 행동, 팀의 기술 역량 등 프로젝트 맥락은 계속 변화하며, ADR은 이러한 변화의 궤적을 단계별로 기록하여 시스템이 변화에 적응하도록 돕습니다 [1].
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
**소스에 ADR 도입 자체에 대한 구체적인 부작용이나 제약 사항에 관한 정보는 부족합니다.**
|
||||
|
||||
다만, 주어진 소스는 **"완벽한 아키텍처란 없으며 모든 결정은 타협(Trade-off)의 결과"**라고 강조합니다 [6]. 따라서 ADR은 특정 아키텍처를 선택하는 과정에서 발생하는 트레이드오프(예: 고도의 보안성을 얻기 위해 성능(대기 시간)을 희생하거나, 일관성을 양보하여 가용성을 높이는 등의 결정)를 식별하고, 이로 인한 제약 사항 및 타협 지점(Trade-off Points)을 투명하게 기록하는 수단으로 기능합니다 [3, 6, 7]. 즉, 기술적 선택의 반대 급부를 관리하고, 이를 시스템의 위험 요소로 명확히 인지하기 위해 ADR이 사용됩니다 [3, 4, 7].
|
||||
|
||||
---
|
||||
|
||||
* **지속적인 리뷰와 업데이트 책임 (유지보수 비용)**
|
||||
요구사항이나 부하 프로필, 운영 현실(Operational realities)이 변경되면 이전에 작성된 ADR의 근거가 더 이상 유효하지 않을 수 있습니다. 따라서 컨텍스트가 변화할 때마다 정기적으로 아키텍처와 ADR을 재검토(Review)하고 수정해야 하는 유지관리 책임이 발생합니다 [4, 6].
|
||||
* **비즈니스 가치와의 일치성 요구**
|
||||
단순히 기술적으로 우수한 패턴이라고 해서 무조건 결정되는 것이 아니라, 해당 아키텍처 결정이 뚜렷한 비즈니스적 가치(Business value)를 제공해야만 합니다. 의사결정이 비즈니스 이해관계자와 일치하지 않거나 유형의 가치를 제공하지 못한다면, 문서화되었더라도 그 결정은 재고되어야 합니다 [3].
|
||||
* **과정의 엄격성에 따른 지연 위험**
|
||||
모든 결정을 ADR로 철저히 남기기 위해 정보를 수집하고 정당화하는 과정은 필수적이나, 이로 인해 결정을 지나치게 미루는 '분석 마비(Analysis paralysis)' 안티패턴에 빠지지 않도록 "마지막 책임 순간(Last responsible moment)"에 결정을 내리는 균형 감각이 필요합니다 [3].
|
||||
|
||||
---
|
||||
|
||||
* **지속적인 리뷰와 업데이트 책임:** ADR은 한 번 작성하고 끝나는 정적인 문서가 아닙니다. 사용량 증가, 새로운 통합 요구사항 발생, 인프라 운영 현실의 변화 등 **컨텍스트가 변경되면 아키텍처도 반드시 적응해야 하며 ADR 역시 함께 갱신**되어야 합니다 [4, 6]. 이를 방치하면 문서와 실제 아키텍처 간의 괴리(침식)가 발생할 수 있습니다.
|
||||
* **비즈니스 가치와의 정렬 필수:** ADR에 기록된 아키텍처 결정은 단순히 기술적 만족을 위한 것이 아니라, 비용, 사용자 만족도, 시장 출시 시간 등 **구체적인 비즈니스 가치에 대한 정당성을 포함**해야 합니다 [3]. 만약 명확한 비즈니스 가치를 제공하지 못하거나 이해관계자의 목표와 엇나간다면, 해당 결정은 재고되어야 합니다 [3].
|
||||
* **분석 마비(Analysis Paralysis)의 위험:** 꼼꼼한 문서화와 완벽한 결정을 내리려는 압박감 때문에 결정을 지연시키는 현상을 경계해야 합니다 [3]. 결정은 충분한 정보를 확보한 **'마지막 책임 순간(last responsible moment)'**에 이루어져야 하며, 개발 팀과의 긴밀한 협력을 통해 진행해야 합니다 [3].
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
|
||||
#### [관계 유형 A: 아키텍처 평가 및 분석 방법론]
|
||||
- [[ATAM (Architecture Trade-offs Analysis Method)]]
|
||||
- 연결 이유: ATAM은 특정 아키텍처가 비즈니스 목표를 얼마나 잘 지원하는지 평가하고 시스템의 트레이드오프를 식별하는 '골드 스탠다드' 방법론입니다 [6, 7]. 이 과정을 통해 도출된 아키텍처의 한계와 타협점들이 ADR에 문서화됩니다 [3, 8].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 추상적인 성능 논의가 아닌, "사용자가 10분 내에 2배로 증가할 때"와 같은 구체적인 '시나리오'를 바탕으로 아키텍처의 리스크와 트레이드오프를 체계적으로 분석하는 과정을 이해할 수 있습니다 [6, 7].
|
||||
|
||||
#### [관계 유형 B: 소프트웨어 품질 및 요구사항 기준]
|
||||
- [[ISO/IEC 25010 (품질 모델)]]
|
||||
- 연결 이유: 아키텍처 대안을 비교하고 평가할 때 객관적인 척도와 기준점을 제공하는 국제 표준 품질 모델입니다 [9].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: ADR의 '근거(Reason)' 항목을 작성할 때 기능 적합성, 성능 효율성, 호환성 등 어떤 품질 속성에 가중치(우선순위)를 두어 결정을 내렸는지 객관적으로 파악하는 기준을 세울 수 있습니다 [9, 10].
|
||||
|
||||
### Deeper Research Questions
|
||||
- ADR을 실무에 도입할 때, 빠르고 반복적인 배포가 이루어지는 애자일(Agile) 환경에서 발생할 수 있는 문서화 유지보수의 오버헤드는 어떻게 극복할 수 있는가?
|
||||
- 비즈니스 요구사항이나 시스템 사용 패턴의 변화로 인해 초기 결정 맥락이 완전히 바뀌었을 때, 기존의 ADR 문서는 어떤 방식으로 업데이트되고 버전 관리가 이루어지는가?
|
||||
- ATAM과 같은 시나리오 기반 분석을 통해 발견된 치명적인 한계점(Sensitivity points)은 ADR의 '위험 및 결과(Risks and consequences)' 섹션에 어떤 형식으로 정량화되어 기술되는가?
|
||||
- 마이크로서비스(MSA)와 모듈형 모놀리스 사이에서 고민할 때, ADR의 대안(Alternatives) 섹션에서 가장 핵심적으로 비교되어야 할 기준은 무엇인가?
|
||||
- 대규모 팀에서 새로운 구성원이 합류하거나 외부 감사가 이루어질 때, 방대한 ADR 이력을 효과적으로 탐색하고 시스템을 파악하게 만드는 베스트 프랙티스는 무엇인가?
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 개발자가 시스템을 구현할 때, 특정한 아키텍처 패턴이 왜 선택되었는지 ADR을 통해 이해함으로써 일관성 있는 코드와 솔루션을 작성하는 가이드라인으로 활용됩니다 [3, 11].
|
||||
- **System Design:** 초기 아키텍처 설계 단계에서 직관이나 유행(트렌드)에 의존하지 않고, 식별된 요구사항과 프로토타입 검증 결과를 기반으로 내린 구조적 결정을 문서로 남겨 설계의 객관성을 확보합니다 [8, 12, 13].
|
||||
- **Operation / Maintenance:** 운영 중 트래픽의 급증이나 새로운 시스템과의 통합 등 환경 변화가 발생했을 때, 기존 ADR을 리뷰하여 당시 아키텍처가 가진 한계와 제약사항을 파악하고 안전하게 시스템을 진화시킵니다 [3-5].
|
||||
- **Learning Path:** 프로젝트에 새로 온보딩하는 구성원들이 시스템이 현재의 복잡한 구조를 갖게 된 역사적 맥락과 진화 과정을 단계별로 학습하는 훌륭한 교보재 역할을 합니다 [3, 4].
|
||||
- **My Project Relevance:** 나의 프로젝트에서 기술 스택을 변경하거나 새로운 아키텍처 패턴을 도입할 때, 구두 합의나 휘발성 높은 이메일 대신 ADR 포맷에 맞춰 논의 과정을 명확히 남김으로써 미래의 기술 부채를 방지할 수 있습니다 [2, 3].
|
||||
|
||||
### Adjacent Topics
|
||||
- [[프로토타이핑 및 개념 증명(PoC)]]
|
||||
- 확장 방향: 아키텍처 결정을 확정하고 ADR을 작성하기 전, 성능이나 기술적 실행 가능성 등 핵심 리스크를 조기에 실험하여 불확실성을 최소화하는 실무적 검증 기법으로 확장이 가능합니다 [14].
|
||||
- [[의사결정 매트릭스(Decision Matrix)]]
|
||||
- 확장 방향: 여러 아키텍처 후보군을 정의된 품질 요구사항을 바탕으로 정량적 비교 및 평가하여, ADR 내 결정 근거(Reason)의 논리를 더욱 탄탄하게 뒷받침하는 방법론으로 연계할 수 있습니다 [15].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
---
|
||||
|
||||
### Related Concepts
|
||||
|
||||
#### [관계 유형 A (평가/분석 프레임워크)]
|
||||
- [[ATAM (Architecture Trade-offs Analysis Method)]]
|
||||
- 연결 이유: ADR에 작성될 '결정 이유', '대안', '위험 및 결과' 항목을 채우기 위해, 결정 이전에 구체적인 시나리오를 바탕으로 아키텍처의 트레이드오프(Trade-offs)를 체계적으로 도출하는 방법론입니다 [7, 8].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 직관적인 결정이 아닌 시나리오 기반 사고를 통해 아키텍처의 숨겨진 위험(Sensitivity points)과 절충안을 ADR에 객관적으로 수치화하고 문서화하는 원리를 이해할 수 있습니다 [7, 8].
|
||||
|
||||
- [[ISO 25010 Quality Model]]
|
||||
- 연결 이유: 아키텍처 결정 시 기준이 되는 품질 요구사항(기능 적합성, 성능 효율성, 유지보수성 등)을 정의하는 국제 표준 프레임워크입니다 [9, 10].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: ADR에서 기술적 선택의 타당성을 입증할 때, 성능을 위해 암호화 수준을 낮춘다거나 확장성을 위해 전달 속도를 양보하는 식의 구체적인 품질 평가 척도를 어떻게 활용하는지 이해할 수 있습니다 [7, 11].
|
||||
|
||||
#### [관계 유형 B (아키텍처 운영/관리 문제)]
|
||||
- [[Software Architecture Erosion (소프트웨어 아키텍처 침식)]]
|
||||
- 연결 이유: 의도된 아키텍처와 실제 구현된 시스템 사이의 격차가 벌어지는 현상으로, 기술 부채와 지식 증발(Knowledge vaporization)로 인해 발생합니다 [12].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: ADR을 작성하고 지속적으로 관리하는 것이 아키텍처 침식을 예방하고, 지식이 증발하여 유지보수 비용이 급증하는 현상을 막기 위한 강력한 예방 조치(Preventative measure)임을 이해할 수 있습니다 [12, 13].
|
||||
|
||||
### Deeper Research Questions
|
||||
- 애자일(Agile) 개발과 같이 빠른 프로토타이핑(Prototyping)과 잦은 피드백 루프가 존재하는 환경에서, ADR 작성 및 업데이트에 소요되는 오버헤드를 어떻게 최소화할 수 있는가? [3, 14, 15]
|
||||
- 이메일이나 파편화된 문서로 존재하던 과거의 아키텍처 의사결정(Legacy decisions)을 추적하고 소프트웨어 아키텍처 복구(Architecture Recovery)를 수행할 때 ADR을 도입하는 베스트 프랙티스는 무엇인가? [3, 16]
|
||||
- 분산 시스템(예: Microservices, Space-Based Architecture)에서 여러 팀이 독립적으로 서비스를 개발할 때, 전체 시스템 수준의 ADR과 팀 단위의 ADR 간의 충돌 및 정렬(Alignment) 문제는 어떻게 해결해야 하는가? [2, 17]
|
||||
- ADR에 명시된 비즈니스적 가치(비용, 시장 출시 시간 등)가 시장 상황 변화에 따라 더 이상 유효하지 않을 때, 이미 구축된 아키텍처를 어떻게 효율적으로 재조정(Refactoring)할 것인가? [3, 13]
|
||||
- ATAM을 통해 도출된 트레이드오프와 리스크(Risks and sensitivity points)를 ADR 템플릿의 각 항목에 구체적으로 매핑(Mapping)하는 정량적인 기준은 어떻게 설계해야 하는가? [1, 7]
|
||||
|
||||
### Practical Application Contexts
|
||||
|
||||
- **Implementation:** 새로운 기능 추가 시 단일 아키텍처 구조로 통합할지, 별도의 플러그인(Microkernel)이나 마이크로서비스로 분리할지에 대한 결정을 내릴 때, 선택하지 않은 대안들과 그 이유를 기록하여 훗날 기술 부채로 인식되지 않게 방어합니다 [1, 18, 19].
|
||||
- **System Design:** 초기 시스템 설계 시, ATAM 및 ISO 25010에 따라 성능, 비용, 개발 노력을 분석한 뒤 도출된 의사결정 결과를 ADR 포맷에 맞춰 저장소(Wiki 등)에 공통 자산으로 중앙화합니다 [1, 3, 11].
|
||||
- **Operation / Maintenance:** 예상보다 사용자가 급증하거나 외부 시스템 연동 요구가 생기는 등 운영(Context) 현실이 달라지면, 기존 ADR을 바탕으로 어떤 품질 특성을 타협(Trade-off)해야 할지 재평가하고 아키텍처를 유연하게 수정합니다 [4, 6].
|
||||
- **Learning Path:** 프로젝트에 새로 합류한 개발자나 아키텍트가 레거시 시스템을 파악할 때, 코드 자체만으로는 알 수 없는 “왜 이런 비효율적으로 보이는 방식을 채택했는가?”에 대한 역사적, 기술적, 비즈니스적 맥락을 학습하는 온보딩 도구로 활용됩니다 [1, 2].
|
||||
- **My Project Relevance:** 현재 진행하거나 기획 중인 모든 소프트웨어 프로젝트에서, 구두나 메신저로 협의한 기술적 결정들을 Wiki 페이지 등에 `Context`, `Decision`, `Reason`, `Alternatives`, `Risks` 양식에 맞추어 하나의 기록물로 남겨두어 단일 진실 공급원(Single source of truth) 체계를 직접 구축할 수 있습니다 [1, 3].
|
||||
|
||||
### Adjacent Topics
|
||||
|
||||
- [[Software Architecture Recovery (소프트웨어 아키텍처 복구)]]
|
||||
- 확장 방향: 아키텍처 결정이 문서화(ADR)되지 않아 노후화되거나 문서가 유실된 레거시 시스템에서, 소스 코드 및 가용 정보를 역공학(Reverse engineering)하여 본래의 아키텍처 구조를 찾아내는 기술적 방법론 탐구 [16].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
---
|
||||
|
||||
### Related Concepts
|
||||
|
||||
#### [아키텍처 평가 및 결정 (Architecture Evaluation & Decision)]
|
||||
* [[ATAM (Architecture Trade-offs Analysis Method)]]
|
||||
* 연결 이유: ADR 작성 전, 여러 아키텍처의 장단점(Trade-offs)을 시나리오 기반으로 분석하고 평가하는 핵심 방법론입니다 [7, 8].
|
||||
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: ADR의 '대안(Alternatives)' 및 '위험(Risks)' 섹션에 채워 넣을 객관적인 지표와 상충 관계를 어떻게 도출하는지 원리를 이해할 수 있습니다.
|
||||
|
||||
* [[ISO 25010 Quality Model]]
|
||||
* 연결 이유: 아키텍처 결정 시 기반이 되는 기능 적합성, 성능, 확장성 등의 비기능적 품질 속성 평가 기준을 제공합니다 [9, 10].
|
||||
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: ADR의 '이유(Reason)' 항목을 작성할 때, 어떤 품질 기준을 근거로 아키텍처의 우위를 판단했는지 체계적인 근거를 마련할 수 있습니다.
|
||||
|
||||
#### [소프트웨어 생명주기 관리 (Software Lifecycle Management)]
|
||||
* [[Architecture Erosion (아키텍처 침식)]]
|
||||
* 연결 이유: 아키텍처 결정이 제대로 문서화(ADR)되지 않아 '지식 증발(knowledge vaporization)'이 일어날 때 발생하는 시스템 구조의 붕괴 현상입니다 [11].
|
||||
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: 왜 ADR을 통한 철저한 기록이 장기적인 시스템의 수명과 유지보수 비용 절감에 직결되는지 그 위험성을 학습할 수 있습니다.
|
||||
|
||||
### Deeper Research Questions
|
||||
* 애자일(Agile) 환경에서 "마지막 책임 순간(last responsible moment)"에 내리는 적시의 아키텍처 결정과 ADR 작성 사이의 속도와 문서화의 균형을 어떻게 맞출 수 있는가?
|
||||
* 요구사항이나 트래픽 프로필이 크게 바뀌어 과거 ADR의 결정 사항이 무효화될 때, 이전 ADR을 어떤 버전 관리 기준으로 보관하고 갱신해야 하는가?
|
||||
* ATAM과 같은 평가 기법으로 도출된 식별된 위험(Sensitivity points)들을 ADR 문서 템플릿에 어떻게 정량적이고 구체적으로 매핑할 것인가?
|
||||
* ADR에 기술적 논거 외에도 비용 최적화, 시장 출시 속도 등 비즈니스 이해관계자를 위한 정당성(Justification)을 효과적으로 융합하는 실무 사례는 무엇인가?
|
||||
* 초기 프로토타입(Prototype) 및 기술 검증(Proof of Concept)의 결과를 ADR 작성 과정에 편입시켜 결정을 검증(Validation)하는 가장 이상적인 타이밍은 언제인가?
|
||||
|
||||
### Practical Application Contexts
|
||||
* **Implementation:** 새로운 데이터베이스나 클라우드 제공자를 프로젝트에 도입할 때, 결정의 배경과 검토했다가 거절한 기술 스택을 ADR로 남겨 후임 개발자들의 중복 검토를 방지합니다.
|
||||
* **System Design:** 모놀리식에서 마이크로서비스(MSA)로 전환하는 등 거시적 아키텍처 변경을 기획할 때, 기술적 대안들과 트레이드오프 분석 결과를 문서로 기록하여 의사결정을 공식화합니다.
|
||||
* **Operation / Maintenance:** 운영 중 시스템 부하가 예상치를 초과하거나 팀 규모가 변경되었을 때, 기존 ADR을 리뷰하고 현재 컨텍스트에 맞게 아키텍처를 진화시킬지 결정하는 기준점으로 삼습니다.
|
||||
* **Learning Path:** 소프트웨어 아키텍트 지망생이 아키텍처 안티패턴(결정 지연, 이메일 기반의 휘발성 소통)을 학습하고, 이를 극복하기 위한 체계적인 문서화 및 지식 관리 프로세스를 실습하는 데 적용됩니다.
|
||||
* **My Project Relevance:** 현재 진행 중인 개인 혹은 팀 프로젝트의 위키(Wiki) 공간에 ADR 템플릿을 도입하여, 팀원들과 시스템 구조에 대한 단일 진실 공급원(SSOT)을 구축하는 기준으로 활용합니다.
|
||||
|
||||
### Adjacent Topics
|
||||
* [[Technical Debt (기술 부채)]]
|
||||
* 확장 방향: 아키텍처의 의도와 구현이 틀어지거나 문서화의 부재로 인해 발생하는 기술 부채의 원인과 이를 측정하고 리팩토링하는 과정을 조사합니다.
|
||||
* [[Architecture Decision Matrix (아키텍처 결정 매트릭스)]]
|
||||
* 확장 방향: 대안들을 객관적으로 비교하기 위해 확장성, 개발 노력, 유지보수성 등 동일한 기준으로 여러 아키텍처를 스코어링(scoring)하는 평가 도구의 활용법을 학습합니다.
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
## Consequences
|
||||
+ Mature ecosystem, ACID, JSONB, pgvector.
|
||||
- Vertical scaling ceiling — needs Citus / sharding past ~30TB.
|
||||
~ Team will invest in `psql` / pgbouncer expertise.
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 2) MADR full template
|
||||
```markdown
|
||||
# Use Postgres for OLTP
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
* Status: Accepted
|
||||
* Deciders: @alice, @bob, @carol
|
||||
* Date: 2026-05-10
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
## Context and Problem Statement
|
||||
...
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
## Decision Drivers
|
||||
* ACID, managed offering, ecosystem
|
||||
* Cost ceiling at 5k QPS
|
||||
* Vector search (pgvector)
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
## Considered Options
|
||||
* Postgres
|
||||
* MySQL
|
||||
* CockroachDB
|
||||
* DynamoDB
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 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]] · [[Software Governance]]
|
||||
- 변형: [[MADR]] · [[Y-Statement]] · [[Nygard ADR]]
|
||||
- 응용: [[ATAM]] · [[RFC Process]] · [[C4 Model]]
|
||||
- Adjacent: [[Documentation as Code]] · [[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_Record)]] 가 매 redirect 로 본 문서를 가리킴.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — Nygard + MADR templates + adr-tools workflow |
|
||||
|
||||
@@ -1,132 +1,160 @@
|
||||
---
|
||||
id: wiki-2026-0508-ai-assisted-refactoring-ai-기반-리팩
|
||||
title: AI Assisted Refactoring (AI 기반 리팩토링)
|
||||
title: AI-Assisted Refactoring (AI 기반 리팩토링)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [AI Refactoring, LLM Refactoring, Agent Refactoring]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [uncategorized]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [refactoring, ai, llm, claude-code, cursor, codemod]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: claude-code
|
||||
---
|
||||
|
||||
# [[AI-Assisted Refactoring (AI 기반 리팩토링)]]
|
||||
# AI-Assisted Refactoring (AI 기반 리팩토링)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
AI 기반 리팩토링은 대형 언어 모델(LLM)과 같은 인공지능 도구를 활용하여 소프트웨어의 외부 동작을 변경하지 않으면서 내부 코드 구조를 분석하고 개선하는 과정을 의미한다 [1, 2]. 이 접근법은 보일러플레이트 코드 작성이나 자동화된 단위 테스트 생성을 통해 리팩토링의 생산성을 크게 높일 수 있지만, 기존 시스템의 암묵적 지식을 파악해야 하는 복잡한 아키텍처 작업에서는 숙련된 개발자의 작업 속도를 오히려 늦출 위험도 존재한다 [3-5]. 따라서 AI 도구는 자동화된 테스트 및 인간 개발자의 철저한 검토와 결합되어 기술 부채를 통제하는 보조 수단으로 전략적으로 활용되어야 한다 [6-8].
|
||||
## 매 한 줄
|
||||
> **"매 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".
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **분석 및 대안 제시 (Analysis & Recommendations):** AI 모델은 방대한 코드베이스를 분석하여 코드 스멜(Code Smell)을 실시간으로 탐지하고, 프로젝트의 코딩 규칙에 맞는 리팩토링 대안을 제안한다 [1, 2, 9]. 다양한 설계 대안을 비교하거나, 레거시 코드를 더 모듈화되고 재사용 가능한 서비스로 일괄 변환(Batch transformation)하는 데 유용하다 [2, 9].
|
||||
* **계층적 다중 에이전트 활용 (Hierarchical Multi-Agent Approach):** 전체 아키텍처와 교차 모듈 간의 의존성을 분석해 리팩토링 계획을 수립하는 플래너 모델(예: Gemini 2.5 Pro)과, 파일 단위의 국지적인 리팩토링과 테스트 생성을 수행하는 실행 모델(예: Cursor)을 분리하여 리팩토링을 수행하는 체계가 연구 및 적용되고 있다 [10, 11].
|
||||
* **작업 유형별 효율성 차이 (Task-Specific Efficiency):** 반복적인 보일러플레이트 코드 작성, 언어 변환, 문서화 및 단위 테스트 생성 등 단순한 작업에서는 AI가 20~55% 수준의 높은 생산성 향상을 제공한다 [5, 12, 13]. 특히 도메인 지식이 부족한 주니어 개발자에게 설계 지식을 보완해주어 큰 효율성(최대 39% 향상)을 제공할 수 있다 [8, 14].
|
||||
* **자동화 테스트를 통한 가드레일 (Test-Guarded Validation):** AI는 코드를 환각(Hallucination)하거나 오류를 유발할 수 있으므로 리팩토링의 안전성을 보장하기 위해서는 인간이 감독(Human-in-the-loop)하고, 리팩토링 전에 AI를 활용하여 포괄적인 단위 테스트(안전망)를 먼저 생성하는 방식이 요구된다 [6, 7, 15, 16].
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
* **AI 생산성 역설 (AI Productivity Paradox):** 숙련된 시니어 개발자가 익숙한 코드베이스에서 AI를 사용할 경우, 개발자는 자신이 20% 더 빨라졌다고 느끼지만 실제로는 작업 속도가 19% 하락하는 39%의 '인식 격차(Perception Gap)'가 발생할 수 있다 [3, 8, 17, 18].
|
||||
* **암묵적 지식 및 인지 비용 (Implicit Knowledge Problem):** 전문가들이 머릿속에 지니고 있는 아키텍처 결정 사항, 과거 버그 내역, 팀의 관례 등의 암묵적 지식을 AI에게 프롬프트로 설명하고(Context-giving) 결과를 검토하는 데 걸리는 시간이, 개발자가 직접 코드를 리팩토링하는 시간보다 더 오래 걸릴 수 있다 [4, 19, 20].
|
||||
* **병목 현상의 전이 (Bottleneck Migration):** AI 도구가 코드 생성 자체의 속도는 크게 단축시키지만, 생성된 코드를 테스트하고 아키텍처에 통합하며 리뷰하는 시간(PR Review Time)이 91%나 증가하게 되어 개발 워크플로우의 병목이 후속 단계로 이동하게 된다 [21, 22].
|
||||
* **핵심 기술 위축 (Skills Atrophy):** AI에 과도하게 의존하여 리팩토링을 수행하면 개발자의 구문 기억력, 문제 분해 능력, 수동 디버깅 직관, 그리고 코드를 읽고 이해하는 깊이 있는 인지 능력이 저하될 위험이 존재한다 [22, 23].
|
||||
### 매 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.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
### 매 적합 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 제거.
|
||||
|
||||
#### [관계 유형 A: 리팩토링 및 검증 기반 (Refactoring & Validation Foundations)]
|
||||
- [[Test-Driven Development (TDD)]]
|
||||
- 연결 이유: AI를 통해 구조를 변경할 때 기존 기능이 보존됨을 보장하려면 선행되는 테스트 구축(Red-Green-Refactor)이 필수적인 안전망으로 작용하기 때문이다 [18, 24].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: AI가 생성한 코드를 인간이 검토하기 전에 자동화된 피드백 루프를 통해 결함을 조기에 발견하고 검증하는 메커니즘을 이해할 수 있다 [24, 25].
|
||||
### 매 부적합 task
|
||||
- 매 architectural redesign — 매 human 의 design 결정 필요.
|
||||
- 매 perf-critical hot path — 매 measurement 없이 매 LLM 의 "looks faster" 신뢰 X.
|
||||
- 매 security-sensitive (auth, crypto) — 매 human review 필수.
|
||||
|
||||
- [[Code Smells]]
|
||||
- 연결 이유: 리팩토링이 필요한 구조적 결함의 지표이며, 현대 AI 코딩 도구들은 방대한 데이터를 학습하여 이 냄새들을 실시간으로 자동 탐지한다 [2, 26, 27].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: AI가 어떤 논리(긴 함수, 중복 코드 등)를 기준으로 리팩토링 대안을 제안하는지 그 근간이 되는 식별 원칙을 이해할 수 있다 [27, 28].
|
||||
### 매 응용
|
||||
1. Legacy codebase 의 점진적 modernization.
|
||||
2. Mass dependency upgrade.
|
||||
3. Test coverage 가속.
|
||||
|
||||
#### [관계 유형 B: AI 활용의 한계 및 조직적 현상 (AI Usage Limits & Phenomena)]
|
||||
- [[AI Productivity Paradox]]
|
||||
- 연결 이유: AI 코딩 보조 도구가 모든 상황에서 리팩토링 속도를 높여주는 것이 아니며, 작업 복잡도 및 개발자 숙련도에 따라 오히려 지연을 초래할 수 있음을 입증하는 현상이다 [3, 8, 29].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 시니어 개발자가 구조적이고 복잡한 리팩토링을 할 때 AI 사용을 전략적으로 취사선택(Task Selector)해야 하는 이유를 이해할 수 있다 [20, 30].
|
||||
## 💻 패턴
|
||||
|
||||
- [[Bottleneck Migration]]
|
||||
- 연결 이유: AI 리팩토링으로 코드 작성 속도가 빨라진 대신, 생성된 코드의 정확성을 검토하는 리뷰(Code Review) 단계로 병목이 이동하는 현상이다 [21, 22].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: AI 도구 도입 시 단순히 작성 속도만 고려할 것이 아니라, 품질 보증(QA) 및 코드 리뷰 역량을 동시에 확장해야 함을 이해할 수 있다 [22].
|
||||
|
||||
### Deeper Research Questions
|
||||
|
||||
- AI를 활용하여 대규모 레거시 코드베이스의 '접점(Seam)'을 자동으로 식별하고 테스트 불가능했던 의존성을 끊어내는 과정을 어디까지 자동화할 수 있는가?
|
||||
- 숙련된 개발자가 복잡한 아키텍처 리팩토링을 수행할 때 AI에게 컨텍스트를 주입(Context-giving)하는 비용을 최소화하기 위한 최적의 프롬프트 및 도구 환경(예: Cursor, Claude Code) 조합은 무엇인가?
|
||||
- AI가 생성한 리팩토링 코드의 무결성과 행동 보존(Behavior Preservation)을 완벽하게 입증하기 위해, 돌연변이 테스트(Mutation Testing) 등과 같은 기법을 어떻게 결합할 수 있는가?
|
||||
- AI 리팩토링 도입 후 증가하는 '코드 리뷰 병목 현상'을 해결하기 위해 개발 조직의 리뷰 프로세스와 자원 분배를 어떻게 재설계해야 하는가?
|
||||
- 개발자의 '기술 위축(Skills Atrophy)'을 방지하면서도 AI 리팩토링의 이점을 취하기 위해, 개발팀 내에 어떠한 의도적 훈련(Deliberate Practice) 사이클을 구축해야 하는가?
|
||||
|
||||
### Practical Application Contexts
|
||||
|
||||
- **Implementation:** 테스트가 부족한 레거시 프론트엔드/백엔드 코드를 리팩토링하기 전, AI 코딩 어시스턴트(예: Gemini 2.5 Pro)를 활용해 기존 동작을 포착하는 포괄적인 단위 테스트(승인 테스트)를 수 시간 내에 일괄 생성하는 데 적용할 수 있다 [31, 32].
|
||||
- **System Design:** 방대한 절차 지향적 코드나 비대해진 모놀리식 클래스의 책임을 분리할 때, AI에게 추상 구문 트리(AST) 수준의 분석을 맡겨 응집도 높은 여러 개의 도메인 모델로 분리하는 구조적 대안을 탐색하는 데 사용할 수 있다 [2, 33].
|
||||
- **Operation / Maintenance:** 매직 넘버 교체, 단순 데이터 객체(Data Class)로의 변환, 변수명 일괄 렌더링 및 보일러플레이트 코드 패턴 수정 등 상대적으로 리스크가 적고 반복적인 리팩토링 작업의 유지보수 속도를 크게 가속할 수 있다 [5, 13].
|
||||
- **Learning Path:** 주니어 개발자가 이해하기 난해한 타인의 레거시 코드를 읽을 때(이해를 위한 리팩토링), AI 모델의 설명 기능(Reasoning)을 결합하여 코드의 원래 의도를 학습하고 개선안을 도출하는 멘토링 도구로 활용 가능하다 [8, 13].
|
||||
- **My Project Relevance:** 프로젝트에 AI 어시스턴트를 도입할 때, 단순 코드 완성과 문서화에는 AI를 적극 활용하되, 핵심 비즈니스 규칙 변경이나 아키텍처 결정 시에는 의존성을 AI에게 맡기지 않고 전문가 판단과 엄격한 동료 리뷰를 거치도록 'AI Task Selector' 가이드를 수립할 수 있다 [5, 20, 30].
|
||||
|
||||
### Adjacent Topics
|
||||
|
||||
- [[Automated Testing Frameworks]]
|
||||
- 확장 방향: AI가 리팩토링한 코드가 기존 로직과 동일하게 동작하는지 자동으로 보장하기 위한 단위 테스트 도구(JUnit, Mockito 등)와의 통합 및 파이프라인(CI) 구성 방법론 탐구 [34-36].
|
||||
- [[Strangler Fig Pattern]]
|
||||
- 확장 방향: 레거시 시스템 전체를 한 번에 재작성(Rewrite)하지 않고, 점진적으로 의존성을 끊고 새로운 아키텍처로 대체하는 과정에서 AI의 모듈 분리 능력을 어떻게 결합할 수 있는지에 대한 연구 [37, 38].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-03*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 1) Claude Code 의 대규모 rename
|
||||
```bash
|
||||
claude
|
||||
> Rename `getUserData` to `fetchUserProfile` across the repo.
|
||||
> Update all callsites, tests, and JSDoc.
|
||||
> Run `npm test` after.
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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.
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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();
|
||||
}
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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."
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]] · [[AI Coding Agents]]
|
||||
- 변형: [[Codemod]] · [[ast-grep]] · [[jscodeshift]]
|
||||
- 응용: [[3의 법칙 (Rule of Three)]] · [[Library Migration]]
|
||||
- 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 |
|
||||
|
||||
@@ -2,121 +2,186 @@
|
||||
id: wiki-2026-0508-api-gateway
|
||||
title: API Gateway
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-80E2D2FE]
|
||||
aliases: [API GW, Gateway pattern, Edge service]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [api-gateway, 마이크로서비스-아키텍처-(microservices-architecture), 서버리스-아키텍처-(serverless-architecture), 서비스-메시-(service-mesh), 레거시-시스템-현대화-(legacy-system-modernization), architecture-principles]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [architecture, microservices, api, gateway, edge]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-02
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: yaml
|
||||
framework: Kong, AWS API Gateway, Envoy
|
||||
---
|
||||
|
||||
# [[API Gateway]]
|
||||
# API Gateway
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
API Gateway는 클라이언트와 마이크로서비스(또는 서버리스 함수) 사이에서 중개자 역할을 수행하는 관리 도구이자 핵심 아키텍처 패턴입니다 [1, 2]. 클라이언트의 API 요청을 접수하여 적절한 백엔드 마이크로서비스로 전달(Forward)하고, 그 결과를 모아 다시 클라이언트에게 반환하는 애플리케이션의 주 진입점(Entry point) 역할을 수행합니다 [2, 3]. 이를 통해 클라이언트에게 일관된 인터페이스를 제공하며 기반 아키텍처의 복잡성을 추상화합니다 [4].
|
||||
## 매 한 줄
|
||||
> **"매 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) 의 추가.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **단일 진입점 및 라우팅 (Entry Point & Routing):** 마이크로서비스 아키텍처에서 API Gateway는 클라이언트가 내부 서비스에 접근하는 방식을 정의하는 주 진입점으로 사용됩니다 [1, 3]. 클라이언트의 요청을 받아 올바른 마이크로서비스로 라우팅하고, 응답을 수신하여 클라이언트에게 반환하는 중개자 역할을 합니다 [2].
|
||||
- **아키텍처 추상화 및 일관성 (Abstraction & Consistency):** 기존 모놀리식 아키텍처에서 서버리스나 마이크로서비스 기반으로 마이그레이션할 때, 기반 아키텍처의 복잡성을 숨기고 클라이언트에게 일관된 인터페이스를 제공하는 전략적 수단으로 사용됩니다 [4].
|
||||
- **서버리스 및 이벤트 기반 워크로드 통합 (Serverless & Event-Driven Integration):** AWS Lambda와 같은 클라우드 서비스와 결합되어 서버리스 아키텍처를 구성하는 데 활용되며 [5], 데이터 스트림 처리, 실시간 분석과 같은 이벤트 기반 워크로드(Event-driven workloads)를 처리하는 데 탁월한 역할을 수행합니다 [6].
|
||||
- **보안 및 관리 도구 (Security & Management Tool):** API Gateway 자체는 마이크로서비스가 아니며, 백엔드 서비스들을 운영하고 관리하는 도구입니다 [2]. 서버리스 및 분산 환경에서는 각 컴포넌트별 권한(Permissions) 제어 및 환경 변수 관리를 세심하게 수행하는 지점이 됩니다 [7].
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **기술 스택의 비대화 및 비용 증가 (Fatter Technology Stack & Cost):** API Gateway를 도입하면 오케스트레이터, 서버 클러스터, 서비스 메시 등과 함께 전체 기술 스택이 두꺼워지며(Fatter technology stack) 더 많은 리소스를 요구하게 됩니다 [8]. 이는 마이크로서비스 기반 소프트웨어 개발 프로젝트의 전체적인 클라우드 리소스 및 인프라 비용을 증가시키는 원인이 됩니다 [9].
|
||||
- **관리의 복잡성 (Management Complexity):** 서버리스 환경에서 API Gateway를 활용할 때 각 컴포넌트(함수)에 대한 권한 및 환경 변수를 세밀하게 관리해야 하는 운영 상의 복잡성이 수반됩니다 [7]. 또한, 백엔드의 마이크로서비스들과 명확하게 연결되어야만 제 기능을 하므로 설계 및 구성 과정에서 추가적인 노력이 필요합니다 [2].
|
||||
### 매 책임
|
||||
- **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).
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
### 매 NOT 책임
|
||||
- Business logic — 매 service 의 책임.
|
||||
- Data persistence — 매 stateless edge.
|
||||
- Heavy aggregation — 매 BFF (Backend-for-Frontend) layer 의 책임.
|
||||
|
||||
#### [관계 유형 A (아키텍처/기반 기술)]
|
||||
- [[마이크로서비스 아키텍처 (Microservices Architecture)]]
|
||||
- 연결 이유: API Gateway는 마이크로서비스 아키텍처에서 클라이언트가 수많은 독립적인 서비스에 접근하기 위해 반드시 필요한 진입점(Entry point) 패턴으로 설계됩니다 [1, 3].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 분산된 시스템 환경에서 개별 서비스의 복잡성을 캡슐화하고 클라이언트 통신을 중개해야 하는 구조적 당위성을 이해할 수 있습니다 [2].
|
||||
- [[서버리스 아키텍처 (Serverless Architecture)]]
|
||||
- 연결 이유: AWS Lambda와 같은 서버리스 함수들을 클라이언트에 노출시키고 이벤트 기반 워크로드를 관리하기 위해 API Gateway가 핵심 인프라로 결합되어 사용됩니다 [5, 6].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 인프라 관리 없이 함수 단위로 코드를 실행하는 환경에서 요청을 어떻게 수신하고 라우팅하는지 파악할 수 있습니다 [4, 10].
|
||||
### 매 응용
|
||||
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.
|
||||
|
||||
#### [관계 유형 B (구현/운영 요소)]
|
||||
- [[서비스 메시 (Service Mesh)]]
|
||||
- 연결 이유: API Gateway와 함께 분산 애플리케이션의 통신, 운영 및 관리를 돕는 도구로 함께 언급되며, 마이크로서비스 환경에서 기술 스택을 두껍게 만드는 주요 요소로 꼽힙니다 [8, 11].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 외부 클라이언트와의 통신을 제어하는 API Gateway와 시스템 내부 마이크로서비스 간의 통신을 제어하는 서비스 메시의 역할 차이 및 상호 보완적인 관계를 이해할 수 있습니다 [2, 11].
|
||||
## 💻 패턴
|
||||
|
||||
### Deeper Research Questions
|
||||
- 모놀리식 아키텍처에서 서버리스 아키텍처로 마이그레이션할 때 API Gateway를 활용하여 점진적으로 시스템을 교체하는 구체적인 원리는 무엇인가? [4, 12]
|
||||
- API Gateway가 클라이언트 요청을 다수의 마이크로서비스로 라우팅할 때 발생할 수 있는 단일 장애점(Single Point of Failure) 문제나 성능 병목 현상은 어떻게 설계적으로 완화할 수 있는가? [2]
|
||||
- API Gateway와 서비스 메시(Service Mesh)는 마이크로서비스 통신 관리 측면에서 어떻게 역할이 명확히 구분되며, 어떤 규모의 시스템에서 결합하여 사용해야 하는가? [2, 8, 11]
|
||||
- 서버리스 아키텍처에서 API Gateway를 통한 이벤트 기반 워크로드 처리 시, 권한 관리와 환경 변수 구성의 복잡성을 최소화하기 위한 아키텍처적 파이프라인이나 접근법은 무엇인가? [6, 7]
|
||||
- API Gateway를 통과하는 트래픽을 관측(Observability)하고 디버깅하기 위해 분산 시스템의 로깅 및 추적 설계는 어떻게 구성되어야 하는가? [13, 14]
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** AWS API Gateway와 같은 클라우드 관리 도구를 사용하여 클라이언트 요청을 백엔드 서버리스 함수로 전달함으로써 Slack과 같은 애플리케이션의 실시간 통신 및 통합 기능을 구현합니다 [5, 6].
|
||||
- **System Design:** 다수의 마이크로서비스로 구성된 이커머스 애플리케이션(예: StoreFrontUI)에서 클라이언트가 내부 서비스 로직에 직접 접근하지 못하도록 일관된 인터페이스를 제공하는 주 진입점(Entry point)으로 설계합니다 [3, 4, 15].
|
||||
- **Operation / Maintenance:** 개별 마이크로서비스 및 서버리스 컴포넌트의 권한 및 환경 설정을 중앙 집중식으로 관리하며 [7], 레거시 모놀리식 시스템을 분산 아키텍처로 마이그레이션할 때 요청 경로를 제어하여 무중단 전환을 지원합니다 [4].
|
||||
- **Learning Path:** 모놀리식 아키텍처와 마이크로서비스 및 서버리스 아키텍처의 차이를 학습한 후, 분산 시스템 환경에서 외부 클라이언트와 통신을 제어하고 시스템 결합도를 낮추는 아키텍처 패턴을 이해하는 과정으로 활용됩니다 [1, 2].
|
||||
- **My Project Relevance:** 소스에 관련 정보가 부족합니다. (제공된 소스 데이터에는 사용자의 특정 프로젝트 구현 맥락에 대한 정보가 존재하지 않습니다.)
|
||||
|
||||
### Adjacent Topics
|
||||
- [[레거시 시스템 현대화 (Legacy System Modernization)]]
|
||||
- 확장 방향: 모놀리식 아키텍처에서 서버리스나 마이크로서비스 구조로 전환 시, API Gateway를 활용해 점진적으로 아키텍처를 교체하고 구형 시스템과 신형 시스템 간의 라우팅을 추상화하는 기법을 탐구합니다 [4].
|
||||
- [[이벤트 기반 아키텍처 (Event-Driven Architecture)]]
|
||||
- 확장 방향: API Gateway가 실시간 분석이나 데이터 스트리밍과 같은 이벤트 기반 워크로드를 어떻게 트리거하고 수용하는지 그 비동기적 통신 구조의 설계 방식을 분석합니다 [6].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### LLM gateway (Portkey-style fallback)
|
||||
```python
|
||||
from portkey_ai import Portkey
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
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"}])
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]]
|
||||
- 변형: [[Backend for Frontend (BFF)]] · [[Service Mesh]] · [[Reverse Proxy]]
|
||||
- 응용: [[Rate Limiting]] · [[OAuth2]] · [[mTLS]]
|
||||
- Adjacent: [[Load Balancer]] · [[CDN]] · [[Ingress Controller]]
|
||||
|
||||
## 🤖 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) |
|
||||
|
||||
@@ -2,82 +2,194 @@
|
||||
id: wiki-2026-0508-api-contract-definition
|
||||
title: API Contract Definition
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-Reinforce-662214]
|
||||
aliases: [API Contract, OpenAPI Contract, Schema-First API, Contract-First Design]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [uncategorized]
|
||||
verification_status: applied
|
||||
tags: [api, openapi, contract, schema, design]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-04-20
|
||||
github_commit: "[P-Reinforce] Mega Batch - Wikified API-Contract-Definition"
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: yaml
|
||||
framework: openapi-3.1
|
||||
---
|
||||
|
||||
# [[API-Contract-Definition]]
|
||||
# API Contract Definition
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> 핵심 요약 작업 진행 중
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
본문 상세 구성 진행 중
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 지식 자산화 및 기존 네트워크 연동 단계.
|
||||
- **정책 변화:** Software Architecture 카테고리의 전문성 확보 및 링크 밀도 최적화.
|
||||
### 매 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 에 유리.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
---
|
||||
### 매 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.
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
### 매 contract testing
|
||||
- **Provider tests**: 매 server 가 매 spec 을 만족하는지 검증 (매 schemathesis, dredd, prism).
|
||||
- **Consumer-driven contracts**: 매 Pact — 매 client 가 매 expectation 을 매 publish, 매 server 가 매 verify.
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
### 매 응용
|
||||
1. SDK auto-generation (Stainless, Speakeasy, OpenAPI Generator).
|
||||
2. Mock server (Prism, Mockoon).
|
||||
3. Fuzz / property test (Schemathesis).
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
## 💻 패턴
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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] }
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 2) gRPC proto
|
||||
```proto
|
||||
syntax = "proto3";
|
||||
package orders.v1;
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
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; }
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 3) GraphQL SDL
|
||||
```graphql
|
||||
type Order {
|
||||
id: ID!
|
||||
total: Float!
|
||||
status: Status!
|
||||
}
|
||||
enum Status { PENDING PAID SHIPPED CANCELED }
|
||||
type Query { order(id: ID!): Order }
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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' }
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]] · [[Schema-First Development]]
|
||||
- 변형: [[OpenAPI]] · [[gRPC]] · [[GraphQL]] · [[AsyncAPI]]
|
||||
- 응용: [[Contract Testing]] · [[SDK Generation]] · [[Mock Server]]
|
||||
- Adjacent: [[JSON Schema]] · [[Pact]] · [[Schemathesis]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -1,161 +1,198 @@
|
||||
---
|
||||
id: wiki-2026-0508-api-first-architecture
|
||||
title: API First Architecture
|
||||
title: API-First Architecture
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [API-first design, Contract-first, Schema-first]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [architecture, api, openapi, contract-first, design]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: yaml
|
||||
framework: OpenAPI 3.1, Stoplight, Spectral, buf
|
||||
---
|
||||
|
||||
# [[API-First Architecture|API-First Architecture]]
|
||||
# API-First Architecture
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> **API-First Architecture**는 애플리케이션 프로그래밍 인터페이스(API)를 시스템의 최우선 제품으로 취급하는 소프트웨어 설계 방식입니다 [1]. 제품을 먼저 구축하고 나중에 API를 덧붙이는 대신, API의 설계와 문서화부터 개발을 시작합니다 [1]. 이러한 계약 우선(contract-first) 방법론을 통해 API의 일관성과 재사용성을 보장하며, 프론트엔드와 백엔드 개발 팀이 분리되어 병렬로 효율적인 작업을 진행할 수 있도록 지원합니다 [1, 2].
|
||||
## 매 한 줄
|
||||
> **"매 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).
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
**API-First Architecture**는 애플리케이션 개발 프로세스에서 사용자의 인터페이스나 데이터베이스 스키마보다 **API 설계(Interface Design)**를 최우선 순위에 두는 전략입니다. 시스템의 핵심 기능을 일관된 API로 먼저 정의하고, 이를 기반으로 프론트엔드, 모바일, 서드파티 통합 등 다양한 클라이언트가 독립적으로 진화할 수 있도록 합니다. 이는 복잡한 마이크로서비스 환경에서 서비스 간 계약(Contract)을 명확히 하고 데이터의 정합성을 유지하는 근간이 됩니다.
|
||||
### 매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **작동 방식 및 주요 원칙**
|
||||
* **계약 주도 개발 (Contract-Driven Development):** 개발 팀들은 OpenAPI나 AsyncAPI와 같은 사양을 사용하여 엔드포인트, 데이터 모델, 인증 방법 등을 명시한 API 계약(contract)에 동의합니다 [3]. 이렇게 정의된 사양은 이후의 모든 개발 및 통합 작업의 명확한 지침이 됩니다 [3].
|
||||
* **독립적인 개발 주기:** API 계약이 정의되면, 프론트엔드 팀은 모의(Mocked) 버전의 API를 기반으로 즉시 UI 개발과 테스트를 진행할 수 있고, 동시에 백엔드 팀은 실제 비즈니스 로직을 구현할 수 있어 개발 주기가 효과적으로 분리됩니다 [2, 3].
|
||||
* **일관된 클라이언트 경험 제공:** 웹 프론트엔드, 모바일 앱, 서드파티 서비스 등 모든 클라이언트를 위한 중앙 통합 지점 역할을 수행하여, API 소비주체들에게 일관되고 예측 가능한 경험을 보장합니다 [1, 3].
|
||||
### 매 응용
|
||||
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.
|
||||
|
||||
* **실행 가능한 구현 팁 (Actionable Implementation Tips)**
|
||||
* **API 사양 언어 사용:** REST 아키텍처의 경우 OpenAPI, 이벤트 주도 아키텍처의 경우 AsyncAPI와 같은 표준화된 사양을 사용하여 명확하고 기계가 읽을 수 있는 계약을 생성해야 합니다 [4].
|
||||
* **코드 및 문서 자동 생성:** API 사양 파일에서 직접 서버 스텁(stubs), 클라이언트 SDK 및 대화형 문서를 자동으로 생성하는 도구를 활용하면 수동 작업을 줄이고 문서가 구식이 되는 것을 방지할 수 있습니다 [4].
|
||||
* **병렬 개발을 위한 API 모킹(Mocking):** Postman이나 Stoplight 같은 도구를 사용하여 사양에 기반한 기능적인 모의 서버(Mock server)를 생성해야 합니다 [4]. 이는 프론트엔드 개발자의 작업 병목을 해소하고 조기 테스트와 피드백을 가능하게 합니다 [4].
|
||||
## 💻 패턴
|
||||
|
||||
* **이상적인 활용 사례 및 기대 효과**
|
||||
* 공개 API([[Public APIs|Public APIs]]) 환경, 다중 팀의 통합이 필요한 프로젝트, 프론트엔드와 백엔드의 병렬 작업이 요구되는 현대적인 분산 시스템에 가장 이상적인 아키텍처입니다 [2, 5].
|
||||
* 명확한 계약의 확립, 병렬 개발을 통한 속도 향상, 더 나은 문서화를 도출할 수 있습니다 [5].
|
||||
|
||||
---
|
||||
|
||||
### 1. 핵심 개념: API as a Product
|
||||
API를 단순한 기술적 연동 수단이 아닌, 외부와 소통하는 하나의 **제품(Product)**으로 취급합니다.
|
||||
* **Contract-First:** 코드를 작성하기 전에 Swagger/OpenAPI와 같은 도구로 API 명세를 먼저 확정합니다.
|
||||
* **Parallel Development:** API 명세가 확정되면 프론트엔드와 백엔드 팀이 Mock API를 활용하여 동시에 개발을 진행할 수 있어 시장 출시 속도(Time-to-Market)가 빨라집니다.
|
||||
|
||||
### 2. 주요 설계 원칙
|
||||
* **일관성 (Consistency):** 모든 API 엔드포인트는 통일된 명명 규칙과 데이터 형식을 따라야 합니다.
|
||||
* **재사용성 (Reusability):** 특정 클라이언트에 종속되지 않는 범용적인 기능을 제공하여 중복 개발을 방지합니다.
|
||||
* **추상화 (Abstraction):** 내부의 복잡한 비즈니스 로직을 API 뒤로 숨겨 클라이언트가 기술적 세부 사항에 신경 쓰지 않게 합니다.
|
||||
|
||||
### 3. 실전 적용 환경
|
||||
* **JAMstack:** 정적 사이트가 다양한 마이크로서비스 API와 연동되는 구조에서 API-First는 필수적입니다.
|
||||
* **Microservices:** 서비스 간 통신 규약을 API로 먼저 정의하여 시스템의 결합도를 낮춥니다.
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 지식 자산화 및 기존 네트워크 연동 단계.
|
||||
- **정책 변화:** Software Architecture 카테고리의 전문성 확보 및 링크 밀도 최적화.
|
||||
|
||||
---
|
||||
|
||||
### ✅ Benefits
|
||||
* **협업 효율 극대화:** 명확한 계약(API Spec) 덕분에 커뮤니케이션 오류가 줄어듭니다.
|
||||
* **개발 경험(DX) 향상:** 문서화가 잘 된 API는 내부 개발자와 외부 파트너의 온보딩을 가속화합니다.
|
||||
* **멀티 플랫폼 지원:** 동일한 API를 사용하여 웹, 모바일, IoT 등 다양한 기기에 대응할 수 있습니다.
|
||||
|
||||
### ⚠️ Challenges
|
||||
* **초기 설계 비용:** 코드 작성 전 설계와 문서화에 상당한 시간과 노력이 투자되어야 합니다.
|
||||
* **버전 관리의 복잡성:** API를 사용하는 클라이언트가 많아질수록 하위 호환성을 유지하며 기능을 업데이트하기가 까다로워집니다.
|
||||
|
||||
---
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** Contract-Driven Development, OpenAPI, AsyncAPI
|
||||
- **Projects/Contexts:** Stripe, Twilio (이 철학으로 잘 문서화된 API를 구축하여 비즈니스를 성장시킨 대표적인 기업 사례 [3])
|
||||
- **Contradictions/Notes:** 소스 내에 상충되는 주장은 존재하지 않습니다. 다만, 이 구조의 구현 복잡성은 '중간(Medium)' 수준이며, 성공적인 도입과 유지를 위해서는 스펙 우선(spec-first)의 규율과 명확한 거버넌스가 요구된다고 명시하고 있습니다 [5].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-18*
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
### Related Concepts
|
||||
* [[Microservices_Architecture]]: API-First 전략이 가장 활발하게 적용되는 아키텍처 환경입니다.
|
||||
* [[JAMstack]]: API 기반의 백엔드 통합을 지향하는 현대 웹 아키텍처입니다.
|
||||
* [[OpenAPI_Specification]]: API-First 설계를 구체화하는 가장 대표적인 표준 도구입니다.
|
||||
|
||||
### Practical Application Contexts
|
||||
* **Digital Transformation:** 기업의 내부 기능을 외부 파트너에게 개방하여 생태계를 확장할 때 API-First 접근이 필수적입니다.
|
||||
* **Agile Development:** 병렬 개발을 통해 전체 프로젝트 기간을 단축합니다.
|
||||
|
||||
---
|
||||
|
||||
|
||||
## 💡 Adjacent Topics
|
||||
* [[API_Gateway]]: 수많은 API를 통합 관리하고 보안을 강화하는 인프라 컴포넌트입니다.
|
||||
* [[Postman]]: API 설계, 테스트, 문서화를 지원하는 협업 플랫폼입니다.
|
||||
* [[GraphQL]]: 클라이언트 요구에 최적화된 API 쿼리를 제공하는 대체 기술입니다.
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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 }
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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+/" }
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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";
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
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
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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)
|
||||
}
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]] · [[Contract-Driven Development]]
|
||||
- 변형: [[Schema-First GraphQL]] · [[Proto-First gRPC]]
|
||||
- 응용: [[OpenAPI]] · [[AsyncAPI]] · [[SDK Generation]]
|
||||
- Adjacent: [[Consumer-Driven Contracts]] · [[Pact Testing]] · [[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) |
|
||||
|
||||
@@ -4,113 +4,186 @@ title: API Fundamentals
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-WEB-API-FUNDAMENTALS, API, 인터페이스, Application Programming Interface, 통신 규약]
|
||||
aliases: [API basics, REST GraphQL gRPC, Web API]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 1.0
|
||||
tags: [Web_API, REST, GraphQL, gRPC, Architecture]
|
||||
raw_sources: [Datacollector_Export_2026-05-02]
|
||||
last_reinforced: 2026-05-02
|
||||
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: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: REST/GraphQL/gRPC/tRPC
|
||||
---
|
||||
|
||||
# [[API 핵심 원리 및 아키텍처 패턴 (API Fundamentals)]]
|
||||
# API Fundamentals
|
||||
|
||||
## 1. 개요
|
||||
API(Application Programming Interface)는 소프트웨어 컴포넌트 간의 통신 방법을 정의하는 규약이다. 현대적 시스템 아키텍처에서 API는 단순한 데이터 교환 수단을 넘어 시스템의 기능 경계를 정의하고, 클라이언트의 진입점(Entry Point) 역할을 수행하는 핵심 뼈대이다.
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 2. API 아키텍처 계층 (4 Layers)
|
||||
1. **상호작용 계층 (Interaction Layer)**: 외부 요청 관리, 인증, 보안 및 통신 효율성 담당.
|
||||
2. **애플리케이션 계층 (Application Layer)**: 핵심 비즈니스 로직 및 기능 실행.
|
||||
3. **통합 계층 (Integration Layer)**: 서비스 간 조율, 데이터 변환 및 유효성 검사 수행.
|
||||
4. **데이터 계층 (Data Layer)**: 데이터베이스 및 저장소와의 상호작용 담당.
|
||||
## 매 핵심
|
||||
|
||||
## 3. 주요 API 통신 패턴
|
||||
- **REST (HTTP/JSON)**: 자원 기반의 무상태 통신. 범용성과 단순성으로 인해 표준으로 널리 사용됨.
|
||||
- **GraphQL**: 클라이언트가 필요한 데이터 구조를 명시적으로 요청. 오버페칭(Overfetching) 문제 해결.
|
||||
- **gRPC (HTTP/2)**: 이진 프로토콜 기반 고속 통신. 마이크로서비스 간 내부 통신에 최적화.
|
||||
- **WebSocket**: 양방향 실시간 스트리밍 통신. 채팅 및 라이브 데이터 처리에 적합.
|
||||
### 매 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.
|
||||
|
||||
## 4. 코드베이스 분석 전략
|
||||
- **진입점(Entry Points) 추적**: 컨트롤러나 라우터 정의부에서 API 엔드포인트를 식별하고, 하향식(Top-down)으로 호출 스택을 분석하여 비즈니스 흐름 파악.
|
||||
- **문서화 활용**: OpenAPI(Swagger) 명세를 통해 시스템의 의존성과 데이터 요구사항을 선제적으로 이해.
|
||||
### 매 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.
|
||||
|
||||
## 5. 지식 연결 (Related)
|
||||
- [[API_First_Architecture]]: 구현보다 설계를 우선하는 API 중심 개발 방법론.
|
||||
- [[Microservices_Architecture]]: API를 통해 서비스 간 경계를 정의하고 연결하는 구조.
|
||||
- [[Security_Best_Practices_for_APIs]]: API 키 관리 및 인증/인가 보안 전략.
|
||||
### 매 응용
|
||||
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.
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
- **정보 상태**: 검증 완료 (Verified)
|
||||
- **출처 신뢰도**: A
|
||||
- **검토 이유**: 시스템 통합과 확장성의 근간이 되는 API의 핵심 개념 및 실천적 분석 방법론 정립.
|
||||
## 💻 패턴
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
|
||||
> *(TODO: 한 문장으로 핵심 통찰을 작성. "X는 Y 조건에서 Z 효과를 낸다" 구조 권장.)*
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
|
||||
**추출된 패턴:**
|
||||
> *(TODO)*
|
||||
|
||||
**세부 내용:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
|
||||
- **과거 데이터와의 충돌:** 없음
|
||||
- **정책 변화:** 없음
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
|
||||
- **Parent:** [[10_Wiki/Topics]]
|
||||
- **Related:** *(TODO: 최소 2개)*
|
||||
- **Opposite / Trade-off:** *(TODO)*
|
||||
- **Raw Source:** 직접 입력
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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));
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
const order = await createOrder(req.body);
|
||||
await redis.setex(`idem:${idemKey}`, 86400, JSON.stringify(order));
|
||||
res.status(201).json(order);
|
||||
});
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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;
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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),
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### gRPC service (proto3)
|
||||
```proto
|
||||
syntax = "proto3";
|
||||
package orders.v1;
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
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]] · [[GraphQL]] · [[gRPC]] · [[tRPC]] · [[WebSocket]]
|
||||
- 응용: [[OpenAPI]] · [[API Gateway]] · [[Service Mesh]]
|
||||
- Adjacent: [[OAuth2]] · [[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) |
|
||||
|
||||
@@ -2,88 +2,222 @@
|
||||
id: wiki-2026-0508-ast-traversal
|
||||
title: AST Traversal
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-Reinforce-CODING-001]
|
||||
aliases: [ast-walk, syntax-tree-traversal, visitor-pattern]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [coding, ast, compiler]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [ast, compilers, codemod, static-analysis]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-04-20
|
||||
github_commit: batch-reinforce-01
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: ts-morph
|
||||
---
|
||||
|
||||
# Abstract Syntax Tree Traversal
|
||||
# AST Traversal
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> 소스 코드의 추상적인 구조를 정의된 규칙에 따라 탐색하며 변환 및 분석의 기틀을 마련하는 컴파일러의 핵심 여정.
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **추출된 패턴:** 비지터 패턴(Visitor Pattern)을 활용하여 데이터 구조와 알고리즘을 분리하고 트리 노드를 순회하는 재귀적 처리 패턴.
|
||||
- **세부 내용:**
|
||||
- 전위/중위/후위 순회를 통한 코드 분석 시점 최적화.
|
||||
- 정적 분석 및 린팅(Linting) 툴의 기초 로직 제공.
|
||||
- 리팩토링 및 코드 자동 생성 도구의 엔진 역할.
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 단순 텍스트 기반 검색과 달리 문맥(Context)을 이해하는 구조적 접근의 필수성 강조.
|
||||
- **정책 변화:** 코딩 표준(w1) 강화에 따라 AST 기반 자동 수정 가중치 상향.
|
||||
### 매 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.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Parent:** 10_Wiki/💡 Topics/Coding
|
||||
- **Related:** [[CST|CST]], [[Parser|Parser]], Visitor-Pattern
|
||||
- **Raw Source:** 00_Raw/2026-04-20/[[Abstract-Syntax-Tree-Traversal|Abstract-Syntax-Tree-Traversal]].md
|
||||
### 매 mutating vs read-only
|
||||
- **Read-only**: linter, complexity metrics, security scanner.
|
||||
- **Mutating**: codemod, formatter, transpiler. 매 immutability + new tree 의 produce 의 best-practice (Babel: `path.replaceWith`).
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
### 매 응용
|
||||
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.
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
## 💻 패턴
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
### 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';
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
const code = `console.log("hello"); foo("world");`;
|
||||
const ast = parse(code);
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
traverse(ast, {
|
||||
CallExpression(path) {
|
||||
const callee = path.node.callee;
|
||||
if (t.isMemberExpression(callee) &&
|
||||
t.isIdentifier(callee.object, { name: 'console' })) {
|
||||
// strip console.* calls
|
||||
path.remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
console.log(generate(ast).code); // foo("world");
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### ts-morph (TypeScript refactor)
|
||||
```ts
|
||||
import { Project, SyntaxKind } from 'ts-morph';
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
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();
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Python — `ast` + NodeTransformer
|
||||
```python
|
||||
import ast
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
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
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
src = "print('hi')\nx = 1"
|
||||
tree = ast.parse(src)
|
||||
StripPrint().visit(tree)
|
||||
ast.fix_missing_locations(tree)
|
||||
print(ast.unparse(tree)) # x = 1
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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
|
||||
- 부모: [[Compilers]] · [[Static-Analysis]]
|
||||
- 변형: [[Codemod]] · [[Tree-Sitter]] · [[Visitor-Pattern]]
|
||||
- 응용: [[ESLint]] · [[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 |
|
||||
|
||||
@@ -1,125 +1,182 @@
|
||||
---
|
||||
id: wiki-2026-0508-atam-architecture-trade-offs-ana
|
||||
title: ATAM (Architecture Trade offs Analysis Method)
|
||||
title: ATAM (Architecture Trade-offs Analysis Method)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-E724CEAB]
|
||||
aliases: [atam, architecture-evaluation, architecture-review]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [atam-(architecture-trade-offs-analysis-method), architecture-decision-records-(adr), iso-25010-(품질-모델), 민감도-지점-(sensitivity-points), tara-(architecture-assessment), architecture-principles]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [architecture, evaluation, atam, sei, quality-attributes]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-02
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: process
|
||||
framework: sei-atam
|
||||
---
|
||||
|
||||
# [[ATAM (Architecture Trade-offs Analysis Method)]]
|
||||
# ATAM (Architecture Trade-offs Analysis Method)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
ATAM(Architecture Trade-offs Analysis Method)은 특정 소프트웨어 아키텍처가 비즈니스 목표를 얼마나 잘 지원하는지 평가하고 아키텍처적 위험 요소를 식별하기 위해 SEI(Software Engineering Institute)에서 개발한 방법론입니다 [1, 2]. 이 방법론은 '완벽한 아키텍처는 없다'는 인식 하에, 의사결정 과정에서 불가피하게 발생하는 타협점(Compromise)을 체계적으로 찾아냅니다 [1]. 소프트웨어 아키텍처를 평가하는 데 있어 '표준(Gold Standard)'으로 간주되며, 직감이나 유행에 따른 아키텍처 선택을 방지하는 객관적인 기준을 제공합니다 [1, 3].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **시나리오 기반 분석 (Scenario-based thinking):** ATAM은 '성능'과 같이 추상적인 품질 목표를 논의하는 대신, 구체적인 시나리오를 사용하여 아키텍처를 평가합니다 [1, 2]. 예를 들어 "사용자가 10분 내에 두 배로 증가할 때 시스템이 어떻게 작동하는가?" 또는 "데이터베이스가 실패할 때 아키텍처가 어떻게 동작하는가?"와 같은 특정한 자극과 반응을 통해 아키텍처의 한계를 시험합니다 [1, 2].
|
||||
* **트레이드오프 식별 (Identification of trade-offs):** 분석 과정을 통해 여러 품질 속성 간의 상호작용과 절충점(Trade-off Points)을 명확히 드러냅니다 [1, 2]. 극단적으로 안전한 시스템(높은 암호화)을 구현하면 성능(지연 시간)을 희생해야 하거나, 가용성을 높이기 위해 일관성을 양보해야 하는 등의 상충 관계를 찾아냅니다 [1, 2].
|
||||
* **위험 및 민감도 지점 도출 (Risks and sensitivity points):** 아키텍처가 어느 부분에서 민감한지(sensitive)를 파악합니다 [1]. 이를 통해 설계자가 단순히 '유행하는 패턴의 관점'에서만 생각하는 것을 방지하고, 라이브 운영(Live operation) 중 발생할 수 있는 예상치 못한 문제들로부터 시스템을 보호합니다 [1].
|
||||
* **아키텍처 비교 및 의사결정:** ATAM은 측정 가능한 품질 기준을 바탕으로 여러 아키텍처 접근법을 비교하는 데 사용되며, 순수한 직감에 의한 결정을 체계적인 의사결정 프로세스로 전환합니다 [3, 4]. 이 과정의 핵심 산출물로는 '위험 테마 및 트레이드오프 보고서'가 생성됩니다 [5].
|
||||
* **사전 분석을 통한 위험 완화:** 시스템이 구축되기 전에 소프트웨어 시스템의 동작을 분석할 수 있는 기반을 제공합니다 [6]. 실제 구축 없이도 시스템이 이해관계자의 요구를 충족하는지 검증함으로써 실질적인 비용 절감과 위험 완화 효과를 가져옵니다 [6].
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
ATAM 자체는 시스템의 트레이드오프를 밝혀내는 분석 방법론이므로, 이 방법론이 도출하는 핵심적인 제약 사항은 바로 "모든 아키텍처 결정은 곧 타협(Trade-off)"이라는 사실입니다 [1].
|
||||
* **품질 속성 간의 상충:** 성능, 보안, 가용성, 유지보수성 등 다양한 품질 속성을 동시에 완벽하게 달성하는 것은 불가능하며, 하나의 품질 속성을 최적화(예: 개발 속도 극대화)하면 필연적으로 다른 속성(예: 향후 유지보수성)이 저하되는 반대 급부가 발생함을 인정해야 합니다 [1, 2].
|
||||
* **패턴 맹신에 대한 경고:** 특정 아키텍처 패턴이 현대적이고 유행한다는 이유만으로 선택해서는 안 되며, 구체적인 시나리오를 바탕으로 철저히 한계를 시험하고 약점을 파악하는 분석 과정을 반드시 거쳐야 한다는 제약을 부여합니다 [1].
|
||||
### 매 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.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
### 매 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.
|
||||
|
||||
#### [관계 유형 A: 아키텍처 평가 및 기록]
|
||||
- [[Architecture Decision Records (ADR)]]
|
||||
- 연결 이유: ATAM 분석을 통해 식별된 트레이드오프와 아키텍처 결정 사항, 그 근거 및 대안들을 문서화하여 기록하는 도구입니다 [5, 7].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: ATAM에서 도출된 평가 결과가 어떻게 시스템의 역사적 자산으로 보존되고, 새로운 팀원이나 이해관계자에게 아키텍처의 의도를 명확히 전달하는지 이해할 수 있습니다 [5, 8].
|
||||
|
||||
- [[ISO 25010 (품질 모델)]]
|
||||
- 연결 이유: ATAM에서 구체적인 시나리오로 평가하고자 하는 성능, 확장성, 호환성 등 아키텍처의 비기능적 품질 요구사항에 대한 표준화된 기준을 제공합니다 [9, 10].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 아키텍처 트레이드오프 분석 시, 시스템 설계자가 어떤 구체적인 품질 특성들을 서로 비교하고 타협해야 하는지 객관적인 평가 척도를 파악할 수 있습니다 [5, 10].
|
||||
|
||||
#### [관계 유형 B: 위험 관리 메커니즘]
|
||||
- [[민감도 지점 (Sensitivity Points)]]
|
||||
- 연결 이유: ATAM 평가를 통해 도출되는 핵심 결과물 중 하나로, 아키텍처가 특정 조건이나 시나리오에 얼마나 취약하게 반응하는지를 나타내는 지점입니다 [1].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 시스템이 라이브 운영 시 직면할 수 있는 병목 현상이나 장애 위험을 사전에 인지하여 시스템의 신뢰성을 높이는 방안을 학습할 수 있습니다 [1].
|
||||
|
||||
### Deeper Research Questions
|
||||
- ATAM 평가 과정에서 추상적인 품질 목표를 대체하는 구체적인 '자극과 반응 시나리오'는 주로 어떤 이해관계자들의 합의를 거쳐 도출되는가?
|
||||
- TARA 등 다른 아키텍처 평가 프레임워크와 비교했을 때, ATAM이 트레이드오프를 식별하는 방식은 실무적으로 어떤 차별점과 한계를 지니는가?
|
||||
- 애자일(Agile) 환경처럼 빠른 개발과 반복이 중요한 상황에서, ATAM과 같은 철저한 시나리오 기반의 아키텍처 검증 과정을 어떻게 병목 없이 적용할 수 있는가?
|
||||
- 마이크로서비스(Microservices)와 이벤트 기반(Event-Driven) 아키텍처를 ATAM으로 비교 평가할 때, 분산 시스템 특유의 복잡성은 어떤 구체적인 트레이드오프 지점(Trade-off Points)으로 나타나는가?
|
||||
- ATAM의 핵심 산출물인 '위험 테마 및 트레이드오프 보고서'는 향후 실제 코드 구현이나 프로토타이핑(Prototyping) 단계의 전략으로 어떻게 구체화되는가?
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 데이터베이스 실패나 10분 내 사용자 두 배 증가와 같은 ATAM의 구체적인 테스트 시나리오를 바탕으로, 코드 레벨에서 이를 견딜 수 있는 장애 조치(예: 서킷 브레이커)나 확장 로직을 직접 구현합니다 [1].
|
||||
- **System Design:** 단순히 현재 유행하는 패턴(예: 무조건적인 MSA 도입)을 따르는 대신, ATAM의 시나리오 기반 평가와 의사결정 매트릭스를 활용하여 프로젝트 요구사항에 가장 적절한 아키텍처를 전략적으로 선택합니다 [2, 3].
|
||||
- **Operation / Maintenance:** ATAM을 통해 밝혀진 아키텍처의 민감도 지점(Sensitivity Points)을 기반으로, 시스템의 취약한 영역에 대한 모니터링을 강화하고 운영 중 발생할 수 있는 불쾌한 사고(unpleasant surprises)에 선제적으로 대비합니다 [1].
|
||||
- **Learning Path:** 개발자가 코드를 넘어 시스템의 거시적인 관점을 가지기 위해 필수적인 단계로, 단순한 패턴의 암기가 아닌 요구사항 간의 충돌을 인지하고 타협하는 아키텍처적 사고 능력을 배양합니다 [1].
|
||||
- **My Project Relevance:** 초기 설계 단계에서 아키텍처 결정이 향후 변경하기 매우 비용이 많이 든다는 점을 고려할 때, 시스템 구축 전에 설계의 한계와 위험성을 미리 검증하여 막대한 기술 부채를 방지하는 데 활용할 수 있습니다 [11, 12].
|
||||
|
||||
### Adjacent Topics
|
||||
- [[TARA (Architecture Assessment)]]
|
||||
- 확장 방향: ATAM과 더불어 산업계에서 소프트웨어 아키텍처를 평가하고 검토하는 데 사용되는 또 다른 평가 기법으로, 아키텍처 평가 방법론의 지식을 더욱 확장할 수 있습니다 [13].
|
||||
- [[소프트웨어 아키텍처 침식 (Software Architecture Erosion)]]
|
||||
- 확장 방향: ATAM 등을 통해 초기 설계 당시 의도되었던 아키텍처가 시스템의 지속적인 진화와 유지보수 과정에서 어떻게 변질되고 붕괴되는지, 그리고 이를 어떻게 막을 것인지에 대한 운영적 관점의 연구로 나아갈 수 있습니다 [14].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 매 scenario template
|
||||
```
|
||||
Stimulus (event) — Source (actor) — Environment (state) →
|
||||
Artifact (component) → Response (system action) → Measure (latency, %, etc.)
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 매 응용
|
||||
1. Pre-build architecture review.
|
||||
2. Major refactor 의 GO/NO-GO.
|
||||
3. Vendor selection — 매 candidate 의 same scenarios 의 score.
|
||||
4. Tech radar 의 input.
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
## 💻 패턴
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Utility tree (Markdown)
|
||||
```markdown
|
||||
# Utility Tree — Order Service v3
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
## Performance
|
||||
- (H, H) p95 checkout latency < 300ms at 10k RPS
|
||||
- (H, M) Cold start < 500ms (serverless)
|
||||
- (M, L) Background job throughput > 1k/s
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
## Availability
|
||||
- (H, H) 99.99% monthly SLO for /checkout
|
||||
- (H, M) Graceful DB failover < 30s
|
||||
- (M, M) Region evacuation < 5min
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 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]]
|
||||
- 변형: [[SAAM]] · [[ARID]] · [[CBAM]] · [[Lightweight-Architecture-Review]]
|
||||
- 응용: [[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 |
|
||||
|
||||
@@ -2,131 +2,31 @@
|
||||
id: wiki-2026-0508-atam-architecture-tradeoff-analy
|
||||
title: ATAM (Architecture Tradeoff Analysis Method)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-550EC936]
|
||||
duplicate_of: none
|
||||
status: duplicate
|
||||
canonical_id: atam-architecture-trade-offs-ana
|
||||
duplicate_of: "[[ATAM (Architecture Trade-offs Analysis Method)]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [atam-(architecture-tradeoff-analysis-method), iso-25010-(quality-model), tara, adr-(architecture-decision-records), 소프트웨어-아키텍처-평가-(software-architecture-evaluation), architecture-principles]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-02
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, architecture, evaluation]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
---
|
||||
|
||||
# [[ATAM (Architecture Tradeoff Analysis Method)]]
|
||||
# ATAM (Architecture Tradeoff Analysis Method)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
ATAM(Architecture Tradeoff Analysis Method)은 특정 아키텍처가 비즈니스 목표를 얼마나 잘 지원하는지 평가하고 아키텍처적 위험 요소를 식별하기 위한 소프트웨어 아키텍처 평가 방법론이다 [1]. 추상적인 품질 목표 대신 구체적인 자극과 반응으로 구성된 '시나리오'를 활용하여 아키텍처의 한계를 시험한다 [1, 2]. 이를 통해 완벽한 아키텍처 대신 각 품질 속성 간의 타협점(Trade-off)을 체계적으로 발견하고 검증하는 데 목적이 있다 [2].
|
||||
> **이 문서는 [[ATAM (Architecture Trade-offs Analysis Method)]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 📖 Core 소스에 관련 정보가 부족합니다.Content
|
||||
* **개발 배경 및 원리:** 소프트웨어 엔지니어링 연구소(SEI)에서 개발되었으며, 소프트웨어 아키텍처 평가의 표준(gold standard)으로 간주된다 [2]. '완벽한 아키텍처는 없으며 모든 결정은 타협의 결과물'이라는 인식에서 출발한다 [2].
|
||||
* **시나리오 기반 사고 (Scenario-based thinking):** '성능'이나 '보안'과 같은 추상적인 용어 대신 구체적인 시나리오를 바탕으로 아키텍처를 분석한다 [2]. 예를 들어, "10분 이내에 사용자 수가 두 배로 증가하면 시스템에 어떤 일이 발생하는가?" 또는 "사용자가 초당 1,000건으로 급증할 때 시스템이 1초 이내에 응답하는가?"와 같은 구체적인 상황을 가정하여 아키텍처가 견딜 수 있는 한계를 평가한다 [1, 2].
|
||||
* **트레이드오프 식별 (Identification of trade-offs):** 아키텍처 결정에 따른 상호작용과 상충 관계를 명확히 보여준다 [2]. 특정 기능을 극대화하기 위해 희생해야 하는 다른 품질 속성들의 관계(예: 보안을 위한 성능 저하, 가용성을 위한 일관성 양보 등)를 시스템적으로 파악하게 한다 [1, 2].
|
||||
* **위험 및 민감도 포인트 분석 (Risks and sensitivity points):** 설계된 아키텍처가 어느 지점에서 민감하게 반응하는지를 찾아낸다 [2]. 이는 아키텍트가 단순히 유행하는 아키텍처 패턴에 매몰되는 것을 방지하고, 실제 라이브 운영에서 발생할 수 있는 불쾌한 상황이나 위험 요소(Single point of failure 등)를 사전에 방지하도록 돕는다 [2, 3].
|
||||
## 핵심 요약
|
||||
- 매 spelling variant — "Trade-offs" (hyphenated) 의 SEI official.
|
||||
- 매 same 9-step process · same utility tree · same risk/sensitivity/tradeoff outputs.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
ATAM 방법론 자체를 프로젝트에 도입할 때 발생하는 제약 사항이나 단점에 대해서는 소스에 관련 정보가 부족합니다.
|
||||
다만, ATAM을 통해 도출되는 시스템 설계상의 트레이드오프는 다음과 같이 나타난다 [1, 2].
|
||||
* **보안 vs. 성능:** 극도로 안전한 암호화 접근 방식을 취하면 처리 지연 시간(latency)이 증가하여 성능에 비용을 치러야 한다 [2].
|
||||
* **가용성 vs. 일관성:** 시스템의 가용성을 극대화하기 위해서는 데이터의 일관성을 일부 양보해야 하는 상황이 명확히 드러난다 [1].
|
||||
* **개발 속도 vs. 유지보수성:** 시스템을 매우 빠르게 개발할 경우, 필연적으로 향후 유지보수가 훨씬 더 어려워지는 반대급부가 발생한다 [2].
|
||||
## 🔗 Graph
|
||||
- 부모: [[ATAM (Architecture Trade-offs Analysis Method)]] (canonical)
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
|
||||
#### [평가 및 분석 도구]
|
||||
- [[ISO 25010 (Quality Model)]]
|
||||
- 연결 이유: ATAM과 같은 아키텍처 평가를 수행할 때 기준점이 되는 객관적이고 포괄적인 소프트웨어 품질 속성(기능 적합성, 성능 효율성 등) 모델을 제공한다 [3, 4].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: ATAM에서 검증하고자 하는 아키텍처 품질 속성의 분류와 가중치 설정 방식을 이해할 수 있다.
|
||||
|
||||
- [[TARA]]
|
||||
- 연결 이유: 소스에서 ATAM과 함께 사용 가능한 또 다른 소프트웨어 아키텍처 평가(Evaluation) 기법으로 언급된다 [5].
|
||||
- 이 구념을 통해 더 깊게 이해할 수 있는 부분: 다양한 아키텍처 평가 방법론의 종류와 각각의 비교 지점을 파악할 수 있다.
|
||||
|
||||
#### [결정 및 문서화 프레임워크]
|
||||
- [[ADR (Architecture Decision Records)]]
|
||||
- 연결 이유: ATAM을 통해 식별된 위험 요소, 대안, 트레이드오프 결과를 바탕으로 최종 아키텍처 결정을 내린 뒤, 이를 기록하고 문서화하는 필수적인 도구이다 [3, 6].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 평가(ATAM) 이후 도출된 결정 사항이 조직 내에서 어떻게 지속되고, 미래의 팀원이나 검사자에게 어떻게 공유되는지 알 수 있다.
|
||||
|
||||
### Deeper Research Questions
|
||||
- ATAM 평가를 수행하기 위한 구체적인 단계와 시나리오 도출의 기준은 무엇인가?
|
||||
- 대규모 마이크로서비스 아키텍처(MSA) 환경에서 분산된 서비스들의 트레이드오프를 ATAM으로 평가할 때 직면하는 특수한 어려움은 무엇인가?
|
||||
- TARA 등 다른 아키텍처 평가 기법과 비교했을 때 ATAM이 가지는 방법론적인 차별점과 한계는 무엇인가?
|
||||
- 요구사항 변경에 따라 기존에 작성된 ATAM 기반 트레이드오프 보고서를 효율적으로 갱신하고 재평가하는 방법은 무엇인가?
|
||||
- 극단적으로 민첩성(Agility)을 요구하는 애자일 환경에서 무거운 아키텍처 분석 기법인 ATAM을 어떻게 조화롭게 적용할 수 있는가?
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 소스에 관련 정보가 부족합니다.
|
||||
- **System Design:** 소프트웨어 설계 초기 단계에서 여러 가지 아키텍처 개념을 결정 매트릭스로 비교하고, 각 접근법이 수용해야 할 타협점(Trade-offs)을 합리적으로 평가하는 검증 과정으로 쓰인다 [2, 7].
|
||||
- **Operation / Maintenance:** "데이터베이스가 실패할 때 아키텍처가 어떻게 동작하는가?"와 같은 구체적인 시나리오를 통해 라이브 시스템 운영 중 발생 가능한 사고와 위험을 사전에 식별하고 방어책을 세운다 [2].
|
||||
- **Learning Path:** 시스템 아키텍트가 단순히 유행하는 아키텍처 패턴에 의존하지 않고, 비즈니스 목표와 품질 속성을 정량적·시나리오 기반으로 분석하는 핵심 훈련 과정으로 작용한다 [2].
|
||||
- **My Project Relevance:** 프로젝트에서 다루고자 하는 품질 목표(예: 동시 접속자 처리량)와 보안, 일관성 등의 다른 제약 조건들 사이의 구조적 위험성을 발견하여, 가장 적합한 아키텍처를 선정하는 기준 도구로 활용할 수 있다.
|
||||
|
||||
### Adjacent Topics
|
||||
- [[소프트웨어 아키텍처 평가 (Software Architecture Evaluation)]]
|
||||
- 확장 방향: ATAM을 포함하여 시스템 아키텍처가 설계 요구사항과 일치하는지를 검증하고 감사하는 전체적인 프로세스와 그 외의 다양한 평가 프레임워크들에 대해 확장해서 조사할 수 있다.
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
|
||||
**추출된 패턴:**
|
||||
> *(TODO)*
|
||||
|
||||
**세부 내용:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
|
||||
@@ -2,87 +2,32 @@
|
||||
id: wiki-2026-0508-abstract-syntax-tree-traversal
|
||||
title: Abstract Syntax Tree Traversal
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
canonical_id: self
|
||||
aliases: [P-Reinforce-AST-TRAVERSAL]
|
||||
duplicate_of: none
|
||||
status: duplicate
|
||||
canonical_id: ast-traversal
|
||||
duplicate_of: "[[AST_Traversal]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.99
|
||||
tags: [AST, Abstract Syntax Tree, Traversal, Visitor Pattern, Static Analysis]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-04-20
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, ast, traversal, compilers]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
---
|
||||
|
||||
# [[Abstract-Syntax-Tree-Traversal|Abstract-Syntax-Tree-Traversal]] (AST 순회)
|
||||
# Abstract Syntax Tree Traversal
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> "언어의 숲을 여행하는 지도 제작자." 코드의 나무(AST)를 뿌리부터 잎새까지 탐험하며, 특정 패턴(예: 변수 선언, 함수 호출)을 찾아내 분석하고 수집하는 행위다.
|
||||
> **이 문서는 [[AST_Traversal]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **Visitor Pattern**:
|
||||
- AST의 각 노드 타입(FunctionDeclaration, Identifier 등)에 방문할 때 실행될 콜백 함수를 정의하여 순회 과정을 구조화하는 설계 패턴.
|
||||
- **Static Code Analysis**:
|
||||
- 코드를 실행하지 않고 순회만 함으로써, 선언되지 않은 변수 사용, 도달할 수 없는 코드(Unreachable code) 등을 사전에 찾아내는 린팅(Linting)의 기반 기술.
|
||||
- **Scope Analysis**:
|
||||
- 변수가 어디서 선언되고 어디까지 유효한지(Scope)를 파악하기 위해 트리 위아래를 오가며 참조 관계를 분석한다.
|
||||
## 핵심 요약
|
||||
- Pre-order / in-order / post-order traversal of AST nodes.
|
||||
- Visitor pattern 매 standard implementation.
|
||||
- 매 use cases: compilation, linting, codemod, code search.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- 트리가 너무 거대하면(수만 줄의 코드) 순회 성능이 급격히 저하된다. 이를 위해 필요한 노드만 선택적으로 방문하거나, 증분식(Incremental) 분석을 통해 변경된 부분만 다시 순회하는 최적화 전략이 실무 도구([[ESLint|ESLint]] 등)에 필수적이다.
|
||||
## 🔗 Graph
|
||||
- 부모: [[AST_Traversal]] (canonical)
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- Related: [[Abstract-Syntax-Tree-Transformation|Abstract-Syntax-Tree-Transformation]] , [[ESLint-Static-Analysis|ESLint-Static-Analysis]]
|
||||
- [[Strategy|Strategy]]: [[Reliability_Safety_First|Reliability_Safety_First]]
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
|
||||
@@ -2,128 +2,190 @@
|
||||
id: wiki-2026-0508-alliance-동맹
|
||||
title: Alliance (동맹)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [Guild, Clan, Faction, 동맹]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [game-design, social-systems, mmo, architecture]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: Game backend (Colyseus, Nakama, custom)
|
||||
---
|
||||
|
||||
# [[Alliance (동맹)|Alliance (동맹)]]
|
||||
# Alliance (동맹)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
Game of War에서 동맹(Alliance)은 최대 100명의 플레이어로 구성되는 복잡한 정치적 및 사회적 연합체입니다 [1]. 이는 단순한 협력 그룹을 넘어 플레이어 간의 자원 공유, 방어용 군집(Hive) 형성, 그리고 왕국(Kingdom)의 통치권을 차지하기 위해 필수적으로 요구되는 핵심 시스템입니다 [2]. 특히 동맹원 간의 상호 원조 기능과 인앱 결제(IAP) 보상을 공유하는 시스템은 플레이어들에게 강력한 유대감과 과금에 대한 사회적 압박을 동시에 부여하는 핵심적인 BM(비즈니스 모델) 동력으로 작용합니다 [2-4].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
'게임 오브 워(Game of War)'를 비롯한 4X 모바일 게임에서 얼라이언스(동맹)는 최대 100명의 플레이어로 구성되는 복잡한 정치적, 사회적 집단입니다 [1]. 단순한 팀의 개념을 넘어 플레이어 간의 협력, 외교, 배신 등 창발적 게임플레이(Emergent Gameplay)를 유도하는 핵심 기반입니다 [2-4]. 특히 얼라이언스 내에서 형성된 사회적 유대감과 상호 압박은 플레이어들이 게임에 지속적으로 참여하고 막대한 인앱 결제(IAP)를 진행하게 만드는 가장 강력한 원동력으로 작용합니다 [5, 6].
|
||||
### 매 구조
|
||||
- **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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **사회적 구조와 역할 분담 (Social Structure and Roles)**
|
||||
* 동맹은 플레이어들이 적의 공격으로부터 서로를 보호하기 위해 도시들을 밀집시키는 '하이브(hive)'를 형성하도록 유도합니다 [2].
|
||||
* 동맹 내부에서 플레이어들은 각자의 특화된 역할을 분담합니다. 자원을 안전하게 보관하는 '은행가(Banker)', 군사력보다는 동맹을 위한 자원 생산에 집중하는 '농부(Farmer)', 맵의 정보를 파악하는 '정찰병(Scout)' 등 매우 고도로 조직화된 형태로 운영됩니다 [5].
|
||||
* 다른 동맹과의 불가침 조약(NPA)을 맺는 등의 외교 활동, 동맹 내 배신이나 파벌 갈등과 같은 정치는 거대한 메타게임을 만들어냅니다 [6].
|
||||
### 매 server-authoritative invariants
|
||||
- 매 single alliance per player 의 enforcement (atomic).
|
||||
- Member cap (typical 50–100) — atomic check-and-insert.
|
||||
- Treasury balance — race-free debit/credit (transactional).
|
||||
- War state machine — pending/active/peace transitions.
|
||||
|
||||
* **BM 구조와 과금 유도 (Monetization & Social Pressure)**
|
||||
* 동맹 시스템은 이 게임의 수익 창출에 가장 중추적인 역할을 담당합니다. 한 동맹원이 인앱 결제 번들을 구매하면 동맹의 다른 모든 인원도 선물을 받게 되는 이른바 '킥백(kick-back)' 보상 시스템이 존재합니다 [3, 4].
|
||||
* 이 시스템은 플레이어가 팀원들을 실망시키지 않고 동맹에 기여해야 한다는 강력한 심리적, 사회적 압박을 만들어내어 지속적인 과금을 이끌어냅니다 [2, 3].
|
||||
* 큰 금액을 과금하는 유저들은 동일하게 적극적으로 과금하는 유저들이 모인 동맹에 속하길 원하며, 과금이나 기여를 하지 않는 무임승차자(Moocher)들은 동맹에서 추방당하는 등 내부적인 자체 규율이 엄격하게 적용됩니다 [3, 4, 7].
|
||||
### 매 응용
|
||||
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.
|
||||
|
||||
* **협동 및 진행 가속 시스템 (Cooperation and Progression)**
|
||||
* 플레이어들은 '동맹 지원(Alliance Help)' 기능을 통해 서로의 건물 건설이나 연구 시간을 단축시켜 줄 수 있습니다 [8, 9]. 이는 플레이어들 간의 이타주의를 이끌어내고 자주 게임에 접속하게 만드는 필수적인 상호작용입니다 [10].
|
||||
* 동맹 퀘스트를 완료하면 플레이어와 동맹 전체 모두에게 보상이 돌아가며 [11], 동맹 상점(Alliance Store)에서 전용 아이템(전쟁 아이템 등)을 구매할 수 있고 동맹 도시(Alliance Cities)를 통해 전체가 공동의 목표를 향해 협력합니다 [12, 13].
|
||||
## 💻 패턴
|
||||
|
||||
* **영토 통제와 엔드게임 (Territory Control and Endgame)**
|
||||
* 동맹의 궁극적인 목표는 게임 내 주요 영토와 권력의 통제입니다 [14].
|
||||
* 동맹 단위로 왕국 중앙의 '원더(Wonder)'나 서버 전체를 대상으로 하는 '슈퍼 원더(Super Wonder)'를 차지하기 위해 대규모 전쟁을 벌입니다 [14, 15].
|
||||
* 원더를 점령한 동맹의 리더는 왕(King)이나 황제(Emperor)로 등극하며, 왕국 내의 다른 유저 및 동맹들에게 강력한 버프 칭호나 모욕적인 디버프 칭호를 부여할 수 있는 절대적인 권력을 행사하게 됩니다 [16-19].
|
||||
* 왕국 대 왕국(KvK) 이벤트와 같은 거대한 서버전 역시 동맹 단위의 철저한 협력과 준비를 기반으로 이루어집니다 [20, 21].
|
||||
### 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()
|
||||
);
|
||||
|
||||
---
|
||||
|
||||
* **사회적 구조와 역할 분담:**
|
||||
얼라이언스 내에서 플레이어들은 단순히 전투만 하는 것이 아니라 고도화된 역할을 분담합니다 [3]. 자원을 전담하여 생산하는 '농부(farmer)', 맵의 정보를 수집하는 '정찰병(scout)', 자원을 안전하게 관리하는 '은행가(banker)' 등으로 역할을 나눕니다 [3]. 공격으로부터 서로를 보호하기 위해 도시들을 밀집시키는 '하이브(hives)'를 형성하며, 게임 내 실시간 번역 시스템을 통해 국적과 언어를 초월한 글로벌 규모의 소통과 합동 군사 작전을 수행합니다 [5, 7, 8].
|
||||
* **강력한 BM 연계 요소 ('킥백' 시스템):**
|
||||
얼라이언스는 게임의 수익화(Monetization) 모델과 직접적으로 연결되어 있습니다 [6]. 가장 대표적인 것은 한 멤버가 인앱 결제(IAP) 번들을 구매하면 얼라이언스 내의 다른 모든 멤버도 선물을 받게 되는 '킥백(kick-back)' 시스템입니다 [6]. 이 시스템은 과금 유저들을 한 얼라이언스로 모이게 하는 효과가 있으며, 동시에 조직에 무임승차하지 않고 기여해야 한다는 강력한 사회적 압박(Social pressure)을 부여해 일반 플레이어들의 과금을 유도합니다 [6, 9, 10].
|
||||
* **엔드게임과 정치적 메타게임:**
|
||||
게임의 궁극적 목표인 '원더(Wonder)'나 다중 서버 이벤트인 '슈퍼 원더(Super Wonder)', 'KvK(Kingdom vs. Kingdom)'를 통제하려면 얼라이언스 단위의 대규모 협력이 필수적입니다 [5, 11, 12]. 특정 얼라이언스가 원더를 점령하면 그 얼라이언스의 리더는 '왕(King)'이나 '황제(Emperor)'가 되어 다른 유저들에게 버프나 디버프 칭호를 내리고 세금을 징수할 권력을 얻습니다 [13, 14]. 이러한 절대 권력의 존재는 얼라이언스 간의 불가침 조약(NPA) 체결, 스파이 활동, 배신, 내전 등 현실의 정치와 유사한 메타게임을 창출합니다 [4].
|
||||
* **전용 기능과 성장 가속:**
|
||||
얼라이언스에 가입하면 동맹 전용 퀘스트, 자원 및 아이템 거래, 전용 도시 건설 등의 혜택을 누릴 수 있습니다 [15, 16]. 또한, 획득한 충성도(Loyalty)를 사용하여 얼라이언스 상점에서 VIP 활성화 아이템이나 전쟁 버프 아이템 등을 구매할 수 있습니다 [17, 18]. 서로의 건설 및 연구 시간을 단축시켜주는 지원(Help) 기능은 게임 세션을 반복적으로 늘리고 유저의 지속적인 접속을 유도하는 핵심 장치입니다 [19].
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
No trade-offs available.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** IAP Kick-back System, Wonder (원더), Social Engineering (사회공학), KvK (Kingdom vs Kingdom)
|
||||
- **Projects/Contexts:** Game of War: Fire Age BM 및 경제 구조 분석, 4X 전략 게임의 수익화 모델
|
||||
- **Contradictions/Notes:** 동맹은 플레이어 간의 상호 원조를 통해 게임 진행을 돕고 보호를 제공하는 필수적인 시스템이지만, 동시에 다른 동맹원들의 과금에 편승하기만 하면 추방당할 수 있다는 강력한 '과금 압박 메커니즘'으로 작용하는 양면성을 가집니다 [3, 7, 10].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-27*
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** 원더 (Wonder), 창발적 게임플레이 (Emergent Gameplay), 수익화 모델 (Monetization), KvK (Kingdom vs Kingdom)
|
||||
- **Projects/Contexts:** [[Game of War- Fire Age|Game of War: Fire Age]], 4X Strategy Games
|
||||
- **Contradictions/Notes:** 얼라이언스는 플레이어에게 필수적인 보호막과 성장 혜택을 제공하지만, 과금을 많이 하는 하드코어 얼라이언스에서는 멤버들에게 결제에 대한 큰 부담을 주며 이를 따르지 않을 경우 강퇴당할 수도 있는 등 긍정적 유대감과 부정적 압박이 혼재된 구조를 가집니다 [6, 10].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-27*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
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);
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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");
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
// 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");
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
await t.none(
|
||||
"INSERT INTO alliance_members(player_id, alliance_id, rank) VALUES($1,$2,1)",
|
||||
[playerId, allianceId]);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### Permission check
|
||||
```typescript
|
||||
const PERMS = {
|
||||
invite: 2, // R2+
|
||||
kick: 3, // R3+
|
||||
promote:4, // R4+
|
||||
disband:5, // leader only
|
||||
} as const;
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
function can(memberRank: number, action: keyof typeof PERMS): boolean {
|
||||
return memberRank >= PERMS[action];
|
||||
}
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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
|
||||
- 부모: [[Game Architecture]] · [[Social Systems]]
|
||||
- 변형: [[Guild]] · [[Clan]] · [[Faction]] · [[Party]]
|
||||
- 응용: [[Alliance Chat]] · [[Alliance War]] · [[Treasury System]]
|
||||
- Adjacent: [[Friendship System]] · [[Matchmaking]] · [[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) |
|
||||
|
||||
@@ -2,112 +2,31 @@
|
||||
id: wiki-2026-0508-alliances
|
||||
title: Alliances
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
canonical_id: self
|
||||
status: duplicate
|
||||
canonical_id: alliance-동맹
|
||||
duplicate_of: "[[Alliance_(동맹)]]"
|
||||
aliases: []
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, alliance, game-design]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
---
|
||||
|
||||
# [[Alliances|Alliances]]
|
||||
# Alliances
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> 동맹은 단순한 팀을 넘어, 킥백(Kick-back) 보상과 사회적 유대감을 통해 개별 유저의 과금을 '집단적 기여'로 승화시키는 강력한 소셜 엔지니어링 엔진이다.
|
||||
> **이 문서는 [[Alliance_(동맹)]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
---
|
||||
## 핵심 요약
|
||||
- "Alliances" (plural)는 영어 표기. 매 canonical 은 한국어 병기 형태.
|
||||
- 매 game-design / strategy context 의 multi-player coalition mechanic — canonical 문서 참조.
|
||||
|
||||
동맹(Alliances)은 최대 200명의 플레이어가 모여 공격을 조율하고 영토를 통제하며 특별한 보상을 얻기 위해 결성하는 플레이어 그룹입니다 [1, 2]. 구성원들은 자원 확보, 상호 방어 지원, 정보 공유 및 통제점(Control Points) 점령 등 다양한 전투 및 지정학적 목표를 위해 협력합니다 [3-5]. 월드 맵의 특정 섹터에서 패권을 장악한 지배적인 동맹은 비공식적인 교전 규칙을 세우고 타 플레이어에게 강제할 정도로 전투 생태계 내에서 막대한 영향력을 행사합니다 [2, 6].
|
||||
## 🔗 Graph
|
||||
- 부모: [[Alliance_(동맹)]] (canonical)
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **추출된 패턴:** 상호 원조(Help) 시스템과 킥백(Kick-back) 보상을 통한 사회적 결속 및 결제 압박 강화.
|
||||
- **핵심 메커니즘:**
|
||||
- **Social Co[[Opera|Opera]]tion:** 건설/연구 시간 단축(Help)과 자원 공유를 통한 이타적 유대감 형성.
|
||||
- **Kick-backSystem:** 한 명의 결제가 동맹 전체의 보상으로 이어져, '결제를 하지 않는 유저'에게 사회적 부채감을 부여.
|
||||
- **Role Distribution:** 은행가(Banker), 농부(Farmer), 정찰병(Scout) 등 자발적 역할 분담을 통한 메타 게임 활성화.
|
||||
- **Territorial Control:** 하이브(Hives) 구축과 원더([[Wonder|Wonder]]) 점령을 통한 집단적 목표 달성 및 권력 쟁취.
|
||||
- **운영 규칙:** 무임승차 방지를 위한 자체 규제(추방 등)와 RTE를 활용한 글로벌 실시간 외교 조율.
|
||||
|
||||
---
|
||||
|
||||
* **전술적 지원 및 혜택:** 동맹은 일일 활동(로그 팩션 공격, 목표 달성, 기지 방어 등)과 이벤트 참여를 통해 동맹 포인트(Alliance Points)를 획득합니다 [3]. 동맹원들은 채팅을 통해 표적을 핑(ping)하고 정보를 공유하며, 전투 리플레이를 시청하면서 공격 및 방어 전략을 함께 분석하는 등 실질적인 전투 백업을 주고받습니다 [3].
|
||||
* **섹터 패권(Hegemony) 및 통제:** 워 커맨더의 200개 섹터 내에서 동맹은 영토 통제권을 두고 경쟁합니다 [2, 7]. 특정 섹터의 80% 이상을 장악한 거대 동맹은 비동맹원의 활동이나 공격 대상을 통제하는 비공식 규칙을 강제하기도 합니다 [2, 6]. 이 과정에서 경쟁자의 기지를 6개의 소대(platoons)로 포위하여 부대 배치 및 자원 채집을 물리적으로 차단하는 '투옥(Jailing)' 전술이 사용되기도 합니다 [2, 6].
|
||||
* **통제점(Control Points) 점령전:** 최소 25명 이상의 플레이어로 구성된 동맹은 분쟁 구역(Contestable Zones) 내의 통제점 전투에 참여할 수 있습니다 [8]. 통제점을 점령하면 CP 레벨에 따라 동맹 전체에 석유 및 토륨(thorium) 생산 부스트가 제공됩니다 [5, 9]. 점령전은 NPC 기지를 파괴한 후, 방어 동맹과 공격 동맹만이 구역 내에 남아 다른 플레이어의 개입 없이 맞붙는 '케이지 매치(cage match)' 형태의 전쟁 단계와 서든 데스 단계를 거쳐 최종 확보(Secured)에 이르게 됩니다 [5, 9, 10].
|
||||
* **외교 및 관리 체계:** 동맹 창설에는 금(Gold) 또는 5,000,000 토륨이 소모되며, 리더와 장교가 구성원 가입 승인, 진급/강등, 추방 등의 관리 권한을 행사합니다 [11-13]. 적대적인 동맹들은 때때로 휴전이나 정전을 맺고 상호 이익을 보호하기 위해 2계층 시스템(two-tier system)의 연합을 형성하여 대규모 구역 전쟁(sector wars)에 대비하기도 합니다 [14, 15].
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
No trade-offs available.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Parent:** Social & Psychology
|
||||
- **Related:** [[Social Engineering|Social Engineering]], Kick-back System, [[Wonder|Wonder]], VIP Activation
|
||||
- **Raw Source:** 00_Raw/Alliances
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-27*
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** 섹터(Sector), 통제점(Control Points), 투옥(Jailing) 전술, 토륨(Thorium)
|
||||
- **Projects/Contexts:** [[War-Commander-전투-생태계-및-지정학적-구조|War Commander 전투 생태계 및 지정학적 구조]]
|
||||
- **Contradictions/Notes:** 소스에 따르면 경쟁자의 기지를 포위하는 '투옥(Jailing)' 전술은 게임의 공식 규칙에 위배되는 행위로 명시되어 있으나, 전투 생태계 내에서 지배적인 동맹들이 패권을 유지하기 위해 빈번하게 사용하는 전술로 설명되고 있습니다 [2, 6]. 또한 동맹 창설 비용과 관련하여 한 소스에서는 '금(Gold)'이 필요하다고 언급하나 [11], 다른 소스에서는 '5,000,000 토륨'이 소모된다고 언급하는 등 내용의 차이가 존재합니다 [13].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-27*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
|
||||
@@ -2,104 +2,202 @@
|
||||
id: wiki-2026-0508-ambient-declarations
|
||||
title: Ambient Declarations
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [.d.ts, declare keyword, TypeScript ambient, Type definitions]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [typescript, types, declarations, dts, interop]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: TypeScript 5.7
|
||||
---
|
||||
|
||||
# [[Ambient Declarations|Ambient Declarations]]
|
||||
# Ambient Declarations
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> 핵심 요약 작업 진행 중
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
> "존재하지만 실체는 없는 것들에 대한 증명." 타입스크립트 컴파일러에게 "이 변수나 함수는 외부에 이미 있으니 타입만 믿고 통과시켜라"라고 알려주는 `declare` 키워드의 본질이다.
|
||||
### 매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
본문 상세 구성 진행 중
|
||||
### 매 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.
|
||||
|
||||
- **declare keyword**:
|
||||
- 실제 컴파일된 JS 파일에는 포함되지 않지만, 타입 전용 공간에서 전역 변수나 라이브러리의 구조를 선언할 때 사용한다.
|
||||
- **.d.ts files**:
|
||||
- 앰비언트 선언들이 모여 있는 파일. 프로젝트 전체에 걸쳐 전역적인 타입 정보를 제공하는 '타입 명세서' 역할을 한다.
|
||||
- **External Library Integration**:
|
||||
- 타입 정보가 없는 레거시 JS 라이브러리를 타입스크립트 프로젝트에서 에러 없이 사용하기 위한 필수 관문이다.
|
||||
## 💻 패턴
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 지식 자산화 및 기존 네트워크 연동 단계.
|
||||
- **정책 변화:** Programming & Language 카테고리의 전문성 확보 및 링크 밀도 최적화.
|
||||
|
||||
---
|
||||
|
||||
- 무분별한 앰비언트 선언은 전역 네임스페이스를 오염시킨다. 현대적 가이드라인은 가능하면 `Module Augmentation`을 사용하거나 `@types` 패키지를 통해 엄격하게 관리하는 것을 권장한다.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- Related: [[Declaration-Files|Declaration-Files]] , Module-Augmentation
|
||||
- Standard: [[Branded-Types-for-Nominal-Typing|Branded-Types-for-Nominal-Typing]]
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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>;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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;
|
||||
}
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### Triple-slash directive (legacy, still used)
|
||||
```typescript
|
||||
/// <reference types="node" />
|
||||
/// <reference path="./vendor.d.ts" />
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### `declare` inside .ts file
|
||||
```typescript
|
||||
// app.ts
|
||||
declare const FEATURE_FLAGS: { newCheckout: boolean };
|
||||
declare function gtag(cmd: string, ...args: unknown[]): void;
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
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]] · [[Type System]]
|
||||
- 변형: [[Module Augmentation]] · [[Global Augmentation]] · [[Triple-slash Directives]]
|
||||
- 응용: [[DefinitelyTyped]] · [[Library Publishing]] · [[Asset Typing]]
|
||||
- Adjacent: [[tsconfig.json]] · [[Type Inference]] · [[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) |
|
||||
|
||||
@@ -2,117 +2,178 @@
|
||||
id: wiki-2026-0508-apache-ignite
|
||||
title: Apache Ignite
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-46783FB6]
|
||||
aliases: [Ignite, In-memory data grid, GridGain]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [apache-ignite, hazelcast, space-based-architecture-pattern, distributed-systems, in-memory-data-grids-(imdg), devops-environment]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [in-memory, data-grid, distributed-cache, sql, compute-grid]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-02
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: java
|
||||
framework: Apache Ignite 2.16
|
||||
---
|
||||
|
||||
# [[Apache Ignite]]
|
||||
# Apache Ignite
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
Apache Ignite는 공간 기반 아키텍처(Space-Based Architecture) 패턴을 구현할 때 활용되는 분산 시스템 도구 중 하나이다 [1]. 이 도구를 다루기 위해서는 분산 시스템에 대한 전문 지식이 필수적으로 요구된다 [1]. 소스에 관련 정보가 부족하여 더 이상의 자세한 정의를 제공하기 어렵다.
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
소스에 관련 정보가 부족합니다.
|
||||
## 매 핵심
|
||||
|
||||
(Apache Ignite 자체에 대한 상세한 작동 원리나 세부 구조는 제공된 소스에 포함되어 있지 않으며, 오직 '공간 기반 아키텍처(Space-Based Architecture)'의 단점(Cons)을 설명하는 과정에서 분산 시스템 도구의 예시로 단 한 차례 짧게 언급되어 있습니다 [1].)
|
||||
### 매 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.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
Apache Ignite를 활용하여 시스템을 구축할 경우, 해당 도구와 분산 시스템 전반에 대한 고도의 전문 지식을 갖춘 인력이 필요하다는 점이 주요 제약 사항이다 [1].
|
||||
그 외 구체적인 부작용이나 최적화 반대급부에 대해서는 소스에 관련 정보가 부족합니다.
|
||||
### 매 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.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
### 매 응용
|
||||
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.
|
||||
|
||||
#### [구현/활용 도구]
|
||||
- [[Hazelcast]]
|
||||
- 연결 이유: Apache Ignite와 함께 공간 기반 아키텍처를 구현하기 위한 분산 시스템 도구의 예시로 나란히 언급된다 [1].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 공간 기반 아키텍처 환경에서 메모리 내 데이터를 관리하는 데 사용되는 대체 도구의 종류를 알 수 있다 [1].
|
||||
## 💻 패턴
|
||||
|
||||
#### [아키텍처/기반 기술]
|
||||
- [[Space-Based Architecture Pattern]]
|
||||
- 연결 이유: Apache Ignite가 주로 활용되는 대상 아키텍처 패턴이다 [1].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 데이터베이스 중심 설계의 병목 현상을 줄이고, 분산된 인메모리 데이터 그리드(IMDG)를 활용하여 높은 확장성과 실시간 처리 성능을 달성하는 구조적 원리를 이해할 수 있다 [2, 3].
|
||||
### 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);
|
||||
|
||||
### Deeper Research Questions
|
||||
- 분산 시스템 환경에서 Apache Ignite를 활용할 때 발생할 수 있는 데이터 복제 지연(data replication delays)과 일시적 데이터 불일치 문제를 어떻게 해결하거나 최소화할 수 있는가? [1]
|
||||
- 공간 기반 아키텍처를 구현함에 있어 Apache Ignite와 Hazelcast의 기술적 차이점과 각각의 최적 적용 사례는 무엇인가? [1]
|
||||
- 고부하 시나리오(high-load scenarios)를 시뮬레이션하기 위한 비용과 시간을 절감하면서 Apache Ignite 기반 시스템을 효과적으로 테스트하는 방법론은 무엇인가? [1]
|
||||
- 소스에 관련 정보가 부족합니다.
|
||||
- 소스에 관련 정보가 부족합니다.
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 실시간 데이터 처리(예: 주식 거래, 사기 탐지)나 동시성이 높은 시스템(예: 전자상거래 판매, 경매 플랫폼)을 구현할 때 트래픽 급증을 처리하기 위한 분산 시스템 도구로 채택될 수 있다 [1, 3].
|
||||
- **System Design:** 데이터베이스 호출로 인한 지연 시간을 줄이고 선형적 확장성(near-linear scalability)을 보장하기 위해 공간 기반 아키텍처를 설계할 때 핵심 도구로 고려된다 [1, 2].
|
||||
- **Operation / Maintenance:** 도구를 운영하고 유지보수하기 위해서는 분산 시스템 아키텍처에 대한 이해도와 전문성을 갖춘 엔지니어링 팀이 필수적으로 뒷받침되어야 한다 [1].
|
||||
- **Learning Path:** 소스에 관련 정보가 부족합니다.
|
||||
- **My Project Relevance:** 소스에 관련 정보가 부족합니다.
|
||||
|
||||
### Adjacent Topics
|
||||
- [[Distributed Systems]]
|
||||
- 확장 방향: Apache Ignite를 올바르게 활용하기 위한 근본적인 기반 학문으로, 분산 환경에서의 상태 관리, 네트워크 통신, 장애 허용성(fault tolerance) 등을 깊이 있게 연구할 수 있다 [1].
|
||||
- [[In-Memory Data Grids (IMDG)]]
|
||||
- 확장 방향: 디스크가 아닌 여러 대의 서버 RAM에 데이터를 분산 저장하여 방대한 데이터에 초고속으로 접근하게 해주는 가상화된 데이터 그리드 기술의 원리를 파악할 수 있다 [2].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
Ignite ignite = Ignition.start(cfg);
|
||||
IgniteCache<Long, Order> orders = ignite.cache("orders");
|
||||
orders.put(1L, new Order(...));
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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);
|
||||
}
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Affinity collocation (cross-cache JOIN performance)
|
||||
```java
|
||||
@QuerySqlField(index = true)
|
||||
private Long customerId;
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
// Affinity key — rows with same customerId on same node
|
||||
@AffinityKeyMapped
|
||||
private Long customerId;
|
||||
// Now JOIN orders ↔ customers stays node-local
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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();
|
||||
}
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]]
|
||||
- 변형: [[Hazelcast]] · [[GridGain]] · [[Redis Cluster]]
|
||||
- 응용: [[Distributed SQL]] · [[Compute Grid]] · [[Service Grid]]
|
||||
- Adjacent: [[JCache]] · [[Caffeine]] · [[Memcached]]
|
||||
|
||||
## 🤖 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) |
|
||||
|
||||
@@ -1,130 +1,176 @@
|
||||
---
|
||||
id: wiki-2026-0508-append-only-log
|
||||
title: Append only log
|
||||
title: Append-only Log
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-7C3B92CC]
|
||||
aliases: [Commit log, WAL, Event log, Immutable log]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [append-only-log, event-sourcing-pattern, cqrs-architecture-pattern, event-stream-processing, online-event-processing-(olep), architecture-principles]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [log, kafka, event-sourcing, wal, storage]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-02
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: java
|
||||
framework: Kafka, Pulsar, Postgres WAL
|
||||
---
|
||||
|
||||
# [[Append-only log]]
|
||||
# Append-only Log
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
**Append-only log(추가 전용 로그)**는 애플리케이션의 상태에 대한 모든 변경 사항을 불변의 이벤트 시퀀스로 캡처하여 저장하는 데이터 구조 메커니즘이다 [1]. 데이터가 덮어쓰이지 않고 지속적으로 추가되며, 스트림 파티션 내에서 엄격하게 정렬되고 영구적으로 기록된다 [2]. 주로 실시간 데이터 처리, 완벽한 감사 추적, 복잡한 비즈니스 로직에 대한 응답 등을 지원하기 위해 이벤트 소싱(Event Sourcing) 및 이벤트 스트리밍 패턴의 핵심 기반으로 사용된다 [1, 2].
|
||||
## 매 한 줄
|
||||
> **"매 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).
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **불변적 상태 변화 기록 (Immutable State Changes):** 데이터베이스에서 기존 상태를 덮어쓰는 대신, 시스템에서 발생하는 모든 상태 변경 사항을 순차적이고 불변(immutable)하는 이벤트 스트림으로 캡처하여 로그 형태로 저장한다 [1].
|
||||
* **스트리밍 및 이벤트 재생 기능 (Streaming & Replayability):** 클라이언트는 단순히 이벤트를 구독하는 것에 그치지 않고 로그 스트림의 어느 위치에서든 데이터를 읽을 수 있으며, 자신의 위치를 전진시키며 처리한다 [2]. 이 메커니즘을 통해 클라이언트는 언제든지 스트림에 참여할 수 있고, 과거의 이벤트를 재생(replay)할 수 있어 버그 수정 후 재처리나 장애 복구 시나리오를 효과적으로 지원한다 [2, 3].
|
||||
* **감사 추적 및 시간 기반 쿼리 (Audit Trails and Temporal Queries):** 모든 변경 내역이 손실 없이 저장되므로, 과거 특정 시점의 데이터 상태(예: 과거 특정 날짜의 계좌 잔액)를 분석하는 시간적 쿼리나 완벽한 감사 추적(Audit Trail) 시스템을 구축하는 데 매우 적합하다 [3, 4].
|
||||
* **비동기 분산 환경의 영구 데이터 관리:** OLEP(Online Event Processing)와 같은 환경에서는 비동기적으로 분산된 이벤트 로그를 사용하여 이기종 시스템 전반에 걸쳐 복잡한 이벤트를 신뢰성 있게 구성하고 영구적인 데이터를 관리한다 [5].
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
* **가파른 학습 곡선:** 전통적인 CRUD(Create, Read, Update, Delete) 방식의 데이터베이스 모델링 마인드셋에서 벗어나 이벤트 기반의 사고방식(event-based thinking)으로 전환해야 하므로 초기 설계 및 구현 난이도가 높다 [3].
|
||||
* **스토리지 비용 증가:** 데이터가 삭제되거나 업데이트되지 않고 이벤트 로그가 지속적으로 누적 및 증가하기 때문에 시간이 지남에 따라 더 높은 데이터 스토리지 비용이 발생한다 [3].
|
||||
* **상태 재구성 오버헤드 및 스냅샷 필수:** 시스템의 현재 상태를 알기 위해 수백만 개의 누적된 이벤트를 처음부터 다시 읽어 상태를 재구성(rebuilding state)해야 하므로 성능 저하가 발생할 수 있으며, 이를 해결하기 위해 주기적인 스냅샷(snapshots) 관리가 필수적이다 [3].
|
||||
* **버전 관리의 복잡성:** 비즈니스 요구사항 변화로 인해 이벤트의 구조(스키마)가 변경될 때, 과거 버전의 이벤트와 새로운 버전의 이벤트를 함께 처리해야 하므로 버전 핸들링 작업이 매우 복잡해진다 [3].
|
||||
* **최종 일관성 (Eventual Consistency):** 시스템이 즉각적인 데이터 일관성(Immediate Consistency)보다는 최종 일관성에 의존하므로, 트랜잭션의 즉각적인 일치성이 강력하게 요구되는 시스템에는 적합하지 않을 수 있다 [4].
|
||||
### 매 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).
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
### 매 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.
|
||||
|
||||
#### [관계 유형 A (아키텍처/기반 기술)]
|
||||
- [[Event Sourcing Pattern]]
|
||||
- 연결 이유: Append-only log는 Event Sourcing 아키텍처 패턴이 애플리케이션 상태 변경을 저장하고 타겟 시스템과 통신하는 핵심 데이터 보관 방식이기 때문이다 [1].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 상태 변경을 연속적인 메시지 스트림으로 만들어 복잡한 비즈니스 워크플로우를 처리하고 롤백을 수행하는 전체 구조의 작동 방식 [1, 4].
|
||||
### 매 응용
|
||||
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.
|
||||
|
||||
- [[CQRS Architecture Pattern]]
|
||||
- 연결 이유: 읽기(Query)와 쓰기(Command)를 분리하는 CQRS 패턴은 데이터를 불변의 이벤트 로그로 기록하는 Event Sourcing(Append-only log)과 결합될 때 강력한 시너지를 발휘하기 때문이다 [3, 4].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 기존 데이터를 마이그레이션하지 않고도 분리된 이벤트 로그에서 새로운 읽기 모델(Projections)을 추가하고 최적화하여 시스템을 유연하게 확장하는 메커니즘 [3].
|
||||
## 💻 패턴
|
||||
|
||||
#### [관계 유형 B (구현/활용 도구)]
|
||||
- [[Event stream processing]]
|
||||
- 연결 이유: Append-only log에 저장된 이벤트들을 클라이언트가 순차적으로 읽고 파티션 내에서 위치를 이동하며 데이터를 처리하는 스트리밍 방식과 직접적으로 연관되기 때문이다 [2, 6].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 지속적으로 발생하는 이벤트(데이터 스트림)를 실시간으로 스크리닝하고 분석하여 구독자에게 정보를 제공하는 데이터 파이프라인의 구성 방식 [6].
|
||||
### 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();
|
||||
|
||||
- [[Online event processing (OLEP)]]
|
||||
- 연결 이유: OLEP는 비동기 분산 이벤트 로그를 핵심으로 사용하여 복잡한 이벤트(Complex events)를 처리하고 영구 데이터를 관리하기 때문이다 [5].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 이기종 시스템 전반에 걸쳐 유연한 분산 패턴을 생성하면서도 강한 일관성(Strong Consistency)을 유지하지만, 처리 시간에 대한 상한선을 보장할 수 없는 한계점 [5].
|
||||
|
||||
### Deeper Research Questions
|
||||
- Append-only log 환경에서 이벤트 스키마(구조)가 변경될 때 시스템의 하위 및 상위 호환성을 유지하기 위한 구체적인 스키마 진화(Schema evolution) 및 버전 관리 전략은 무엇인가? [3, 7]
|
||||
- 장기간 운영되어 이벤트 로그가 수백만 개 이상 누적된 시스템에서, 스냅샷(Snapshots)을 효율적으로 생성하고 상태 재구성(Rebuilding state) 지연 시간을 최소화하기 위한 최적의 아키텍처 설계는 무엇인가? [3]
|
||||
- Append-only log 및 최종 일관성(Eventual Consistency)을 기본으로 하는 분산 시스템에서, 즉각적인 일관성이 필수적인 비즈니스 트랜잭션 요구사항을 어떻게 절충하고 해결할 수 있는가? [4, 8]
|
||||
- 클라이언트가 Append-only log 스트림 내에서 자신의 위치를 전진시키다 시스템 장애가 발생했을 때, 정확히 실패한 시점부터 이벤트를 다시 재생(Replay)하는 구체적인 복구 메커니즘은 어떻게 구현되는가? [2]
|
||||
- 분산 이벤트 로그를 사용하는 OLEP(Online Event Processing) 아키텍처가 처리 시간의 상한선(upper bounds)을 보장할 수 없는 이유는 무엇이며, 실시간성이 중요한 환경에서 이를 어떻게 극복할 수 있는가? [5]
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 버그가 발생하거나 특정 시점의 데이터 복원이 필요할 때, 디버깅 과정에서 Append-only log의 과거 이벤트들을 다시 재생(Replay)하여 문제를 추적하고 상태를 롤백하는 데 활용된다 [3, 4].
|
||||
- **System Design:** 애플리케이션의 읽기와 쓰기 책임을 분리하는 CQRS 패턴을 설계할 때, 쓰기 모델을 위한 데이터 저장소로 채택되어 이벤트 로그와 읽기 모델을 비동기적으로 동기화하도록 설계한다 [3, 4].
|
||||
- **Operation / Maintenance:** 헬스케어나 금융 뱅킹 시스템 등 과거 특정 날짜의 거래 승인 거절 사유 등을 명확히 감사(Audit)해야 하는 시스템 운영에서, 완전한 감사 추적 기록(Audit Trail)을 제공하는 용도로 사용된다 [3, 4]. 로그 크기 증가에 따른 인프라 스토리지 확장과 비용 관리 운영이 수반되어야 한다 [3].
|
||||
- **Learning Path:** 기존의 테이블 행을 업데이트하고 삭제하는 CRUD 데이터베이스 중심 사고방식에서 벗어나, 시스템의 모든 변화를 독립적이고 불변하는 이벤트 객체로 파악하는 도메인 주도 설계(DDD) 및 이벤트 기반 사고(Event-based thinking)를 훈련해야 한다 [3, 4].
|
||||
- **My Project Relevance:** 타겟 시스템이나 웹 서버와 메시징 스트림을 기반으로 통신하며, 장애 복구 시 데이터 손실 없이 상태를 완벽히 재구축해야 하는 데이터 집약적 백엔드 파이프라인 개발에 직접적으로 적용될 수 있다.
|
||||
|
||||
### Adjacent Topics
|
||||
- [[Message Brokers (e.g., Kafka, RabbitMQ)]]
|
||||
- 확장 방향: 이벤트 로그를 저장하고 생산자와 소비자 간에 메시지를 조율하며 분산 스트리밍 환경을 제공하는 핵심 미들웨어 채널 및 브로커 인프라의 기술적 동작 원리로의 확장 [9, 10].
|
||||
- [[Distributed Tracing]]
|
||||
- 확장 방향: 비동기적으로 통신하는 이벤트 로그 환경에서 수많은 마이크로서비스 간에 이벤트가 어떻게 전달되고 소비되는지 전체 요청 경로를 추적하고 오류의 근본 원인을 디버깅하는 방법론으로의 확장 [7, 8, 11].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
prod.beginTransaction();
|
||||
prod.send(new ProducerRecord<>("orders", orderId, json));
|
||||
prod.send(new ProducerRecord<>("audit", orderId, audit));
|
||||
prod.commitTransaction();
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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
|
||||
}
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Event sourcing aggregate
|
||||
```typescript
|
||||
type OrderEvent =
|
||||
| { type: "Created", id: string, items: Item[] }
|
||||
| { type: "Paid", amount: number }
|
||||
| { type: "Shipped", trackingId: string };
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
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 };
|
||||
}
|
||||
}
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
const state = events.reduce(applyEvent, {} as Order);
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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
|
||||
- 부모: [[Storage Systems]] · [[Distributed Systems]]
|
||||
- 변형: [[Kafka]] · [[Pulsar]] · [[WAL]] · [[Event Store]]
|
||||
- 응용: [[Event Sourcing]] · [[CDC]] · [[Outbox Pattern]] · [[CQRS]]
|
||||
- Adjacent: [[Stream Processing]] · [[Idempotency]] · [[Saga Pattern]]
|
||||
|
||||
## 🤖 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) |
|
||||
|
||||
@@ -2,129 +2,200 @@
|
||||
id: wiki-2026-0508-architectural-violations
|
||||
title: Architectural Violations
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-C08C3C0C]
|
||||
aliases: [Architecture Erosion, Architecture Drift, Layer Violations, Dependency Violations]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [architectural-violations, architecture-erosion, technical-debt, static-code-analysis-tools, software-architecture-recovery, architecture-principles]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [architecture, violations, erosion, drift, archunit]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-02
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: java/kotlin/typescript
|
||||
framework: ArchUnit / Sonargraph / dependency-cruiser
|
||||
---
|
||||
|
||||
# [[Architectural Violations]]
|
||||
# Architectural Violations
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
아키텍처 위반(Architectural Violations)은 기술 부채의 축적(accumulation of technical debt), 지식 증발(knowledge vaporization)과 함께 **소프트웨어 아키텍처 침식(Architecture erosion)을 일으키는 주요 원인 중 하나**입니다 [1]. 이는 시간이 지남에 따라 초기에 의도했던 설계와 실제 구현된 아키텍처 간의 격차가 점진적으로 벌어지는 현상을 초래합니다 [1]. 소스 내에서는 아키텍처 침식의 원인으로서 간략하게 언급되어 있으며, 아키텍처 위반이라는 단일 개념에 대한 구체적인 정의나 세부 사례에 관한 정보는 부족합니다.
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 Core 소스에 관련 정보가 부족합니다.
|
||||
소스에 아키텍처 위반(Architectural Violations) 자체에 대한 구체적이고 세부적인 정보는 부족합니다. 다만, 이 개념이 핵심 원인으로 작용하는 **아키텍처 침식(Architecture erosion)**의 맥락을 통해 다음과 같은 내용을 합성할 수 있습니다.
|
||||
## 매 핵심
|
||||
|
||||
* **아키텍처 침식 유발**: 아키텍처 위반은 소프트웨어 개발 수명 주기(SDLC)의 여러 단계에서 발생할 수 있으며, 의도된 아키텍처와 구현된 아키텍처 사이의 간극을 만들어 점진적인 아키텍처 침식을 초래합니다 [1].
|
||||
* **시스템에 미치는 치명적 영향**: 아키텍처 위반이 누적되어 침식이 발생하면 **소프트웨어 성능이 저하**되고, 시스템의 **진화 및 유지보수 비용(evolutionary costs)이 실질적으로 증가**하며, 전반적인 **소프트웨어 품질이 하락**하게 됩니다 [1, 2].
|
||||
* **탐지 및 식별 접근법**: 이러한 위반과 침식을 조기에 발견하고 완화하기 위해 일관성 기반(consistency-based), 진화 기반(evolution-based), 결함 기반(defect-based), 결정 기반(decision-based) 접근법이 제안되었습니다 [2]. 구체적으로는 **자동화된 아키텍처 적합성 검사(automated architecture conformance checks)**와 **정적 코드 분석 도구(static code analysis tools)**, 그리고 리팩토링 기술이 식별에 활용됩니다 [2].
|
||||
### 매 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.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
소스에 아키텍처 위반 선택에 따른 직접적인 제약 사항이나 반대 급부(Trade-off)에 대한 세부 정보가 부족합니다. 그러나 위반을 통제하기 위한 관리적 측면에서 다음과 같은 한계와 기회비용이 존재합니다.
|
||||
### 매 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.
|
||||
|
||||
* **예방 및 치료적 조치의 비용 vs 방치 시의 막대한 위험**: 아키텍처 위반을 방지하기 위해서는 아키텍처 규칙 강제, 정기적인 코드 리뷰, 자동화된 테스트와 같은 **'예방적 조치(preventative measures)'**를 엄격히 시행해야 합니다 [3]. 또한 이미 발생한 위반에 대해서는 리팩토링, 재설계, 문서 업데이트 등의 **'치료적 조치(remedial measures)'**가 수반되어야 합니다 [3]. 이러한 조치들은 개발 과정에서 시간과 노력을 요구하지만, 위반을 방치할 경우 초기 설계 결함과 지속적인 변경으로 인해 2년이라는 시간을 재개발에 소모해야 했던 넷스케이프(Netscape)의 모질라(Mozilla) 브라우저 사례처럼 막대한 수리 비용과 프로젝트 지연을 감수해야만 합니다 [1, 3].
|
||||
### 매 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).
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
## 💻 패턴
|
||||
|
||||
#### [소프트웨어 아키텍처 문제 및 현상]
|
||||
- [[Architecture Erosion]]
|
||||
- 연결 이유: 아키텍처 위반이 궁극적으로 초래하는 가장 직접적인 결과이자 현상입니다 [1].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 아키텍처 위반이 방치되었을 때 시스템의 성능, 유지보수 비용, 품질에 미치는 장기적인 파급 효과를 포괄적으로 이해할 수 있습니다 [1, 2].
|
||||
- [[Technical Debt]]
|
||||
- 연결 이유: 아키텍처 위반, 지식 증발과 함께 아키텍처 침식을 일으키는 또 다른 주요 원인으로 동반 언급됩니다 [1].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 임시방편적인 구조적 위반이 향후 시스템에 어떠한 기술적 부담과 이자(비용)로 되돌아오는지 파악할 수 있습니다 [1].
|
||||
### 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)")
|
||||
|
||||
#### [위반 탐지 및 해결 도구/기법]
|
||||
- [[Static Code Analysis Tools]]
|
||||
- 연결 이유: 아키텍처 위반 및 침식을 조기에 식별하고 완화하기 위해 실무적으로 사용되는 주요 접근법입니다 [2].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 개발 과정에서 자동화된 방식으로 아키텍처 위반을 모니터링하고 코드베이스의 일관성을 유지하는 구현 방법을 이해할 수 있습니다 [2].
|
||||
|
||||
### Deeper Research Questions
|
||||
- 일관성 기반(consistency-based) 및 결함 기반(defect-based) 접근법은 아키텍처 위반을 시스템적으로 어떻게 탐지하고 분류하는가?
|
||||
- 아키텍처 규칙을 강제(enforcing architectural rules)하고 자동화된 적합성 검사를 CI/CD 파이프라인에 통합하는 최적의 방법론은 무엇인가?
|
||||
- 축적된 아키텍처 위반을 해결하기 위해 리팩토링(Refactoring)과 전면적인 재설계(Redesign)를 선택하는 임계 기준은 어떻게 설정되는가?
|
||||
- 지식 증발(knowledge vaporization) 현상은 개발팀 내에서 아키텍처 위반의 발생 빈도를 어떻게 가속화시키는가?
|
||||
- 모질라(Mozilla) 프로젝트의 사례에서, 아키텍처 위반이 소프트웨어의 진화 비용(evolutionary costs)을 기하급수적으로 증가시킨 구체적인 메커니즘은 무엇이었는가?
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 정적 코드 분석 도구와 자동화된 아키텍처 적합성 검사를 도입하여 구현 과정에서 발생하는 아키텍처 위반 사항을 코딩 단계에서 조기에 식별합니다 [2].
|
||||
- **System Design:** 모질라의 실패 사례를 교훈 삼아, 초기 설계 결함이 아키텍처 위반 및 침식으로 이어지지 않도록 시스템 구조를 유연하고 일관성 있게 설계합니다 [1].
|
||||
- **Operation / Maintenance:** 유지보수 과정에서 아키텍처 규칙을 강제하고, 정기적인 코드 리뷰와 문서 업데이트를 수행하여 위반 발생과 지식 증발을 최소화합니다 [3].
|
||||
- **Learning Path:** 아키텍처 위반, 기술 부채, 아키텍처 침식 간의 상관관계를 학습하여 지속 가능한 소프트웨어 유지보수 전략과 선제적 아키텍처 관리의 중요성을 터득합니다 [1].
|
||||
- **My Project Relevance:** 현재 진행 중인 프로젝트 내에 존재하는 아키텍처 위반 사항을 추적하고, 이를 해결하기 위한 리팩토링이나 재설계 등의 치료적 조치(remedial measures)를 계획합니다 [3].
|
||||
|
||||
### Adjacent Topics
|
||||
- [[Software Architecture Recovery]]
|
||||
- 확장 방향: 이미 심각한 아키텍처 위반과 침식이 진행되어 문서와 구현이 불일치하는 시스템에서, 현재 구현된 아키텍처를 역공학(reverse engineering)하여 본래의 의도와 구조를 복구해 내는 기법 및 프로세스로 이해를 확장할 수 있습니다 [3].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
|
||||
**추출된 패턴:**
|
||||
> *(TODO)*
|
||||
|
||||
**세부 내용:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
@ArchTest
|
||||
val no_repo_in_controller: ArchRule = noClasses()
|
||||
.that().resideInAPackage("..web..")
|
||||
.should().dependOnClassesThat().resideInAPackage("..persistence..")
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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>
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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 { /* ... */ }
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
```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]] · [[Reflexion Model]]
|
||||
- 응용: [[Architecture Review (아키텍처 및 설계 리뷰)]] · [[Architecture_Refactor]] · [[Technical Debt]]
|
||||
- Adjacent: [[ArchUnit]] · [[Sonargraph]] · [[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 |
|
||||
|
||||
@@ -2,82 +2,217 @@
|
||||
id: wiki-2026-0508-architectural-constraint-enforce
|
||||
title: Architectural Constraint Enforcement
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-Reinforce-4F930E]
|
||||
aliases: [archunit, dependency-cruiser, fitness-functions]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [uncategorized]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [architecture, fitness-functions, archunit, constraints]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-04-20
|
||||
github_commit: "[P-Reinforce] Mega Batch - Wikified Architectural-Constraint-Enforcement"
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: java
|
||||
framework: archunit
|
||||
---
|
||||
|
||||
# [[Architectural-Constraint-Enforcement]]
|
||||
# Architectural Constraint Enforcement
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> 핵심 요약 작업 진행 중
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
본문 상세 구성 진행 중
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 지식 자산화 및 기존 네트워크 연동 단계.
|
||||
- **정책 변화:** Software Architecture 카테고리의 전문성 확보 및 링크 밀도 최적화.
|
||||
### 매 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.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
---
|
||||
### 매 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.
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
### 매 응용
|
||||
1. CI gate — 매 PR 의 violation 의 block.
|
||||
2. Refactor safety — 매 large refactor 의 invariant 의 hold.
|
||||
3. Onboarding — 매 implicit rule 의 explicit code 의 됨.
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
## 💻 패턴
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
### 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;
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
@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..");
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
@ArchTest
|
||||
static final ArchRule no_cycles =
|
||||
slices().matching("..banking.(*)..").should().beFreeOfCycles();
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
@ArchTest
|
||||
static final ArchRule services_named_correctly =
|
||||
classes().that().resideInAPackage("..service..")
|
||||
.and().areNotInterfaces()
|
||||
.should().haveSimpleNameEndingWith("Service");
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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' } }
|
||||
};
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
```bash
|
||||
npx depcruise src --config .dependency-cruiser.cjs
|
||||
npx depcruise src --output-type dot | dot -T svg > deps.svg
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### NetArchTest (.NET 8)
|
||||
```csharp
|
||||
using NetArchTest.Rules;
|
||||
using Xunit;
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
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 ?? []));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### Konsist (Kotlin)
|
||||
```kotlin
|
||||
import com.lemonappdev.konsist.api.Konsist
|
||||
import com.lemonappdev.konsist.api.verify.assertTrue
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
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]]
|
||||
- 변형: [[Linting]] · [[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 |
|
||||
|
||||
@@ -2,140 +2,197 @@
|
||||
id: wiki-2026-0508-architecture-description-아키텍처-명세
|
||||
title: Architecture Description (아키텍처 명세)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-8C24E3F6]
|
||||
aliases: [Architecture Description, 아키텍처 명세, AD, Software Architecture Document, SAD]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [architecture-description-(아키텍처-명세), iso/iec/ieee-42010, "kruchten's-4+1-view-model", architecture-decision-records-(adr), architectural-views, architecture-principles]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [architecture, documentation, c4, 4plus1-view, iso-42010]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-02
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: markdown
|
||||
framework: Structurizr / C4 / arc42
|
||||
---
|
||||
|
||||
# [[Architecture Description (아키텍처 명세)]]
|
||||
# Architecture Description (아키텍처 명세)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
아키텍처 명세(Architecture Description)는 소프트웨어 아키텍처 프로세스 중 생성된 시스템의 설계를 문서화하고 기록하는 행위를 의미한다[1]. 이는 초기 고수준의 설계 결정을 캡처하여 이해관계자 간의 원활한 소통을 촉진하고, 다른 프로젝트에서 설계 컴포넌트를 재사용할 수 있도록 돕는다[2]. 아키텍처 명세는 ISO/IEC/IEEE 42010 표준에 의해 체계화되어 있으며, 다양한 이해관계자의 관심사를 반영하기 위해 다각도의 뷰(View)를 활용하고 결정 사항의 근거를 기록하는 것을 핵심으로 한다[3-5].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
**1. 아키텍처 명세의 국제 표준 (ISO/IEC/IEEE 42010)**
|
||||
소프트웨어 아키텍처 영역의 첫 번째 공식 표준은 소프트웨어 집약적 시스템의 아키텍처 명세에 대한 권장 관행을 담은 IEEE 1471-2000이었으며, 이는 이후 2011년에 ISO/IEC/IEEE 42010:2011("Systems and software engineering – Architecture description")로 통합 및 대체되었다[4]. 이 최신 표준은 하드웨어와 소프트웨어뿐만 아니라 인간, 프로세스, 설비 등을 모두 포함하는 포괄적인 시스템 정의를 수용하여 기업 아키텍처(Enterprise Architecture)와 솔루션 아키텍처 간의 관계를 반영한다[4].
|
||||
## 매 핵심
|
||||
|
||||
**2. 아키텍처 뷰(Views)와 다각도 모델링**
|
||||
복잡성을 줄이기 위해 아키텍트는 아키텍처를 독립적인 관점으로 분리하여 모델링하고 묘사한다[3]. 이를 아키텍처 뷰(Architectural Views)라고 한다[3].
|
||||
* **Kruchten의 4+1 뷰 모델:** 시스템 아키텍처를 문서화하기 위해 제안된 대표적인 모델로, 여러 뷰의 구성을 제안한다[1].
|
||||
* 일반적으로 아키텍처 명세에는 시스템의 코드 구조를 보여주는 **정적 뷰(Static view)**, 실행 중인 시스템의 동작을 보여주는 **동적 뷰(Dynamic view)**, 그리고 하드웨어에 시스템이 어떻게 배치되는지 보여주는 **배포 뷰(Deployment view)**가 포함된다[1].
|
||||
### 매 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.
|
||||
|
||||
**3. 아키텍처 결정 기록 (Architecture Decision Records, ADR)**
|
||||
아키텍처 결정은 문서화되고 합리적인 근거가 제공되어야 한다[6]. 이를 효과적으로 명세하는 수단이 ADR이다[7].
|
||||
* **포함 요소:** ADR은 초기 상황(Context), 결정된 사항(Decision), 선택의 이유(Reason), 기각된 대안(Alternatives), 그리고 직면할 단기적/장기적 위험과 결과(Risks and consequences)를 포함해야 한다[5, 7, 8].
|
||||
* **목적과 가치:** ADR은 시간이 지난 후에도 의사결정의 근거를 명확하게 추적할 수 있도록 보장하며, 새로운 팀원, 감사자, 이해관계자, 그리고 미래의 개발 과정에 필수적인 자산이 된다[5, 8].
|
||||
### 매 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.
|
||||
|
||||
**4. 지식 관리 및 소통(Knowledge Management and Communication)**
|
||||
아키텍처 명세(문서화)는 아키텍처 지원 활동(Supporting activities) 중 하나로, 요구사항 분석 및 설계 단계부터 핵심적인 역할을 한다[1]. 소프트웨어 아키텍처 지식은 이해관계자들의 머릿속에 암묵적으로 존재하는 경우가 많으므로, 이를 문서화하여 '지식 증발(Knowledge vaporization)'을 막고 명확히 소통하는 것이 아키텍처 명세의 중요한 목표이다[1, 9].
|
||||
### 매 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.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
* **과도한 사전 설계(Big Design Up Front) vs. 애자일(Agility):** 특히 애자일 소프트웨어 개발의 지지자들 사이에서는 아키텍처 명세가 너무 방대한 사전 설계를 유도할 수 있다는 우려가 존재한다[10]. 이에 대응하기 위해 DSDM과 같은 애자일 방법론은 아키텍처의 기반을 다질 때 '딱 필요한 만큼(just enough)'의 아키텍처 설계와 문서화만을 수행할 것을 권장한다[10].
|
||||
* **아키텍처 침식(Architecture Erosion)의 위험:** 명세된 아키텍처가 시스템의 지속적인 변경을 제대로 반영하지 못하고 방치될 경우, 의도된 설계(명세)와 실제 구현된 아키텍처 간의 격차가 발생하는 '아키텍처 침식'이 일어난다[9]. 이는 시스템 성능과 품질을 저하시키고 유지보수 비용을 급증시키므로 지속적인 문서 업데이트와 리팩토링이 필요하다[9, 11].
|
||||
* **소통 채널의 파편화 (이메일 사용의 부작용):** 아키텍처 결정을 이메일로 주고받거나 제대로 문서화하지 않으면, 결정 사항이 잊혀지고 이해되지 않아 동일한 논의가 무한 반복되는 안티패턴(Anti-pattern)이 발생한다[12]. 따라서 ADR은 접근 가능한 단일 진실 공급원(Single source of truth) 중앙 저장소(예: 위키)에 보관되어야 한다[12].
|
||||
## 💻 패턴
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
|
||||
#### [표준 및 모델 지침]
|
||||
- `[[ISO/IEC/IEEE 42010]]`
|
||||
- 연결 이유: 소프트웨어 집약적 시스템의 아키텍처 명세 방법과 개념을 정의한 가장 핵심적이고 공식적인 국제 표준이다[4].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 아키텍처가 어떻게 소프트웨어, 하드웨어뿐만 아니라 프로세스와 인간까지 포괄하여 명세되어야 하는지 구조적인 표준 모델을 이해할 수 있다.
|
||||
|
||||
- `[[Kruchten's 4+1 View Model]]`
|
||||
- 연결 이유: 아키텍처를 문서화할 때 다양한 이해관계자의 관점(정적, 동적, 배포 뷰 등)을 분리하여 설명하기 위해 흔히 사용되는 프레임워크다[1, 3].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 추상적인 아키텍처를 개발자, 관리자, 시스템 엔지니어 등 타겟 오디언스의 목적에 맞게 분리하여 다각도로 명세하는 기법을 알 수 있다.
|
||||
|
||||
#### [실무 문서화 및 의사결정 도구]
|
||||
- `[[Architecture Decision Records (ADR)]]`
|
||||
- 연결 이유: 설계와 관련된 문맥, 결정, 대안, 리스크 등을 체계적이고 투명하게 기록하여 아키텍처의 의사결정을 문서화하는 실무 표준 양식이다[5, 7].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 프로젝트가 장기화되거나 팀원이 변경되더라도 아키텍처 진화의 역사와 의사결정의 기술적 타당성을 추적하는 방법을 학습할 수 있다.
|
||||
|
||||
- `[[Architectural Views]]`
|
||||
- 연결 이유: 하나의 시스템을 다양한 이해관계자의 관심사(Concerns)를 분리(Separation of concerns)하여 서술한 각각의 아키텍처 명세 묘사물이다[3].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 아키텍처의 복잡성을 낮추고, 이해관계자들이 자신의 요구사항이 어떻게 충족되었는지 검증하게 하는 의사소통 도구로서의 역할을 이해할 수 있다.
|
||||
|
||||
### Deeper Research Questions
|
||||
- ISO/IEC/IEEE 42010 표준이 제정된 이후, 마이크로서비스 및 클라우드 네이티브 환경으로 전환되면서 아키텍처 명세 체계는 산업 현장에서 어떻게 진화해 왔는가?
|
||||
- 애자일 방법론 환경에서 'Big Design Up Front'의 안티패턴을 피하면서도 시스템 유지보수를 위해 적절한 수준의 아키텍처 명세(Just enough architecture)를 유지할 수 있는 최적의 프로세스는 무엇인가?
|
||||
- Architecture Decision Records (ADR)를 지속적으로 최신화하고 일관되게 관리하기 위해, 현대 CI/CD 파이프라인이나 개발 팀의 깃(Git) 워크플로우에 이를 어떻게 자동화하고 통합할 수 있는가?
|
||||
- 아키텍처 명세 문서(의도된 설계)와 실제 구현된 코드 간의 괴리가 발생하는 아키텍처 침식(Architecture Erosion)을 조기에 탐지할 수 있는 정적 코드 분석 및 구조적 검증 도구는 어떻게 작동하는가?
|
||||
- 다양한 이해관계자(비즈니스 관리자, 인프라 운영자, 개발자 등)의 각기 다른 비기능적 요구사항(품질 속성)을 충돌 없이 단일 아키텍처 명세의 뷰(Views)에 통합하고 평가하는 구체적 방법론은 무엇인가?
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 새로운 기능 추가나 구조 변경 전 ADR을 작성하여 동료들과 설계 대안, 리스크를 검토하고 합의된 내용을 중앙 위키(Wiki)에 저장하여 일관된 코드 작성을 유도한다[5, 12].
|
||||
- **System Design:** 소프트웨어 설계 단계에서 4+1 View Model을 도입하여, 컴포넌트의 정적 구조(코드 관점), 동적 흐름(데이터와 행위 관점), 그리고 하드웨어 배포 아키텍처를 구분해 명세서를 작성한다[1].
|
||||
- **Operation / Maintenance:** 시스템의 사용자 부하 증가나 새로운 클라우드 통합 등으로 운영 컨텍스트가 변화할 때마다, 아키텍처 명세와 ADR을 다시 검토하고 갱신함으로써 기술 부채 축적과 아키텍처 침식을 방지한다[9, 13].
|
||||
- **Learning Path:** 소프트웨어 아키텍처의 기본 원리 이해 ➔ ISO/IEC/IEEE 42010 아키텍처 표준 학습 ➔ 4+1 View 및 다양한 아키텍처 뷰 작성 기법 습득 ➔ ADR 작성 실습을 통한 체계적인 의사결정 프로세스 체득.
|
||||
- **My Project Relevance:** 현재 진행 중인 프로젝트에 도입된 핵심 기술 스택이나 아키텍처 패턴(예: 이벤트 기반 또는 계층형)을 선택하게 된 배경을 팀원들에게 명확히 설명하고 후임자를 위해 문서(Wiki, Git 저장소) 형태로 ADR을 남겨 지식 자산화에 활용한다.
|
||||
|
||||
### Adjacent Topics
|
||||
- `[[Architecture Erosion (아키텍처 침식)]]`
|
||||
- 확장 방향: 아키텍처 명세가 업데이트되지 않았을 때 현실 시스템과 문서 간의 격차가 벌어지는 원인과 이를 식별, 교정하는 정적 분석 도구 및 리팩토링 기법에 대한 연구로 확장[9, 11].
|
||||
- `[[Requirements Engineering (요구사항 공학)]]`
|
||||
- 확장 방향: '어떻게(How)'를 다루는 아키텍처 명세와, 상호보완적으로 '무엇을(What)'을 다루는 요구사항 공학 간의 시너지 모델(예: Twin Peaks 모델) 및 상호작용 이해로 확장[14, 15].
|
||||
- `[[Architecture Tradeoff Analysis Method (ATAM)]]`
|
||||
- 확장 방향: 작성된 아키텍처 명세와 설계 결정을 바탕으로 시스템이 요구되는 품질 속성을 실질적으로 충족하는지 시나리오를 통해 검증하고 트레이드오프를 평가하는 분석 방법론에 대한 탐구로 확장[16, 17].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### arc42 template skeleton (Markdown, 12 sections)
|
||||
```markdown
|
||||
# 1. Introduction & Goals
|
||||
## 1.1 Requirements Overview
|
||||
## 1.2 Quality Goals (top 3-5)
|
||||
## 1.3 Stakeholders
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
# 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
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### ADR (Architecture Decision Record, Michael Nygard format)
|
||||
```markdown
|
||||
# ADR-0042: Use PostgreSQL over MongoDB for tx store
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
## Status
|
||||
Accepted (2026-04-15) — supersedes ADR-0021.
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
## Context
|
||||
Transactional integrity 의 critical. Document flexibility 의 secondary.
|
||||
PostgreSQL 16 의 JSONB columns 의 hybrid 의 enable.
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 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]] · [[ISO-IEC-IEEE 42010]]
|
||||
- 변형: [[4+1 View Model]] · [[C4 Model]] · [[arc42]]
|
||||
- 응용: [[Architecture Decision Records]] · [[Architecture_Diagramming_Standards]] · [[Architecture Review (아키텍처 및 설계 리뷰)]]
|
||||
- Adjacent: [[Architectural Views]] · [[Stakeholder Analysis]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -2,145 +2,33 @@
|
||||
id: wiki-2026-0508-architecture-erosion-아키텍처-침식
|
||||
title: Architecture Erosion (아키텍처 침식)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-1AE99216]
|
||||
duplicate_of: none
|
||||
status: duplicate
|
||||
canonical_id: architectural-constraint-enforcement
|
||||
duplicate_of: "[[Architectural-Constraint-Enforcement]]"
|
||||
aliases: [architecture-drift, architectural-decay]
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [architecture-erosion-(아키텍처-침식), technical-debt, knowledge-vaporization, big-ball-of-mud, software-architecture-recovery, architecture-principles]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-02
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, architecture, erosion, drift]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
---
|
||||
|
||||
# [[Architecture Erosion (아키텍처 침식)]]
|
||||
# Architecture Erosion (아키텍처 침식)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
아키텍처 침식(Architecture Erosion)은 시간이 지남에 따라 초기 의도된 소프트웨어 아키텍처와 실제 구현된 아키텍처 사이에 점진적인 격차가 발생하는 현상을 의미한다 [1]. 이 현상은 소프트웨어 개발 생명주기(SDLC)의 전 단계에서 발생할 수 있으며, 개발 속도를 저하시키고 유지보수 비용을 증가시킨다 [1]. 주로 아키텍처 위반, 기술 부채의 축적, 지식 증발(knowledge vaporization)과 같은 요인들로 인해 발생한다 [1].
|
||||
> **이 문서는 [[Architectural-Constraint-Enforcement]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 📖 Core 대Content
|
||||
- **발생 원인 및 구조적 현상**
|
||||
아키텍처 침식은 개발 과정에서 아키텍처 규칙을 위반하거나, 기술 부채가 누적되고, 시스템 구조에 대한 지식이 소실(증발)되면서 발생한다 [1]. 또한, 특정 아키텍처 패턴을 잘못 운영할 때도 나타나는데, 예를 들어 계층형 아키텍처(Layered Architecture)에서는 시간이 지남에 따라 비즈니스 로직이 여러 계층으로 누수(leak)되는 형태로 나타날 수 있다 [2]. 모듈형 모놀리스(Modular Monolith) 아키텍처에서도 모듈 간의 경계가 엄격히 강제되지 않으면 강하게 결합된 코드와 종속성 확산으로 인해 시스템이 "거대한 진흙 뭉치(big ball of mud)"로 전락하는 침식을 겪을 수 있다 [3].
|
||||
## 핵심 요약
|
||||
- 매 architecture erosion = 매 intended architecture 와 actual code 의 divergence.
|
||||
- 매 cause: 매 deadline pressure, 매 missing enforcement, 매 onboarding gap.
|
||||
- 매 fix: 매 ArchUnit/Dependency-Cruiser 의 automated constraint enforcement (canonical 참조).
|
||||
|
||||
- **시스템에 미치는 영향**
|
||||
침식이 진행되면 소프트웨어의 성능이 감소하고, 시스템을 진화시키거나 업데이트하는 데 드는 비용이 상당히 증가하며, 전반적인 소프트웨어 품질이 저하된다 [4]. 대표적인 아키텍처 침식의 피해 사례로 넷스케이프(Netscape)가 만든 초기 모질라(Mozilla) 웹 브라우저가 있다 [1]. 지속적인 변경으로 인해 코드베이스가 너무 복잡해지고 유지보수가 힘들어지면서, 넷스케이프는 값비싼 재작업과 프로젝트 지연을 감수하고 2년 동안 브라우저를 완전히 재개발해야만 했다 [1].
|
||||
## 🔗 Graph
|
||||
- 부모: [[Architectural-Constraint-Enforcement]] (canonical)
|
||||
- Adjacent: [[Architecture_Refactor]] · [[Architecture Review (아키텍처 및 설계 리뷰)]]
|
||||
|
||||
- **탐지 방법론 및 도구**
|
||||
아키텍처 침식을 탐지하기 위해 다양한 접근법과 도구가 제안되었으며, 이는 크게 일관성 기반(consistency-based), 진화 기반(evolution-based), 결함 기반(defect-based), 의사결정 기반(decision-based)의 네 가지 범주로 분류된다 [4]. 실제 현장에서는 자동화된 아키텍처 적합성 검사, 정적 코드 분석 도구, 리팩토링 기술 등을 사용하여 침식을 조기에 식별하고 완화할 수 있다 [4].
|
||||
|
||||
- **예방 및 치료(복구) 전략**
|
||||
아키텍처 침식을 해결하기 위한 조치는 예방적(preventative) 조치와 치료적(remedial) 조치로 나뉜다 [5].
|
||||
- **예방적 조치**: 아키텍처 규칙 강제, 정기적인 코드 리뷰, 자동화된 테스트를 통해 사전에 구조적 변질을 차단한다 [5].
|
||||
- **치료적 조치**: 이미 발생한 침식을 해결하기 위해 리팩토링, 재설계, 그리고 문서 업데이트를 수행한다 [5]. 노후화되거나 시대에 뒤떨어진 문서 및 아키텍처의 의사결정 편차를 해결하기 위해, 정적 프로그램 분석 등을 활용하여 구현된 시스템으로부터 아키텍처를 역공학으로 유추해내는 소프트웨어 아키텍처 복구(Software architecture recovery) 과정이 필요할 수 있다 [5].
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
아키텍처 침식을 관리하고 방지하기 위한 노력은 소프트웨어 품질 유지와 개발 속도 사이의 트레이드오프를 수반한다.
|
||||
|
||||
* **예방 및 유지보수 비용 vs. 단기 개발 속도**: 아키텍처 침식을 방지하기 위해 엄격한 아키텍처 규칙을 강제하고, 지속적인 코드 리뷰와 자동화된 테스트를 수행하는 예방적 조치는 초기와 진행 과정에서 상당한 리소스와 시간의 투자를 요구한다 [5]. 이러한 아키텍처 규율을 지키는 것은 팀에게 단기적으로 개발 속도를 늦추거나 오버헤드로 느껴질 수 있다. 하지만 이를 방치하면 기술 부채가 축적되어 결국 성능 저하와 막대한 진화 비용이라는 더 큰 대가를 치르게 된다 [4, 5].
|
||||
* **리팩토링 및 복구의 한계**: 시스템이 이미 심각하게 침식된 경우, 이를 바로잡기 위한 아키텍처 복구(Architecture Recovery)나 전면적인 재설계를 수행해야 한다 [5]. 그러나 모질라의 사례처럼, 침식이 일정 수준을 넘어서면 단순한 치료를 넘어 수년간의 재개발이라는 막대한 시간적·금전적 비용 및 비즈니스 지연(Trade-off)을 초래할 수 있다는 점을 유의해야 한다 [1].
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
|
||||
#### [발생 원인 및 결함(Causes & Defects)]
|
||||
- [[Technical Debt]]
|
||||
- 연결 이유: 아키텍처 침식을 발생시키는 주요 원인 중 하나로 명시되어 있다 [1].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 초기 개발 속도를 위해 타협한 설계가 시간이 지남에 따라 어떻게 유지보수 비용을 증가시키고 아키텍처를 파괴하는지 이해할 수 있다.
|
||||
- [[Knowledge Vaporization]]
|
||||
- 연결 이유: 지식의 증발은 아키텍처 규칙과 설계 의도가 개발자들 사이에서 잊혀지면서 구조적 침식을 야기하는 핵심 원인이다 [1].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 문서화 부재 및 소통 부재가 장기적인 시스템 구조에 미치는 악영향을 파악할 수 있다.
|
||||
|
||||
#### [구조적 안티 패턴(Structural Anti-patterns)]
|
||||
- [[Big Ball of Mud]]
|
||||
- 연결 이유: 모듈형 모놀리스 등에서 경계가 무너지고 종속성이 얽히면서 나타나는 심각한 아키텍처 침식의 결과물 형태이다 [3].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 아키텍처 경계(Boundary) 강제가 실패했을 때 나타나는 스파게티 코드의 극단적인 사례를 파악할 수 있다.
|
||||
|
||||
#### [대응 및 복구 전략(Countermeasures & Recovery)]
|
||||
- [[Software Architecture Recovery]]
|
||||
- 연결 이유: 침식되어 문서와 불일치하게 된 시스템의 실제 아키텍처 상태를 코드나 가용 정보로부터 역으로 추론하여 파악하는 치료적 조치이다 [5].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 노후화된 레거시 시스템이나 고도로 침식된 프로젝트에서 구조적 가시성을 회복하기 위한 리버스 엔지니어링 기법을 배울 수 있다.
|
||||
|
||||
### Deeper Research Questions
|
||||
- 아키텍처 침식을 조기에 탐지하기 위한 4가지 분류 방식(일관성 기반, 진화 기반, 결함 기반, 의사결정 기반)의 구체적인 작동 원리와 차이점은 무엇인가?
|
||||
- 모듈형 모놀리스나 계층형 아키텍처에서 비즈니스 로직 누수 및 종속성 확산(침식)을 시스템적으로 엄격하게 강제(enforce)하는 설계 기법이나 도구에는 어떤 것들이 있는가?
|
||||
- '지식 증발(Knowledge Vaporization)' 현상이 아키텍처 침식에 미치는 영향을 최소화하기 위해 애자일(Agile) 조직은 어떤 방식의 문서화 또는 소통 방식을 취해야 하는가?
|
||||
- 소프트웨어 아키텍처 복구(Architecture Recovery) 과정에서 정적 프로그램 분석(Static program analysis)은 어떤 메커니즘으로 침식된 아키텍처의 의도를 재구성해내는가?
|
||||
- 넷스케이프의 모질라 브라우저 실패 사례처럼, 점진적 침식에 대한 '치료(Remedial measure)'를 멈추고 '전면 재개발(Redevelopment)'을 선택해야만 하는 구조적 임계점(Tipping point)은 어떻게 판단할 수 있는가?
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 코드 작성 시 정적 코드 분석 도구나 자동화된 아키텍처 적합성 검사 파이프라인(CI/CD 연동)을 적용하여, 개발자가 의도된 아키텍처 패턴을 위반(침식)하는 코드를 작성하지 않도록 조기에 탐지한다.
|
||||
- **System Design:** 초기 시스템 설계 시 모듈 간 경계와 종속성 규칙을 명확히 설정하고, 시간이 지나도 설계 의도가 잊혀지지 않도록 문서화 시스템(ADR 등)을 확립하여 지식 증발을 막는다.
|
||||
- **Operation / Maintenance:** 유지보수 기간 동안 정기적인 코드 리뷰와 아키텍처 평가를 수행하고, 구현과 설계가 어긋난 부분이 발견되면 즉각적인 리팩토링을 통해 기술 부채를 해소한다.
|
||||
- **Learning Path:** 다양한 아키텍처 패턴(Layered, Microservices 등)의 이상적인 구조를 학습한 뒤 -> 현장에서 발생하는 위반 사례(침식)와 안티 패턴을 분석하고 -> 이를 극구하거나 복구하는 리팩토링 및 아키텍처 복구 기법으로 학습을 확장한다.
|
||||
- **My Project Relevance:** 프로젝트 규모가 확장되고 팀원이 교체되는 과정에서 "거대한 진흙 뭉치"로 변질될 위험이 존재하므로, 초기 설계의 무결성을 지키기 위해 예방적 조치(자동화 테스트, 규칙 강제)를 프로젝트 관리 기준에 포함시킨다.
|
||||
|
||||
### Adjacent Topics
|
||||
- [[Architecture Decision Records (ADR)]]
|
||||
- 확장 방향: 아키텍처 결정 사항, 맥락, 대안 및 타협점(Trade-offs)을 기록하는 문서화 기법으로, '지식 증발'로 인한 침식을 막기 위한 실무적 대응책을 심도 있게 연구할 수 있다.
|
||||
- [[Anti-patterns]]
|
||||
- 확장 방향: 아키텍처 침식을 가속화하는 나쁜 설계 습관과 관행들을 폭넓게 조사하여 시스템 복잡성이 기하급수적으로 늘어나는 원인을 분석할 수 있다.
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
|
||||
**추출된 패턴:**
|
||||
> *(TODO)*
|
||||
|
||||
**세부 내용:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
|
||||
@@ -2,129 +2,33 @@
|
||||
id: wiki-2026-0508-architecture-evaluation-아키텍처-평가
|
||||
title: Architecture Evaluation (아키텍처 평가)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-6AF151C4]
|
||||
duplicate_of: none
|
||||
status: duplicate
|
||||
canonical_id: atam-architecture-trade-offs-analysis-method
|
||||
duplicate_of: "[[ATAM (Architecture Trade-offs Analysis Method)]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [architecture-evaluation-(아키텍처-평가), atam-(architecture-tradeoff-analysis-method), 품질-모델-(iso/iec-25010), adr-(architecture-decision-record), 프로토타이핑-및-개념-증명-(poc), architecture-principles]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-02
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, architecture, evaluation]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
---
|
||||
|
||||
# [[Architecture Evaluation (아키텍처 평가)]]
|
||||
# Architecture Evaluation (아키텍처 평가)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
아키텍처 평가는 제안되거나 현재 사용 중인 소프트웨어 설계가 비즈니스 목표와 분석 과정에서 도출된 요구사항을 얼마나 잘 충족하는지 결정하는 체계적인 과정이다 [1, 2]. 이 과정은 특정 패턴의 도입이 프로젝트의 품질 요구사항(성능, 확장성, 보안 등)에 적합한지 구체적인 시나리오를 바탕으로 검증한다 [2, 3]. 대표적인 평가 방법론으로는 ATAM(Architecture Tradeoff Analysis Method)이 활용되며, 이를 통해 설계에 내재된 타협점(Trade-off)을 명확히 식별하여 정보에 기반한 의사결정을 지원한다 [1, 4].
|
||||
> **이 문서는 [[ATAM (Architecture Trade-offs Analysis Method)]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **평가의 목적 및 근본 원리:** 모든 아키텍처 결정에는 타협(Trade-off)이 따르며 "완벽한 아키텍처"란 존재하지 않는다 [4]. 따라서 아키텍처 평가는 단순히 유행하는 기술을 선택하는 것이 아니라, 프로젝트의 맥락과 우선순위화된 품질 목표(가용성, 성능, 유지보수성 등)를 바탕으로 어떤 설계가 가장 수용 가능한 타협안을 제시하는지 객관적으로 비교하는 과정이다 [2, 4, 5].
|
||||
* **시나리오 기반 평가 기법 (ATAM 등):** SEI에서 개발한 ATAM은 아키텍처를 평가하는 가장 대표적인 방법론이다 [4]. "성능 향상"과 같은 추상적인 목표 대신, "10분 내에 사용자 수가 두 배로 증가할 때 시스템의 반응"과 같은 구체적인 '시나리오'를 사용하여 아키텍처의 한계와 민감도(Sensitivity points)를 시험한다 [2, 4]. 이 외에도 TARA, SARA 프레임워크 등이 평가 기법을 돕는 데 사용된다 [1].
|
||||
* **평가 기준으로서의 품질 모델:** 평가 시에는 ISO/IEC 25010과 같은 표준 품질 모델을 참조한다 [1, 6, 7]. 기능 적합성, 성능 효율성, 호환성, 상호작용 능력 등의 지표를 기반으로 프로젝트 요구사항의 가중치를 정량화하여 아키텍처 개념들을 비교하기 위한 의사결정 매트릭스를 구성한다 [6-9].
|
||||
* **리스크 최소화를 위한 초기 검증:** 성능, 부하, 통합, 운영 측면에서 주요 기술적 리스크를 평가할 때는 프로토타이핑(Prototyping)이나 개념 증명(Proof of Concept)이 핵심적으로 활용된다 [10]. 이 과정을 통한 조기 검증(Early validation)은 훗날 발생할 수 있는 막대한 재작업 비용과 잘못된 결정을 줄인다 [11].
|
||||
* **결정의 문서화와 지속적 검토:** 평가의 최종 결과는 아키텍처 결정 기록(ADR, Architecture Decision Records)으로 문서화되어야 한다. 여기에는 결정의 배경, 대안, 타협점 및 리스크가 명시되어야 한다 [11-13]. 아키텍처는 고정불변이 아니므로 사용자 규모나 팀 상황이 변경될 때마다 정기적인 평가 및 수정이 이루어져야 한다 [14].
|
||||
## 핵심 요약
|
||||
- 매 architecture evaluation 의 most-used method 는 ATAM.
|
||||
- 매 quality attribute scenario 의 prioritization + risk/non-risk identification.
|
||||
- 매 SAAM, ARID, CBAM 등 variant 의 존재 — 매 ATAM 의 default.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
* **품질 속성 간의 상충 관계 (Trade-offs):** 아키텍처 평가는 궁극적으로 서로 충돌하는 요구사항 간의 교환을 인지하고 수용하는 과정이다 [2, 4]. 예를 들어, 극도로 안전한 시스템을 위해 암호화 수준을 높이면 응답 시간(성능)이 저하되며, 가용성을 높이려 하면 데이터 일관성을 어느 정도 양보해야 할 수 있다 [2, 4]. 빠른 개발(Fast delivery)을 우선순위에 두면, 확장성이나 유지보수성이 나빠지는 구조를 선택할 위험을 감수해야 한다 [4, 9].
|
||||
* **분석 마비 (Analysis Paralysis) 위험:** 잘못된 결정을 내릴 것에 대한 두려움으로 아키텍처 평가를 지연시키거나 지나치게 길게 끄는 '분석 마비' 함정에 빠질 수 있다 [15]. 따라서 충분한 정보를 확보하여 결정을 정당화할 수 있는 "마지막 책임 순간(last responsible moment)"에 적절히 결정을 내리고, 팀의 피드백을 통해 이를 지속적으로 조정해야 한다 [15].
|
||||
* **조직적 제약 조건 고려:** 아키텍처 평가 시 기술적 요소뿐만 아니라 팀의 구조, 규모, 스킬셋, 인프라 및 도구의 가용성(Conway's Law 등)을 반드시 고려해야 한다. 팀이 구축하고 장기적으로 유지할 수 없는 아키텍처는 실패한 결정이다 [16, 17].
|
||||
## 🔗 Graph
|
||||
- 부모: [[ATAM (Architecture Trade-offs Analysis Method)]] (canonical)
|
||||
- Adjacent: [[Architecture Review (아키텍처 및 설계 리뷰)]] · [[Architecture Erosion (아키텍처 침식)]]
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
|
||||
#### [관계 유형 A (평가 프레임워크 및 기준)]
|
||||
- [[ATAM (Architecture Tradeoff Analysis Method)]]
|
||||
- 연결 이유: 아키텍처가 비즈니스 목표를 얼마나 잘 지원하는지 객관적으로 검증하는 시나리오 기반의 가장 대표적인 평가 방법론이다 [1, 2, 4].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 보안과 성능, 개발 속도와 확장성 등 서로 상충하는 품질 목표 간의 교환(Trade-off) 지점을 구체적으로 식별하고 분석하는 메커니즘.
|
||||
- [[품질 모델 (ISO/IEC 25010)]]
|
||||
- 연결 이유: 아키텍처 평가 시 비교의 기준이 되는 성능 효율성, 유지보수성, 호환성 등의 비기능적 요구사항(품질 속성) 지표를 표준화하여 제공한다 [1, 6, 7].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 아키텍처 결정 매트릭스를 정량적으로 구성할 때 각 항목이 의미하는 구체적 정의 및 소프트웨어 품질의 객관적 측정 방식.
|
||||
|
||||
#### [관계 유형 B (검증 및 지식 관리 도구)]
|
||||
- [[ADR (Architecture Decision Record)]]
|
||||
- 연결 이유: 평가를 통해 도출된 아키텍처 결정 사항, 거절된 대안, 그리고 그에 수반된 리스크와 근거를 영구적으로 보존하는 지식 관리 문서이다 [11-13].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 이해관계자와의 소통 부재를 막고, 시스템이 진화하거나 새로운 팀원이 합류할 때 아키텍처적 일관성을 유지하게 돕는 추적 관리 체계.
|
||||
- [[프로토타이핑 및 개념 증명 (PoC)]]
|
||||
- 연결 이유: 특정 아키텍처 패턴이나 기술이 요구사항을 감당할 수 있는지 조기에(Early validation) 검증하기 위해 평가 단계에서 도입되는 구현 기법이다 [10].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 이론적인 아키텍처 구조가 실제 부하 조건이나 인프라와 결합되었을 때 발생하는 한계를 최소한의 비용으로 밝혀내는 방법.
|
||||
|
||||
### Deeper Research Questions
|
||||
|
||||
- ATAM과 같은 시나리오 기반 평가 기법을 적용할 때, 극단적인 부하나 예상치 못한 시스템 장애 시나리오는 구체적으로 어떻게 도출하고 테스트해야 하는가?
|
||||
- 분석 마비(Analysis Paralysis)를 방지하면서도 충분한 근거를 확보하기 위한 '마지막 책임 순간(last responsible moment)'은 실제 프로젝트 맥락에서 어떤 지표로 결정할 수 있는가?
|
||||
- 조직의 비즈니스 목표에 따라 ISO 25010 품질 모델에서 도출된 다양한 품질 속성들 간에 충돌이 발생할 때, 평가 매트릭스의 가중치를 객관적으로 산정하는 효과적인 방법론은 무엇인가?
|
||||
- 초기 평가에서 의도된 아키텍처가 시간이 지나면서 변질되는 '아키텍처 침식(Architecture erosion)' 현상을 피트니스 함수(Fitness functions)와 정기적 검토로 어떻게 방어할 수 있는가?
|
||||
- 아키텍처 평가 단계에서 기술적 제약뿐 아니라 현재 개발팀의 조직 구조나 스킬셋(조직적 환경)이 미치는 영향을 객관적으로 평가에 반영하는 기준은 어떻게 세워야 하는가?
|
||||
|
||||
### Practical Application Contexts
|
||||
|
||||
- **Implementation:** 핵심 기술 리스크가 존재하는 컴포넌트에 대해 간소화된 프로토타입이나 개념 증명(PoC) 코드를 작성하여 성능과 확장성을 실제적으로 초기 검증(Early validation)하는 과정에 적용된다 [10].
|
||||
- **System Design:** 추상적인 성능 목표를 설정하는 대신 "데이터베이스 다운 시 시스템의 반응", "특정 시간대 트래픽 급증 시 응답 지연 시간"과 같은 구체적인 스트레스 시나리오를 설정하여 설계의 한계를 시험하는 기준으로 삼는다 [2, 4].
|
||||
- **Operation / Maintenance:** 변화하는 사용자 트래픽, 새로운 인프라 요구사항, 규제 환경의 변화 등이 감지될 때, 이전에 작성된 ADR을 기반으로 현재 아키텍처의 적합성을 재평가하고 시스템을 진화시키는 근거로 활용한다 [14].
|
||||
- **Learning Path:** 다양한 아키텍처 패턴(MSA, Event-Driven, Space-Based 등)의 특징을 배운 후, 해당 패턴들이 필연적으로 갖게 되는 타협점(Trade-offs)을 ATAM, SARA와 같은 평가 프레임워크를 통해 실증적으로 비교, 분석하는 심화 학습 단계에 위치한다 [1, 4].
|
||||
- **My Project Relevance:** 프로젝트 시작 시, 유행하는 아키텍처를 맹목적으로 따르지 않고 팀의 기술 숙련도, 예산 제한, 보안, 성능 요구사항 등을 정량화한 아키텍처 결정 매트릭스를 작성하여 최적의 패턴을 선택하는 합리적 과정에 직접 사용할 수 있다 [3, 5, 18].
|
||||
|
||||
### Adjacent Topics
|
||||
|
||||
- [[아키텍처 침식 (Software Architecture Erosion)]]
|
||||
- 확장 방향: 초기에 평가 및 채택된 아키텍처가 시스템 변경 및 기술 부채 누적과 함께 본래 설계 의도와 어긋나게 되는 현상으로, 이를 자동화된 정적 분석이나 정기 검토로 어떻게 감지하고 복구할지 연구한다 [19].
|
||||
- [[소프트웨어 아키텍처 복구 (Software Architecture Recovery)]]
|
||||
- 확장 방향: 문서화가 유실되거나 침식이 심하게 진행된 기존 시스템의 구현물(코드)로부터 현재의 실제 아키텍처를 역공학으로 추출하여 재평가하기 위한 기법들을 탐구한다 [20].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
|
||||
@@ -2,112 +2,33 @@
|
||||
id: wiki-2026-0508-architecture-review-아키텍처-및-설계-리뷰
|
||||
title: Architecture Review (아키텍처 및 설계 리뷰)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
duplicate_of: none
|
||||
status: duplicate
|
||||
canonical_id: atam-architecture-trade-offs-analysis-method
|
||||
duplicate_of: "[[ATAM (Architecture Trade-offs Analysis Method)]]"
|
||||
aliases: [design-review, arch-review]
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [uncategorized]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, architecture, review]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
---
|
||||
|
||||
# [[Architecture Review (아키텍처 및 설계 리뷰)|Architecture Review (아키텍처 및 설계 리뷰]]
|
||||
# Architecture Review (아키텍처 및 설계 리뷰)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
아키텍처 리뷰(Architecture Review)는 라인 단위의 구현 세부 사항을 넘어, 코드 변경 사항의 구조적 무결성과 장기적인 생존성을 평가하는 고수준의 특화된 검토 프로세스입니다 [1, 2]. 이 과정은 아키텍처의 표류(Architectural drift)와 기술 부채의 축적을 방지하는 전략적 체크포인트 역할을 수행합니다 [1, 3]. 궁극적으로 새로운 기능이 시스템의 거시적인 디자인 패턴(예: MVC, 클린 아키텍처) 및 설계 원칙(예: SOLID)에 부합하여, 확장성과 유지보수성을 보장하도록 만드는 것을 목표로 합니다 [1, 4].
|
||||
> **이 문서는 [[ATAM (Architecture Trade-offs Analysis Method)]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **목적 및 평가 초점:** 자동화된 도구가 포착하기 어려운 고수준의 설계 의사결정을 검증하여 시스템의 장기적인 건전성을 유지합니다 [3, 7]. 코드의 국소적 정확성보다는, 새로운 모듈이 기존 아키텍처 원칙과 정렬되며 시스템이 '거대한 진흙 뭉치(Big Ball of Mud)'가 되는 것을 방지하는 데 집중합니다 [3, 5].
|
||||
* **설계 원칙 및 정합성 검증:** SOLID 원칙(SRP, OCP 등) 준수 여부와 컴포넌트 간의 결합도(Coupling)를 검토합니다 [3, 4]. 하나의 모듈 변경이 연관 없는 다른 컴포넌트의 연쇄 수정을 유발하지 않도록 모듈성을 보장해야 합니다 [6].
|
||||
* **과도한 엔지니어링 방지:** 미래의 유연성을 확보하되, 현재 요구사항에 비해 불필요하게 복잡한 '오버 엔지니어링(Over-engineering)'이 도입되지 않았는지 평가합니다 [3, 8]. 적절한 추상화 수준을 유지하는 것이 핵심입니다.
|
||||
* **의존성 및 서드파티 검토:** 새로운 외부 라이브러리나 서비스 도입 시, 시스템의 의존성 전이 위험, 보안 취약점, 라이선스 호환성 등을 면밀히 검토하여 공급망 안정성을 확보합니다.
|
||||
* **리뷰 타이밍과 문서화:** 실제 코드가 작성되기 전, 설계 문서나 다이어그램 단계에서 사전 리뷰를 수행하는 것(시프트 레프트)이 가장 효율적입니다 [9]. 합의된 중요한 결정 사항은 **아키텍처 결정 기록(ADR, Architecture Decision Records)**으로 문서화하여 역사적 맥락을 보존합니다 [9].
|
||||
## 핵심 요약
|
||||
- 매 lightweight review 의 ad-hoc walkthrough — 매 ATAM 의 formal version.
|
||||
- 매 RFC + ADR + design doc review 의 modern equivalent.
|
||||
- 매 quality attribute 의 prioritization 의 ATAM 의 core differentiator.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
* **높은 비용 및 전문성 요구:** 아키텍처 리뷰는 시스템 전반에 대한 깊은 지식이 필요하므로 시니어 개발자의 시간이 많이 소요됩니다 [10]. 이는 자칫 개발 파이프라인의 병목(Bottleneck)이 될 수 있습니다 [12].
|
||||
* **완벽주의의 함정:** 완벽한 아키텍처와 미래 확장성만을 쫓다 보면, 당장의 비즈니스 요구사항 해결이 늦어지거나 불필요한 복잡성이 주입될 수 있습니다 [8, 15].
|
||||
* **유연성 저하:** 특정 디자인 패턴을 무조건적으로 강제하는 등 지나치게 엄격한 원칙 적용은 실용적인 문제 해결을 방해할 수 있습니다 [16].
|
||||
## 🔗 Graph
|
||||
- 부모: [[ATAM (Architecture Trade-offs Analysis Method)]] (canonical)
|
||||
- Adjacent: [[Architecture Evaluation (아키텍처 평가)]] · [[Architecture_Refactor]]
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
* **[[SOLID Principles|SOLID Principles]]**: 아키텍처 리뷰 시 견고한 객체 지향 설계를 판단하는 절대적인 척도입니다.
|
||||
* **Architecture Decision Records (ADR**: 리뷰를 통해 합의된 설계 선택과 트레이드오프를 기록하는 공식적인 도구입니다.
|
||||
* **Over-engineering**: 리뷰어가 가장 경계해야 할, 시스템 유지보수성을 해치는 불필요한 추상화와 일반화입니다.
|
||||
* **Shift-Left Strategy**: 설계 결함을 구현 전 초기 단계에서 잡아내어 리팩토링 비용을 예방하는 전략입니다.
|
||||
|
||||
### Deeper Research Questions
|
||||
* ADR 작성 프로세스를 애자일 스프린트나 PR 워크플로우 내에 마찰 없이 매끄럽게 통합하기 위한 자동화 방안은 무엇인가?
|
||||
* '오버 엔지니어링'과 '적절한 확장성 설계' 사이의 경계를 명확히 구분 지을 수 있는 정성적/정량적 평가 프레임워크는 무엇인가?
|
||||
* 마이크로서비스 아키텍처(MSA) 환경에서 서비스 간 상호작용의 사각지대를 포착하는 '크로스 서비스(Cross-service) 리뷰'는 어떻게 운영해야 하는가?
|
||||
* AI가 제안한 초기 아키텍처 구조가 프로젝트의 핵심 설계 원칙을 준수하는지 인간 리뷰어가 효율적으로 검증하는 체크리스트는 어떻게 구성되는가?
|
||||
* 비즈니스 성장 속도가 최우선인 스타트업 환경에서 기술 부채를 통제하기 위한 '최소 필수 아키텍처 리뷰(Minimum Viable Review)'의 범위는 어디까지인가?
|
||||
|
||||
### Practical Application Contexts
|
||||
* **Implementation:** 대규모 구현 전 설계 문서(RFC) 단계에서 사전 리뷰를 받아 전면 재작성 비용을 예방합니다 [50].
|
||||
* **System Design:** 새로운 모듈 추가 시 기존 컴포넌트와의 결합도를 통제하고 설계 원칙 위반을 걸러내어 시스템 구조를 보호합니다 [51].
|
||||
* **Operation / Maintenance:** 트래픽 증가 및 데이터 볼륨 확대에 대비한 확장성 검토를 통해 운영 안정성을 확보합니다.
|
||||
* **Learning Path:** 시니어 아키텍트와의 리뷰 세션을 통해 팀 전체의 설계 역량을 상향 평준화하는 멘토링 기회로 활용합니다 [53].
|
||||
* **My Project Relevance:** 중대한 구조 변경 시 요구되는 별도의 '설계 승인(Design Approval)' 단계를 도입하여 아키텍처 표류를 방지합니다.
|
||||
|
||||
### Adjacent Topics
|
||||
* **Technical Debt (기술 부채**: 아키텍처 리뷰 소홀로 인해 누적되는 장기적인 비용과 운영 리스크에 대해 탐구합니다.
|
||||
* **Code Smells**: 고수준의 설계 결함이 소스 코드 레벨에서 어떤 구현 안티 패턴으로 발현되는지 분석합니다.
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
|
||||
@@ -4,115 +4,185 @@ title: Architecture Diagramming Standards
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-ARCH-DIAGRAMS, 아키텍처 다이어그램, Architecture Diagram, 시스템 청사진]
|
||||
aliases: [c4-model, arch-diagrams]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 1.0
|
||||
tags: [Architecture, Visualization, C4_Model, Documentation, Communication]
|
||||
raw_sources: [Datacollector_Export_2026-05-02]
|
||||
last_reinforced: 2026-05-02
|
||||
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: unspecified
|
||||
framework: unspecified
|
||||
language: mermaid
|
||||
framework: c4-plantuml
|
||||
---
|
||||
|
||||
# [[아키텍처 다이어그램 작성 표준 (Architecture Diagramming Standards)]]
|
||||
# Architecture Diagramming Standards
|
||||
|
||||
## 1. 개요
|
||||
아키텍처 다이어그램은 소프트웨어 시스템의 구조, 컴포넌트 간의 관계, 통신 채널을 시각적으로 표현한 청사진이다. 복잡한 시스템을 추상화하여 이해관계자 간의 정렬을 돕고, 설계 의도를 명확히 전달하며, 유지보수 및 온보딩의 가이드라인 역할을 수행한다.
|
||||
## 매 한 줄
|
||||
> **"매 diagram 의 audience 의 결정한다"**. 매 C4 model (Simon Brown, 2018) 의 Context → Container → Component → Code 의 4-level zoom 의 default standard 의 됨. 매 2026 의 PlantUML + Mermaid + Structurizr DSL 의 most-used toolchain.
|
||||
|
||||
## 2. 주요 다이어그램 유형 및 용도
|
||||
- **시스템 컨텍스트 다이어그램**: 시스템과 외부 액터(사용자, 외부 시스템) 간의 경계 정의.
|
||||
- **컨테이너 다이어그램**: 배포 가능한 기술 단위(웹 앱, DB 등)와 주요 통신 프로토콜 명시.
|
||||
- **컴포넌트 다이어그램**: 특정 컨테이너 내부의 논리적 모듈 구조와 의존성 표현.
|
||||
- **배포 다이어그램**: 소프트웨어가 실제 물리적/논리적 인프라에 매핑되는 방식 시각화.
|
||||
- **시퀀스 다이어그램**: 특정 유즈케이스 시나리오에 따른 객체/서비스 간의 시간적 상호작용 흐름 표현.
|
||||
## 매 핵심
|
||||
|
||||
## 3. 작성 모범 사례 (Best Practices)
|
||||
- **독자 중심 설계**: 독자의 지식 수준(경영진 vs 엔지니어)에 맞춰 추상화 깊이 조절. (C4 모델 활용 권장)
|
||||
- **일관된 표기법 및 범례**: 모양, 색상, 선 스타일의 의미를 통일하고 반드시 범례(Legend) 포함.
|
||||
- **명확한 라벨링**: 컴포넌트 이름뿐만 아니라 기술 스택, 통신 프로토콜(HTTP, gRPC 등)을 명확히 기재.
|
||||
- **Diagrams as Code**: 이미지 파일 대신 PlantUML, Mermaid 등을 사용하여 코드와 함께 버전 관리.
|
||||
### 매 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).
|
||||
|
||||
## 4. 트레이드오프 및 주의사항
|
||||
- **아키텍처 드리프트 (Architectural Drift)**: 코드가 변경됨에 따라 다이어그램이 구식이 되지 않도록 자동화 또는 정기적 업데이트 필요.
|
||||
- **과도한 복잡성 방지**: 하나의 다이어그램에 모든 정보를 담으려 하지 말고, 단일 목적성에 집중하여 분리 작성.
|
||||
- **기술 숭배 지양**: 논리적 구조보다 특정 라이브러리 명칭 기재에 집착하면 시스템의 개념적 이해를 방해함.
|
||||
### 매 supplementary diagrams
|
||||
- **Sequence**: 매 request flow / interaction.
|
||||
- **Deployment**: 매 infra topology (k8s, regions).
|
||||
- **Dynamic**: 매 runtime view, message sequence.
|
||||
- **State**: 매 entity lifecycle.
|
||||
|
||||
## 5. 지식 연결 (Related)
|
||||
- [[C4_Modeling_Framework]]: 다이어그램의 추상화 수준을 관리하는 실용적 프레임워크.
|
||||
- [[UML_Unified_Modeling_Language]]: 정밀한 기술 명세를 위한 표준 모델링 언어.
|
||||
- [[Architectural_Drift_Prevention]]: 다이어그램과 실제 코드 간의 불일치를 관리하는 전략.
|
||||
### 매 응용
|
||||
1. ADR 의 embedded diagram — 매 context.
|
||||
2. Onboarding 의 system overview.
|
||||
3. Incident postmortem 의 affected component highlight.
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
- **정보 상태**: 검증 완료 (Verified)
|
||||
- **출처 신뢰도**: A
|
||||
- **검토 이유**: 시스템 설계의 투명성을 확보하고 기술적 의사소통의 효율성을 높이기 위한 시각화 표준 확립.
|
||||
## 💻 패턴
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
|
||||
> *(TODO: 한 문장으로 핵심 통찰을 작성. "X는 Y 조건에서 Z 효과를 낸다" 구조 권장.)*
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
|
||||
**추출된 패턴:**
|
||||
> *(TODO)*
|
||||
|
||||
**세부 내용:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
|
||||
- **과거 데이터와의 충돌:** 없음
|
||||
- **정책 변화:** 없음
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
|
||||
- **Parent:** [[10_Wiki/Topics]]
|
||||
- **Related:** *(TODO: 최소 2개)*
|
||||
- **Opposite / Trade-off:** *(TODO)*
|
||||
- **Raw Source:** 직접 입력
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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")
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
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]] · [[Documentation]]
|
||||
- 변형: [[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 |
|
||||
|
||||
@@ -2,96 +2,197 @@
|
||||
id: wiki-2026-0508-architecture-refactor
|
||||
title: Architecture Refactor
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [550e8400-e29b-41d4-a716-446655440001]
|
||||
aliases: [strangler-fig, big-bang-rewrite, modernization]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [skybound, architecture, performance, zero-leak]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [architecture, refactor, strangler-fig, modernization]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-04-21
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: polyglot
|
||||
framework: strangler-fig
|
||||
---
|
||||
|
||||
# Skybound 아키텍처 리팩토링
|
||||
# Architecture Refactor
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> 엔진-모듈 간의 '의도(Intent)' 기반 통신과 선언적 파이프라인 도입을 통해 시스템 신뢰도와 성능을 동시에 확보하는 'Zero-Leak' 아키텍처로 진화함.
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **추출된 패턴:**
|
||||
- **Intent-Based Communication**: 엔진의 핵심 상태를 직접 조작하는 대신 허용된 Intent 인터페이스를 통해 시스템 간 격리를 강화.
|
||||
- **Phase-Aware Pipeline**: 시스템 실행 순서를 선언적으로 관리하여 비동기 레이스 컨디션을 원천 차단.
|
||||
- **세부 내용:**
|
||||
- `EntityPool` 최적화를 통해 루프 연산 시 CPU 점유율을 15-20% 개선.
|
||||
- 불필요한 이벤트 리스너 재등록을 차단하여 장기 실행 시의 메모리 누수 방지.
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 기존의 파편화된 비동기 호출 방식(Ghost UI 발생 원인)을 대체함.
|
||||
- **정책 변화:** 성능보다는 '예측 가능성(Predictability)'을 우선하는 설계 원칙 수립.
|
||||
### 매 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 의 가능.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Parent:** 10_Wiki/Projects/Skybound
|
||||
- **Related:** 10_Wiki/Decisions/Skybound/IDE_Stability_Fix, 10_Wiki/Decisions/Skybound/Frame_Type_Restoration
|
||||
- **Raw Source:** 00_Raw/2026-04-21-Skybound_Architecture_Refactor_Plan
|
||||
### 매 refactor 의 prerequisite
|
||||
- **Test coverage**: 매 characterization tests (Feathers) 의 minimum.
|
||||
- **Observability**: 매 metrics + traces 의 before/after diff.
|
||||
- **Feature flag**: 매 reversibility 의 prerequisite.
|
||||
- **ADR**: 매 decision rationale 의 documented.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts (Auto-Linked)
|
||||
* [[Architecture]]
|
||||
* [[Frame_Type_Restoration]]
|
||||
* [[IDE_Stability_Fix]]
|
||||
* [[decisions]]
|
||||
### 매 응용
|
||||
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.
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
## 💻 패턴
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
### Strangler Fig — Nginx routing facade
|
||||
```nginx
|
||||
upstream legacy { server legacy.internal:8080; }
|
||||
upstream new { server new.internal:8080; }
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
server {
|
||||
listen 443 ssl;
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
# New endpoints — gradual rollout
|
||||
location /api/v2/orders { proxy_pass http://new; }
|
||||
location /api/v2/users { proxy_pass http://new; }
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
# Everything else still legacy
|
||||
location / { proxy_pass http://legacy; }
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Branch by Abstraction (Java)
|
||||
```java
|
||||
// Step 1 — extract interface
|
||||
interface PaymentGateway {
|
||||
Receipt charge(Order o);
|
||||
}
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
// Step 2 — wrap legacy
|
||||
class LegacyStripeGateway implements PaymentGateway { /* ... */ }
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
// Step 3 — new impl behind flag
|
||||
class AdyenGateway implements PaymentGateway { /* ... */ }
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
// 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
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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);
|
||||
}
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]]
|
||||
- 변형: [[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 |
|
||||
|
||||
@@ -2,94 +2,202 @@
|
||||
id: wiki-2026-0508-arrangement-and-composition
|
||||
title: Arrangement and Composition
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-Reinforce-AUTO-ARCO-002]
|
||||
aliases: [composition-over-inheritance, function-composition, ui-composition]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
tags: [auto-reinforced, arrangement, composition, design, Systems-Thinking, structure]
|
||||
verification_status: applied
|
||||
tags: [composition, design, architecture, functional]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-04-20
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: react
|
||||
---
|
||||
|
||||
# [[Arrangement-and-Composition|Arrangement-and-Composition]]
|
||||
# Arrangement and Composition
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> "배열이 창조하는 의미: 개별 요소들은 그대로일지라도 그것들을 어떤 순서로, 어떤 간격으로 배치하느냐에 따라 전체 시스템의 기능과 미적 가치가 완전히 달라지는 '관계의 인지 과학'."
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
배치와 구성(Arrangement-and-Composition)은 각 부분 요소를 조직화하여 하나의 통일된 전체(Wholeness)를 만드는 예술적, 공학적 행위입니다.
|
||||
## 매 핵심
|
||||
|
||||
1. **배치의 원칙**:
|
||||
* **Proximity (근접성)**: 가까이 있는 것끼리 의미적으로 연관되어 있다고 느낌 (게슈탈트 원칙).
|
||||
* **Hierarchy (위계)**: 크기나 위치를 통해 정보의 우선순위를 시각화함.
|
||||
* **Rhythm (리듬)**: 반복과 변주를 통해 시각적/지적 흐름을 유도함.
|
||||
2. **구성과 기능**:
|
||||
* **Modular Composition**: 독립된 모듈을 조립하여 복잡한 시스템을 구축 ([[Agent Architecture|Agent Architecture]]와 연결).
|
||||
* **Balance vs Tension**: 균형 잡힌 배열은 안정감을 주고, 의도적으로 깨진 배열은 주의력을 환기시킴.
|
||||
3. **지식 관리에서의 적용**:
|
||||
* 노트 간의 연결(Graph)과 폴더 구조의 배치가 지식의 인출 효율을 결정함.
|
||||
### 매 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.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌**: 과거에는 고정된 그리드 시스템 내의 '정적 배치'가 미덕이었으나, 현대의 반응형 디자인 정책은 사용자의 기기에 따라 배치를 유연하게 바꾸는 '액티브 레이아웃 정책'으로 변화함(RL Update).
|
||||
- **정책 변화(RL Update)**: 음악 및 영상 창작 정책에서, AI가 개별 음표가 아닌 '악기 간의 배치(Arrangement)'와 '전체 흐름(Composition)'을 학습하여 인간 프로듀서 수준의 곡을 완성하는 'AI 오케스트레이션 정책'이 실용화됨.
|
||||
### 매 arrangement axes
|
||||
- **Horizontal**: 매 sibling 의 parallel — fan-out / fan-in.
|
||||
- **Vertical**: 매 layer / pipeline — sequential.
|
||||
- **Tree**: 매 hierarchy — 매 component tree / DOM.
|
||||
- **Graph**: 매 arbitrary edges — 매 dataflow / DAG.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- [[Structural Principles|Structural Principles]], [[Aesthetic-Value|Aesthetic-Value]], Design Theory, [[Agent Architecture|Agent Architecture]], Workflow-InteGrity
|
||||
- **Modern Tech/Tools**: [[Figma|Figma]] (Auto-layout), [[CSS Grid|CSS Grid]], AI-powered music arrangers (Suno, Udio).
|
||||
---
|
||||
### 매 응용
|
||||
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).
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
## 💻 패턴
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
### Function composition (TypeScript / fp-ts)
|
||||
```ts
|
||||
import { pipe, flow } from 'fp-ts/function';
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
const trim = (s: string) => s.trim();
|
||||
const lower = (s: string) => s.toLowerCase();
|
||||
const slug = (s: string) => s.replace(/\s+/g, '-');
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
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"
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Composition over inheritance (Go — embedding)
|
||||
```go
|
||||
type Logger struct{ prefix string }
|
||||
func (l Logger) Log(msg string) { fmt.Println(l.prefix, msg) }
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
type Counter struct{ n int }
|
||||
func (c *Counter) Inc() { c.n++ }
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
// HTTP server composes both — no inheritance
|
||||
type Server struct {
|
||||
Logger // embedded → Server.Log() works
|
||||
*Counter // embedded pointer
|
||||
addr string
|
||||
}
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
s := &Server{Logger: Logger{"[srv]"}, Counter: &Counter{}, addr: ":8080"}
|
||||
s.Log("starting"); s.Inc()
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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>
|
||||
);
|
||||
}
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
<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]] · [[Pipe-and-Filter]]
|
||||
- 응용: [[React]] · [[Airflow]] · [[Unix-Philosophy]]
|
||||
- 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 |
|
||||
|
||||
@@ -2,132 +2,223 @@
|
||||
id: wiki-2026-0508-aspect-oriented-programming-aop
|
||||
title: Aspect Oriented Programming (AOP)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-AUTO-16E587]
|
||||
aliases: [AOP, Aspect Programming, Cross-cutting Concerns]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [auto-reinforced]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [architecture, paradigm, spring, decorator]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-03
|
||||
github_commit: "[P-Reinforce] Continuous Worker - Aspect-Oriented Programming (AOP)"
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: Java / TypeScript / Python
|
||||
framework: Spring AOP / AspectJ / NestJS
|
||||
---
|
||||
|
||||
# [[Aspect-Oriented Programming (AOP)|Aspect-Oriented Programming (AOP)]]
|
||||
# Aspect-Oriented Programming (AOP)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
Aspect-Oriented Programming(AOP)은 소프트웨어 시스템 내 여러 모듈에 걸쳐 공통적으로 나타나는 **횡단 관심사(Cross-Cutting Concerns)를 핵심 비즈니스 로직과 분리하여 모듈화하는 프로그래밍 방법론**이다 [1]. 주로 로깅, 예외 처리, 트랜잭션, 보안 등 애플리케이션 전반에 필수적이지만 도메인 로직 자체는 아닌 기능들을 캡슐화하는 데 사용된다 [2], [3]. 이를 통해 비즈니스 코드를 수정하지 않고도 공통 기능을 적용할 수 있어 코드의 중복(Scattering)을 막고 시스템의 가독성과 유지보수성을 극대화한다 [4], [5].
|
||||
## 매 한 줄
|
||||
> **"매 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을 매 한 곳에 모음.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **관심사의 분리 (Core vs Cross-Cutting):**
|
||||
소프트웨어 시스템은 일차적 요구사항인 핵심 관심사(Core Concerns, 예: 비즈니스 로직)와 이차적 요구사항인 횡단 관심사(Cross-Cutting Concerns)로 나뉜다 [2]. AOP는 이 중 로깅, 보안, 데이터 유효성 검사, 예외 처리처럼 여러 계층(프레젠테이션, 비즈니스, 데이터 등)에 걸쳐 반복적으로 등장하는 로직을 추출해 내는 역할을 한다 [6], [7], [2], [8], [9].
|
||||
* **코드 산재(Scattering)와 얽힘(Tangling) 방지:**
|
||||
AOP를 적용하지 않으면 수백, 수천 개의 클래스에 `try-catch` 블록이나 로깅 코드가 반복적으로 산재하게 된다 [8], [10]. AOP는 이러한 로직을 하나의 '관점(Aspect)'으로 중앙 집중화하여 비즈니스 코드의 오염을 막고 단일 책임 원칙(SRP)과 DRY(Don't Repeat Yourself) 원칙을 준수하도록 돕는다 [4], [11], [12].
|
||||
* **프레임워크별 실전 아키텍처 패턴:**
|
||||
* **Spring Boot (Java):** AOP는 메서드 레벨에서 작동하며, 컨트롤러, 서비스, 리포지토리 등 모든 Spring 빈(Bean) 메서드의 실행을 가로챌 수 있다 [5]. `@Aspect` 어노테이션과 함께 `@Before`, `@After`, `@Around` 등의 Advice를 사용하여 비즈니스 로직을 터치하지 않고 횡단 관심사를 적용하는 것이 가장 강력한 실전 패턴이다 [5], [13], [14].
|
||||
* **C# / .NET:** C#은 AOP를 네이티브 수준에서 완전하게 지원하지 않는다 [1]. 따라서 속성(Attributes)을 정의하고 `Castle.DynamicProxy`와 같은 런타임 인터셉터를 사용하여 메서드 호출을 가로채는 방식으로 간접적인 AOP를 구현해야 한다 [1].
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
* **코드의 마법 같은 동작(Magical Behavior)과 디버깅 난이도:**
|
||||
AOP의 가장 큰 단점은 코드가 명시적으로 호출되지 않아도 은연중에 실행되기 때문에 로직의 흐름이 너무 "마법처럼" 보일 수 있다는 점이다 [15], [16]. 이로 인해 새로운 개발자가 특정 동작이 어디서 유발되는지 파악하기 어려우며, 의도치 않은 곳에서 로직이 실행되거나 에러가 발생할 경우 디버깅 추적이 매우 까다로워진다 [15], [16].
|
||||
* **성능 오버헤드 (Performance Cost):**
|
||||
C# 등에서 `Castle.DynamicProxy`와 같은 런타임 인터셉터를 사용하는 AOP 접근법은 각 메서드나 클래스에 대해 런타임 프록시 래퍼를 생성해야 하므로 성능 비용(Runtime cost)이 발생한다 [17].
|
||||
* **세밀한 컨텍스트 제어의 한계:**
|
||||
특정 상황의 세부적인 맥락(예: 함수 내 특정 지역 변수의 상태 포맷팅)이 필요한 로깅의 경우, AOP 외부 래퍼에서 그 데이터에 접근하기 어려워 기존 로깅 라이브러리를 코드 내부에서 직접 호출하는 것보다 유연성이 떨어질 수 있다 [18].
|
||||
### 매 용어
|
||||
- **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.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
### 매 cross-cutting concerns
|
||||
- Logging / tracing
|
||||
- Transaction management
|
||||
- Security / authorization
|
||||
- Caching
|
||||
- Performance monitoring
|
||||
- Error handling / retry
|
||||
- Audit trail
|
||||
|
||||
#### [관계 유형 A: 아키텍처/기반 기술]
|
||||
* **[[Cross-Cutting Concerns]]** (횡단 관심사)
|
||||
* 연결 이유: AOP가 기술적으로 해결하고자 하는 근본적인 대상이 바로 애플리케이션 전반에 걸쳐 영향을 미치는 횡단 관심사이기 때문이다 [6], [1].
|
||||
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: 로깅, 예외 처리, 캐싱, 보안 정책 등이 왜 비즈니스 핵심 로직과 분리되어 관리되어야 하는지 그 아키텍처적 당위성을 이해할 수 있다 [7], [3].
|
||||
* **[[Separation of Concerns]]** (관심사 분리)
|
||||
* 연결 이유: 핵심 도메인 규칙과 시스템 인프라 로직을 물리적/논리적으로 분리하는 소프트웨어 설계의 대원칙으로, AOP 탄생의 철학적 기반이다 [7], [19].
|
||||
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: 클린 아키텍처 및 헥사고날 아키텍처에서 비즈니스 로직을 외부 프레임워크나 횡단 관심사로부터 어떻게 고립시키는지 그 메커니즘을 파악할 수 있다 [7], [20].
|
||||
### 매 응용
|
||||
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.
|
||||
|
||||
#### [관계 유형 B: 구현/활용 도구]
|
||||
* **[[Filters]] & [[Interceptors]]**
|
||||
* 연결 이유: Spring Boot와 같은 프레임워크에서 AOP와 함께 횡단 관심사를 처리하는 대표적인 파이프라인 컴포넌트들이다 [19], [21], [16].
|
||||
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: AOP(임의의 빈 메서드 레벨), Filter(서블릿 레벨), Interceptor(웹 컨트롤러 레벨)가 각각 어느 계층에서 어떤 역할(예: CORS, 보안, 세부 로깅 등)에 가장 적합한지 비교 분석할 수 있다 [13], [22].
|
||||
## 💻 패턴
|
||||
|
||||
### Deeper Research Questions
|
||||
* Spring Boot 시스템에서 로깅이나 보안 같은 횡단 관심사를 구현할 때, 서블릿 계층의 Filter, MVC 계층의 Interceptor, 서비스 계층의 AOP 중 어느 것을 선택하는 것이 가장 최적의 성능과 유지보수성을 보장하는가? [13], [22]
|
||||
* C# 및 .NET 환경에서 런타임 프록시 생성으로 인한 성능 오버헤드를 방지하기 위해, 컴파일 타임(Compile-Time) 위빙을 통한 AOP 구현 방식에는 어떤 것들이 있는가? [17]
|
||||
* AOP의 '마법 같은(magical)' 비명시적 실행 흐름으로 인한 디버깅 추적의 어려움을 해결하기 위해, 대규모 엔터프라이즈 환경에서는 어떠한 아키텍처적 안전장치나 모니터링 도구를 도입하는가? [15], [16]
|
||||
* 클린 아키텍처(Clean Architecture)나 헥사고날 아키텍처(Hexagonal Architecture) 패턴 내에서 AOP를 적용할 때, 핵심 도메인 모델을 침범하지 않고 인프라스트럭처 레이어와 자연스럽게 연결하는 방법은 무엇인가? [7], [19]
|
||||
* 마이크로서비스나 분산 시스템 환경에서 AOP를 사용하여 여러 서비스에 걸친 분산 추적(Distributed Tracing) 및 에러 핸들링의 일관성을 어떻게 유지할 수 있는가? [23], [24], [25]
|
||||
### Spring AOP — @Around aspect
|
||||
```java
|
||||
@Aspect
|
||||
@Component
|
||||
public class LoggingAspect {
|
||||
|
||||
### Practical Application Contexts
|
||||
* **Implementation:** Spring Boot 애플리케이션에서 특정 비즈니스 로직(Service)의 실행 시간을 측정하거나 로깅을 남길 때, 코드 내부에 `System.out.println` 등을 산재시키지 않고 `@Aspect`와 `@Around` 어노테이션을 활용하여 깔끔하게 캡슐화하여 구현한다 [10], [5], [13].
|
||||
* **System Design:** 시스템 전반에 걸친 보안 검사, 트랜잭션 롤백, 글로벌 예외 처리 정책을 설계할 때, 핵심 비즈니스 로직에서 해당 책임을 제거하고 AOP 계층이나 중앙 집중화된 파이프라인 행동(Pipeline Behaviors)으로 추상화하여 확장 가능한 시스템을 설계한다 [19], [26], [8], [27].
|
||||
* **Operation / Maintenance:** 로깅 프레임워크를 변경하거나 보안 인가(Authorization) 정책을 대대적으로 수정해야 할 때, 수천 개의 파일을 개별적으로 수정하는 대신 단일 Aspect 정의부만 수정하여 유지보수성을 극대화한다 [10], [4].
|
||||
* **Learning Path:** 소프트웨어 기능의 분류(Core vs Cross-Cutting) 이해 ➔ 의존성 주입(DI)의 필요성 파악 ➔ Filter/Interceptor 등 기존 계층적 패턴 학습 ➔ 최종적으로 AOP의 핵심 요소(Aspect, Pointcut, Advice)를 적용하는 단계적 학습 모델을 거친다 [2], [13].
|
||||
* **My Project Relevance:** 현대 개발 프레임워크 아키텍처에서 비즈니스 로직과 인프라 관심사를 융합 없이 격리하는 필수 전략으로 다뤄지지만, 동시에 '기술 부채(Technical Debt)'를 야기할 수 있는 디버깅 복잡성을 이해하고 방어적으로 적용해야 하는 핵심 패턴이다 [16], [28].
|
||||
|
||||
### Adjacent Topics
|
||||
* **[[Dependency Injection (DI)]]**
|
||||
* 확장 방향: AOP가 인터셉터나 관점(Aspect)을 애플리케이션 곳곳의 객체에 적용하기 위해서는 객체의 생명주기를 관리하는 제어의 역전(IoC) 및 의존성 주입 컨테이너의 지원이 필수적이므로, IoC/DI 컨테이너의 작동 원리로 학습을 확장한다 [29], [30].
|
||||
* **[[Hexagonal Architecture]]**
|
||||
* 확장 방향: 도메인 로직을 외부 데이터베이스나 UI 인프라로부터 철저히 분리하고 보호한다는 철학이 AOP의 관심사 분리와 일맥상통하므로, 포트와 어댑터(Ports and Adapters) 패턴에서 횡단 관심사가 어떻게 매핑되는지로 개념을 확장한다 [20], [31].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-03*
|
||||
---
|
||||
*Last updated: 2026-05-03*
|
||||
- Raw Source: 00_Raw/2026-05-03/Aspect-Oriented Programming (AOP).md
|
||||
---
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Spring — @Transactional declarative TX
|
||||
```java
|
||||
@Service
|
||||
public class OrderService {
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
@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;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### NestJS — Interceptor (AOP-style)
|
||||
```typescript
|
||||
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
|
||||
import { Observable, tap } from 'rxjs';
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
@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`)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
@Controller('orders')
|
||||
@UseInterceptors(TimingInterceptor)
|
||||
export class OrdersController { /* ... */ }
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]]
|
||||
- 변형: [[Decorator-Pattern]] · [[Proxy-Pattern]] · [[Middleware]]
|
||||
- 응용: [[Spring-Framework]] · [[NestJS]] · [[OpenTelemetry]]
|
||||
- Adjacent: [[Dependency-Injection]] · [[Functional-Composition]] · [[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 |
|
||||
|
||||
@@ -2,95 +2,168 @@
|
||||
id: wiki-2026-0508-automated-refactoring-tools
|
||||
title: Automated Refactoring Tools
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [Refactoring Tools, IDE Refactoring, Codemod Tools]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [uncategorized]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [refactoring, tooling, ast, codemod]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: ts-morph,jscodeshift,comby,ast-grep
|
||||
---
|
||||
|
||||
# [[Automated Refactoring Tools]]
|
||||
# Automated Refactoring Tools
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
자동화된 리팩토링 도구는 소프트웨어의 외부 동작을 보존하면서 내부 구조를 기계적으로 변경해 주는 소프트웨어 유틸리티 및 IDE 기능을 의미합니다 [1, 2]. 과거 스몰토크(Smalltalk)의 리팩토링 브라우저부터 현대의 통합 개발 환경(IDE)에 이르기까지, 이 도구들은 코드 재구성의 속도와 안정성을 높이는 데 기여해 왔습니다 [3, 4]. 최근에는 대형 언어 모델(LLM)을 기반으로 한 AI 도구들이 등장하여 다중 파일 리팩토링 및 단위 테스트 생성을 지원하는 등 그 역할과 능력이 더욱 확장되고 있습니다 [5, 6].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **통합 개발 환경(IDE)의 기본 지원**: IntelliJ IDEA, Eclipse, Visual Studio, PyCharm 등의 현대적 IDE는 변수 이름 변경, 필드 캡슐화, 메서드 추출과 같은 마이크로 리팩토링(Micro-refactorings)을 자동화하여 제공합니다 [4, 7, 8].
|
||||
* **정적 코드 분석기(Static Code Analyzers)**: Codacy, PMD, JArchitect, NDepend, RuboCop 등의 분석 도구들은 코드를 실행하지 않고도 프로그래밍 결함이나 코드 스멜을 식별하여 개발자가 리팩토링할 대상을 쉽게 찾도록 돕습니다 [9].
|
||||
* **AI 기반 리팩토링 도구**: IBM Bob, Amazon CodeGuru Reviewer, GitHub Copilot, Cursor AI, Claude Code 등의 생성형 AI 도구는 방대한 코드베이스의 문맥을 파악하여 실시간으로 리팩토링을 제안하고 실행합니다 [6, 10, 11]. 특히 IBM watsonx Code Assistant와 같은 도구는 COBOL 등의 레거시 애플리케이션 구조를 동적으로 리팩토링하고 현대화하는 데 활용되기도 합니다 [11].
|
||||
* **의존성 및 아키텍처 분석 도구**: 마이크로소프트의 'MaX'와 같은 도구는 함수 및 바이너리 모듈 수준의 의존성을 분석하고 바람직하지 않은 의존성 사이클을 식별하여, 대규모 시스템의 아키텍처 리팩토링 결정을 지원합니다 [12, 13].
|
||||
* **자동화 도구의 기술적 요구사항**: 올바른 리팩토링 도구는 단순한 텍스트 검색이 아닌 구문 분석 트리(Parse Trees)와 의미론적 분석을 통해 프로그램 데이터베이스를 구축해야 합니다 [2, 14, 15]. 또한, 개발자가 안전하게 코드 설계를 탐색할 수 있도록 빠른 실행 속도와 신뢰할 수 있는 '실행 취소(Undo)' 기능을 필수적으로 갖추어야 합니다 [16, 17].
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
* **수동 리팩토링 선호 및 도구의 한계**: 많은 개발자들이 자동화 도구의 존재를 알면서도 리팩토링의 약 86%를 수동으로 처리합니다 [18, 19]. 이는 IDE가 제공하는 리팩토링이 개발자가 의도하는 고차원적인 아키텍처 변경 수준에 미치지 못하는 경우가 많기 때문입니다 [20, 21]. 더불어, 리팩토링 도구 자체에 버그가 존재하거나 에러를 제대로 소통하지 못해 개발자가 도구 사용을 기피하는 경우도 발생합니다 [22, 23].
|
||||
* **AI 도구의 환각 및 검증 부담**: AI를 활용한 리팩토링은 유용하지만, 환각(Hallucination) 현상으로 인해 코드에 새로운 오류를 도입할 위험을 수반합니다 [24, 25]. 따라서 자동화된 테스트 제품군(Test Suite)을 통한 지속적인 검증과 개발자의 꼼꼼한 코드 리뷰(Human-in-the-loop)가 필수적으로 동반되어야 합니다 [24-26].
|
||||
* **AI 생산성 역설(Productivity Paradox)**: 복잡한 레포지토리나 익숙한 코드베이스에서 작업하는 숙련된 시니어 개발자의 경우, 프롬프트를 정교하게 작성하고 AI의 결과물을 검토 및 수정하는 데 드는 인지적 오버헤드 때문에 오히려 작업 속도가 19%까지 저하될 수 있습니다 [27-30]. 또한 AI를 통해 코드 생성과 리팩토링 속도를 높이더라도, 코드 리뷰 단계의 소요 시간이 급증(예: PR 리뷰 시간 91% 증가)하여 결과적으로 프로젝트의 병목 위치만 하류(Downstream)로 이동하는 부작용이 나타날 수 있습니다 [31, 32].
|
||||
### 매 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`).
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-03*
|
||||
### 매 응용
|
||||
1. 매 framework migration (Vue 2 → Vue 3, React class → hook).
|
||||
2. API breaking change 의 fan-out fix.
|
||||
3. Code style 의 mechanical enforcement.
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
## 💻 패턴
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
### ts-morph: rename + add property
|
||||
```typescript
|
||||
import { Project } from "ts-morph";
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
const project = new Project({ tsConfigFilePath: "tsconfig.json" });
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
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()" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
|
||||
- **Parent:** [[10_Wiki/Topics]]
|
||||
- **Related:** *(TODO: 최소 2개)*
|
||||
- **Opposite / Trade-off:** *(TODO)*
|
||||
- **Raw Source:** 직접 입력
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
await project.save();
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### jscodeshift: Vue Options → Composition API
|
||||
```javascript
|
||||
export default function transformer(file, api) {
|
||||
const j = api.jscodeshift;
|
||||
const root = j(file.source);
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
root.find(j.ObjectExpression)
|
||||
.filter(p => p.node.properties.some(pr => pr.key?.name === "data"))
|
||||
.forEach(path => {
|
||||
// emit setup() function with refs
|
||||
// ...
|
||||
});
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
return root.toSource();
|
||||
}
|
||||
```
|
||||
```bash
|
||||
jscodeshift -t vue-comp-api.js src/
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### comby (language-agnostic structural search)
|
||||
```bash
|
||||
comby 'console.log(:[args])' 'logger.debug(:[args])' .ts -i
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]] · [[Abstract-Syntax-Tree-Traversal]]
|
||||
- 변형: [[Codemod]] · [[Structural Search]]
|
||||
- 응용: [[Framework Migration]] · [[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 |
|
||||
|
||||
@@ -2,160 +2,35 @@
|
||||
id: wiki-2026-0508-bim-모델-렌더링
|
||||
title: BIM 모델 렌더링
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
canonical_id: self
|
||||
status: duplicate
|
||||
canonical_id: cad-rendering-optimization
|
||||
duplicate_of: "[[CAD 렌더링 최적화]]"
|
||||
aliases: []
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
confidence_score: 0.85
|
||||
verification_status: redirected
|
||||
tags: [duplicate, bim, cad, rendering, aec]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
---
|
||||
|
||||
# [[BIM 모델 렌더링|BIM 모델 렌더링]]
|
||||
# BIM 모델 렌더링
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> BIM(건축 정보 모델) 및 CAD 모델 렌더링은 수십만 개의 고유하거나 반복되는 기하학적 요소로 이루어진 대규모 건설 데이터를 웹 브라우저 등에서 효율적으로 시각화하는 과정입니다 [1-3]. 이 과정에서는 막대한 드로우 콜([[Draw Call|Draw Call]])과 메모리 대역폭 한계로 인한 성능 저하를 방지하기 위해 형상 병합(Merging), 인스턴싱(Instancing), 배칭(Batching) 등의 기법을 적재적소에 활용해야 합니다 [4-7]. 최근에는 [[WebGPU|WebGPU]]를 도입하여 500MB 이상의 거대 BIM 데이터를 실시간으로 렌더링하고 컴퓨트 셰이더를 통해 무거운 연산을 병렬 처리하는 방식이 대규모 건설 뷰어의 핵심 기술로 부상하고 있습니다 [8-10].
|
||||
> **이 문서는 [[CAD 렌더링 최적화]] 의 specialization 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
---
|
||||
## 핵심 요약 (BIM specialization)
|
||||
- **BIM (Building Information Modeling)**: 매 IFC · Revit · Navisworks 의 native format.
|
||||
- 매 distinguishing aspect: semantic metadata (door · wall · MEP · IfcRelAggregates) 의 carry — 매 pure CAD 의 X.
|
||||
- 매 rendering: same techniques (instancing · LOD · spatial hierarchy) + IFC class 의 group · filter.
|
||||
- **2026 stack**: Three.js + IFC.js · Forge Viewer · Speckle · Unreal Datasmith.
|
||||
- 매 detail · pattern · code 의 [[CAD 렌더링 최적화]] 의 see.
|
||||
|
||||
> BIM(Building Information Modeling) 모델 시뮬레이션은 수십만 개의 개별 부품으로 구성된 건축 및 건설 데이터를 웹 환경 등에서 실시간으로 렌더링하고 상호작용하는 기술입니다 [1, 2]. 이러한 대규모 데이터셋은 CPU와 GPU 간의 병목 현상을 쉽게 유발하므로 성능 유지를 위해 인스턴싱, 지오메트리 병합, 그리고 최신 그래픽스 API의 활용이 필수적입니다 [2, 3]. 최근에는 대형 모델 처리를 위해 [[WebGPU|WebGPU]]의 컴퓨트 셰이더를 활용하여 연산 부하를 획기적으로 낮추는 방법이 도입되고 있습니다 [4, 5].
|
||||
## 🔗 Graph
|
||||
- 부모: [[CAD 렌더링 최적화]] (canonical)
|
||||
- 관련: [[Architecture Diagramming Standards]] · [[3D Rendering Pipeline]] · [[IFC]]
|
||||
|
||||
---
|
||||
|
||||
> 대규모 건축물 및 지형 뷰어(BIM)는 병원 캠퍼스, 공항 터미널, 도시 규모의 디지털 트윈 등 500MB를 초과하는 방대한 규모의 3D 모델을 실시간으로 시각화하는 시스템이다 [1, 2]. 이러한 모델은 보, 기둥, HVAC 시스템과 같이 수십만 개의 개별 구성 요소로 이루어져 있어 막대한 렌더링 부하를 유발한다 [3]. 이를 원활하게 렌더링하고 시각적 상호작용을 지원하기 위해서는 [[WebGPU|WebGPU]], BatchedMesh, 공간 분할 알고리즘 등 드로우 콜([[Draw Call|Draw Call]])을 최소화하고 메모리를 관리하는 고도의 최적화 기술이 필수적으로 요구된다 [3-5].
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **BIM 모델의 구조적 특징과 렌더링 과제:**
|
||||
BIM 또는 CAD 모델은 벽, 바닥, 파이프, 문, 창문 등 수많은 개별 부품(Component)으로 구성되어 있습니다 [1]. 이를 각각 개별적인 메쉬(Mesh)로 렌더링할 경우 CPU에서 GPU로 그리기 명령을 보내는 드로우 콜이 폭증하여 심각한 병목 현상이 발생합니다 [3]. 특히 통합 GPU 환경 등에서는 대용량 정점 데이터를 처리할 때 메모리 대역폭의 한계에 부딪혀 프레임 스터터링이 일어날 수 있습니다 [11, 12].
|
||||
|
||||
- **하이브리드 렌더링 및 최적화 전략 (Fragment 시스템):**
|
||||
건설 데이터의 렌더링 효율을 높이기 위해 IFC.js 프로젝트 등에서는 객체의 특성에 맞춘 하이브리드 방식을 제안합니다 [5, 13]. 벽이나 바닥처럼 폴리곤 수는 적으나 형태가 고유한 객체들은 단일 `[[BufferGeometry|BufferGeometry]]`로 병합(Merging)하여 드로우 콜을 최소화합니다 [5, 14]. 반면, 의자나 문 등 형태가 동일하고 폴리곤이 많은 객체는 메모리 사용량이 적은 `[[InstancedMesh|InstancedMesh]]`를 활용하여 수백, 수천 개의 복제본을 단 한 번의 드로우 콜로 렌더링합니다 [4-6].
|
||||
|
||||
- **BatchedMesh를 활용한 이질적 기하학 처리:**
|
||||
Revit 등에서 추출한 모델 내에서 재질은 같으나 기하학적 형태가 다른 수많은 벽이나 부품들을 렌더링할 때는 `BatchedMesh`가 유용하게 사용됩니다 [6, 15, 16]. 이는 단일 렌더 콜로 거대한 어셈블리를 그리면서도 각 객체의 가시성과 변환 행렬, 색상 등을 개별적으로 쉽게 제어 및 수정할 수 있게 해줍니다 [7, 16].
|
||||
|
||||
- **WebGPU를 통한 대규모 건설 뷰어의 진화:**
|
||||
2026년 기준, 500MB 이상의 거대한 대형 건설 뷰어에서는 성능 한계를 극복하기 위해 WebGPU의 네이티브 기능이 필수적입니다 [8, 9]. WebGPU의 컴퓨트 셰이더([[Compute Shader|Compute Shader]])를 활용하면 대규모 BIM 데이터 세트의 실시간 필터링, 물리 연산, 충돌 감지 등을 GPU에서 병렬로 처리하여 메인 스레드의 부하를 없애고 기존보다 100배 이상의 엄청난 처리 속도 향상을 이끌어낼 수 있습니다 [10, 17, 18].
|
||||
|
||||
- **CAD 데이터 특화 렌더링 최적화 기법:**
|
||||
거대한 좌표계를 가지는 CAD 모델 렌더링 시 32-bit 부동소수점 한계로 인해 모델이 떨리는 정밀도 저하(Precision collapse) 현상을 막기 위해 기하학적 데이터를 GPU에 업로드하기 전 기준점을 중심으로 좌표를 오프셋(Re-centering)하는 작업이 필요합니다 [19]. 또한 내부 구조가 겹겹이 존재하는 복잡한 어셈블리 모델은 오버드로우([[Overdraw|Overdraw]])가 심하므로, 색상 기록 없이 Z-버퍼만 채우는 깊이 사전 패스([[Depth Pre-Pass|Depth Pre-Pass]])를 수동으로 적용하여 프래그먼트 셰이더의 연산 부하를 획기적으로 줄일 수 있습니다 [20, 21].
|
||||
|
||||
---
|
||||
|
||||
* **BIM 데이터의 렌더링 한계**
|
||||
BIM 및 CAD 모델은 벽, 바닥, 파이프, 공조 시스템 등 수천에서 수십만 개의 서로 다른 부품으로 구성되는 경우가 많습니다 [1-3]. 이 때문에 모든 객체가 동일한 기하학적 구조를 공유해야만 하는 **`[[InstancedMesh|InstancedMesh]]` 최적화 기법을 단독으로 적용하는 것은 불가능하거나 매우 비효율적**입니다 [3]. 예를 들어, 건물의 콘크리트 벽면들은 동일한 재질을 공유하지만 고유한 형태와 크기를 가지기 때문입니다 [6].
|
||||
* **하이브리드 및 배치([[Batching|Batching]]) 렌더링 전략**
|
||||
문이나 창문처럼 기하학적 형태가 반복되는 객체는 인스턴싱(`InstancedMesh`)을 사용하고, 고유한 형태를 지닌 벽이나 바닥 같은 객체는 `BatchedMesh`를 사용하여 단일 드로우 콜로 묶어 처리하는 방식이 고려됩니다 [1, 7]. 하지만 1,200만 개 이상의 너무 거대한 폴리곤 데이터를 `BatchedMesh`로 묶을 경우, 버퍼 패킹 과정에서 오히려 CPU 오버헤드가 급증하여 일반적인 메쉬 렌더링보다 프레임이 심각하게 떨어지는 병목 현상이 보고되기도 합니다 [8-11].
|
||||
* **WebGPU와 컴퓨트 셰이더([[Compute Shader|Compute Shader]])의 활용**
|
||||
대규모 BIM 데이터셋의 실시간 필터링, 충돌 감지, 구조 시뮬레이션과 같이 자원 소모가 큰 작업에는 **WebGPU의 컴퓨트 셰이더가 게임 체인저로 활용**됩니다 [4, 5]. 이는 CPU의 메인 스레드를 짓누르던 병목 작업들을 GPU의 수많은 코어에서 병렬로 처리하게 함으로써, 성능을 기존 대비 10배에서 100배까지 향상시킬 수 있습니다 [2, 5].
|
||||
* **프로젝트 규모에 따른 플랫폼 선택 기준**
|
||||
500MB 이하의 표준적인 BIM 뷰어나 모델 구성기(Configurator)를 개발할 때는, 빠르고 풍부한 생태계를 갖춘 **Three.js**를 사용하는 것이 엔지니어링 노력 대비 훌륭한 성능을 제공합니다 [12, 13]. 그러나 모델 용량이 500MB를 초과하는 도시 규모의 디지털 트윈이거나, 실시간 구조 응력 시뮬레이션 같은 극단적인 성능이 요구될 경우에는 직접적인 GPU 메모리 관리와 파이프라인 제어가 가능한 **Native WebGPU** 시스템을 구축하는 것이 필수적입니다 [14, 15].
|
||||
|
||||
---
|
||||
|
||||
- **BIM 모델의 렌더링 병목 현상:** BIM 및 CAD 데이터 모델은 벽, 바닥, 파이프 등 수많은 고유 부품과 객체로 구성되어 있어 이를 개별적으로 렌더링할 경우 드로우 콜 오버헤드로 인해 심각한 CPU 및 GPU 병목이 발생한다 [3, 6, 7]. 특히 콘크리트 벽체처럼 동일한 재질을 공유하되 각기 다른 기하학적 형태를 지닌 객체들은 단일 기하학적 구조만 지원하는 `[[InstancedMesh|InstancedMesh]]`를 그대로 적용하기 어렵다는 구조적 한계가 있다 [4, 8].
|
||||
- **BatchedMesh와 InstancedMesh의 하이브리드 활용:** 고유한 형태를 가진 저폴리곤 객체(벽, 바닥 등)는 `BatchedMesh`나 기하학 병합([[Geometry Merging|Geometry Merging]])을 통해 드로우 콜을 줄이고, 반복되는 고폴리곤 객체(문, 가구, 창문 등)는 `InstancedMesh`로 처리하는 하이브리드 최적화(예: Fragment 시스템) 방식이 대안으로 사용된다 [4, 9, 10]. `BatchedMesh`는 단일 드로우 콜로 여러 다른 기하학적 구조를 렌더링하면서도 개별 객체의 가시성과 색상을 독립적으로 제어할 수 있어 BIM 시각화 요구사항에 부합한다 [4, 11].
|
||||
- **WebGPU 및 컴퓨트 셰이더 도입:** 500MB 이상의 거대한 건축 모델이나 실시간 구조 시뮬레이션을 다룰 때는 자바스크립트의 단일 스레드 한계를 극복할 수 있는 Native WebGPU의 도입이 권장된다 [12-14]. 컴퓨트 셰이더([[Compute Shader|Compute Shader]])를 활용하면 대규모 BIM 데이터셋의 실시간 필터링이나 충돌 감지 연산을 수천 개의 GPU 코어에서 병렬로 처리할 수 있어, 기존 CPU 처리 방식 대비 압도적인 성능 향상을 달성할 수 있다 [15, 16].
|
||||
- **가시성 판별(Culling) 및 메모리 최적화:** 뷰어의 성능을 안정적으로 유지하기 위해 화면에 보이지 않는 객체를 렌더링 파이프라인에서 제외하는 최적화가 필수적이다. CPU 기반의 공간 분할(Octree/BVH) 기술이나, GPU 컴퓨트 셰이더를 활용해 시야 포함 여부와 가림 현상(Occlusion)을 판별하는 GPU 주도 렌더링([[GPU-driven Rendering|GPU-driven Rendering]]) 기법이 적용된다 [5, 17, 18]. 더불어, 메모리 대역폭 한계와 크래시 현상을 극복하기 위해 텍스처 아틀라스를 사용하거나 Web Worker와 `SharedArrayBuffer`를 연계한 제로 카피(Zero-copy) 데이터 디코딩 구조가 활용된다 [19, 20].
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Graphics & Performance 분야의 자동 자산화 수행.
|
||||
|
||||
---
|
||||
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Graphics & Performance 분야의 자동 자산화 수행.
|
||||
|
||||
---
|
||||
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Graphics & Performance 분야의 자동 자산화 수행.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** [[InstancedMesh|InstancedMesh]], BatchedMesh, WebGPU, [[Draw Call|Draw Call]]
|
||||
- **Projects/Contexts:** IFC.js, [[Revit 모델 렌더링|Revit 모델 렌더링]], [[대규모 건설 뷰어(Construction Viewers)|대규모 건설 뷰어(Construction Viewers]]
|
||||
- **Contradictions/Notes:** 다양한 형태의 객체를 단일 드로우 콜로 처리하여 성능을 높이기 위해 `BatchedMesh`를 사용하는 것이 일반적으로 권장되지만, 수백만 개의 정점과 수십만 개의 서브 지오메트리가 있는 거대한 Revit 기반 건축 모델에 이를 그대로 적용할 경우, 내부 버퍼 업데이트와 데이터 복사 등의 오버헤드로 인해 오히려 CPU 사용량이 40~60% 이상 폭증하고 프레임(FPS)이 급락하는 심각한 성능 역전 현상이 보고되기도 하므로 데이터 규모에 따른 주의가 필요합니다 [15, 22-25].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-19*
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** [[WebGPU|WebGPU]], InstancedMesh, BatchedMesh, [[Compute Shader|Compute Shader]]
|
||||
- **Projects/Contexts:** 대규모 건설 뷰어(Large-Scale Construction Viewers)
|
||||
- **Contradictions/Notes:** 다양한 부품이 혼재된 BIM 모델 최적화를 위해 다중 드로우를 하나로 묶는 `BatchedMesh`가 대안으로 제시되지만, 정점 및 면(face)의 수가 1,000만 개 단위를 넘어갈 정도로 너무 큰 경우에는 과도한 버퍼 연산으로 인해 CPU 점유율이 오히려 치솟는 치명적인 성능 저하가 발생한다는 한계가 있습니다 [8, 9, 11].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-19*
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** [[WebGPU|WebGPU]], BatchedMesh, InstancedMesh, Compute Shader, [[Draw Call|Draw Call]], [[Frustum Culling|Frustum Culling]]
|
||||
- **Projects/Contexts:** Three.js, IFC.js, [[Cesium|Cesium]]
|
||||
- **Contradictions/Notes:** 소스에 따르면 `BatchedMesh`는 BIM 모델처럼 다양한 기하학적 객체를 통합하는 데 필수적이라고 평가받지만 [4], 1,000만 개 이상의 정점과 다수의 고유 기하학을 포함하는 환경에서 정렬(Sort) 및 개별 절두체 컬링(perObjectFrustumCulled) 기능을 활성화할 경우, 도리어 단순 병합 메쉬(Merged Mesh)보다 30~50% 더 심각한 CPU 성능 저하를 일으킬 수 있다는 실증적 한계가 보고되고 있습니다 [21-26].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-19*
|
||||
|
||||
---
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
|
||||
+175
-100
@@ -1,128 +1,203 @@
|
||||
---
|
||||
id: wiki-2026-0508-bloc
|
||||
title: BLoC
|
||||
category: Architecture
|
||||
status: needs_review
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [BLoC, Business Logic Component, flutter_bloc]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-wikified, technical-documentation, architecture]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [flutter, state-management, dart, reactive]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: dart
|
||||
framework: flutter,flutter_bloc
|
||||
---
|
||||
|
||||
# BLoC
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
BLoC(Business Logic Component)는 Flutter 생태계에서 프로젝트의 규모에 따라 활용되는 스트림(Stream) 기반의 이벤트 중심 상태 관리 패턴입니다 [1]. 이 패턴은 엄격한 관심사 분리를 요구하여 비즈니스 로직을 분리하는 데 사용됩니다 [1]. 높은 테스트 용이성과 상태 변화에 대한 예측 가능성을 제공하기 때문에, 특히 대규모 엔터프라이즈 프로젝트에서 널리 선호되는 아키텍처 패턴입니다 [1].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 Core 소스에 기반한 Content
|
||||
* **스트림 및 이벤트 중심 아키텍처**: BLoC는 데이터의 흐름을 스트림(Stream)을 기반으로 처리하며, 이벤트 중심(Event-driven) 방식으로 상태 관리를 수행합니다 [1].
|
||||
* **엄격한 관심사 분리**: 애플리케이션 내에서 UI(프레젠테이션) 레이어와 비즈니스 로직 레이어를 엄격하게 분리하도록 강제합니다 [1].
|
||||
* **대규모 엔터프라이즈 환경 최적화**: BLoC 패턴이 강제하는 엄격한 구조적 특징은 코드의 예측 가능성을 높이고 테스트를 매우 용이하게 만듭니다. 이러한 장점 덕분에 복잡도가 높은 대규모 엔터프라이즈 모바일 프로젝트를 설계할 때 가장 적합한 상태 관리 방식으로 평가받고 있습니다 [1].
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
BLoC 패턴은 애플리케이션의 테스트 용이성과 예측 가능성을 극대화하지만, 그 반대급부로 설계 시 '엄격한 관심사 분리'를 반드시 충족해야 하는 제약과 복잡성이 따릅니다 [1]. 상대적으로 배우기 쉽고 유연하여 중소규모 프로젝트에서 높은 생산성을 내는 Provider나 Riverpod 상태 관리 패턴에 비해, 초기 구조를 잡고 유지하는 데 더 높은 학습 곡선과 코딩 비용(보일러플레이트 등)이 요구될 수 있음을 시사합니다 [1]. 그 외 BLoC 패턴의 기술적 부작용이나 최적화 한계에 대해서는 소스에 관련 정보가 부족합니다.
|
||||
### 매 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.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
### 매 component
|
||||
- `BlocProvider` — DI · scope.
|
||||
- `BlocBuilder` — rebuild 의 state change 의 reactive.
|
||||
- `BlocListener` — side-effect (snackbar · navigation).
|
||||
- `BlocConsumer` — builder + listener.
|
||||
- `RepositoryProvider` — data layer DI.
|
||||
|
||||
#### [상태 관리 아키텍처 (State Management Patterns)]
|
||||
- [[Provider & Riverpod]]
|
||||
- 연결 이유: Flutter 생태계에서 BLoC과 경쟁하는 또 다른 주요 상태 관리 패턴들입니다 [1].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: BLoC이 대규모 엔터프라이즈용으로 적합한 반면, Provider와 Riverpod는 중소규모 프로젝트에서 생산성과 유연성을 어떻게 제공하는지 대조적으로 비교하며 적절한 기술 스택을 선정하는 기준을 이해할 수 있습니다 [1].
|
||||
### 매 응용
|
||||
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).
|
||||
|
||||
#### [기반 기술 및 프레임워크 (Foundational Tech & Framework)]
|
||||
- [[스트림(Stream)]]
|
||||
- 연결 이유: BLoC 패턴이 상태와 이벤트를 처리하기 위해 근간으로 삼고 있는 데이터 비동기 흐름 처리 메커니즘입니다 [1].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: BLoC 내부에서 UI 이벤트가 비즈니스 로직으로 전달되고, 변경된 상태가 다시 UI로 방출되는 구조적 원리를 이해할 수 있습니다.
|
||||
- [[Flutter]]
|
||||
- 연결 이유: BLoC이 상태 관리 솔루션으로 활발하게 사용되는 구글의 크로스 플랫폼 모바일 개발 프레임워크입니다 [1, 2].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: Flutter가 지닌 선언적 UI 구조와 BLoC 패턴이 어떻게 결합하여 모바일 생태계의 성능과 개발 생산성을 끌어올리는지 이해할 수 있습니다 [1, 2].
|
||||
## 💻 패턴
|
||||
|
||||
### Deeper Research Questions
|
||||
- BLoC 패턴이 기반으로 하는 스트림(Stream) 처리 방식은 Redux Toolkit이나 Zustand와 같은 타 프레임워크의 상태 관리 메커니즘과 비교할 때 렌더링 성능 최적화 측면에서 어떤 구조적 이점과 단점을 가지는가?
|
||||
- 대규모 엔터프라이즈 애플리케이션에서 BLoC을 활용할 때, 횡단 관심사(예: 에러 핸들링, 로깅)는 BLoC 구조 내에서 어떻게 주입되고 관리되어야 하는가?
|
||||
- 엄격한 관심사 분리로 인해 필연적으로 발생하는 BLoC의 보일러플레이트 코드를 최소화하기 위해 실무에서는 어떤 코드 제너레이션(Code Generation) 도구나 디자인 패턴을 병행하는가?
|
||||
- 최근 부상한 반응형 패턴인 Riverpod와 BLoC 간의 구체적인 아키텍처적 차이는 무엇이며, BLoC에서 Riverpod로 마이그레이션할 때 얻을 수 있는 이득과 손실은 무엇인가?
|
||||
- 이벤트 중심(Event-driven) 상태 관리를 수행하는 BLoC 모델에서 캐싱(Caching) 및 오프라인 데이터 동기화 전략은 어떻게 결합하여 사용되는가?
|
||||
### Bloc (event-driven)
|
||||
```dart
|
||||
sealed class CounterEvent {}
|
||||
class Increment extends CounterEvent {}
|
||||
class Decrement extends CounterEvent {}
|
||||
|
||||
### Practical Application Contexts
|
||||
class CounterBloc extends Bloc<CounterEvent, int> {
|
||||
CounterBloc() : super(0) {
|
||||
on<Increment>((event, emit) => emit(state + 1));
|
||||
on<Decrement>((event, emit) => emit(state - 1));
|
||||
}
|
||||
}
|
||||
|
||||
- **Implementation:** Flutter 앱 개발 시, UI에서 발생한 사용자 이벤트를 스트림 기반으로 수신하고 순수한 비즈니스 로직만을 처리한 후, 새로운 상태를 배출하도록 컴포넌트를 구현하는 데 적용됩니다 [1]. (구체적인 구현 코드나 라이브러리 사용법에 대해서는 소스에 관련 정보가 부족합니다.)
|
||||
- **System Design:** 유지보수와 확장이 필수적인 대규모 엔터프라이즈 모바일 플랫폼의 아키텍처를 설계할 때, UI와 비즈니스 로직의 결합도를 낮추기 위한 표준 패턴으로 도입됩니다 [1].
|
||||
- **Operation / Maintenance:** 상태 변화의 원인이 이벤트로 명확히 분리되고 예측 가능성이 높아지므로, 향후 애플리케이션의 버그 추적이나 기능 변경 시 안정적인 유지보수가 가능해집니다 [1].
|
||||
- **Learning Path:** Flutter를 학습하는 개발자가 기초적인 상태 관리를 넘어 대규모 아키텍처 지식을 강화하고자 할 때 필수적으로 탐구해야 하는 패턴입니다 [2].
|
||||
- **My Project Relevance:** 복잡도 높은 비즈니스 로직과 철저한 단위 테스트가 요구되는 대형 모바일 프로젝트를 기획하거나 설계 중일 때 즉각적으로 도입을 고려해야 하는 아키텍처 설계 기준이 됩니다 [1].
|
||||
|
||||
### Adjacent Topics
|
||||
|
||||
- [[React Native 상태 관리 (Redux Toolkit, Zustand, React Query)]]
|
||||
- 확장 방향: Flutter 생태계의 BLoC 및 Riverpod 패턴과 대조되는 React Native 진영의 상태 관리 패턴(Redux Toolkit, Zustand, TanStack Query 등)을 함께 조사하여, 크로스 플랫폼 프레임워크 전반의 최신 상태 관리 트렌드와 철학적 차이를 폭넓게 이해할 수 있습니다 [1].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-03*
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
|
||||
**추출된 패턴:**
|
||||
> *(TODO)*
|
||||
|
||||
**세부 내용:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
// usage
|
||||
BlocProvider(
|
||||
create: (_) => CounterBloc(),
|
||||
child: BlocBuilder<CounterBloc, int>(
|
||||
builder: (ctx, count) => Text('$count'),
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Cubit (simpler · method-based)
|
||||
```dart
|
||||
class CounterCubit extends Cubit<int> {
|
||||
CounterCubit() : super(0);
|
||||
void increment() => emit(state + 1);
|
||||
void decrement() => emit(state - 1);
|
||||
}
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
// trigger
|
||||
context.read<CounterCubit>().increment();
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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); }
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
class LoginBloc extends Bloc<LoginEvent, LoginState> {
|
||||
final AuthRepository auth;
|
||||
LoginBloc(this.auth) : super(LoginInitial()) {
|
||||
on<SubmitLogin>(_onSubmit);
|
||||
}
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]] · [[Reactive Programming]]
|
||||
- 변형: [[Cubit]] · [[Hydrated Bloc]] · [[ReplayBloc]]
|
||||
- 응용: [[Flutter App Architecture]] · [[Clean Architecture]]
|
||||
- Adjacent: [[Provider]] · [[Riverpod]] · [[GetX]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
+197
-101
@@ -1,128 +1,224 @@
|
||||
---
|
||||
id: wiki-2026-0508-bpm
|
||||
title: BPM
|
||||
title: BPM (Business Process Management)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-0C43BD75]
|
||||
aliases: [Business Process Management, Workflow Automation, Process Orchestration]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [bpm, event-driven-architecture, mediator-topology, bpel, jbpm, architecture-principles]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [enterprise, workflow, bpmn, orchestration]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-02
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: BPMN 2.0 / Java / TypeScript
|
||||
framework: Camunda 8 / Temporal / AWS Step Functions
|
||||
---
|
||||
|
||||
# [[BPM]]
|
||||
# BPM (Business Process Management)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
BPM(Business Process Management) 실행 엔진은 이벤트 기반 아키텍처(Event-Driven Architecture)의 메디에이터 토폴로지(Mediator Topology) 내에서, 주로 인간의 개입이 필요하거나 실행 시간이 긴 복잡한 이벤트 조정 및 오류 처리를 수행하는 데 사용되는 정교한 프로세스 자동화 엔진입니다 [1].
|
||||
## 매 한 줄
|
||||
> **"매 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 중심.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
소스에서 제공하는 BPM에 대한 핵심 내용은 이벤트 기반 아키텍처의 메디에이터(Mediator) 구현 방식과 연관되어 제한적으로 설명되어 있습니다.
|
||||
## 매 핵심
|
||||
|
||||
* **인간의 개입과 장기 실행 프로세스 처리:** 이벤트 조정 및 오류 처리 과정에서 인간의 상호작용(human intervention)이 필요하여 처리 시간이 길어지는(long run times) 경우, BPEL(Business Process Execution Language) 매니저보다 더 고도화된 BPM 실행 엔진을 사용하는 것이 적합합니다 [1].
|
||||
* **고도화된 프로세스 자동화:** BPM 엔진은 다수의 도메인 특화 언어(DSL, Domain Specific Language)를 사용하여 보다 정교한 프로세스 자동화 기능을 제공합니다 [1].
|
||||
* **구현 인프라:** 이러한 BPM 기반의 이벤트 메디에이터 구현을 지원하는 인프라 라이브러리의 대표적인 예시로 jBPM이 활용됩니다 [1].
|
||||
### 매 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.
|
||||
|
||||
*참고: BPM의 세부적인 작동 원리나 구조, 그 외 아키텍처적 특성에 대해서는 소스에 관련 정보가 부족합니다.*
|
||||
### 매 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.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
*소스에 관련 정보가 부족합니다.*
|
||||
### 매 응용
|
||||
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).
|
||||
|
||||
(다만 소스 내용을 통해 추론할 때, 단순한 프로그래밍 기반 메디에이터나 BPEL로는 처리하기 어려운 '인간의 개입' 및 '긴 실행 시간'을 다루기 위해 더 정교한(sophisticated) 다중 DSL 기반의 엔진이 필요하다는 제약에서 BPM이 도입됨을 알 수 있습니다 [1]. 구체적인 단점이나 부작용에 대한 언급은 소스에 포함되어 있지 않습니다.)
|
||||
## 💻 패턴
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
#### [아키텍처/기반 기술]
|
||||
- [[Event-Driven Architecture]]
|
||||
- 연결 이유: BPM 엔진은 이벤트 기반 아키텍처 생태계 내에서 복잡한 비즈니스 프로세스와 이벤트의 흐름을 통제하는 목적으로 활용되기 때문입니다 [1-3].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: BPM이 비동기 통신 환경에서 이벤트를 어떻게 소비하고 후속 처리를 트리거하는지에 대한 구조적 배경을 이해할 수 있습니다.
|
||||
### Camunda 8 — BPMN service task (Zeebe)
|
||||
```typescript
|
||||
import { ZBClient } from 'zeebe-node';
|
||||
|
||||
- [[Mediator Topology]]
|
||||
- 연결 이유: BPM은 이벤트 흐름을 중앙에서 통제하고 에러 처리를 담당하는 이벤트 메디에이터(Event Mediator)의 한 구현 형태로 사용됩니다 [1, 3].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 중앙 집중식 이벤트 조정, 프로세스 상태 유지(State management), 그리고 복잡한 로직 처리 방법을 깊이 있게 학습할 수 있습니다.
|
||||
const zbc = new ZBClient();
|
||||
|
||||
#### [구현/활용 도구]
|
||||
- [[BPEL]]
|
||||
- 연결 이유: BPEL 역시 복잡한 이벤트 메디에이터를 선언적으로 구현하는 데 사용되지만, 인간의 개입이 필요한 장기 실행 프로세스에서는 BPM이 더 적합하다는 점에서 직접적인 비교 대상이 됩니다 [1].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 이벤트 처리 자동화를 위한 언어적 접근법과 복잡도에 따른 도구 선택 기준을 비교할 수 있습니다.
|
||||
|
||||
- [[jBPM]]
|
||||
- 연결 이유: 소스에서 명시적으로 언급된 BPM 이벤트 메디에이터 구현을 위한 인프라 라이브러리입니다 [1].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 이론적인 BPM 개념이 실제 시스템 설계 및 코드 레벨에서 어떻게 인프라로 통합되는지 확인할 수 있습니다.
|
||||
|
||||
### Deeper Research Questions
|
||||
- 이벤트 기반 아키텍처의 메디에이터 토폴로지에서 BPEL을 사용하는 것과 BPM 실행 엔진을 사용하는 것을 결정하는 정확한 복잡도 임계점(Threshold)은 무엇인가?
|
||||
- 인간의 개입이 필요한 장기 실행 프로세스(long run times)에서 BPM 엔진은 시스템 장애 시 상태(State) 손실을 막기 위해 어떠한 복구 및 저장 메커니즘을 사용하는가?
|
||||
- 다수의 DSL(Domain Specific Language)을 활용하는 BPM 엔진의 특성이 시스템 개발 및 유지보수 학습 곡선(Learning Curve)에 미치는 영향은 무엇인가?
|
||||
- 고도로 분산된 마이크로서비스 아키텍처 환경에서 중앙 집중형 구조인 BPM 기반 메디에이터를 도입할 때 발생할 수 있는 병목 현상(Bottleneck)과 해결책은 무엇인가?
|
||||
- jBPM과 같은 BPM 라이브러리를 이벤트 브로커(Event Broker) 패턴과 혼합한 하이브리드 아키텍처에서 사용할 때 이벤트 통신 지연(Latency)은 어떻게 관리되는가?
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 비즈니스 요구사항 중 인간의 승인 절차(결재 등)가 포함되어 즉각적인 처리가 불가능한 워크플로우를 구현할 때, jBPM과 같은 라이브러리를 인프라로 도입하여 이벤트를 제어합니다 [1].
|
||||
- **System Design:** 단순 라우팅 이상의 복잡한 조건 분기 및 프로세스 오케스트레이션이 필요한 이벤트 스트림이 있을 경우, 시스템 설계 시 중앙 통제 역할을 하는 BPM Event Mediator를 배치합니다 [1, 4].
|
||||
- **Operation / Maintenance:** *소스에 관련 정보가 부족합니다.*
|
||||
- **Learning Path:** 이벤트 기반 아키텍처의 기본 원리 학습 -> 메디에이터 및 브로커 토폴로지 비교 -> 프로세스 조정을 위한 BPEL 학습 -> 더 정교한 상호작용 처리를 위한 BPM 실행 엔진(jBPM) 순으로 시스템 설계 지식을 확장합니다.
|
||||
- **My Project Relevance:** 복잡한 비즈니스 로직과 수동 검토 과정이 얽혀 있는 이벤트 파이프라인을 설계할 때, 시스템의 프로세스 상태 추적과 처리를 자동화하기 위한 핵심 기술로 BPM 도입을 검토할 수 있습니다.
|
||||
|
||||
### Adjacent Topics
|
||||
- [[Microservices Architecture]]
|
||||
- 확장 방향: MSA 환경에서는 각 서비스가 독립적인 데이터베이스를 가지므로(분산 시스템), 여러 마이크로서비스에 걸친 복잡한 비즈니스 트랜잭션을 조정할 때 BPM과 같은 오케스트레이터(Orchestrator)가 어떻게 활용될 수 있는지 탐구할 수 있습니다.
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
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}`);
|
||||
}
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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>
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Temporal — code-first workflow
|
||||
```typescript
|
||||
import { proxyActivities, sleep } from '@temporalio/workflow';
|
||||
import * as activities from './activities';
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
const { validateOrder, chargeCard, shipOrder } =
|
||||
proxyActivities<typeof activities>({
|
||||
startToCloseTimeout: '1 minute',
|
||||
retry: { maximumAttempts: 5 },
|
||||
});
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
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);
|
||||
}
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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 }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]]
|
||||
- 변형: [[Saga-Pattern]] · [[Process-Mining]] · [[State-Machine]]
|
||||
- 응용: [[Camunda]] · [[Temporal]] · [[AWS-Step-Functions]] · [[Order-Management]]
|
||||
- Adjacent: [[Microservices]] · [[Event-Driven-Architecture]] · [[Choreography-vs-Orchestration]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -2,147 +2,219 @@
|
||||
id: wiki-2026-0508-base-layouts
|
||||
title: Base Layouts
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [layout-primitives, app-shell, holy-grail-layout]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [layout, css, ui, responsive, shell]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: tsx
|
||||
framework: tailwind
|
||||
---
|
||||
|
||||
# [[Base Layouts|Base Layouts]]
|
||||
# Base Layouts
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
War Commander에서 Base Layouts은 사령부(Command Center), 자원 저장소, 발전소와 같은 핵심 인프라를 보호하기 위해 건물, 포탑, 장벽, 방어 유닛을 전략적으로 배치하는 것을 의미합니다 [1-3]. 이는 공격자가 겹치는 화망과 함정 구역을 통과하도록 강제하는 기하학적 억지력(Geometric Deterrence)으로 작용합니다 [3]. 궁극적인 목표는 공격자의 전략에 지속적으로 적응하고 전술을 수정하여 80% 이상의 방어 성공률을 유지하는 것입니다 [1].
|
||||
## 매 한 줄
|
||||
> **"매 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 의 만들었다.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
기지 레이아웃은 게임 내에서 자원을 보호하고 적의 공격을 방어하기 위해 건물을 기하학적으로 배치하는 끊임없이 변화하는 퍼즐입니다 [1, 2]. 효과적인 기지 설계는 방어 구조물과 포탑을 활용하여 겹치는 사격망(kill zones)을 만들고, 명령 센터와 같은 핵심 인프라를 보호하는 데 중점을 둡니다 [2, 3]. 플레이어는 방어 성공률을 높이고 적의 다양한 메타에 대응하기 위해 스퀘어 베이스나 블리츠 베이스 등 특정 전술 철학이 담긴 레이아웃을 구성하게 됩니다 [4, 5].
|
||||
### 매 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.
|
||||
|
||||
War Commander에서 기지 방어 레이아웃은 적의 공격으로부터 자원, 지휘 본부(Command Center), 발전소를 보호하기 위해 방어 건물과 유닛을 전략적으로 배치하는 끊임없이 변화하는 퍼즐이다 [1-3]. 성공적인 방어는 공격자가 여러 킬존(Kill zones)을 통과하도록 유도하여 방어 효율을 극대화하는 형태적 계층화(Geometric layering)에 기반한다 [3]. 목표는 기지 방어율을 80% 이상으로 유지하는 것이며, 리플레이를 통해 적의 접근 경로를 파악하여 레이아웃을 지속적으로 개선해야 한다 [1, 4].
|
||||
### 매 응용
|
||||
1. Admin dashboard.
|
||||
2. Editor (VS Code-style).
|
||||
3. Marketing landing.
|
||||
4. Mobile app shell — 매 bottom nav.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **핵심 원칙 및 주요 구조물 보호:** 효율적인 기지 설계는 형태보다 기능을 우선시합니다. 사령부, 자원 저장 시설, 발전소는 기지 중앙에 배치하고, 그 주위를 덜 중요한 건물과 방어선으로 둘러싸야 합니다 [2, 3]. 특히 전력이 부족하면 포탑의 발사 속도가 느려지고 자원 생산이 감소하므로 발전소를 장벽과 포탑으로 철저히 보호하는 것이 필수적입니다 [4, 5]. 또한, 군수 공장(War Factory), 헬기장(Helipad), 병영(Barracks)과 같은 방어 시설 역시 방어 유닛을 원활히 전개할 수 있도록 보호되어야 합니다 [6].
|
||||
* **포탑 및 장애물 배치:** 포탑은 방어 건물을 보호하고 겹치는 화망을 구성하도록 배치해야 합니다 [3, 7]. 장벽(Walls)은 적의 접근 경로를 차단하고 썬더볼트(Thunderbolt)와 같은 항공기의 공격을 대신 흡수하여 포탑을 보호하며, 적 지상군을 지뢰(Land mines)가 매설된 좁은 구역으로 몰아넣는 역할을 합니다 [5, 7, 8].
|
||||
* **고급 기지 설계(Advanced Base Designs):**
|
||||
* **Square Base (사각 기지):** 코어 주변에 포탑을 "기관총-박격포-기관총-박격포(Gun-Mortar-Gun-Mortar)" 패턴으로 교차 배치하는 보편적인 디자인입니다 [9, 10]. 공격자가 사각지대를 파악하거나 우회하기 어렵지만, 체력이 높은 탱킹 유닛(예: Behemoth)의 진입에는 취약할 수 있습니다 [9, 10].
|
||||
* **Blitz Base (블리츠 기지):** 유인(Baiting) 전술에 대항하기 위한 설계입니다. 대공 보병(Heavy Gunners/Stingers)이 탑재된 감시탑(Watch Towers)을 대칭으로 배치하여 사전 공중 공격을 차단하고, 장거리 공성 전차를 막기 위해 박격포 팀과 저격수를 배치한 요새(Stronghold)를 활용합니다 [11, 12].
|
||||
* **Square (Mortars only):** 포탑은 100% 대지상용(박격포)으로, 방어 유닛은 100% 대공용으로 구성하여 적의 중전차 유인 전술을 무력화합니다 [13]. 그러나 광역 피해를 주는 적 항공기(Raptors, Havoks 등) 조합에는 매우 취약하다는 단점이 있습니다 [13].
|
||||
* **전술적 기만 및 방어 응용:** 방어자는 일부러 약해 보이는 지점(Honey Pot)을 만들어 공격자를 유인한 뒤, 해당 경로에 밀집된 지뢰밭으로 유도해 심각한 피해를 줄 수 있습니다 [14]. 또한, 사령부처럼 높이가 높은 건물이나 버려진 건물 뒤에 자살 폭탄병(Suicide Bombers)이나 헤라클레스(Hercules) 같은 유닛을 시각적으로 숨겨 적을 기습하는 것도 효과적입니다 [14, 15]. 헬파이어(Hellfire) 전차의 장거리 공성을 막기 위해서는 더 사거리가 긴 포탑이나 최고 레벨의 벙커 저격수를 전방에 배치합니다 [16].
|
||||
* **기지 확장(Base Expansion):** 수십억 단위의 자원을 저장하고 점점 복잡해지는 방어망을 구축하기 위해, 플레이어는 사령부의 "Expand Borders(국경 확장)" 업그레이드를 사용하여 기지의 건설 가능 영역을 최대 7번(회당 8%씩) 확장할 수 있습니다 [17-19].
|
||||
## 💻 패턴
|
||||
|
||||
---
|
||||
### 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; }
|
||||
|
||||
**기본 원칙과 기능성**
|
||||
* 기지 방어는 플레이어가 얼마나 많은 금속을 지켜낼 수 있는가와 직결되며, 일반적으로 방어율을 80% 이상으로 유지하는 것을 목표로 합니다 [1].
|
||||
* 기지 레이아웃은 형태보다 기능성이 훨씬 중요합니다 [3]. 명령 센터([[Command Center|Command Center]]), 자원 저장소, 발전소(Power Plants) 등 가장 중요한 건물들을 기지 중앙에 배치하고, 비교적 덜 중요한 건물들로 그 주위를 방어막처럼 둘러싸야 합니다 [3, 6].
|
||||
* 방어 건물이 내부의 방어 유닛을 원활하게 전장으로 내보낼 수 있도록 설계하는 것이 필수적이며, 이를 위해 War Factory, Helicopter pad, Barracks 중 2개 이상을 중점적으로 보호하는 것이 권장됩니다 [7].
|
||||
|
||||
**주요 기지 레이아웃 유형**
|
||||
* **스퀘어 베이스 (Square Base):** 가장 보편적이고 효과적인 설계로, 총기(Gun) 포탑과 박격포(Mortar)를 기지 중심부 주변에 번갈아가며(Gun-Mortar-Gun-Mortar 패턴) 배치하는 방식입니다 [4, 8]. 이는 우회하거나 약점을 정찰하기 어려운 균일한 방어망을 생성합니다 [4]. 모든 포탑을 대지상용(Mortar)으로만 구성하고 방어 유닛을 대공용으로 채우는 변형 형태도 존재합니다 [9].
|
||||
* **블리츠 베이스 (Blitz Base):** 적의 유인([[Baiting|Baiting]]) 전술을 방지하기 위한 특수 레이아웃입니다 [5, 10]. 중요한 건물을 중앙에 두고, 공중 공격을 차단하기 위해 감시탑(Watch Towers)을 대칭으로 배치합니다 [5, 10]. 또한, 적의 장거리 헬파이어(Hellfires) 전차 공격을 저지하기 위해 감시탑 남쪽에 요새(Stronghold)를 배치하고 스나이퍼와 박격포 팀을 주둔시킵니다 [5, 10].
|
||||
* **원형 방어선 (Circle Perimeter):** 중요한 건물 주위를 둥글게 감싸는 형태로, 적에게 명확한 공격 지점을 노출하지 않아 혼란을 주는 방어선 구축 방식입니다 [11].
|
||||
|
||||
**함정 및 지형지물 활용 전술**
|
||||
* 포탑으로 주요 방어 건물을 감싼 뒤에는 장벽(Walls)과 지뢰(Mines)를 활용해 적의 접근 경로를 차단해야 합니다 [12]. 장벽은 적을 좁은 공간으로 몰아넣어 지뢰나 방어 유닛으로 제압할 수 있게 돕고, 썬더볼트(Thunderbolt)나 랩터(Raptor) 같은 공중 유닛의 공격으로부터 데미지를 대신 흡수해 포탑을 보호하기도 합니다 [6, 12].
|
||||
* **허니팟(Honeypot) 전술:** 일부러 약해 보이는 방어 지점(예: 외곽으로 뺀 포탑)을 만들어 적을 유인한 뒤, 해당 구역에 지뢰를 집중적으로 배치하여 접근하는 적의 전차 부대를 궤멸시키는 고도의 기만전술입니다 [11].
|
||||
* 명령 센터처럼 높이가 높은 건물이나 버려진 건물 뒤의 사각지대에 헤라클레스(Hercules)나 자살 폭탄 트럭 같은 유닛을 숨겨두어 방심하고 접근하는 적을 기습하는 전략도 매우 유용합니다 [11, 13].
|
||||
|
||||
---
|
||||
|
||||
* **핵심 방어 건물 보호:** 효율적인 방어를 위해서는 지휘 본부, 자원 저장소, 발전소를 기지 중앙에 배치하고 덜 중요한 건물들로 그 주위를 둘러싸는 기능 중심의 배치가 중요하다 [2, 3].
|
||||
* **유닛 생산 시설과의 연계:** 기지 레이아웃은 전쟁 공장(War Factory), 헬리패드(Helicopter pad), 병영(Barracks)과 같은 방어 유닛 생산 건물을 보호하는 데 초점을 맞춰야 한다 [4]. 터렛이 대공 방어에 집중되어 있다면 대지 유닛을 주로 생산하는 전쟁 공장과 헬리패드를 더 강력하게 보호해야 하며, 반대로 병영에는 현재 기지에 부족한 방어 속성(대공 또는 대지)을 보완하는 유닛을 배치해야 한다 [5, 6].
|
||||
* **장벽과 지뢰의 전략적 활용:** 장벽은 지상 사격을 차단하고 적의 접근 경로를 좁은 공간으로 강제하여, 적을 지뢰와 다른 방어 유닛의 함정으로 유도하는 데 사용된다 [7, 8]. 장벽은 Thunderbolt나 Raptor와 같은 공중 유닛의 공격 방향에 배치하여 터렛을 보호하는 방패 역할을 하기도 한다 [7]. 또한 고급 플레이어는 의도적으로 취약해 보이는 지점을 만들어 적을 유인하고, 그곳에 지뢰를 집중 배치하는 '허니팟(Honey Pot)' 전략을 사용할 수 있다 [9].
|
||||
* **주요 레이아웃 전략 (Base Layout Philosophies):**
|
||||
* **사각 기지 (Square Base):** 기지 코어 주변에 기관총(Gun) 터렛과 박격포(Mortar) 터렛을 교대로 배치하여 균일한 방어망을 구축하는 범용적인 디자인이다 [10, 11]. 우회하기 어렵지만, 체력이 높은 유닛의 공격에 방어선이 뚫릴 위험이 있다 [10, 11]. 이를 변형하여 터렛은 박격포만 배치하고 공중 방어는 유닛에 전담시키는 방식도 존재한다 [12].
|
||||
* **블리츠 기지 (Blitz Base):** 적의 유인(Baiting) 전술을 방지하기 위해 고안된 특수 형태이다 [13, 14]. 중앙에 중요 건물을 두고 대공 유닛(Heavy Gunners 또는 Stingers)이 배치된 감시탑(Watch Tower)을 대칭으로 배치하여 적의 공중 선제공격을 차단한다 [13, 14]. 장거리 공성 유닛을 저지하기 위해 박격포를 외곽에, 기관총을 그 뒤에 배치한다 [13, 14].
|
||||
* **원형 기지 (Circle Perimeter) 및 은폐:** 핵심 건물 주위를 원형으로 둘러싸면 적의 명확한 공격 지점을 모호하게 만들 수 있다 [9]. 또한, 높이가 높은 지휘 본부나 버려진 건물 뒤에 방어 유닛(예: 자폭 폭격기, 탱크 등)을 숨겨두면 적이 접근할 때 기습적인 피해를 줄 수 있다 [9].
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- 신규 지식 자산화 (2026-04-27).
|
||||
- War Commander 전투 생태계 데이터 통합.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** Defensive Grid, Turrets, [[Baiting Tactics|Baiting Tactics]], [[Command Center|Command Center]]
|
||||
- **Projects/Contexts:** War Commander Base Defense Strategy, Geometric Deterrence
|
||||
- **Contradictions/Notes:** 소스에 따르면 모든 공격을 방어할 수 있는 마법 같은 단일 레이아웃 공식은 존재하지 않으며, 방어자는 리플레이를 관찰하고 공격자와의 끊임없는 메타(Meta) 싸움에 맞춰 기지 레이아웃을 퍼즐처럼 지속해서 변화시켜야 한다고 강조합니다 [1, 6].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-27*
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** 방어 건물(Defense Buildings), [[유인 전술(Baiting)|유인 전술(Baiting]], 전투 시스템(CombatSystem)
|
||||
- **Projects/Contexts:** War Commander Combat Ecosystem
|
||||
- **Contradictions/Notes:** 스퀘어 베이스(Square Base)는 방어에 탁월한 보편적 설계지만, 베히모스(Behemoth)나 진보된 전차같이 체력이 매우 높고 폭발 저항력을 갖춘 유닛을 대동한 공격에는 쉽게 무너질 수 있다는 치명적인 약점이 있습니다 [4, 8]. 반대로 대다수의 플레이어가 선호하지 않는 블리츠 베이스는 장기적인 유인 공격 및 혼합 유닛 공격을 방어하는 데 훨씬 뛰어난 성능을 보입니다 [10].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-27*
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** 방어 건물(Defense Buildings), [[유인 전술(Baiting)|유인 전술(Baiting)]]
|
||||
- **Projects/Contexts:** War Commander 전투 생태계의 구조적 역학(Structural Dynamics of Combat Ecosystem)
|
||||
- **Contradictions/Notes:** 사각 기지(Square Base) 디자인은 정찰과 우회가 불가능에 가까운 튼튼하고 균일한 방어선으로 평가되지만, 베히모스(Behemoth)와 같이 체력이 매우 높아 피해를 흡수할 수 있는 '탱킹' 유닛이나 장거리 공성 전차(Hellfire Tanks)의 집중 포화에는 치명적으로 뚫릴 수 있는 취약점이 있다 [10, 11].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-27*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
@media (max-width: 768px) {
|
||||
.app {
|
||||
grid-template:
|
||||
"header" auto
|
||||
"nav" auto
|
||||
"main" 1fr
|
||||
"aside" auto
|
||||
"footer" auto / 1fr;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Centered (Cover)
|
||||
```css
|
||||
.cover {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
min-height: 100dvh;
|
||||
padding: 1rem;
|
||||
}
|
||||
.cover > * { max-inline-size: 60ch; }
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Split-pane (resizable)
|
||||
```tsx
|
||||
// react-resizable-panels (2025 default)
|
||||
import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
<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>
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### Auto-fit dashboard grid
|
||||
```css
|
||||
.cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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
|
||||
- 부모: [[CSS]] · [[UI Patterns]]
|
||||
- 변형: [[Holy-Grail-Layout]] · [[App-Shell]]
|
||||
- 응용: [[Dashboard]] · [[Editor-Layout]]
|
||||
- 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 |
|
||||
|
||||
@@ -2,118 +2,181 @@
|
||||
id: wiki-2026-0508-bayesian-inference
|
||||
title: Bayesian Inference
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [Bayesian Inference, Bayesian Statistics, Posterior Inference]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.95
|
||||
verification_status: applied
|
||||
tags: [statistics, ml, probabilistic, mcmc]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: python
|
||||
framework: pymc,numpyro,stan
|
||||
---
|
||||
|
||||
# Bayesian-Inference (베이지안 추론)
|
||||
# Bayesian Inference
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> "믿음은 고정된 것이 아니라 정보에 따라 진화한다." 기존의 배경 지식(Prior)에 새로운 근거(Evidence)를 더해 더 정확한 진실(Posterior)에 다가가는 통계학적 통찰이다.
|
||||
## 매 한 줄
|
||||
> **"매 prior + likelihood = posterior — 매 belief 의 evidence 에 의해 의 update"**. Bayes 1763 의 origin, 20세기 frequentist 의 dominance, 2026 의 NumPyro/PyMC + GPU MCMC + variational inference 의 mainstream — 매 LLM uncertainty quantification 의 backbone.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
베이지안 추론(Bayesian Inference)은 베이즈 정리(Bayes' Theorem)를 바탕으로, 새로운 증거가 수집될 때마다 가설의 확률(신뢰도)을 지속적으로 갱신해 나가는 통계적 추론 방법론입니다 [1, 2]. 이는 지능 시스템이 불확실한 환경에서 점진적으로 학습하고 세계관을 수정해 나가는 핵심 원리입니다 [1].
|
||||
### 매 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).
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **Prior Probability (사전 확률)**:
|
||||
- 새로운 데이터를 보기 전에 우리가 이미 알고 있는 지식이나 가설의 확률.
|
||||
- **Likelihood (우도)**:
|
||||
- 어떤 가설이 참일 때, 현재 관찰된 데이터가 나타날 확률.
|
||||
- **Posterior Probability (사후 확률)**:
|
||||
- 새로운 데이터를 반영한 후 업데이트된 우리의 최종 믿음.
|
||||
- **Application**:
|
||||
- 스팸 메일 필터링, 의료 진단, 자율주행 차의 센서 융합 등 불확실성이 큰 환경의 의사결정에 필수적이다.
|
||||
### 매 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.
|
||||
|
||||
* **베이지안 업데이트 (Bayesian Updating)**
|
||||
- **사전 확률 (Prior)**: 새로운 데이터를 관찰하기 전의 기존 신뢰도입니다 [1, 3].
|
||||
- **가능도 (Likelihood)**: 가설이 참일 때 관찰된 데이터가 나타날 확률입니다 [1].
|
||||
- **사후 확률 (Posterior)**: 새로운 증거를 반영하여 업데이트된 최종 신뢰도입니다 [1, 4].
|
||||
- 이 과정을 통해 시스템은 노이즈 섞인 데이터 하나에 일희일비하지 않고 전체적인 추세에 따라 점진적으로 지식을 수정합니다 [1, 5].
|
||||
## 💻 패턴
|
||||
|
||||
* **지능 시스템에서의 활용**
|
||||
- **능동적 학습 (Active Learning)**: 어떤 데이터가 사후 확률을 가장 크게 변화시킬지 판단하여 효율적으로 학습 대상을 선택합니다 [1].
|
||||
- **베이지안 뇌 가설 (Bayesian Brain Hypothesis)**: 인간의 뇌가 감각 정보를 능동적으로 처리하고 확률 분포를 통해 미래를 예측한다는 이론으로, 현대 AI 상황 판단 모듈 설계의 모티브가 됩니다 [1, 6].
|
||||
### 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
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- 베이지안 추론은 '사전 확률'을 설정할 때 주관이 개입된다는 비판을 받기도 한다(빈도주의 통계학과의 논쟁). 하지만 데이터가 적은 초기 상태에서는 베이지만큼 강력한 예측 도구가 없다.
|
||||
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)
|
||||
|
||||
---
|
||||
|
||||
- **사전 확률의 주관성**: 초기 설정한 사전 확률(Prior)에 따라 결과가 달라질 수 있다는 비판이 있으나, 충분한 데이터가 쌓이면 사후 확률은 데이터의 본질에 수렴하게 됩니다 [1, 7].
|
||||
- **연산 복잡도**: 복잡한 모델에서 베이지안 적분을 직접 계산하는 것은 매우 어렵기 때문에, MCMC(Markov Chain Monte Carlo)나 변분 추론(Variational Inference)과 같은 근사 기법이 널리 사용됩니다 [1].
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- Related: [[Automated-Reasoning|Automated-Reasoning]] , [[Behavioral-Economics|Behavioral-Economics]]
|
||||
- Foundation: Computational Theory & Math/Information Theory
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics**: 베이즈 정리 (Bayes' Theorem, 확률론 (Probability Theory), 능동적 학습 (Active Learning), 예측 코딩 (Predictive Coding
|
||||
- **Projects/Contexts**: Antigravity 상황 판단 엔진, 초개인화 추천 알고리즘
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-30*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
mcmc = MCMC(NUTS(model), num_warmup=1000, num_samples=2000, num_chains=4)
|
||||
mcmc.run(random.PRNGKey(0), X, y)
|
||||
mcmc.print_summary()
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### PyMC: Bayesian A/B test (Beta-Bernoulli)
|
||||
```python
|
||||
import pymc as pm
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
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)
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
prob_b_better = (idata.posterior["lift"] > 0).mean().item()
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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)
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### Variational inference (SVI)
|
||||
```python
|
||||
from numpyro.infer import SVI, Trace_ELBO
|
||||
from numpyro.infer.autoguide import AutoNormal
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
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]] · [[Empirical Bayes]]
|
||||
- 응용: [[Belief-System]] · [[Bayesian A/B Test]] · [[Bayesian Neural Network]]
|
||||
- Adjacent: [[Frequentist Inference]] · [[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 |
|
||||
|
||||
@@ -2,173 +2,164 @@
|
||||
id: wiki-2026-0508-beat-saber
|
||||
title: Beat Saber
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [Beat Saber, VR Rhythm Game]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.85
|
||||
verification_status: applied
|
||||
tags: [vr, game-architecture, rhythm-game, unity, ecs]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: csharp
|
||||
framework: unity,unity-dots,openxr
|
||||
---
|
||||
|
||||
# [[Beat Saber|Beat Saber]]
|
||||
# Beat Saber
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> 'Beat Saber'는 모션 트래킹 기술을 활용해 플레이어가 가상현실 속에서 광선검을 휘둘러 리듬에 맞춰 표적을 베고 장애물을 피하는 인기 VR 리듬 엑서게임(Exergame)입니다 [1]. 전 세계적으로 200만 장 이상 판매된 성공적인 상업 게임으로, 햅틱 및 시청각 피드백을 통해 높은 몰입감을 제공합니다 [1, 2]. 실제 테니스와 맞먹는 에너지 소모량을 바탕으로 신체 활동을 돕는 유용한 도구로 인정받고 있으며, VR 멀미([[VR Sickness|VR Sickness]]) 및 몰입 상태([[Flow State|Flow State]])를 분석하는 학술 연구에서도 널리 활용되고 있습니다 [2, 3].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
> 비트 세이버(Beat Saber) 실험은 널리 알려진 가상현실(VR) 엑서게임(exergame)인 '비트 세이버'를 활용하여 VR 노출 시간이 사용자의 시각, 인지 및 사이버스멀미([[VR Sickness|VR Sickness]])에 미치는 후유증을 조사한 연구입니다 [1]. 36명의 참가자를 대상으로 10분(단기) 및 50분(장기) 동안 게임을 플레이하게 한 후, VR 사용 전, 직후, 그리고 40분 후의 상태 변화를 측정했습니다 [1]. 이 실험은 VR 엑서게임의 잠재적 이점을 고려할 때 지속적인 사용을 제한하는 부작용을 식별하고 안전한 사용 환경을 이해하는 데 중점을 두었습니다 [1].
|
||||
### 매 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.
|
||||
|
||||
> 이 연구는 전 세계적으로 인기 있는 가상현실(VR) 엑서게임인 '비트 세이버(Beat Saber)'를 플레이한 후 사용자에게 나타나는 시각적, 인지적, 신체적 사후 영향(Aftereffects)을 조사한 결과입니다 [1, 2]. 참가자들이 10분(단기) 및 50분(장기) 동안 게임을 플레이한 후 조절력, 수렴력, 인지 반응 속도, VR 멀미 수준이 어떻게 변화하는지 측정했습니다 [3]. 연구 결과 게임 플레이로 인한 대부분의 부작용은 일시적이었으나, 장시간 플레이할 경우 VR 멀미 증상이 유의미하게 증가하며 일부 사용자는 회복에 긴 시간이 필요한 것으로 나타났습니다 [4].
|
||||
### 매 응용
|
||||
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.
|
||||
|
||||
---
|
||||
## 💻 패턴
|
||||
|
||||
> 비트 세이버(Beat Saber)는 비트 게임즈(Beat Games)에서 개발한 상업용 가상 현실(VR) 리듬 운동 게임(exergame)으로, 전 세계적으로 200만 장 이상 판매된 가장 성공적인 게임 중 하나입니다 [1, 2]. 이 게임은 모션 트래킹 기술을 활용하여 핸드헬드 컨트롤러를 광선검처럼 시뮬레이션하며, 사용자는 음악의 비트에 맞춰 날아오는 목표물을 베고 장애물을 적극적으로 피해야 합니다 [2]. 또한 햅틱, 청각 및 성과 피드백을 결합하여 높은 몰입감을 선사하며, 실제 테니스를 치는 것과 비슷한 수준의 에너지를 소모하게 하는 특징이 있습니다 [1, 2].
|
||||
### 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);
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **게임의 특징과 신체적 효과:** Beat Games에서 개발한 Beat Saber는 플레이어에게 햅틱, 청각, 그리고 성과 기반 피드백을 제공하여 강렬한 몰입감을 선사합니다 [1]. 가상현실 건강 및 운동 연구소(VR Health Institute)에 따르면, 이 게임을 플레이할 때 소모되는 에너지는 실제 테니스를 치는 것과 유사합니다 [2]. 사용자들은 몰입형 환경이 운동의 힘든 강도로부터 주의를 분산시켜 주며, 현실에서의 운동과 비슷한 신체 활동 효과를 얻을 수 있다고 평가합니다 [4].
|
||||
- **VR 사후 효과(Aftereffects) 및 멀미 연구 도구:** 이 게임은 단기(10분) 및 장기(50분) VR 노출이 사용자의 시각, 인지, 웰빙 및 VR 멀미에 미치는 영향을 조사하는 연구의 테스트 베드로 사용되었습니다 [2, 5]. 연구 결과, Beat Saber는 멀미로 인한 중도 포기자가 발생하지 않을 정도로 전반적으로 플레이어들에게 잘 수용되는(well tolerated) 것으로 나타났습니다 [6, 7]. 발생하는 즉각적인 사후 효과 역시 대부분 일시적이었으며 게임 종료 40분 후 기저 수준으로 회복되었으나, 장시간(50분) 플레이한 일부 참가자(약 14%)는 회복 후에도 여전히 높은 수준의 멀미를 경험한 것으로 확인되었습니다 [6, 8].
|
||||
- **몰입(Flow) 상태 유도 및 검증:** Beat Saber는 플레이어의 기술과 과제의 난이도 간의 균형을 맞추기 용이한 통제된 싱글 플레이어 게임이라는 특성이 있습니다 [3]. 이러한 장점 덕분에 e스포츠 및 게임 환경에서 플레이어의 신경 생리학적 몰입 상태(Flow [[State|State]])를 안정적으로 유도하고 측정하기 위한 실험실 기반의 고충실도 검증(high-fidelity validation) 연구 모델에서도 핵심적인 과제로 제안 및 활용됩니다 [3].
|
||||
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;
|
||||
}
|
||||
|
||||
- **실험 목적 및 배경:** 실세계의 테니스와 맞먹는 신체적 활동량을 요구하는 인기 VR 엑서게임 '비트 세이버'를 10분 및 50분 동안 플레이했을 때 사용자의 웰빙, 시각, 인지 측면에 미치는 후유증(aftereffects)을 평가하기 위해 설계되었습니다 [1], [2].
|
||||
- **연구 방법:** HTC Vive Pro HMD를 사용하여 36명의 참가자(남성 21명, 여성 15명)를 대상으로 반복 측정 개체 내 설계(repeated measures within-subject design)를 적용했습니다 [1], [3], [4]. VR 노출 전, 노출 직후, 그리고 노출 종료 40분 후의 세 시점에서 시각적 요인(조절 및 폭주), 인지적 요인(결정 속도, 이동 속도), 시뮬레이터 멀미 설문지(SSQ)를 통한 주관적 멀미 증상을 측정했습니다 [1], [2].
|
||||
- **시각 및 인지 기능 변화:** 단기(10분) 및 장기(50분) 노출 직후 시각의 조절(accommodation) 및 폭주(convergence) 능력에 변화가 관찰되었으나, 40분 후의 후기 검사에서는 모두 기준치(baseline)로 회복되었습니다 [5], [6], [7]. 인지 측정(결정 및 이동 속도)에서는 우려할 만한 저하가 나타나지 않았으며, 오히려 10분 노출 직후에는 이동 속도가 약간 향상되는 양상을 보였습니다 [5], [8].
|
||||
- **사이버스멀미 증상 및 회복:** 멀미로 인한 중도 포기자가 발생하지 않아 비트 세이버는 전반적으로 잘 수용된 것으로 나타났습니다 [5], [9]. SSQ(시뮬레이터 멀미 설문지) 점수는 VR 체험 직후에 상승했고 50분 노출이 10분 노출보다 유의미하게 더 높은 증상을 유발했으나, 그룹 평균적으로는 40분 후에 기준치로 회복되었습니다 [5], [10].
|
||||
- **개인별 멀미 지속 차이:** 그룹의 평균적인 회복세와는 달리, 50분 플레이 후 40분이 지난 시점에서도 참가자의 약 14%는 여전히 높은 수준의 멀미 증상을 보고했습니다 [5], [11]. 또한, 짧은 노출(10분)에서 심한 멀미를 경험한 참가자는 긴 노출(50분)에서도 높은 증상을 겪을 가능성이 매우 큰 것으로 확인되었습니다 [5].
|
||||
|
||||
---
|
||||
|
||||
- **연구 배경 및 목적:** VR 엑서게임은 사용자가 신체적 노력보다 게임의 몰입형 환경에 주의를 돌리게 하여 좌식 행동(sedentary [[Behavior|Behavior]])을 개선하고 운동 동기를 부여하는 강력한 도구입니다 [5, 6]. 비트 세이버의 경우 실제 테니스를 치는 것과 맞먹는 에너지를 소비하는 것으로 알려져 있습니다 [2]. 이 연구는 비트 세이버 플레이가 시력, 인지 기능 및 자기 보고식 VR 멀미([[VR Sickness|VR Sickness]])에 미치는 장단기적 영향을 파악하기 위해 진행되었습니다 [2].
|
||||
- **실험 방법론:** 36명의 참가자를 대상으로 HTC Vive Pro 헤드마운트 디스플레이(HMD)를 사용하여 비트 세이버를 플레이하도록 하였습니다 [7, 8]. 시각적 조절(accommodation) 및 수렴(convergence), 인지적 결정 속도와 이동 속도(CANTAB 반응 시간 테스트), 그리고 시뮬레이터 멀미 설문지(SSQ)를 활용하여 VR 노출 전, 노출 직후, 그리고 노출 40분 후(지연 테스트)의 세 시점에서 데이터를 측정했습니다 [3, 9-12].
|
||||
- **시각 및 인지 기능에 미치는 영향:** VR 노출 직후 안구의 조절력과 수렴력에 뚜렷한 변화가 관찰되었으나, 40분이 지난 후에는 모두 기준치(baseline) 수준으로 회복되었습니다 [4]. 인지 기능인 반응 시간 측정에서는 우려할 만한 저하가 관찰되지 않았으며, 10분 플레이 직후에는 오히려 이동 속도가 소폭 향상되는 현상도 확인되었습니다 [4, 13].
|
||||
- **VR 멀미(VR Sickness) 발생 및 회복:** SSQ를 통해 측정한 멀미 점수는 게임 직후 급격히 상승했으며, 특히 10분 노출보다 50분 노출에서 그 수치가 통계적으로 유의하게 더 높았습니다 [4, 14]. 집단 평균적으로는 40분 대기 후 멀미 수치가 원래대로 돌아왔으나, 50분을 플레이한 참가자의 약 14%는 40분이 지나서도 여전히 높은 수준의 멀미 증상을 호소했습니다 [4, 15].
|
||||
- **안전 권고 사항:** 연구진은 긴 시간 엑서게임에 노출되기 전에 사용자가 짧은 세션을 먼저 시도하여 멀미 민감도를 확인할 것을 권장합니다 [16]. 또한, VR 노출 후에는 자동차 운전과 같이 부상 위험이 따르는 활동을 재개하기 전 최소 40분 이상의 휴식 및 대기 시간을 가져야 한다고 조언합니다 [16].
|
||||
|
||||
---
|
||||
|
||||
- **가상 현실 후유증(VR Aftereffects) 및 멀미 연구**: 비트 세이버는 방대한 사용자 기반을 갖추고 있으며 역동적이고 즐거운 경험을 제공하기 때문에, 장단기 VR 노출이 사용자에게 미치는 후유증을 연구하는 데 강력한 테스트 사례로 사용됩니다 [1, 2]. 실제로 10분 및 50분 동안 비트 세이버를 플레이한 후 시각, 인지, 멀미에 미치는 영향을 분석한 연구에서 멀미로 인한 실험 중도 포기자가 발생하지 않아, 이 게임이 사용자들에게 신체적으로 무리 없이 잘 수용되는(well tolerated) 것으로 나타났습니다 [1, 3, 4].
|
||||
- **신체적 운동 효과 및 상호작용**: 사용자는 자신의 게임 플레이를 주도하여 원하는 곡과 난이도를 자유롭게 선택할 수 있으며, 난이도가 높아질수록 시각적 자극과 요구되는 움직임의 양도 크게 증가합니다 [5]. 가상 현실 건강 및 운동 연구소(VR Health Institute)는 비트 세이버의 에너지 소모량이 실제 테니스와 맞먹는다고 평가하였으며, 이는 주로 앉아서 생활하는 습관(sedentary [[Behavior|Behavior]])을 개선할 수 있는 매력적인 운동 전략으로 간주됩니다 [1, 3].
|
||||
- **몰입 상태([[Flow State|Flow State]])의 안정적 유도**: 비트 세이버는 사용자의 기술 수준에 맞춘 난이도 조절과 명확하고 즉각적인 피드백을 통해 몰입(Flow) 상태를 효과적으로 이끌어냅니다 [2, 6]. 이러한 특성 덕분에 신경생리학적 정밀도를 추구하는 고충실도(high-fidelity) 실험실 연구에서, 과업을 표준화하고 몰입 상태의 신경 및 자율신경계 신호를 안정적으로 유도하기 위한 통제된 단일 플레이어 게임으로 널리 활용되고 있습니다 [6].
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
|
||||
---
|
||||
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
|
||||
---
|
||||
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
|
||||
---
|
||||
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** VR Exergame, [[VR Sickness|VR Sickness]], [[Flow State|Flow State]]
|
||||
- **Projects/Contexts:** 가상현실 노출 사후 효과(VR Aftereffects) 연구, 몰입 상태 예측 프레임워크(Flow State Prediction Framework)
|
||||
- **Contradictions/Notes:** 소스 연구에 따르면 Beat Saber 플레이 후의 사후 효과(멀미 등)는 전반적으로 일시적이며 40분 내에 기저 수준으로 회복되어 멀미로 인한 실험 탈락자가 없었지만 [6, 7], 장시간(50분) 노출될 경우 특정 사용자 집단(약 14%)에서는 게임 종료 40분 후에도 여전히 높은 수준의 멀미가 유지되는 등 개인의 민감도와 노출 시간에 따라 상이한 결과가 나타납니다 [6, 8].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-19*
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** 사이버스멀미(VR Sickness), [[엑서게임(Exergaming)|엑서게임(Exergaming]], [[시뮬레이터 멀미 설문지(SSQ)|시뮬레이터 멀미 설문지(SSQ]]
|
||||
- **Projects/Contexts:** 가상현실 엑서게임 후유증 조사(Investigation of Virtual Reality Aftereffects)
|
||||
- **Contradictions/Notes:** 연구 결과에서 그룹 평균적으로는 50분간의 VR 노출 후 40분이 지나면 멀미 증상이 기준치로 돌아온다고 보고하지만, 개별 참가자 데이터를 분석하면 약 14%의 인원은 40분 후에도 여전히 높은 수준의 멀미를 경험한다는 점에서 그룹 평균과 개인별 회복 양상 간에 뚜렷한 차이가 존재함을 지적합니다 [5], [10], [11].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-19*
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** [[VR 멀미 (VR Sickness)|VR 멀미(VR Sickness]], 엑서게임(Exergaming), [[시뮬레이터 멀미 설문지(SSQ)|시뮬레이터 멀미 설문지(SSQ]]
|
||||
- **Projects/Contexts:** 비트 세이버(Beat Saber) VR 사후 영향 조사 연구
|
||||
- **Contradictions/Notes:** 연구 결과에서 엑서게임 직후의 멀미 증상은 그룹 평균치로 보았을 때 40분 이내에 완전히 회복되는 것으로 나타났으나, 개인차를 고려할 때 50분 장기 플레이를 한 참가자의 약 14%는 40분 후에도 회복되지 않은 높은 수준의 증상을 보인다는 점을 유의해야 합니다 [15].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-19*
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** 운동 게임(Exergame), 몰입 상태(Flow [[State|State]]), 가상 현실 멀미([[VR Sickness|VR Sickness]])
|
||||
- **Projects/Contexts:** 가상 현실 후유증 조사(Investigation of Virtual Reality Aftereffects)
|
||||
- **Contradictions/Notes:** 소스에 관련 정보가 부족합니다.
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-19*
|
||||
|
||||
---
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
ecb.Playback(state.EntityManager);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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;
|
||||
}
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
float speed = saberVelocity.magnitude;
|
||||
float angle = Vector3.Angle(saberVelocity, note.RequiredCutDirection);
|
||||
float accuracy = 1f - Mathf.Clamp01(angle / 60f);
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
result = new CutResult {
|
||||
Score = Mathf.RoundToInt(speed * accuracy * 115f),
|
||||
IsValid = speed > 2f && angle < 60f,
|
||||
};
|
||||
return result.IsValid;
|
||||
}
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### Audio-visual sync (NJS-based)
|
||||
```csharp
|
||||
// Note 의 spawn position 의 calc
|
||||
float jumpDist = njs * (60f / bpm) * halfJumpDuration * 2f;
|
||||
Vector3 spawnPos = playerPosition + Vector3.forward * jumpDist;
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
// Note 의 frame 마다 의 lerp
|
||||
float t = (Time.timeAsDouble - spawnTime) / (hitTime - spawnTime);
|
||||
note.transform.position = Vector3.Lerp(spawnPos, hitPos, (float)t);
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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
|
||||
- 부모: [[Game Architecture]] · [[VR Development]]
|
||||
- 변형: [[Rhythm Game]] · [[Audio-Synced Gameplay]]
|
||||
- 응용: [[bitECS와_SharedArrayBuffer의_실제_코드_통합]] · [[ECS Pattern]]
|
||||
- Adjacent: [[Object Pool]] · [[Frame Budget Optimization]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -2,92 +2,174 @@
|
||||
id: wiki-2026-0508-belief-system
|
||||
title: Belief System
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-Reinforce-AUTO-BESY-001]
|
||||
aliases: [Belief System, Agent Belief, Knowledge Base, BDI Beliefs]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.94
|
||||
tags: [auto-reinforced, belief-system, worldview, culture, Cognitive-Architecture, orientation]
|
||||
confidence_score: 0.85
|
||||
verification_status: applied
|
||||
tags: [agent-architecture, ai, bdi, knowledge-representation]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-04-20
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: python
|
||||
framework: bdi,langchain,owl-rdf
|
||||
---
|
||||
|
||||
# [[Belief-System|Belief-System]]
|
||||
# Belief System
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> "세상을 해석하는 운영체제: 개인이 진실이라고 믿는 수많은 판단과 가치들이 촘촘하게 얽혀 만들어진 거대한 네트워크로, 새로운 정보를 필터링하고 행동의 방향을 결정하는 무의식적 가이드라인."
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
신념 체계(Belief-System)는 한 개인이 세상과 자기 자신에 대해 가지고 있는 확고한 믿음들의 집합체입니다.
|
||||
## 매 핵심
|
||||
|
||||
1. **구조적 특징**:
|
||||
* **Core [[Beliefs|Beliefs]]**: 가장 깊은 곳에 자리 잡은 근본 신념 (수정이 매우 힘듦). ([[Axioms|Axioms]]와 연결)
|
||||
* **[[Support|Support]]ing Beliefs**: 핵심 신념을 지탱하는 지류 신념들.
|
||||
* **Interconnectivity**: 하나의 신념이 바뀌면 연결된 다른 신념들의 가독성도 바뀜 (웹 형태의 조직).
|
||||
2. **기능**:
|
||||
* **Cognitive Economy**: 매 순간 일어나는 일을 처음부터 분석하지 않고 기존 체계에 비추어 빠르게 판단하게 해줌.
|
||||
* **identity**: "나는 어떤 사람인가"를 규정하는 정체성의 토대.
|
||||
### 매 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.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌**: 과거에는 신념 체계를 혈연이나 지역적 종교 정책에 의해 고정된 것으로 보았으나, 현대의 정보 유통 정책은 개인의 취향과 알고리즘 추천에 의해 시시각각 재구성되는 '유동적 신념 체계 정책'으로 이행함(RL Update).
|
||||
- **정책 변화(RL Update)**: 기업 문화 정책 수립 시, 단순히 사훈을 외우게 하는 정책 대신 구성원 각자의 신념 체계가 회사의 비전과 조화를 이루게 하는 '가치 공유 프로세스 기획 정책'이 조직 관리의 핵심이 됨.
|
||||
### 매 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).
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- [[Beliefs|Beliefs]], [[Belief-Revision|Belief-Revision]], [[Axiology|Axiology]], [[Axiomatic-Systems|Axiomatic-Systems]], [[Sociology of Knowledge|Sociology of Knowledge]]
|
||||
- **Modern Tech/Tools**: Psychometric profiling, Cognitive [[Behavior|Behavior]]al therapy frameworks.
|
||||
---
|
||||
### 매 응용
|
||||
1. 매 BDI agent (JADE · Jadex · Jason).
|
||||
2. Robot world model (ROS knowledge_base).
|
||||
3. LLM agent scratchpad (Claude · LangGraph state).
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
## 💻 패턴
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
### BDI-style belief base (Python)
|
||||
```python
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
@dataclass
|
||||
class BeliefBase:
|
||||
facts: dict[str, Any] = field(default_factory=dict)
|
||||
confidence: dict[str, float] = field(default_factory=dict)
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
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
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
def query(self, key: str) -> tuple[Any, float] | None:
|
||||
if key not in self.facts: return None
|
||||
return self.facts[key], self.confidence[key]
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
bb = BeliefBase()
|
||||
bb.add("door_open", True, 0.9)
|
||||
bb.add("battery_pct", 73, 1.0)
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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}
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
Task: {task}
|
||||
Plan your next action and explain reasoning."""
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
# 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
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### Vector belief store (long-term memory)
|
||||
```python
|
||||
import chromadb
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
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]]
|
||||
- 변형: [[BDI]] · [[Bayesian_Inference]]
|
||||
- 응용: [[LLM Agent]] · [[Robot Knowledge Base]]
|
||||
- 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) |
|
||||
|
||||
@@ -2,93 +2,166 @@
|
||||
id: wiki-2026-0508-big-data
|
||||
title: Big Data
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-Reinforce-AUTO-BIGD-001]
|
||||
aliases: [Big Data, Large-Scale Data Processing]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.97
|
||||
tags: [auto-reinforced, big-data, data-science, analytics, scalable-systems, infrastructure]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [data, distributed-systems, analytics, lakehouse]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-04-20
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: python
|
||||
framework: spark,duckdb,iceberg,polars
|
||||
---
|
||||
|
||||
# [[Big-Data|Big-Data]]
|
||||
# Big Data
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> "데이터의 바다, 지능의 양분: 기존의 방식으로는 처리할 수 없을 만큼 거대하고 빠른 데이터 뭉치로부터, 인공지능이 복잡한 패턴을 학습하여 정교한 예측과 자동화를 가능케 한 현대 문명의 원유."
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
빅데이터(Big-Data)는 수신, 저장, 관리, 분석 역량을 넘어서는 대규모 데이터셋을 의미하며, 보통 5V로 정의됩니다.
|
||||
## 매 핵심
|
||||
|
||||
1. **5V Characteristics**:
|
||||
* **Volume**: 압도적인 데이터의 양.
|
||||
* **Velocity**: 실시간으로 생성되고 소멸되는 속도.
|
||||
* **Variety**: 텍스트, 이미지, 로그 등 비정형 데이터의 다양성.
|
||||
* **Veracity**: 데이터의 정확성과 신뢰도 확보의 어려움.
|
||||
* **Value**: 가공을 통해 얻어낼 수 있는 실질적인 가치.
|
||||
2. **분석의 차원**:
|
||||
* **Correlation over Causation**: "왜 발생하는가"보다 "무엇과 무엇이 같이 발생하는가"라는 상관 관계 분석에 우선 집중하여 빠른 비즈니스 의사결정 지원.
|
||||
### 매 5 V
|
||||
- **Volume**: TB-PB scale.
|
||||
- **Velocity**: streaming · near-real-time.
|
||||
- **Variety**: structured + semi + unstructured.
|
||||
- **Veracity**: data quality · trust.
|
||||
- **Value**: ROI of analytics.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌**: 과거에는 무조건 많이 모으는 '데이터 댐' 정책이 유행이었으나, 현대 정책은 쓰레기 데이터 입력 시 쓰레기 결과가 나온다는(GIGO) 교훈 하에 '데이터 품질(Data-centric AI) 관리 정책'으로 전환함(RL Update).
|
||||
- **정책 변화(RL Update)**: 개인 정보 보호 정책(GDPR 등) 강화로 인해, 데이터를 한 곳으로 모으지 않고 기기단에서 학습하는 '연합 학습(Federated Learning) 정책'이 빅데이터 활용의 새로운 표준이 됨.
|
||||
### 매 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.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- [[Artificial Intelligence (AI)|Artificial Intelligence (AI)]], Foundational Models, [[Statistics & Data Analysis|Statistics & Data Analysis]], [[Backups|Backups]], [[Technical-Architecture|Technical-Architecture]]
|
||||
- **Modern Tech/Tools**: Hadoop, Spark, NoSQL (MongoDB, Cassandra), Data Lake (Snowflake).
|
||||
---
|
||||
### 매 응용
|
||||
1. 매 BI 의 dashboard.
|
||||
2. ML training pipeline (feature store).
|
||||
3. Operational analytics (real-time fraud, ad bidding).
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
## 💻 패턴
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
### Iceberg table 의 Spark 에서 의 write
|
||||
```python
|
||||
from pyspark.sql import SparkSession
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
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()
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
df = spark.read.json("s3a://raw/events/*.json")
|
||||
df.writeTo("local.events.daily").partitionedBy("date").createOrReplace()
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### DuckDB: 매 single-node "big data" (laptop 의 100GB)
|
||||
```python
|
||||
import duckdb
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
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()
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Polars: out-of-core lazy
|
||||
```python
|
||||
import polars as pl
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
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))
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### Flink: streaming aggregation
|
||||
```java
|
||||
DataStream<Event> events = env.fromSource(kafkaSource, ...);
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
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]] · [[Data Lake]]
|
||||
- 응용: [[Apache Ignite]] · [[BI]] · [[ML Pipeline]]
|
||||
- Adjacent: [[Append-only log]] · [[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 |
|
||||
|
||||
@@ -2,203 +2,181 @@
|
||||
id: wiki-2026-0508-bottom-up-approach
|
||||
title: Bottom Up Approach
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [Bottom-Up Design, Bottom-Up vs Top-Down, Composition-First Design]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [design, methodology, top-down, bottom-up, architecture]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: Polyglot
|
||||
framework: Methodology
|
||||
---
|
||||
|
||||
# [[Bottom-Up-Approach|Bottom-Up-Approach]]
|
||||
# Bottom Up Approach
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> "작은 성공의 조립: 거창한 전체 계획부터 세우지 않고, 가장 구체적이고 당장 실행 가능한 작은 부품들을 먼저 만들어 검증한 뒤 이들을 연결하여 점진적으로 거대한 시스템을 완성하는 실용주의적 전략."
|
||||
## 매 한 줄
|
||||
> **"매 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 이 다시 부상.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
상향식 접근법은 복잡한 소프트웨어 시스템의 코드베이스를 해독하고 이해할 때 정보의 흐름을 추적하는 근본적인 전략 중 하나이다 [1]. 이 방식은 데이터가 최종적으로 도달하거나 영속화되는 지점에서 시작하여, 이를 호출하는 상위 함수들을 역추적하며 코드를 분석한다 [1]. 버그 수정, 성능 최적화, 부수 효과 분석 등을 수행할 때 시스템의 기술적 한계와 물리적 제약 사항을 파악하는 데 특히 유용하다 [2].
|
||||
### 매 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 의 핵심.
|
||||
|
||||
상향식 탐색(Bottom-Up Approach)은 데이터가 최종적으로 도달하거나 영속화되는 지점(예: 데이터베이스 스토리지), 혹은 개발자가 변경해야 하는 구체적인 코드 위치에서 시작하여 이를 호출하는 상위 함수나 클래스를 역추적하며 코드베이스를 이해하는 전략이다 [1, 2]. 이 방식은 주로 버그 수정, 성능 최적화, 부수 효과(Side effect) 분석 시 핵심적으로 활용되며, 작업에 필요한 종속성(Dependent graph)에만 집중하여 불필요한 코드 파악에 드는 시간을 줄여준다 [1, 2].
|
||||
### 매 weaknesses
|
||||
- **No big picture**: 매 individual unit 우수해도 system 일관성 부재 가능.
|
||||
- **YAGNI risk**: 매 안 쓰일 primitive 까지 만들 수 있음.
|
||||
- **Integration debt**: 매 끝에 가서야 합쳐지는 surprise.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
상향식 접근법(Bottom-Up-Approach)은 기초적인 요소들에서 시작하여 점차 상위 수준의 종합적인 시스템으로 나아가는 방식입니다.
|
||||
### 매 응용
|
||||
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.
|
||||
|
||||
1. **특징**:
|
||||
* **Emergent Intelligence**: 작고 독립적인 컴포넌트들의 상호작용에서 예상치 못한 복잡한 지능이 발현됨. ([[Autonomous-Agents|Autonomous-Agents]]와 연결)
|
||||
* **Early Validation**: 핵심 부품을 먼저 만들어 봄으로써 이론적 가설이 실제 작동하는지 즉시 확인 가능.
|
||||
* **Flexibility**: 바닥부터 탄탄하게 쌓았으므로 환경 변화에 맞춰 상위 시스템을 유연하게 수정하기 좋음.
|
||||
2. **적용 사례**:
|
||||
* **에이전틱 코딩**: 작은 함수들을 먼저 작성하고 테스트한 뒤 이를 결합해 앱을 만듦.
|
||||
* **생물학**: 개별 세포의 특성에서 출발해 생명 전체를 이해하려는 시도.
|
||||
## 💻 패턴
|
||||
|
||||
---
|
||||
### Functional combinator (bottom-up)
|
||||
```haskell
|
||||
-- primitives
|
||||
add1 :: Int -> Int
|
||||
add1 x = x + 1
|
||||
|
||||
- **분석의 시작점:** 상향식 접근법은 데이터베이스 스토리지, 메시지 큐, 외부 시스템으로의 원격 프로시저 호출(RPC) 위치, 외부 API 클라이언트 등 시스템의 가장 하위 혹은 물리적 데이터 종착지에서 시작한다 [1, 2].
|
||||
- **핵심 분석 대상:** 이 접근법을 통해 주로 데이터 변환 과정, 상태 전이 로직, 그리고 시스템의 물리적 제약 사항들을 심층적으로 파악하게 된다 [2].
|
||||
- **적용 시나리오:** 구체적인 기술적 문제를 해결하는 데 강력한 효과를 발휘하며, 주로 버그 수정, 성능 최적화, 그리고 특정 코드 실행으로 인해 발생하는 부수 효과(Side effect)를 분석해야 할 때 적합하다 [2].
|
||||
- **추적 메커니즘:** 가장 종단에 위치한 로직에서 출발해 해당 코드를 호출하는 상위 함수로 거슬러 올라가는 역추적 방식을 사용함으로써, 데이터가 어떻게 처리되고 시스템에 도달하는지 그 흐름을 규명한다 [1].
|
||||
double :: Int -> Int
|
||||
double x = x * 2
|
||||
|
||||
---
|
||||
-- composition (no top-level spec needed)
|
||||
addThenDouble :: Int -> Int
|
||||
addThenDouble = double . add1
|
||||
|
||||
- **탐색의 시작점**: 상향식 탐색은 DB 스키마, 메시지 큐, 외부 API 클라이언트 등 데이터 변환과 물리적 제약이 존재하는 가장 낮은 수준의 컴포넌트에서 주로 시작된다 [2]. 또한, 이해가 안 되는 방대한 코드베이스 전체를 위에서부터 훑기보다는, 자신이 작업 중이거나 이미 알고 있는 코드 조각에서 출발하여 사용된 함수와 클래스의 정의를 따라 밖으로 확장해 나가는 방식을 취한다 [1].
|
||||
- **적용 시점과 장점**: 버그를 수정하거나, 성능을 최적화하고, 특정 수정 사항에 대한 부수 효과를 분석해야 할 때 가장 효과적이다 [2]. 본인이 작업하는 영역과 관련된 종속성만 파악하면 되므로, 개발자가 전혀 신경 쓸 필요 없는 시스템 상층부의 무관한 정보까지 학습해야 하는 인지적 과부하를 방지할 수 있다 [1]. 문서화되지 않은 소프트웨어를 다룰 때 변경이 필요한 특정 부분에만 집중하는 매우 실용적인 접근법이다 [3].
|
||||
- **하이브리드 전략 (Hybrid Strategy)**: 대규모 시스템을 완벽하게 그리기 위해 상향식 탐색은 단독으로 쓰이기보다 하향식 탐색(Top-down)과 혼합되어 사용된다 [4]. 하향식으로 비즈니스 의도와 전체 요청 흐름을 파악하고, 상향식으로 기술적인 한계를 확인하며 그 중간 지점에서 일관된 이해를 형성하는 과정이 필수적이다 [2, 4].
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌**: 과거에는 완벽한 초기 설계(Top-down) 정책이 실패를 막는 유일한 길이라 믿었으나, 현대의 애자일 및 스타트업 정책은 빠른 실패와 학습이 가능한 '상향식 실행 정책'을 압도적으로 선호함(RL Update).
|
||||
- **정책 변화(RL Update)**: 지식 관리 정책(예: 이 Wiki)에서, 전체 카테고리부터 완벽히 짜는 대신 개별 지식 카드들을 먼저 풍성하게 주입하고 나중에 이들의 연결(Graph)을 통해 구조를 발견하는 '상향식 지식 생성 정책'이 채택됨 ([[Ps-Reinforce|Ps-Reinforce]] 핵심 철학).
|
||||
|
||||
---
|
||||
|
||||
상향식 접근법만을 단독으로 사용할 경우, 개별 데이터 변환 로직이나 물리적 제약 사항에 매몰되어 시스템 전체의 비즈니스 의도나 사용자 가치 사슬을 파악하기 어렵다는 한계가 있다 [2, 3]. 따라서 복잡한 시스템의 전체상을 효율적으로 그리기 위해서는 최상위 계층에서 시작하는 하향식(Top-Down) 접근법과 혼합하는 '하이브리드 전략'이 필수적이다 [2]. 하향식으로 비즈니스 의도를 파악하고, 상향식으로 기술적 한계를 확인하며 두 접근법이 만나는 중간 지점에서 일관된 이해를 형성해야 전체 시스템을 온전히 파악할 수 있다 [2, 3].
|
||||
|
||||
---
|
||||
|
||||
상향식 탐색은 변경해야 하는 코드와 기술적 제약 사항을 명확하고 효율적으로 파악할 수 있게 해주지만, 코드베이스 전체의 아키텍처나 고수준의 비즈니스 의도(Intent)를 즉각적으로 이해하기는 어렵다는 명확한 한계가 있다 [1, 4]. 상향식만 고집할 경우 큰 그림을 놓치고 지엽적인 기술 구현이나 물리적 제약에만 시야가 매몰될 수 있다 [2, 4]. 따라서 상향식으로 코드의 종속성을 파악한 이후에는, 시스템 최상위 디렉토리의 목적이나 비즈니스 맥락을 알고 있는 팀원에게 설명을 요청하거나 하향식 탐색을 병행하여 좁은 이해의 폭을 넓히고 보완하는 작업이 필요하다 [1, 4].
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- [[Big-Picture|Big-Picture]], [[Analysis|Analysis]], [[Emergence|Emergence]], [[Agile-Philosophy|Agile-Philosophy]], [[Rapid-Prototyping|Rapid-Prototyping]]
|
||||
- **Modern Tech/Tools**: Component-based UI (React), Microservices, Modular [[Hardware|Hardware]].
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
### Related Concepts
|
||||
|
||||
#### [탐색 및 분석 전략]
|
||||
- [[하향식 접근법 (Top-Down Approach)]]
|
||||
- 연결 이유: 상향식 접근법과 대비되는 또 다른 근본적 탐색 전략으로, 이 두 가지를 혼합하여 사용할 때 복잡한 시스템을 파악하는 데 가장 효율적이기 때문이다 [1, 2].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 공용 API나 UI 라우터 등 최상위 계층에서 시작하여 비즈니스 의도, 권한 검증, 서비스 오케스트레이션을 파악하는 방법을 이해할 수 있다 [2].
|
||||
- [[하이브리드 전략 (Hybrid Strategy)]]
|
||||
- 연결 이유: 하향식과 상향식 접근법을 상황에 맞게 혼합하여 시스템의 전체상을 그리는 데 필수적인 방식이기 때문이다 [2].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 비즈니스 가치 사슬(하향식)과 기술적 구현체(상향식) 사이의 연결 고리를 찾고 일관된 시스템 이해를 형성하는 과정을 배울 수 있다 [2, 3].
|
||||
|
||||
#### [코드 분석 도구 및 기능]
|
||||
- [[사용처 찾기 (Find Usages)]]
|
||||
- 연결 이유: 특정 함수나 코드가 상위의 어떤 함수들에서 참조되는지 시스템 전체에서 확인할 때 사용하는 강력한 현대적 IDE 기능이기 때문이다 [4].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 종단점(DB, 외부 API 등)에서 시작하여 이를 호출하는 상위 계층으로 로직을 거슬러 올라가는 상향식 역추적의 실무적 적용 방법을 파악할 수 있다 [1, 4].
|
||||
- [[디버깅 도구의 중단점 (Breakpoints)]]
|
||||
- 연결 이유: 코드를 역추적할 때 호출 스택과 변수 값의 변화를 실시간으로 관찰할 수 있게 해주는 핵심 분석 도구이기 때문이다 [5].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 복잡한 비동기 작업이나 메시지 큐의 흐름 등 정적인 코드만으로는 파악하기 힘든 동적 행동을 추적하는 기법을 이해할 수 있다 [5].
|
||||
|
||||
### Deeper Research Questions
|
||||
- 상향식 접근법을 활용하여 버그 수정이나 성능 최적화를 수행할 때, 데이터베이스 스키마나 외부 API 클라이언트에서 가장 먼저 확인해야 할 물리적 제약 사항의 구체적 사례는 무엇인가?
|
||||
- IDE의 '사용처 찾기(Find Usages)'와 런타임 분석 시의 '호출 스택(Call Stack)' 관찰은 상향식 탐색 과정에서 어떻게 상호보완적으로 작용하는가?
|
||||
- 하향식 접근법으로 파악한 '비즈니스 의도'와 상향식 접근법으로 파악한 '기술적 한계'가 충돌하는 중간 지점을 발견했을 때, 이를 해결하기 위한 리팩토링 전략은 무엇인가?
|
||||
- 복잡한 레거시 시스템에서 상향식으로 의존성을 역추적할 때, 클린 아키텍처나 계층형 아키텍처의 부패(예: 하위 계층이 상위 계층을 참조하는 현상)를 발견하는 방법은 무엇인가?
|
||||
- 상향식으로 데이터 변환 및 상태 전이 로직을 파악하는 과정에서 테스트 코드(단위 테스트 등)는 어떤 방식으로 실행 가능한 문서 역할을 제공하는가?
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 버그 수정 작업 시, 오류가 발생한 데이터베이스 영속화 지점이나 메시지 큐 등에서 시작하여 해당 컴포넌트를 호출한 비즈니스 로직을 역추적해 근본 원인을 파악한다 [1, 2].
|
||||
- **System Design:** 애플리케이션의 성능 최적화를 설계할 때, 가장 하위의 외부 API 연동부나 스토리지 로직의 물리적 제약 사항을 우선 분석하여 아키텍처 개선 포인트를 도출한다 [2].
|
||||
- **Operation / Maintenance:** 타 시스템과의 연동 중에 발생하는 의도치 않은 부수 효과(Side effect)를 분석하기 위해, 통신을 담당하는 최하단 클라이언트 코드에서부터 상위 기능으로 거슬러 올라가며 유지보수를 수행한다 [1, 2].
|
||||
- **Learning Path:** 방대한 코드베이스에 새로 합류한 개발자가 핵심 데이터 모델이나 스키마부터 파악한 뒤, 이를 다루는 변환 로직을 따라 올라가며 시스템의 뼈대를 학습한다 [2].
|
||||
- **My Project Relevance:** 문제 발생 시 UI나 겉으로 드러난 엔드포인트에서 디버깅을 시작하기보다, 에러 로그가 가리키는 최하단 데이터 처리부에서부터 상향식으로 원인을 추적하면 복잡한 런타임 환경에서 더 신속하게 이슈를 해결할 수 있다 [2, 5].
|
||||
|
||||
### Adjacent Topics
|
||||
- [[아키텍처 스타일 (Architecture Styles)]]
|
||||
- 확장 방향: 계층형 아키텍처, 헥사고날 아키텍처, 도메인 주도 설계(DDD) 등의 구조적 특징과 의존성 방향을 학습하여, 상향식 역추적이 어떤 계층과 패키지를 거치게 될지 예측하는 능력을 기를 수 있다 [2, 6].
|
||||
- [[런타임 분석 (Runtime Analysis)]]
|
||||
- 확장 방향: 단순히 정적인 코드의 역추적을 넘어, 프로파일링 도구와 로그 분석을 활용해 실제 애플리케이션 실행 환경에서 동적인 상태 전이와 객체의 수명 주기를 파악하는 방법으로 확장할 수 있다 [5].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
---
|
||||
|
||||
### Related Concepts
|
||||
|
||||
#### [분석 및 탐색 전략]
|
||||
- [[하향식 탐색 (Top-Down Approach)]]
|
||||
- 연결 이유: 상향식 탐색과 상호보완적으로 작용하는 반대 방향의 탐색 기법으로, 이 둘을 결합한 하이브리드 전략을 통해 코드베이스의 전체상을 그릴 수 있다 [2, 4].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 상향식으로는 파악하기 힘든 시스템의 비즈니스 가치 사슬, 사용자 인터페이스, 전체 서비스 오케스트레이션 및 의도 [2, 4].
|
||||
|
||||
- [[하이브리드 전략 (Hybrid Strategy)]]
|
||||
- 연결 이유: 상향식의 장점과 하향식의 장점을 상황에 맞추어 혼합하여 시스템을 가장 효율적으로 이해하는 프레임워크이다 [4].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 비즈니스 의도(하향식)와 기술적 한계(상향식) 사이의 틈을 좁혀 중간 지점에서 일관된 이해를 형성하는 방법 [4].
|
||||
|
||||
#### [코드 분석 목적]
|
||||
- [[부수 효과 분석 (Side Effect Analysis)]]
|
||||
- 연결 이유: 상향식 탐색 기법이 가장 유용하게 적용되는 주요 엔지니어링 분석 활동 중 하나이다 [2].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 데이터베이스나 하위 시스템의 변경 사항이 상위 호출자(Callers)와 전체 시스템 흐름에 미치는 파급 효과를 추적하는 과정 [2].
|
||||
|
||||
### Deeper Research Questions
|
||||
- 하향식으로 파악한 비즈니스 의도와 상향식으로 파악한 기술적 한계가 불일치할 때, 이를 해결하고 코드베이스 내에서 일관된 멘탈 모델을 형성하는 구체적인 방법은 무엇인가?
|
||||
- 문서화가 전혀 되어 있지 않은 거대한 레거시 코드베이스에서 상향식 탐색 시 마주치게 되는 '무의미한 코드(Dead code)'나 방대한 '종속성(Dependencies)'의 길 잃음 현상을 방지하는 기준은 무엇인가?
|
||||
- 단위 테스트(Unit tests)나 유저 인터페이스(UI)를 상향식 탐색의 시작점으로 활용할 때 얻을 수 있는 통찰력의 차이는 무엇인가?
|
||||
- 최근의 AI 기반 코드 분석 도구(예: Kodesage, Qodo)들은 개발자의 상향식 역추적 속도와 종속성 파악 능력을 어떻게 보조하고 가속하는가?
|
||||
- 상향식 탐색을 통해 발견한 코드 레벨의 기술적 제약을 고수준 아키텍처 다이어그램(예: C4 모델)에 반영하기 위한 모범 사례는 무엇인가?
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 개발자가 변경 작업을 수행해야 하는 특정 파일, 기능 혹은 알려진 API 종속성에서 출발하여 관련된 클래스의 정의와 사용처를 파악하며 구현한다 [1, 3].
|
||||
- **System Design:** DB 스키마, 메시지 큐 등 데이터 영속화와 상태 전이 로직에서 시작하여 물리적 제약 사항이 상위 설계에 어떤 영향을 미치는지 점검한다 [2].
|
||||
- **Operation / Maintenance:** 오류가 발생한 지점(예: 버그 재현 위치나 로그)을 식별한 뒤, 해당 지점으로 연결되는 호출 스택(Call stack)을 역추적하며 버그의 근본 원인과 부수 효과를 수정한다 [2, 5].
|
||||
- **Learning Path:** 대규모 프로젝트에 처음 투입되었을 때 모든 디렉토리를 위에서부터 읽어 내려가며 압도당하기보다는, 자신에게 할당된 작은 버그 수정이나 자신이 아는 작은 모듈에서부터 점진적으로 지식의 범위를 확장해 나간다 [1, 5].
|
||||
- **My Project Relevance:** 거대하고 문서가 없는 시스템에서 불필요한 코드를 모두 읽는 시간을 낭비하지 않고, 작업에 관련된 종속성 그래프에만 초점을 맞춰 효율적으로 실무에 임할 수 있게 한다 [1, 3].
|
||||
|
||||
### Adjacent Topics
|
||||
- [[디버깅 (Debugging)]]
|
||||
- 확장 방향: 상향식으로 논리를 추적할 때 중단점(Breakpoints)과 로그를 활용하여 런타임에 동적으로 변경되는 변수 값과 호출 스택을 파악하는 실행 분석 기법으로 지식을 확장할 수 있다 [5, 6].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
-- application emerges by composing
|
||||
process :: [Int] -> [Int]
|
||||
process = map (double . add1) . filter (> 0)
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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)))
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Embedded — HAL up
|
||||
```c
|
||||
// 1. register-level primitive
|
||||
void gpio_set_high(uint32_t pin) { GPIO_BSRR = 1u << pin; }
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
// 2. driver
|
||||
void led_on(led_t led) { gpio_set_high(led.pin); }
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
// 3. application
|
||||
void heartbeat(void) {
|
||||
while (1) { led_on(STATUS_LED); delay_ms(500); led_off(STATUS_LED); delay_ms(500); }
|
||||
}
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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} />;
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
// 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
|
||||
- 부모: [[Software_Design]] · [[Methodology]]
|
||||
- 변형: [[Top_Down_Approach]] · [[Meet_in_the_Middle]] · [[Outside_In_TDD]]
|
||||
- 응용: [[Functional_Programming]] · [[Atomic_Design]] · [[Spike_Solution]]
|
||||
- Adjacent: [[Composition]] · [[YAGNI]] · [[Discovery_Process]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -2,127 +2,185 @@
|
||||
id: wiki-2026-0508-branded-types
|
||||
title: Branded Types
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [Branded Types, Nominal Types, Opaque Types, Tagged Types]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.95
|
||||
verification_status: applied
|
||||
tags: [typescript, type-system, nominal-typing, domain-modeling]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: typescript-5.x,zod,effect-ts
|
||||
---
|
||||
|
||||
# [[Branded-Types|Branded-Types]] (브랜디드 타입)
|
||||
# Branded Types
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> "본질적으로 같은 `string`이라도, 유저 ID와 주문 ID는 엄격히 구분되어야 한다." 타입스크립트에 가짜 딱지를 붙여 '이름 기반 타입 시스템(Nominal Typing)'을 흉내 내는 고수의 기술이다.
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
> 브랜디드 타입(Branded Types) 또는 오파크 타입(Opaque Types)은 TypeScript의 구조적 타이핑([[Structural Typing|Structural Typing]]) 시스템 내에서 발생할 수 있는 의미론적 오류를 방지하기 위해 사용되는 디자인 패턴이다 [1, 2]. 컴파일 시점에만 존재하는 고유한 가상 속성이나 심볼을 타입에 부여하여, 런타임 구조가 동일한 타입이라도 명목적 타이핑(Nominal Typing) 효과를 내며 엄격히 구분되도록 강제한다 [2-4]. 이를 통해 사용자 ID와 주문 ID처럼 형태는 같지만 의미가 전혀 다른 데이터의 혼용을 막고, 시스템 내 데이터의 무결성을 안전하게 보호한다 [4-6].
|
||||
### 매 problem
|
||||
- TS structural: 매 `string` 의 모든 `string` 의 assignable.
|
||||
- `function sendEmail(userId: string, email: string)` — 매 swap 의 type check pass.
|
||||
- 매 nominal hint 의 require — but TS 의 native 의 no.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **Problem: [[Structural Typing|Structural Typing]]**:
|
||||
- 타입스크립트는 구조가 같으면 같은 타입으로 본다. `type UserId = string; type PostId = string;`일 때, 둘을 바꿔 써도 컴파일러는 잡지 못한다.
|
||||
- **[[Solution|Solution]]: Intersecting with Unique Tag**:
|
||||
- `type UserId = string & { __brand: "UserId" };` 처럼 실제 데이터에는 없지만 타입 세계에만 존재하는 고유 속성을 추가한다.
|
||||
- **Type Guards**:
|
||||
- 단순 캐스팅(`as UserId`)보다는 검증 함수를 거쳐야만 해당 타입을 얻을 수 있게 설계하여 데이터 무결성을 보장한다.
|
||||
### 매 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).
|
||||
|
||||
* **구조적 타이핑의 한계와 '기본 타입 집착(Primitive Obsession)'**
|
||||
TypeScript는 구조(형태)가 동일하면 서로 호환되는 것으로 간주하는 구조적 타이핑을 채택하고 있다 [1, 7]. 이로 인해 문자열(string)이나 숫자(number)와 같은 기본 타입을 사용할 때, 이메일 주소, ID, 다른 통화 단위 등 완전히 별개의 용도를 가진 데이터들이 서로 오류 없이 교체 할당될 수 있는 '기본 타입에의 집착(Primitive Obsession)' 문제를 유발하며 컴파일러가 이를 잡아내지 못한다 [3, 4, 8, 9].
|
||||
## 💻 패턴
|
||||
|
||||
* **브랜디드 타입의 구현 원리**
|
||||
이러한 한계를 극복하기 위해, 런타임에는 존재하지 않는 특수한 가상 속성(예: `__brand` 또는 `__type`)을 타입에 교집합(`&`)으로 묶어 선언한다 [2, 10]. 특히 `unique symbol`을 활용하여 브랜드 속성을 정의하면, 타입의 브랜드가 전역적으로 고유해지므로 다른 모듈 간에도 우연한 타입 혼용을 철저히 차단할 수 있다 [4, 6].
|
||||
### Vanilla TS brand
|
||||
```typescript
|
||||
type Brand<T, B> = T & { readonly __brand: B };
|
||||
|
||||
* **브랜드의 강도 (Brand Strength)**
|
||||
설계 목적에 따라 브랜디드 타입은 격리 수준을 조정할 수 있다 [4].
|
||||
* **Weak Brand**: `type T = string & { __brand: 'T' }` 형태로 정의되며, 기본 타입으로의 암시적 변환은 허용하지만 엄격함은 상대적으로 떨어진다 [4, 11].
|
||||
* **Strong Brand**: `type T = (string & { __brand: 'T' }) | { __brand: 'T' }` 형태로 구성되며, 명시적인 캐스팅 없이는 기본 타입과 호환되지 않아 높은 격리 수준을 보장한다 [4, 11, 12].
|
||||
* **Super Brand**: 기본 타입을 포함하지 않고 오직 가상의 속성만으로 구성하여 외부 기본 타입으로의 유출이나 호환성을 매우 엄격하게 차단한다 [4, 12, 13].
|
||||
type UserId = Brand<string, "UserId">;
|
||||
type OrderId = Brand<string, "OrderId">;
|
||||
|
||||
* **값의 할당과 런타임 검증**
|
||||
브랜디드 타입으로 지정된 변수에 값을 할당하기 위해서는 `as` 키워드를 사용한 타입 단언(Type Assertions)을 통해 타입 시스템에 의도를 알려야 한다 [14]. 그러나 단순 단언은 부정확한 값 주입에 취약하므로, 타입 가드(Type Predicates)나 단언 함수(Assertion Functions)를 작성해 런타임 로직으로 데이터를 검증한 후 브랜디드 타입으로 확정하는 방식이 더 안전하다 [15-17]. Zod와 같은 런타임 검증 라이브러리의 `.brand()` 메서드와 결합하면 "검증하지 말고 파싱하라(Parse, Don't Validate)" 철학을 구현하여 검증된 데이터만 시스템 경계 내부로 진입하게 할 수 있다 [18, 19].
|
||||
const UserId = (s: string): UserId => s as UserId;
|
||||
const OrderId = (s: string): OrderId => s as OrderId;
|
||||
|
||||
* **대안 및 트레이드오프**
|
||||
브랜디드 타입은 프로그램의 안전성을 극대화하지만 동시에 코드베이스의 개념적 복잡성을 증가시키는 비용을 수반한다 [20, 21]. 따라서 단순하게 한정된 값의 집합을 나타내는 데이터라면 유니온(Unions), 열거형(Enums), 또는 템플릿 리터럴 타입(Template Literal Types) 등 언어에 이미 내장된 간단한 대체제를 사용하는 것이 유지 보수에 더 유리할 수 있다 [22-25].
|
||||
function getUser(id: UserId) { /* ... */ }
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- 런타임에는 이 '낙인(Brand)'이 사라진다. 따라서 브랜디드 타입은 오직 컴파일 타임의 실수 방지용이다. 시스템이 매우 거대해져서 ID 값들이 혼동될 우려가 있는 엔터프라이즈급 프로젝트에서 그 가치가 증명된다.
|
||||
const u = UserId("u-123");
|
||||
const o = OrderId("o-456");
|
||||
|
||||
---
|
||||
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- Related: [[TypeScript_Type_Safety|TypeScript_Type_Safety]] , [[Branded-Types-for-Nominal-Typing|Branded-Types-for-Nominal-Typing]]
|
||||
- Foundation: [[클린 아키텍처 (Clean Architecture)|Clean-[[Architecture]]-TypeScript]]
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** 구조적 타이핑 (Structural Typing), [[타입 단언 (Type Assertions)|타입 단언 (Type Assertions]], [[타입 가드 (Type Predicates)|타입 가드 (Type Predicates]]
|
||||
- **Projects/Contexts:** [[도메인 주도 설계 (DDD)|도메인 주도 설계 (DDD]], Zod를 활용한 런타임 데이터 파싱
|
||||
- **Contradictions/Notes:** 별도의 래퍼(Wrapper) 클래스를 만들어 기본 타입을 객체지향적으로 감싸는 방식도 무결성을 챙길 수 있는 대안으로 언급되나, 이는 브랜디드 타입(런타임 오버헤드가 없음)과 달리 매 생성마다 런타임 메모리와 성능 오버헤드를 유발하므로 극도의 안정성이 필요한 경우에만 제한적으로 사용해야 함을 소스는 경고하고 있습니다 [3, 26, 27].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-18*
|
||||
|
||||
---
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
getUser(u); // OK
|
||||
getUser(o); // ❌ Type error — 매 nominal 의 distinguish
|
||||
getUser("u-123"); // ❌ raw string 의 reject
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Branded with smart constructor (validate + brand)
|
||||
```typescript
|
||||
type Email = Brand<string, "Email">;
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
function Email(s: string): Email {
|
||||
if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(s)) {
|
||||
throw new Error(`invalid email: ${s}`);
|
||||
}
|
||||
return s as Email;
|
||||
}
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
// 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" };
|
||||
}
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### Zod brand (runtime + type)
|
||||
```typescript
|
||||
import { z } from "zod";
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
const UserIdSchema = z.string().uuid().brand<"UserId">();
|
||||
type UserId = z.infer<typeof UserIdSchema>;
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
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]] · [[Domain Modeling]]
|
||||
- 변형: [[Nominal Typing]] · [[Opaque Types]] · [[Phantom Types]]
|
||||
- 응용: [[Parse Don't Validate]] · [[DDD Value Object]]
|
||||
- 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 |
|
||||
|
||||
@@ -2,93 +2,257 @@
|
||||
id: wiki-2026-0508-breaking-dependencies
|
||||
title: Breaking Dependencies
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [Decoupling, Dependency Breaking, Refactoring Legacy]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [uncategorized]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [refactoring, architecture, legacy-code, testing]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: Java / TypeScript / Python
|
||||
framework: language-agnostic
|
||||
---
|
||||
|
||||
# [[Breaking Dependencies]]
|
||||
# Breaking Dependencies
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
'Breaking Dependencies(의존성 제거)'는 단위 테스트 작성을 방해하거나 시스템의 유연성을 저해하는 코드 간의 강한 결합을 끊어내는 리팩토링 과정이다 [1-3]. 주로 데이터베이스 연결이나 외부 서드파티 서버 호출과 같이 코드를 독립적으로 실행하기 어렵게 만드는 무거운 자원을 식별하고, 이를 가짜 객체(Mock) 등 가벼운 대체물로 교체하기 위해 수행된다 [1-3]. 이를 통해 개발자는 레거시 코드에 안전한 테스트를 추가하고, 궁극적으로 더 큰 규모의 리팩토링과 새로운 기능을 안전하게 추가할 수 있는 기반을 마련할 수 있다 [2, 4, 5].
|
||||
## 매 한 줄
|
||||
> **"매 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 가 핵심.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **레거시 코드 딜레마 극복의 핵심**: 레거시 코드를 안전하게 리팩토링하려면 테스트가 필수적이지만, 테스트를 작성하려면 먼저 코드를 수정해 복잡한 의존성을 끊어내야 하는 모순적인 상황에 직면하게 된다 [2, 6]. 단위 테스트 작성을 가로막는 문제의 99%는 의존성 문제(Dependency Problem)로 귀결되며, 외부 API 호출, 전역 의존성(Global Dependency), 혹은 생성하기 까다로운 매개변수 등이 이에 해당한다 [1, 7]. 의존성 제거는 이 딜레마를 돌파하는 첫 번째 관문이다 [2].
|
||||
* **접점(Seam)의 식별과 활용**: 의존성을 끊기 위해 개발자는 소스 코드를 직접 수정하지 않고도 프로그램의 동작을 변경할 수 있는 지점인 '접점(Seam)'을 찾아야 한다 [1, 2, 4]. 예를 들어, 객체 지향 언어에서는 문제가 되는 클래스를 확장(Extend)하여 테스트 환경에서 실제 DB에 연결되지 않도록 메서드의 동작을 덮어쓰는 방식을 취해 의존성을 우회할 수 있다 [8, 9].
|
||||
* **의존성 제거를 위한 구체적 기법들**: 마이클 페더스(Michael Feathers)는 안전하게 의존성을 끊어내기 위한 24가지의 '의존성 제거 기법(Dependency-Breaking Techniques)' 카탈로그를 제시한다 [10]. 여기에는 매개변수 적응시키기(Adapt Parameter), 메서드 객체 추출(Break Out Method Object), 인터페이스 추출(Extract Interface), 인스턴스 위임자 도입(Introduce Instance Delegator), 생성자/메서드 매개변수화(Parameterize Constructor/Method), 하위 클래스화 및 메서드 재정의(Subclass and Override Method) 등의 실용적인 패턴들이 포함된다 [11, 12].
|
||||
* **모듈 및 아키텍처 수준의 의존성 제거**: 의존성 분리는 단일 클래스나 메서드 단위의 테스트 목적을 넘어, 시스템 아키텍처를 개선하기 위해서도 사용된다. 윈도우(Windows) 리팩토링 사례에서는 여러 바이너리 간에 복잡하게 얽혀 있던 원치 않는 모듈 간 의존성(inter-module dependencies)을 끊어내기 위해 특정 API 기능을 다른 바이너리로 이동시키고 분할하는 시스템 규모의 리팩토링을 수행했다 [13, 14].
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
* **코드의 미학적 손상**: 기존 코드에 단위 테스트를 적용하기 위해 의존성을 제거하는 과정에서, 불가피하게 임시적인 간접 계층이나 불필요해 보이는 메서드를 추가해야 할 수 있다. 이로 인해 리팩토링의 특정 단계에서는 코드가 이전보다 미학적으로 약간 더 지저분해지거나(uglier) 복잡해지는 제약이 발생한다 [15, 16].
|
||||
* **병적인 코드 베이스에서의 어려움**: 운이 좋다면 의존성이 작고 국소적으로 모여있지만, 코드가 심각하게 망가진 병적인(pathological) 시스템의 경우 의존성이 수없이 많고 코드 전반에 광범위하게 퍼져 있어 이를 끊어내는 과정 자체가 극도로 고통스럽고 오랜 시간이 소요될 수 있다 [5].
|
||||
* **전처리기 및 링커 접점의 부작용**: 객체 접점(Object Seams)을 사용할 수 없는 C/C++ 같은 언어에서 전처리기 매크로나 링커를 활용해 의존성을 끊는 방식(Preprocessing / Link Seams)은 테스트 환경과 프로덕션 환경의 차이를 불명확하게 만들어, 파악하기 힘든 까다로운 버그를 유발할 수 있다 [17, 18]. 이러한 방식은 테스트의 유지보수성도 저하시키므로 더 나은 대안이 없는 최후의 수단으로만 사용해야 한다 [19].
|
||||
### 매 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 행위 가짐.
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-03*
|
||||
### 매 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 로.
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
### 매 응용
|
||||
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 화.
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
## 💻 패턴
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
### 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);
|
||||
}
|
||||
}
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
// AFTER — Extract Interface + DI
|
||||
public interface Notifier {
|
||||
void send(String to, String body);
|
||||
}
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
public class EmailSender implements Notifier { /* impl */ }
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
|
||||
- **Parent:** [[10_Wiki/Topics]]
|
||||
- **Related:** *(TODO: 최소 2개)*
|
||||
- **Opposite / Trade-off:** *(TODO)*
|
||||
- **Raw Source:** 직접 입력
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
// 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());
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Sprout Method (TypeScript)
|
||||
```ts
|
||||
// BEFORE — 매 huge method, 매 add new logic 못 testable
|
||||
class Invoice {
|
||||
process(): void {
|
||||
// 200 lines 의 legacy
|
||||
// 매 new logic 추가하면 매 테스트 X
|
||||
}
|
||||
}
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
// AFTER — sprout 로 새 행동만 분리
|
||||
class Invoice {
|
||||
process(): void {
|
||||
// 200 lines 의 legacy (그대로)
|
||||
this.applyLoyaltyDiscount(); // 매 sprouted
|
||||
}
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
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;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### Extract and Override Call (Python)
|
||||
```python
|
||||
# BEFORE
|
||||
class Job:
|
||||
def run(self):
|
||||
now = datetime.utcnow() # 매 hard
|
||||
if now.weekday() >= 5: return
|
||||
self.do_work()
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
# AFTER
|
||||
class Job:
|
||||
def run(self):
|
||||
if self._now().weekday() >= 5: return
|
||||
self.do_work()
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
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]] · [[Software-Design]] · [[Legacy-Code]]
|
||||
- 변형: [[Sprout-Method]] · [[Extract-Interface]] · [[Adapter-Pattern]]
|
||||
- 응용: [[Test-Driven-Development]] · [[Hexagonal-Architecture]] · [[Strangler-Fig-Pattern]]
|
||||
- Adjacent: [[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 |
|
||||
|
||||
@@ -2,129 +2,201 @@
|
||||
id: wiki-2026-0508-broker-topology
|
||||
title: Broker Topology
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-15DEEFAA]
|
||||
aliases: [Event Broker Topology, Pub-Sub Topology]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [broker-topology, event-driven-architecture, mediator-topology, choreography, message-broker, architecture-principles]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [event-driven, architecture, kafka, messaging]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-02
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: kafka-nats-rabbitmq
|
||||
---
|
||||
|
||||
# [[Broker Topology]]
|
||||
# Broker Topology
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
Broker Topology(브로커 토폴로지)는 이벤트 기반 아키텍처(Event-Driven Architecture)를 구현하는 두 가지 주요 토폴로지 중 하나로, 중앙의 조정자(Orchestrator)나 메디에이터 없이 컴포넌트들이 비동기적으로 이벤트를 브로드캐스트하는 구조입니다 [1, 2]. 이 방식은 중앙 통제 대신 각 독립적인 이벤트 핸들러가 자율적으로 이벤트에 반응하는 형태(Choreography)를 취합니다 [2, 3]. 결합도가 매우 낮아 확장성과 반응성이 뛰어나며 단일 장애점을 최소화할 수 있지만, 복잡한 트랜잭션 관리와 워크플로우 제어에는 불리한 특성이 있습니다 [1-3].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **핵심 구성 요소 (Core Components):**
|
||||
브로커 토폴로지는 주로 개시 이벤트(Initiating Event), 이벤트 브로커(Event Broker), 이벤트 채널(Event Channel), 이벤트 핸들러(Event Handler), 처리 이벤트(Processing Event) 등 5가지 요소로 구성됩니다 [1, 4]. 클라이언트가 이벤트를 발생시키면 이벤트 브로커의 특정 채널로 전달되고, 해당 채널을 수신하는 이벤트 핸들러들이 이벤트를 가져와 처리한 뒤, 다음 단계를 위한 새로운 처리 이벤트를 다시 브로커에 발행하는 연쇄적인 방식으로 동작합니다 [4].
|
||||
* **중앙 조정자의 부재 (Lack of Central Coordinator):**
|
||||
"Broker is a dumb pipe"라는 개념처럼, 이벤트 브로커는 메시지 전달 서비스만 제공할 뿐 비즈니스 프로세스의 논리를 제어하거나 상태(State)를 유지하지 않습니다 [5]. 이로 인해 개별 컴포넌트는 다단계 비즈니스 트랜잭션의 상태를 소유하거나 인지하지 않은 채, 자신과 관련된 이벤트에만 자율적으로 반응(반응 또는 무시)합니다 [2, 5].
|
||||
* **고도의 확장성과 유연성 (Scalability and Extensibility):**
|
||||
각 이벤트 핸들러는 서로 독립적인 컨테이너로 배포될 수 있으므로, 부하에 맞춰 개별적으로 오토스케일링(Auto-scaling)이 가능합니다 [6]. 또한, 기존 컴포넌트를 전혀 수정하지 않고도 동일한 채널에 새로운 이벤트 핸들러를 추가하거나, 아직 시스템이 처리하지 않는 이벤트를 무시하게 설정해둠으로써 향후 시스템의 기능 확장을 용이하게 만듭니다 [7]. 브로커 자체도 단일 병목을 방지하기 위해 여러 컴퓨팅 노드에 연합(Federated) 형태로 분산 배포될 수 있습니다 [6].
|
||||
* **최적의 사용 사례 (Best Use Cases):**
|
||||
이 토폴로지는 여러 단계의 복잡한 오케스트레이션(Orchestration)이 필요 없는 단순한 이벤트 스트림 처리에 가장 적합합니다 [8]. 예를 들어, 보안 시스템에서 침입 센서가 이벤트를 발생시키면 이를 직접 브로커로 전달하고, 경보 울림, 경찰 통보 등의 개별 프로세서가 이 알림에 비동기적으로 반응하는 시나리오 등에 효과적입니다 [9].
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
* **복잡한 에러 처리 및 트랜잭션 복구의 한계:** 중앙에서 프로세스를 조정하는 요소가 없으므로, 여러 서비스에 걸친 분산 트랜잭션을 관리하기가 매우 위험하고 까다롭습니다 [2]. 중간 단계에서 오류가 발생하더라도 이를 인지하고 전체 프로세스를 재시작(Restart)하거나 재생(Replay)하는 내장 메커니즘이 부족하므로 수동 개입 전략이나 별도의 에러 핸들러 설계가 요구됩니다 [2, 5].
|
||||
* **데이터의 일관성 문제 (Data Inconsistency):** 모든 행위가 비동기적으로 분리되어 실행되기 때문에, 각 서브시스템이 이벤트를 처리하고 상태를 업데이트하는 속도가 다를 수 있습니다 [2, 10]. 이로 인해 일시적으로 서비스 간 데이터의 불일치가 발생하는 최종 일관성(Eventual Consistency) 모델을 감수해야 합니다 [2, 10].
|
||||
* **워크플로우 모니터링의 난해함:** 모든 처리가 개별 핸들러들의 자율적인 안무(Choreography) 방식으로 이루어지기 때문에, 비즈니스 워크플로우의 전체적인 진행 상황을 파악하거나 추적하기 어렵습니다 [3]. 이를 해결하기 위해 모든 이벤트에 상관 ID(Correlation ID)를 포함시켜 분산 추적(Distributed Tracing)을 가능하게 하는 부가적인 노력이 필수적입니다 [11].
|
||||
### 매 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 |
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
### 매 컴포넌트
|
||||
- **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.
|
||||
|
||||
#### [아키텍처/기반 기술]
|
||||
* [[Event-Driven Architecture]]
|
||||
* 연결 이유: 브로커 토폴로지는 이벤트 기반 아키텍처(EDA)를 구축하기 위한 두 가지 핵심 위상(Topology) 중 하나입니다 [1, 12].
|
||||
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: 비동기 방식의 메시지 전달, 시스템 디커플링, 이벤트 스트림 프로세싱 등 브로커 토폴로지가 기반을 두고 있는 아키텍처의 전반적인 특징을 이해할 수 있습니다 [10, 13, 14].
|
||||
* [[Mediator Topology]]
|
||||
* 연결 이유: 브로커 토폴로지와 대비되는 이벤트 기반 아키텍처의 또 다른 구성 방식으로, 중앙 집중식 제어(Orchestration)를 담당합니다 [1, 2, 12].
|
||||
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: 브로커 토폴로지가 지닌 단점(트랜잭션 및 에러 관리의 한계)을 메디에이터 토폴로지가 중앙의 상태 관리 및 오류 복구 기능을 통해 어떻게 보완하는지 비교할 수 있습니다 [2, 5, 15].
|
||||
### 매 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).
|
||||
|
||||
#### [동작 메커니즘/구현 도구]
|
||||
* [[Choreography]]
|
||||
* 연결 이유: 브로커 토폴로지는 중앙 오케스트레이터 없이 각 컴포넌트가 알아서 이벤트를 주고받으며 비즈니스 로직을 완수하는 분산된 '안무(Choreography)' 방식으로 동작합니다 [3, 10].
|
||||
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: 마이크로서비스 간에 중앙 통제 없이 독립적으로 워크플로우를 구성하고 분산 트랜잭션(Saga 패턴 등)을 이어가는 원리를 이해할 수 있습니다 [3, 10].
|
||||
* [[Message Broker]]
|
||||
* 연결 이유: 이벤트 채널을 수용하고 브로커 토폴로지의 이벤트 흐름을 실제로 관리하기 위해 ActiveMQ, RabbitMQ, Kafka 등과 같은 메시지 브로커가 인프라로 사용됩니다 [6, 16].
|
||||
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: 이벤트를 보관하는 큐(Queue)와 스트림(Stream) 기반 처리의 차이, 그리고 브로커 인프라가 시스템의 연합(Federation) 및 확장성을 어떻게 지원하는지 파악할 수 있습니다 [6, 17, 18].
|
||||
### 매 응용
|
||||
1. Order events (e-commerce fan-out).
|
||||
2. CDC (Debezium → Kafka → multiple sinks).
|
||||
3. IoT telemetry ingestion.
|
||||
4. Analytics event pipeline.
|
||||
|
||||
### Deeper Research Questions
|
||||
* 브로커 토폴로지의 한계인 분산 트랜잭션 오류 및 데이터 불일치를 보완하기 위해 시스템에 안전하게 보상 트랜잭션(Compensating Transaction)을 구현하는 방법은 무엇인가?
|
||||
* 특정 비즈니스 워크플로우 내에서 브로커 토폴로지의 안무(Choreography) 방식과 메디에이터 토폴로지의 오케스트레이션(Orchestration) 방식을 결합하는 하이브리드 설계의 기준은 무엇인가?
|
||||
* 이벤트 브로커 구현 시 큐(Queue) 방식 대신 스트림(Stream) 방식을 선택할 때, 시스템의 과거 데이터 분석 및 이벤트 소싱(Event Sourcing) 기능 구현에 어떤 이점이 발생하는가?
|
||||
* 개별 이벤트 핸들러가 수많은 이벤트를 병렬 스레드로 처리할 때, 이벤트의 순서를 보장(Ordering)하거나 정확히 한 번(Exactly-once) 처리되도록 설계하는 아키텍처적 기법은 무엇인가?
|
||||
* 단일 브로커 컴포넌트가 성능 병목이나 단일 장애점(SPOF)이 되는 것을 방지하기 위해 분산 연합 브로커(Federated Event Broker)를 구성할 때 고려해야 할 통신 지연 및 동기화 이슈는 무엇인가?
|
||||
## 💻 패턴
|
||||
|
||||
### Practical Application Contexts
|
||||
* **Implementation:** 복잡한 롤백이나 상태 추적이 필요 없는 단방향 이벤트 처리(예: 단순 사용자 액션에 대한 로그 수집 및 실시간 알림 전송)를 구현할 때 적합합니다 [9, 14].
|
||||
* **System Design:** 컴포넌트 간 결합도를 최하로 낮추고 무중단 스케일링이 필요한 클라우드 네이티브 환경에서, 서비스 간 직접 통신(Point-to-point)을 대체하는 비동기 메시지 버스로 설계됩니다 [2, 4, 10].
|
||||
* **Operation / Maintenance:** 개별 이벤트 처리기의 장애가 전체 시스템에 영향을 주지 않아 운영 안정성이 향상되지만, 로그 추적(Correlation ID 도입 등)과 장애 이벤트 처리(Dead Letter Queue) 시스템 구축이 필수적입니다 [7, 10, 11].
|
||||
* **Learning Path:** 소프트웨어 아키텍트가 이벤트 기반 시스템(EDA)을 설계할 때, 첫 번째 분기점인 '단순성(Broker)'과 '제어력(Mediator)' 사이의 트레이드오프를 결정하는 핵심 학습 경로가 됩니다 [1, 3, 19].
|
||||
* **My Project Relevance:** IoT 센서 데이터 수집 시스템이나, 여러 팀이 별도로 운영하는 기능(예: 결제 완료 후 이메일 전송, 인벤토리 업데이트, 고객 포인트 적립)들이 동일한 이벤트(결제 완료)를 병렬적으로 수신해 처리해야 할 때 도입을 검토할 수 있습니다 [14, 20].
|
||||
### Kafka producer (TypeScript / KafkaJS)
|
||||
```typescript
|
||||
import { Kafka } from 'kafkajs';
|
||||
|
||||
### Adjacent Topics
|
||||
* [[Broker Architecture Pattern]]
|
||||
* 확장 방향: 브로커 토폴로지와 유사하게 분산 시스템에서 컴포넌트 간의 통신을 매개하여 구조를 디커플링하는 상위 레벨의 브로커 패턴 전반의 활용과 클라이언트-서버 간 중재 방식을 연구할 수 있습니다 [21, 22].
|
||||
* [[Microservices Architecture (MSA)]]
|
||||
* 확장 방향: 마이크로서비스 간 느슨한 결합(Loose Coupling)을 실현하고 서비스 자율성을 부여하기 위한 내부 통신 수단으로서 브로커 토폴로지가 어떻게 접목되는지 탐구합니다 [10, 23].
|
||||
const kafka = new Kafka({
|
||||
clientId: 'orders',
|
||||
brokers: ['kafka-1:9092', 'kafka-2:9092'],
|
||||
});
|
||||
const producer = kafka.producer();
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
await producer.connect();
|
||||
await producer.send({
|
||||
topic: 'order.created',
|
||||
messages: [{
|
||||
key: order.id,
|
||||
value: JSON.stringify(order),
|
||||
headers: { 'content-type': 'application/json' },
|
||||
}],
|
||||
});
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Kafka consumer (consumer group fan-out)
|
||||
```typescript
|
||||
const consumer = kafka.consumer({ groupId: 'shipping-svc' });
|
||||
await consumer.connect();
|
||||
await consumer.subscribe({ topic: 'order.created' });
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
await consumer.run({
|
||||
eachMessage: async ({ message }) => {
|
||||
const order = JSON.parse(message.value!.toString());
|
||||
await createShipment(order);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### NATS JetStream
|
||||
```typescript
|
||||
import { connect, JSONCodec } from 'nats';
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
const nc = await connect({ servers: 'nats://localhost:4222' });
|
||||
const js = nc.jetstream();
|
||||
const jc = JSONCodec();
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
await js.publish('orders.created', jc.encode(order));
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
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]] · [[Messaging]]
|
||||
- 변형: [[Mediator Topology]] · [[Choreography]]
|
||||
- 응용: [[Kafka]] · [[NATS]] · [[Pulsar]]
|
||||
- Adjacent: [[Schema Registry]] · [[CDC]] · [[Saga Pattern]]
|
||||
|
||||
## 🤖 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 패턴 |
|
||||
|
||||
@@ -2,91 +2,183 @@
|
||||
id: wiki-2026-0508-browser
|
||||
title: Browser
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-Reinforce-AUTO-BROW-001]
|
||||
aliases: [Web Browser, Browser Internals, Rendering Engine]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [auto-reinforced, browser, web-access, rendering-engine, internet-infrastructure, client-side]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [browser, web, rendering, javascript, networking]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-04-20
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: C++/Rust
|
||||
framework: Chromium/Gecko/WebKit
|
||||
---
|
||||
|
||||
# [[Browser|Browser]]
|
||||
# Browser
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> "인터넷 세상의 망원경이자 창: 서버로부터 전송받은 복잡한 코드(HTML, CSS, JS)를 인간이 보고 즐길 수 있는 아름다운 화면으로 실시간으로 번역하여 우주보다 넓은 웹의 바다를 항해하게 해주는 도구."
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
웹 브라우저(Web Browser)는 인터넷상에 존재하는 정보를 검색하고 표시하며 사용자와 상호작용하는 소프트웨어입니다.
|
||||
## 매 핵심
|
||||
|
||||
1. **핵심 기능**:
|
||||
* **Rendering**: 코드를 해석하여 픽셀로 변환. ([[Visual-Effects-VFX|Visual-Effects-VFX]]와 맥락 공유)
|
||||
* **Execution**: [[JavaScript|JavaScript]] 엔진(예: V8)을 통해 복잡한 웹 앱 구동.
|
||||
* **Caching & Persistence**: 방문 기록, 쿠키 등을 저장하여 성능 향상 및 보안 유지.
|
||||
2. **OS로서의 브라우저**:
|
||||
* 현대 브라우저는 단순한 문서 뷰어를 넘어, 오피스, 게임, AI 도구들이 실행되는 '온라인 운영체제' 역할을 수행함.
|
||||
### 매 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.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌**: 과거 브라우저 정책은 단순 정보 조희(Read-only) 중심이었으나, 현대 정책은 사용자의 데이터 주권을 지키고 AI 에이전트가 직접 웹을 탐색하며 작업을 수행하는 '에이전틱 브라우징 정책'으로 진화함(RL Update).
|
||||
- **정책 변화(RL Update)**: 서드파티 쿠키 차단 정책(Cookieless) 등 개인정보 보호 정책이 강화됨에 따라, 브라우저가 사용자 익명성을 보장하는 동시에 광고 성과를 측정하는 새로운 추적 차단 정책과 표준이 수립됨.
|
||||
### 매 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 합성.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- [[Backend|Backend]], [[API-Key-Management|API-Key-Management]], [[Availability-and-Persistence|Availability-and-Persistence]], [[Visual-Effects-VFX|Visual-Effects-VFX]], [[Technical-Architecture|Technical-Architecture]]
|
||||
- **Modern Tech/Tools**: [[Chrome|Chrome]], Firefox, Safari, [[Chromium|Chromium]]-based browsers, [[WebAssembly|WebAssembly]] (Wasm).
|
||||
---
|
||||
### 매 JS engine tiers (V8)
|
||||
- **Ignition** (interpreter) → **Sparkplug** (baseline JIT) → **Maglev** (mid-tier) → **TurboFan** (optimizing JIT).
|
||||
- 매 hot function 만 점진적 promotion.
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
### 매 응용
|
||||
1. **Web app development**: 매 performance budgeting.
|
||||
2. **Extension / DevTools**: 매 internal API.
|
||||
3. **Embedded webview**: 매 Electron, Tauri, CEF.
|
||||
4. **Headless**: 매 Puppeteer, Playwright scraping/test.
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
## 💻 패턴
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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>
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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
|
||||
});
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
// GOOD — batch reads then writes
|
||||
const widths = boxes.map(b => b.offsetWidth);
|
||||
boxes.forEach((b, i) => b.style.width = (widths[i] * 2) + 'px');
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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))
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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));
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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);
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
// 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
|
||||
- 부모: [[Web_Platform]] · [[Operating_System]]
|
||||
- 변형: [[Chromium]] · [[Gecko]] · [[WebKit]] · [[Servo]]
|
||||
- 응용: [[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 |
|
||||
|
||||
@@ -4,112 +4,164 @@ title: C4 Modeling Framework
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-ARCH-C4-MODEL, C4 Model, 계층적 아키텍처 모델링, 시스템 시각화]
|
||||
aliases: [C4 Model, C4 Diagrams, Simon Brown C4]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 1.0
|
||||
tags: [Architecture, Modeling, C4_Model, Visualization, Documentation]
|
||||
raw_sources: [Datacollector_Export_2026-05-02]
|
||||
last_reinforced: 2026-05-02
|
||||
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: unspecified
|
||||
framework: unspecified
|
||||
language: DSL
|
||||
framework: Structurizr
|
||||
---
|
||||
|
||||
# [[C4 모델 아키텍처 시각화 프레임워크]]
|
||||
# C4 Modeling Framework
|
||||
|
||||
## 1. 개요
|
||||
C4 모델은 소프트웨어 아키텍처를 **컨텍스트(Context), 컨테이너(Container), 컴포넌트(Component), 코드(Code)**의 4가지 추상화 수준으로 계층화하여 표현하는 접근법이다. 지도를 확대(Zoom-in)하듯 상위 수준의 시스템 개요부터 세부 구현까지 점진적으로 시각화하여 다양한 이해관계자와 일관된 어휘로 소통할 수 있게 돕는다.
|
||||
## 매 한 줄
|
||||
> **"매 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 이 핵심 가치.
|
||||
|
||||
## 2. 4단계 계층 (Four Levels)
|
||||
1. **L1: 시스템 컨텍스트 (Context)**: 시스템을 블랙박스로 취급하며, 사용자 및 외부 시스템과의 상호작용 경계를 정의. (경영진/비기술자 대상)
|
||||
2. **L2: 컨테이너 (Container)**: 시스템 내부의 실행/배포 가능한 단위(웹 앱, DB, 모바일 앱 등)와 기술 스택, 통신 채널 명시. (개발자/운영자 대상)
|
||||
3. **L3: 컴포넌트 (Component)**: 컨테이너 내부의 주요 구조적 구성 요소와 그들 간의 책임 및 의존성 기술. (개발자 대상)
|
||||
4. **L4: 코드 (Code)**: 클래스 다이어그램 등 가장 낮은 수준의 뷰. 코드가 실제로 어떻게 구성되어 있는지 상세 표현. (선택적 사용)
|
||||
## 매 핵심
|
||||
|
||||
## 3. 핵심 이점
|
||||
- **인지적 부하 감소**: 필요한 만큼의 정보만 단계적으로 제공하여 복잡한 코드베이스 탐색을 용이하게 함.
|
||||
- **의사소통 효율화**: 청중의 지식 수준에 맞춰 다이어그램의 깊이를 조절 가능.
|
||||
- **지속 가능성**: Structurizr와 같은 도구를 통해 '코드로서의 다이어그램(Diagrams as Code)'으로 관리하여 문서 최신화 보장.
|
||||
### 매 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 가 대신.
|
||||
|
||||
## 4. 트레이드오프 및 주의사항
|
||||
- **장점**: 명확한 추상화 수준 분리, 이해관계자 간 정렬 용이.
|
||||
- **단점**: 고도로 정밀한 시맨틱 명세(UML 대비)나 물리적 클라우드 인프라(VPC, 서브넷 등) 표현에는 한계가 있음.
|
||||
### 매 supplementary diagrams
|
||||
- **Deployment diagram**: 매 container → infrastructure node mapping.
|
||||
- **Dynamic diagram**: 매 runtime sequence/collaboration.
|
||||
- **System landscape**: 매 enterprise-wide multi-system view.
|
||||
|
||||
## 5. 지식 연결 (Related)
|
||||
- [[UML_Unified_Modeling_Language]]: C4의 L4(Code) 레벨에서 주로 사용되는 상세 모델링 언어.
|
||||
- [[Architecture_Diagramming_Standards]]: 시스템을 시각화하는 일반적인 원칙과 기법.
|
||||
- [[Hexagonal_Architecture]]: C4 모델을 통해 시각화하기 좋은 대표적인 내부 아키텍처 패턴.
|
||||
### 매 응용
|
||||
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 시각화.
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
- **정보 상태**: 검증 완료 (Verified)
|
||||
- **출처 신뢰도**: A
|
||||
- **검토 이유**: 시스템 구조의 명확한 전달과 문서화를 위한 현대적 시각화 표준 정립.
|
||||
## 💻 패턴
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
### 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"
|
||||
|
||||
> *(TODO: 한 문장으로 핵심 통찰을 작성. "X는 Y 조건에서 Z 효과를 낸다" 구조 권장.)*
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
|
||||
**추출된 패턴:**
|
||||
> *(TODO)*
|
||||
|
||||
**세부 내용:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
|
||||
- **과거 데이터와의 충돌:** 없음
|
||||
- **정책 변화:** 없음
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
|
||||
- **Parent:** [[10_Wiki/Topics]]
|
||||
- **Related:** *(TODO: 최소 2개)*
|
||||
- **Opposite / Trade-off:** *(TODO)*
|
||||
- **Raw Source:** 직접 입력
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
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
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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")
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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"
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
signInController -> authService "uses"
|
||||
accountsController -> accountsRepo "reads"
|
||||
authService -> db "verifies credentials"
|
||||
}
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### Deployment view
|
||||
```dsl
|
||||
deploymentEnvironment "Production" {
|
||||
deploymentNode "AWS us-east-1" {
|
||||
deploymentNode "EKS Cluster" {
|
||||
containerInstance webApp
|
||||
containerInstance api
|
||||
}
|
||||
deploymentNode "RDS" {
|
||||
containerInstance db
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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/
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]] · [[4+1_View_Model]] · [[UML]]
|
||||
- 응용: [[ADR]] · [[Diagram_as_Code]] · [[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 |
|
||||
|
||||
@@ -2,94 +2,183 @@
|
||||
id: wiki-2026-0508-cad-렌더링-최적화
|
||||
title: CAD 렌더링 최적화
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-Reinforce-AUTO-40FA98]
|
||||
aliases: [CAD Rendering Optimization, CAD Performance, Engineering Visualization]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
tags: [auto-reinforced]
|
||||
verification_status: applied
|
||||
tags: [cad, rendering, gpu, lod, webgpu]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-04-20
|
||||
github_commit: "[P-Reinforce] Continuous Worker - CAD 렌더링 최적화"
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: TypeScript
|
||||
framework: WebGPU/Three.js
|
||||
---
|
||||
|
||||
# [[CAD 렌더링 최적화|CAD 렌더링 최적화]]
|
||||
# CAD 렌더링 최적화
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> CAD 렌더링 최적화는 브라우저 및 통합 GPU(iGPU) 환경에서 메모리 대역폭과 CPU-GPU 간 통신 병목을 극복하여 수백만 개의 폴리곤을 가진 대규모 다중 본체 어셈블리(Multi-Body Assemblies)를 부드럽게 렌더링하는 일련의 기술적 과정입니다 [1, 2]. 이를 위해 `BatchedMesh`나 `[[InstancedMesh|InstancedMesh]]`를 통한 드로우 콜 최소화, 정밀도 붕괴 방지를 위한 원점 이동(Origin-Shifting), 메모리 관리 효율화를 위한 Web Worker 및 `SharedArrayBuffer` 활용이 필수적으로 요구됩니다 [3-5]. 또한, 오버드로우를 줄이는 깊이 사전 패스([[Depth Pre-Pass|Depth Pre-Pass]])와 시각적 끊김이 없는 디더링 LOD 등의 렌더링 기법을 결합하여 고성능의 시각화 경험을 제공합니다 [6-8].
|
||||
## 매 한 줄
|
||||
> **"매 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 달성.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **하드웨어 및 메모리 대역폭의 병목 극복:** 통합 GPU(Intel UHD, AMD Radeon Vega 등)는 UMA(Unified [[memory|memory]] [[Architecture|Architecture]]) 환경을 사용하여 시스템 RAM을 CPU와 공유하므로 메모리 대역폭이 주된 성능 제약이 됩니다 [1, 9]. 100만 개 이상의 삼각형을 가진 CAD 모델을 파싱하고 디코딩할 때 발생하는 메인 스레드 프리징과 메모리 중복을 방지하기 위해 Web Worker와 `SharedArrayBuffer`를 연동한 제로 카피(Zero-copy) 아키텍처를 도입해야 합니다 [5].
|
||||
- **지오메트리 통합과 드로우 콜 최적화:** CAD 어셈블리를 구성하는 수많은 부품을 개별 메쉬로 렌더링하면 엄청난 드로우 콜 오버헤드가 발생합니다 [2]. 볼트나 브래킷 같은 반복 부품은 `InstancedMesh`로 처리하고, 고유한 기하학적 형태가 섞인 다양한 부품들은 `BatchedMesh`를 사용해 단일 드로우 콜로 묶어 처리해야 iGPU의 오버헤드를 크게 줄일 수 있습니다 [3, 10]. 정적인 하위 어셈블리는 지오메트리를 타일 단위로 병합(`mergeBufferGeometries`)하는 전략을 활용할 수 있습니다 [11].
|
||||
- **좌표 정밀도 붕괴(Precision Collapse) 방지:** CAD 데이터의 거대한 좌표계(예: 10^7 단위 이상)를 [[WebGL|WebGL]]의 32-bit float 환경으로 가져오면 소수점 이하 정밀도가 부족해져 정점이 흔들리거나 진동하는 현상(Vertex Snapping/Jitter)이 발생합니다 [4]. 이를 막기 위해 64-bit 공간에서 전체 어셈블리의 중심(basePoint)을 계산한 뒤, 정점 좌표를 오프셋 처리(Re-centering shift)하여 GPU에 업로드해야 합니다 [4].
|
||||
- **가시성 판별(Visibility Determination) 및 오클루전 컬링:** 복잡한 내부 부품이 겹쳐 있는 CAD 모델에서 오버드로우를 줄이기 위해 색상 쓰기를 비활성화한 채 Z-버퍼만 먼저 채우는 '깊이 사전 패스(Depth Pre-Pass)'를 수행하면 프래그먼트 셰이더 부하를 최대 30%까지 줄일 수 있습니다 [6]. 또한 옥트리(Octree)나 BVH(Bounding Volume Hierarchy)를 통해 CPU 공간 분할을 적용하여 보이지 않는 노드에 대한 연산을 렌더링에서 배제합니다 [12].
|
||||
- **LOD 및 엣지(Edge) 렌더링 최적화:** 부품을 정밀 검토할 때 시각적으로 튀는 팝핑(Popping) 현상을 막기 위해, 화면 공간 디더링 패턴(Dithered LOD Blend)을 활용한 매끄러운 형태의 LOD 전환 기법을 구현합니다 [7, 13]. 또한 CAD 도면 특유의 날카로운 모서리(Wireframe/Edge)를 표현하기 위해 `EdgesGeometry`를 사용하면 정점 부하가 2배로 늘어나므로, 무게 중심 좌표(Barycentric Coordinate)를 활용하여 단일 패스의 프래그먼트 셰이더 안에서 절차적으로 엣지를 렌더링하는 기법이 권장됩니다 [14, 15].
|
||||
- **자원 및 상태 관리 ([[State|State]] Management):** 수백 개의 색상을 표현하기 위해 개별 재질(Material)을 번갈아 쓰지 않고 '텍스처 아틀라스([[Texture Atlas|Texture Atlas]])'와 파트 ID를 활용해 셰이더 전환을 최소화해야 합니다 [16]. 아울러 배터리 소모와 발열을 막기 위해 변경 사항이 있을 때만 프레임을 업데이트하는 Render-on-Demand(요청 시 렌더링) 방식을 적용하며, 값비싼 물리 기반 렌더링(MeshStandardMaterial) 대신 `MeshPhongMaterial` 또는 'Flat Shaded + Edge' 커스텀 셰이더를 사용하여 프래그먼트 연산 비용을 아낍니다 [8, 17-19].
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
### 매 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.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** BatchedMesh, [[InstancedMesh|InstancedMesh]], Depth Pre-Pass, SharedArrayBuffer, Frustum Culling, [[Level of Detail (LOD)|Level of Detail (LOD]]
|
||||
- **Projects/Contexts:** [[WebGPU 대규모 건설 뷰어|WebGPU 대규모 건설 뷰어]], [[BIM 모델 시뮬레이션|BIM 모델 시뮬레이션]]
|
||||
- **Contradictions/Notes:** 지오메트리 병합(`[[BufferGeometry|BufferGeometry]]Utils.mergeBufferGeometries`) 기법은 드로우 콜을 가장 효과적으로 줄여주지만, 단일 바운딩 볼륨으로 묶이기 때문에 시야 절두체 컬링([[Frustum Culling|Frustum Culling]])의 효율성을 떨어뜨린다는 딜레마를 가집니다 [11]. 또한, `InstancedMesh`는 단일 지오메트리의 반복 렌더링에는 매우 유리하지만 서로 다른 기하학적 구조를 가진 부품이 수천 개 모인 CAD 모델에는 부적합하며, 이 경우 다중 지오메트리를 지원하는 `BatchedMesh`를 사용하는 것이 더 올바른 대안입니다 [3, 10, 20].
|
||||
### 매 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 비용 절감.
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-19*
|
||||
### 매 응용
|
||||
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.
|
||||
|
||||
---
|
||||
## 💻 패턴
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### GPU instancing for fasteners
|
||||
```typescript
|
||||
const boltMesh = loadMesh('m6_socket_head.glb');
|
||||
const transforms = new Float32Array(boltCount * 16); // packed mat4
|
||||
fillTransforms(transforms, boltInstances);
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
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
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### BVH-based frustum culling
|
||||
```typescript
|
||||
class BVHNode {
|
||||
bounds: AABB;
|
||||
children?: [BVHNode, BVHNode];
|
||||
parts?: CadPart[];
|
||||
}
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
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);
|
||||
}
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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;
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
@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]]
|
||||
- 변형: [[Nanite_Virtual_Geometry]] · [[Mesh_Shaders]]
|
||||
- 응용: [[Digital_Twin]] · [[AR_VR_Rendering]]
|
||||
- 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 |
|
||||
|
||||
@@ -2,119 +2,185 @@
|
||||
id: wiki-2026-0508-cst
|
||||
title: CST
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [Concrete Syntax Tree, Parse Tree, Lossless Syntax Tree]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.95
|
||||
verification_status: applied
|
||||
tags: [parser, compiler, ast, cst, ide, refactoring]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: Polyglot
|
||||
framework: tree-sitter/Roslyn/rust-analyzer
|
||||
---
|
||||
|
||||
# [[CST (구체 구문 트리)|CST (구체 구문 트리]]
|
||||
# CST
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> CST(구체 구문 트리) 또는 파스 트리(parse tree)는 문맥 자유 문법(context-free grammar)의 트리 표현으로, 컴파일러가 코드를 어떻게 이해하는지 보여주는 공식적인 표현 방식입니다 [1]. AST(추상 구문 트리)와 달리 포괄적인 구문 요소뿐만 아니라 미세한 문체, 어휘 및 레이아웃(공백, 들여쓰기 등)의 세부 사항까지 코드의 모든 측면을 정밀하게 포착하여 계층적 구조로 렌더링합니다 [2]. 이러한 특징으로 인해 코드 서식 지정이나 축소 등 레이아웃의 변화를 감지할 수 있어 프로그래머의 코딩 스타일을 분석하고 작성자를 식별하는 코드 스타일로메트리(Code stylometry)에 유용하게 활용됩니다 [3, 4].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **정의 및 구조**
|
||||
CST는 주어진 문맥 자유 문법에 기반한 순서 트리(ordered tree)로, 루트(root), 비단말(Non-terminal) 노드, 단말(Terminal) 노드로 구성되어 컴파일러가 코드를 해석하는 계층적인 구조를 시각화합니다 [1, 2, 5]. 트리의 각 노드는 클래스 정의, 함수 정의 또는 변수 할당과 같은 명확한 코드 구성 요소와 연결됩니다 [2].
|
||||
### 매 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 반환.
|
||||
|
||||
* **AST(추상 구문 트리)와의 차이점**
|
||||
구문 기능과 일부 어휘적 특징만 보존하고 레이아웃의 특징을 추상화하여 무시하는 AST와 달리, CST는 코드의 레이아웃(공백, 줄 바꿈, 들여쓰기 등)과 어휘적 세부 사항을 모두 포함합니다 [3, 4]. 예를 들어, 코드를 철저하게 다시 들여쓰기(re-indent)하는 소스-대-소스 변환을 수행할 경우 파싱된 후의 AST 구조는 동일하게 유지되지만, CST는 시각적이고 구조적으로 크게 변경됩니다 [3].
|
||||
### 매 응용
|
||||
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 변환.
|
||||
|
||||
* **코드 스타일로메트리(저자 식별)에서의 활용**
|
||||
레이아웃 및 어휘적 특징이 개인의 코딩 스타일을 결정하는 핵심 요소이므로, 이를 포착하기 위해 코드 작성자 분류 모델에서 CST가 중요한 입력 데이터로 사용됩니다 [4, 6]. 구체적인 단말 노드 간의 경로를 해시화하여 나타낸 '경로 컨텍스트(path context)'의 집합(bag)은 입력된 소스 코드의 문체, 레이아웃 및 구문적 특징을 훌륭하게 유지합니다 [7, 8]. 한 연구 결과에 따르면 파이썬 소스 코드 분류에 AST 대신 CST를 도입했을 때 프로그래머의 식별 정확도가 51.00%에서 67.86%로 현저히 향상되었습니다 [6, 9].
|
||||
## 💻 패턴
|
||||
|
||||
---
|
||||
### tree-sitter — incremental CST
|
||||
```javascript
|
||||
const Parser = require('tree-sitter');
|
||||
const Java = require('tree-sitter-java');
|
||||
const parser = new Parser();
|
||||
parser.setLanguage(Java);
|
||||
|
||||
- **추출된 패턴:** 구두점, 공백, 키워드 등 코드의 모든 텍스트 요소를 노드로 보존하여 파싱 트리를 구성하는 패턴.
|
||||
- **세부 내용:**
|
||||
- AST(추상 구문 트리)와 달리 원본 소스로의 완벽한 복원이 가능함.
|
||||
- 서식 보존 리팩토링(Fidelity-preserving Refactoring) 도구의 근간.
|
||||
- 파서 생성기(ANTLR 등)에서 소스 코드의 물리적 배치를 분석할 때 활용.
|
||||
const source = `class A { int x = 1; }`;
|
||||
const tree = parser.parse(source);
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
|
||||
---
|
||||
|
||||
- **과거 데이터와의 충돌:** 효율성을 위해 세부 정보를 생략하는 AST와 정보량 측면에서 상보적 관계를 형성.
|
||||
- **정책 변화:** 지식 연결성(w2) 관점에서 AST 문서와 1:1 비교 분석 구도 형성.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** [[AST (추상 구문 트리)|AST (추상 구문 트리]], 코드 스타일로메트리 (Code Stylometry), 코드 포매팅 (Code Formatting), [[코드 축소 (Code minification)|코드 축소 (Code Minification]]
|
||||
- **Projects/Contexts:** [[코드 서식 지정과 축소가 코드 스타일로메트리(작성자 인식)에 미치는 영향을 평가하는 기계 학습 모델 분류 연구|코드 서식 지정과 축소가 코드 스타일로메트리(작성자 인식)에 미치는 영향을 평가하는 기계 학습 모델 분류 연구]]
|
||||
- **Contradictions/Notes:** 소스에 관련된 모순된 정보는 없으며, 기존의 주류 문헌들이 코드 표상을 위해 주로 AST를 사용하는 것에서 벗어나, 서식 지정과 축소에 따른 표면적 변화를 측정하기 위해 CST의 사용이 필수적이었다는 점을 강조합니다 [4].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-18*
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- **Parent:** 10_Wiki/💡 Topics/Coding
|
||||
- **Related:** [[AST_Traversal|AST_Traversal]], Parser, [[Formatting|Formatting]]-Tools
|
||||
- **Raw Source:** 00_Raw/2026-04-20/[[Concrete Syntax Tree (CST)|Concrete Syntax Tree (CST]].md
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
// 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
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### rust-analyzer rowan
|
||||
```rust
|
||||
use rowan::{GreenNode, SyntaxNode};
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
// 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);
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
for token in syntax.descendants_with_tokens() {
|
||||
println!("{:?} @ {:?}", token.kind(), token.text_range());
|
||||
// includes whitespace, comments, error tokens
|
||||
}
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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()
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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
|
||||
- 부모: [[Compiler]] · [[Parser]]
|
||||
- 변형: [[AST]] · [[Lossless_Syntax_Tree]] · [[Green_Red_Tree]]
|
||||
- 응용: [[Code_Formatter]] · [[IDE]] · [[Refactoring_Tools]]
|
||||
- Adjacent: [[tree_sitter]] · [[Roslyn]] · [[rust_analyzer]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -2,148 +2,31 @@
|
||||
id: wiki-2026-0508-call-stack
|
||||
title: Call Stack
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
canonical_id: self
|
||||
status: duplicate
|
||||
canonical_id: wiki-2026-0508-call-stack-analysis
|
||||
duplicate_of: "[[Call_Stack_Analysis]]"
|
||||
aliases: []
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, call-stack, profiling]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
---
|
||||
|
||||
# [[Call Stack|Call Stack]]
|
||||
# Call Stack
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> "함수들이 쌓아 올리는 기억의 탑: 프로그램이 어떤 순서로 함수를 호출해왔는지, 함수가 끝나면 어디로 돌아가야 하는지를 관리하는 '후입선출(LIFO)' 방식의 지능형 작업 일지이자 메모리 영역."
|
||||
> **이 문서는 [[Call_Stack_Analysis]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
---
|
||||
## 핵심 요약
|
||||
- 매 generic "call stack" 개념 — runtime 의 frame stack — 은 [[Call_Stack_Analysis]] 의 first section 에서 다룸.
|
||||
- 매 sampling, flame graph, multi-language tooling 까지 canonical 에 통합.
|
||||
|
||||
호출 스택(Call Stack)은 복잡한 소프트웨어 시스템의 코드베이스를 읽고 런타임 흐름을 추적할 때 유용하게 쓰이는 개념입니다 [1, 2]. 하향식(Top-down) 코드 분석 시, 시스템의 최상위 진입점에서 시작하여 호출 스택을 따라 내려감으로써 비즈니스 로직이 어떻게 오케스트레이션되는지 파악할 수 있습니다 [3]. 또한, 디버거의 중단점(Breakpoints)과 함께 사용하면 실행 시점의 호출 스택과 변수 값을 실시간으로 관찰하여 정적 읽기만으로는 알 수 없는 시스템의 동적인 특성을 깊이 이해할 수 있습니다 [4].
|
||||
## 🔗 Graph
|
||||
- 부모: [[Call_Stack_Analysis]] (canonical)
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
콜 스택(Call Stack)은 컴퓨터 프로그램의 현재 실행 중인 서브루틴(함수)들에 대한 정보를 저장하는 스택 자료구조입니다.
|
||||
|
||||
1. **동작 메커니즘**:
|
||||
* **Push**: 함수를 호출하면 해당 함수의 실행 컨텍스트(변수, 리턴 주소 등)가 스택 맨 위에 쌓임.
|
||||
* **Pop**: 함수 실행이 종료되면 스택 맨 위에서 제거되고, 이전 함수로 제어권이 넘어감.
|
||||
2. **주요 이슈**:
|
||||
* **Stack Overflow**: 재귀 함수가 끝나지 않고 계속 스택을 쌓거나, 함수 중첩이 너무 깊어 메모리 한계를 넘었을 때 발생.
|
||||
* **Debugging**: 에러 발생 시 출력되는 'Stack Trace'는 이 스택의 기록을 역순으로 보여주어 버그의 원점을 추적하게 도움. ([[Analysis|Analysis]]와 연결)
|
||||
|
||||
---
|
||||
|
||||
- **하향식(Top-Down) 탐색의 경로 제공:** 대규모 코드베이스에 직면했을 때 API 가이드나 UI와 같은 진입점을 식별한 뒤, 호출 스택을 따라 내려가면서 코드를 읽는 하향식 접근법이 활용됩니다 [3]. 이를 통해 구체적인 구현의 상세로 자연스럽게 진입하며 비즈니스 로직의 흐름을 관찰할 수 있습니다 [3].
|
||||
- **동적 특성 파악과 런타임 분석:** 정적인 코드 읽기만으로는 파악하기 어려운 런타임 흐름을 이해하려면 디버깅 도구를 통한 호출 스택 분석이 필수적입니다 [2, 4]. IDE 등의 중단점을 활용하면, 단순한 로그만 사용할 때보다 호출 스택이나 변수 값 변화에 대한 훨씬 더 많은 정보를 실시간으로 얻을 수 있습니다 [2, 4].
|
||||
- **새로운 코드베이스 학습 및 버그 추적:** 완전히 낯선 코드베이스에 접근할 때, 재현 가능한 간단한 버그를 찾고 이를 유발하는 호출 스택을 추적해 보는 것이 시스템을 구조적으로 파악하는 훌륭한 학습 방법이 됩니다 [1].
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌**: 과거의 스택 정책은 단순히 '순차 실행'을 관리하는 정적 정책이었으나, 현대 자바스크립트 등 비동기 언어 정책에서는 '이벤트 루프(Event Loop)' 및 '마이크로태스크 큐'와 상호작용하며 복잡한 비동기 흐름을 관리하는 동적 정책으로 이해됨(RL Update).
|
||||
- **정책 변화(RL Update)**: 브라우저 성능 최적화 정책에서, 메인 스레드 점유 정책([[Main Thread|Main Thread]] [[Blocking|Blocking]])을 막기 위해 콜 스택을 너무 무겁게 유지하지 않고 작업을 쪼개는 '비동기 스택 정책'이 웹 앱 성능의 핵심 지표가 됨. (Blocking과 연결)
|
||||
|
||||
---
|
||||
|
||||
소스에 호출 스택 구조 자체가 가지는 기술적, 메모리 관점의 제약 사항에 대한 관련 정보가 부족합니다. 다만, 호출 스택을 추적하며 코드를 분석하는 '방식'이 가지는 제약 사항과 부작용이 소스에 아래와 같이 언급되어 있습니다 [1].
|
||||
- **인지적 미아 현상과 시간 낭비:** 대규모 시스템에서 버그를 해결하거나 코드를 이해하기 위해 호출 스택을 무작정 따라가다 보면 깊은 계층 속에서 길을 잃고 헤매기 쉽습니다 [1].
|
||||
- **타임박싱(Timeboxing)의 필요성:** 이와 같은 문제를 방지하기 위해, 호출 스택을 추적할 때는 반드시 추적 시간을 제한(Timebox)해야 합니다 [1]. 일정 시간 내에 파악하지 못하고 길을 잃었다면 무리하지 말고 코드베이스에 지식이 있는 사람에게 즉시 도움을 요청하는 것이 바람직합니다 [1].
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- [[Blocking|Blocking]], [[Analysis|Analysis]], [[Technical-Architecture|Technical-Architecture]], Memory-Management, Recursion
|
||||
- **Modern Tech/Tools**: [[Chrome DevTools|Chrome DevTools]] Call Stack view, [[V8 Engine|V8 Engine]] stack management.
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
### Related Concepts
|
||||
|
||||
#### [관계 유형 A: 코드베이스 분석 전략]
|
||||
- [[하향식 접근법 (Top-Down Approach)]]
|
||||
- 연결 이유: 호출 스택을 따라 내려가는 행위 자체가 복잡한 시스템을 파악하기 위한 하향식 코드 탐색의 주요 기법으로 설명되기 때문입니다 [3].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 시스템의 전체 기능과 사용자 가치 사슬부터 시작해 내부 구현 로직으로 진입하는 방법론적 맥락.
|
||||
|
||||
#### [관계 유형 B: 구현/활용 도구]
|
||||
- [[중단점 (Breakpoints)]]
|
||||
- 연결 이유: 호출 스택의 흐름과 변수 상태를 실시간으로 확인하기 위해 디버거에서 가장 필수적으로 사용되는 기능이기 때문입니다 [2, 4].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 정적 소스 코드만으로는 알 수 없는 프로그램의 실제 런타임 동작과 데이터의 동적 전이 과정.
|
||||
|
||||
- [[런타임 분석 (Runtime Analysis)]]
|
||||
- 연결 이유: 호출 스택 추적은 코드가 실제로 실행되는 런타임 환경의 흐름을 직접적으로 들여다보는 분석 과정의 일부입니다 [2, 4].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 객체의 수명 주기나 시스템 내부 논리가 실행 중에 어떻게 동작하고 반응하는지에 대한 동적 특성.
|
||||
|
||||
### Deeper Research Questions
|
||||
- 코드베이스 온보딩 시 호출 스택을 추적하다 길을 잃는 문제를 최소화하기 위한 타임박스(Timebox)의 적정 기준 시간은 실무적으로 어떻게 산정하는가?
|
||||
- 하향식 접근법으로 호출 스택을 관찰할 때, 비동기 프로그래밍 구조나 이벤트 주도 아키텍처(Event-Driven Architecture)로 인해 끊어지는 스택 트레이스는 어떻게 추적해야 하는가?
|
||||
- 호출 스택 정보와 동적 런타임 프로파일링 도구를 결합하여 레거시 시스템의 복잡성과 기술적 부채를 시각화하는 효율적인 방법은 무엇인가?
|
||||
- 중단점을 설정하여 실시간 관찰을 할 수 없는 운영 환경(Production)에서 발생하는 버그의 호출 스택을 어떻게 분석하고 로컬 환경에 효과적으로 재현할 수 있는가?
|
||||
- 호출 스택을 타고 내려가며 비즈니스 로직의 오케스트레이션을 확인할 때, 계층형 아키텍처(Layered Architecture)의 엄격한 의존성 규칙 위반을 어떻게 식별해 낼 수 있는가?
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 새로운 기능을 구현하거나 버그를 수정할 때, 디버깅 도구의 중단점을 활용해 호출 스택을 확인하며 내가 작성한 코드가 올바른 컨텍스트에서 실행되는지 검증합니다 [1, 2, 4].
|
||||
- **System Design:** 하향식 관점에서 진입점부터 최종 호출지까지의 스택 흐름을 분석하여, 시스템의 비즈니스 로직 오케스트레이션이 아키텍처 원칙에 맞게 동작하는지 확인합니다 [3].
|
||||
- **Operation / Maintenance:** 운영 중 발생한 버그를 재현하고 이를 유도한 호출 스택을 역추적하여, 시스템 내부 논리와 데이터 처리 구조의 근본적인 결함을 신속하게 탐색합니다 [1, 4].
|
||||
- **Learning Path:** 낯선 대규모 프로젝트에 합류했을 때 처음부터 전체 코드를 무작정 읽기보다는, 작은 버그 수정 티켓을 잡아 호출 스택을 파헤치는 타임박스 경험을 통해 시스템 이해도를 점진적으로 넓혀갈 수 있습니다 [1].
|
||||
- **My Project Relevance:** 복잡한 코드의 런타임 데이터 흐름을 추적하거나 이해하기 어려운 버그를 디버깅할 때, 호출 스택을 적극적으로 활용하여 코드베이스 파악 및 온보딩 속도를 비약적으로 높이는 데 직결됩니다 [1, 2].
|
||||
|
||||
### Adjacent Topics
|
||||
- [[시스템 오케스트레이션 (System Orchestration)]]
|
||||
- 확장 방향: 호출 스택을 통해 파악한 개별 서비스나 함수들의 런타임 흐름이 모여, 더 큰 단위의 비즈니스 요구사항을 어떻게 조율하고 완성해내는지 상위 아키텍처 관점으로 이해를 확장합니다.
|
||||
- [[정적 코드 분석 (Static Code Analysis)]]
|
||||
- 확장 방향: 호출 스택을 확인하는 동적 런타임 분석과 대비되는 개념으로, 코드를 실행하지 않고 구문 트리나 제어 흐름을 파악하여 구조적 위험성을 찾아내는 기법을 학습합니다.
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
|
||||
@@ -4,113 +4,169 @@ title: Call Stack Analysis
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-DEV-CALL-STACK-ANALYSIS, 호출 스택, Call Stack, 스택 트레이스, 런타임 추적, 디버깅 흐름]
|
||||
aliases: [Call Stack, Stack Trace Analysis, Flame Graph, Profiling Stack]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 1.0
|
||||
tags: [Debugging, Runtime, Analysis, Architecture, Onboarding]
|
||||
raw_sources: [Datacollector_Export_2026-05-02]
|
||||
last_reinforced: 2026-05-02
|
||||
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: unspecified
|
||||
framework: unspecified
|
||||
language: Polyglot
|
||||
framework: perf/eBPF/pprof
|
||||
---
|
||||
|
||||
# [[호출 스택 분석과 런타임 흐름 추적 (Call Stack Analysis)]]
|
||||
# Call Stack Analysis
|
||||
|
||||
## 1. 개요
|
||||
호출 스택(Call Stack)은 프로그램 실행 중 현재 활성화된 서브루틴(함수, 메서드 등)의 정보를 저장하는 스택 구조의 메모리 영역이다. 개발자에게 호출 스택은 코드가 실제로 실행되는 런타임의 동적인 흐름을 이해하고, 특정 지점에 도달하기까지의 인과 관계를 추적하는 가장 강력한 디버깅 및 분석 도구로 기능한다.
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 2. 분석 전략 및 기법
|
||||
- **하향식 추적 (Top-down Trace)**: 애플리케이션의 최상위 진입점(Entry Point)에서 시작하여 호출 스택을 따라 깊숙한 내부 구현체로 진입하며 시스템의 오케스트레이션 로직 파악.
|
||||
- **상향식 분석 (Bottom-up Analysis)**: 에러가 발생한 최종 지점에서 시작하여 호출 스택을 거슬러 올라가며, 어떤 상위 계층의 데이터가 문제를 유발했는지 근본 원인(Root Cause) 식별.
|
||||
- **실시간 관찰 (Live Debugging)**: 디버거의 중단점(Breakpoints)을 활용하여 특정 시점의 호출 스택과 메모리 상태, 변수 값을 직접 확인하며 정적 코드 독해의 한계 극복.
|
||||
- **타임박싱 (Timeboxing)**: 대규모 시스템에서 스택의 깊이가 너무 깊어질 경우 길을 잃을 위험이 크므로, 추적 시간을 제한하고 필요시 동료의 도움을 받는 효율적인 탐색 전략 병행.
|
||||
## 매 핵심
|
||||
|
||||
## 3. 엔지니어링 가치
|
||||
- **복잡성 해독**: 정적으로는 파악하기 어려운 비동기 호출, 콜백 구조, 다형성을 통한 동적 바인딩 등의 실제 실행 경로를 명확히 가시화.
|
||||
- **온보딩 가속화**: 낯선 코드베이스에서 작은 버그를 재현하고 스택을 추적해 보는 과정을 통해, 시스템의 전반적인 레이어 구조와 책임 분산 방식 실전 학습.
|
||||
- **성능 및 안정성 진단**: 불필요하게 깊은 재귀 호출이나 비효율적인 호출 연쇄를 발견하여 아키텍처적 개선 지점 도출.
|
||||
### 매 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.
|
||||
|
||||
## 4. 트레이드오프 및 주의사항
|
||||
- **비동기 흐름의 단절**: 이벤트 루프나 비동기 프라미스 구조에서는 전통적인 호출 스택이 끊어질 수 있다. 이 경우 비동기 스택 추적(Async Stack Traces) 기능을 지원하는 도구 활용 필요.
|
||||
- **성능 오버헤드**: 상세한 스택 트레이스를 지속적으로 생성하고 로깅하는 것은 런타임 성능에 영향을 줄 수 있으므로, 운영 환경에서는 임계치 조절 필요.
|
||||
- **인지 부하**: 너무 방대한 호출 스택은 오히려 개발자를 혼란에 빠뜨릴 수 있다. 비즈니스 로직과 무관한 프레임워크 내부 스택은 필터링하여 핵심 흐름에 집중.
|
||||
### 매 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 통합.
|
||||
|
||||
## 5. 지식 연결 (Related)
|
||||
- [[Intentional_Failure_Induction]]: 호출 스택을 얻기 위해 고의로 에러를 유발하는 기법.
|
||||
- [[Testability_Architecture]]: 호출 스택 추적이 용이하도록 명확한 계층 구조를 설계하는 원칙.
|
||||
- [[Logs_and_Error_Messages]]: 스택 트레이스가 기록되는 주요 매체 및 분석 단서.
|
||||
### 매 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 사냥.
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
- **정보 상태**: 검증 완료 (Verified)
|
||||
- **출처 신뢰도**: A
|
||||
- **검토 이유**: 시스템의 실행 흐름을 정밀하게 분석하고 런타임 결함을 신속하게 진단하기 위한 기술적 분석 표준 정립.
|
||||
### 매 응용
|
||||
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.
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
## 💻 패턴
|
||||
|
||||
> *(TODO: 한 문장으로 핵심 통찰을 작성. "X는 Y 조건에서 Z 효과를 낸다" 구조 권장.)*
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
|
||||
**추출된 패턴:**
|
||||
> *(TODO)*
|
||||
|
||||
**세부 내용:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
|
||||
- **과거 데이터와의 충돌:** 없음
|
||||
- **정책 변화:** 없음
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
|
||||
- **Parent:** [[10_Wiki/Topics]]
|
||||
- **Related:** *(TODO: 최소 2개)*
|
||||
- **Opposite / Trade-off:** *(TODO)*
|
||||
- **Raw Source:** 직접 입력
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### eBPF profile (BCC)
|
||||
```bash
|
||||
profile-bpfcc -F 99 -f 30 > out.folded
|
||||
flamegraph.pl out.folded > flame.svg
|
||||
# advantages: lower overhead, kernel+user merged
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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
|
||||
- 부모: [[Performance_Engineering]] · [[Observability]]
|
||||
- 변형: [[Flame_Graph]] · [[Off_CPU_Profile]] · [[Differential_Flame_Graph]]
|
||||
- 응용: [[Continuous_Profiling]] · [[Performance_Regression_Detection]]
|
||||
- Adjacent: [[eBPF]] · [[perf]] · [[pprof]] · [[Brendan_Gregg]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -2,125 +2,223 @@
|
||||
id: wiki-2026-0508-characterization-tests-특성화-테스트
|
||||
title: Characterization Tests (특성화 테스트)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [Golden Master Tests, Approval Tests, Pinning Tests, Snapshot Tests]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [uncategorized]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [testing, legacy-code, feathers, refactoring]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript-python
|
||||
framework: jest-pytest-approvaltests
|
||||
---
|
||||
|
||||
# [[Characterization Tests (특성화 테스트)]]
|
||||
# Characterization Tests (특성화 테스트)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
캐릭터리제이션 테스트(특성화 테스트)는 코드가 '무엇을 해야 하는지'가 아니라 '실제로 무엇을 하는지' 현재의 동작을 그대로 캡처하고 기록하는 테스트 기법이다 [1, 2]. 주로 테스트가 없는 난해한 레거시 코드(Legacy Code)에 빠르고 효과적으로 안전망(Safety net)을 구축하여, 코드를 안전하게 리팩토링할 수 있도록 돕는 데 사용된다 [1, 2].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **현재 동작의 캡처 (Capturing Current Behavior):**
|
||||
포괄적인 단위 테스트(Comprehensive Unit Tests)를 작성하여 기대하는 결과를 검증하는 대신, 기존 코드의 현재 동작 상태에 대한 스냅샷(Snapshot)을 찍어 특성화한다 [1].
|
||||
* **실제 동작의 우선성:**
|
||||
대부분의 레거시 시스템에서는 코드가 '어떻게 동작해야 하는가(what it should do)'보다 '실제로 어떻게 동작하고 있는가(what it actually does)'가 훨씬 더 중요하게 취급된다 [2]. 이 테스트는 이러한 실제 동작이 변경되지 않았음을 강력하게 보장한다 [2].
|
||||
* **실무적 대체 용어:**
|
||||
현업 및 개발 생태계에서는 이 기법을 승인 테스트(Approval Testing), 스냅샷 테스트(Snapshot Testing) 또는 골든 마스터(Golden Master)라는 이름으로도 부른다 [2, 3].
|
||||
* **리팩토링을 위한 빠르고 든든한 안전망:**
|
||||
테스트가 없고 코드를 이해하기조차 어려운 상황에서, 개발자는 이 테스트를 통해 레거시 코드를 빠르게 커버하고 리팩토링을 시작하기 위한 1차적인 안전망을 확보할 수 있다 [2].
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
* **의도된 로직의 올바름을 검증하지 않음:** 캐릭터리제이션 테스트는 코드의 현재 동작을 그대로 기록(Snapshot)하여 그것이 변하지 않았는지를 확인하는 데 목적이 있다 [1, 2]. 즉, 코드가 논리적으로 올바르게 작성되었는지 검증하는 것이 아니며, 기존 코드에 버그가 있다면 그 버그가 포함된 동작 자체를 정상 기준으로 삼아 캡처하게 된다는 제약이 있다 [2].
|
||||
* **단위 테스트의 완벽한 대체재가 아님:** 이 테스트는 코드를 이해하기 어렵거나 시간이 부족할 때 안전하게 리팩토링을 수행하기 위한 수단(Safety net)으로 사용된다 [1, 2]. 시스템의 개별 컴포넌트를 설계적 관점에서 고립시켜 검증하는 전통적인 포괄적 단위 테스트(Unit Tests)를 완전히 대체하는 것은 아니다 [1].
|
||||
* 그 외 캐릭터리제이션 테스트의 구체적인 부작용이나 최적화 시 발생할 수 있는 기술적 반대 급부(Trade-off)에 대해서는 **소스에 관련 정보가 부족합니다.** (단지 도입을 위한 휴리스틱 등이 목차 수준에서만 언급됨 [4]).
|
||||
### 매 정의 (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."
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
### 매 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 |
|
||||
|
||||
#### [레거시 코드 제어 (Legacy Code Control)]
|
||||
- [[Legacy Code (레거시 코드)]]
|
||||
- 연결 이유: 캐릭터리제이션 테스트는 본질적으로 '테스트가 없는 코드'인 레거시 코드를 안전하게 다루고 리팩토링하기 위해 고안된 기법이다 [2, 5].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 피드백(자동화된 테스트) 없이 코드를 변경하는 것이 왜 위험하며, 리팩토링에 앞서 안전망 구축이 왜 필수적인지 그 당위성을 깊이 이해할 수 있다.
|
||||
### 매 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.
|
||||
|
||||
- [[Seam (접점)]]
|
||||
- 연결 이유: 레거시 코드에 캐릭터리제이션 테스트를 적용하려면, 소스 코드를 직접 편집하지 않고도 프로그램의 동작을 변경하거나 의존성을 끊을 수 있는 '접점(Seam)'을 먼저 식별해야 한다 [6, 7].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 테스트 불가능해 보이는 복잡한 의존성을 가진 코드를 어떻게 테스트 가능한 상태로 격리하는지 원리를 파악할 수 있다.
|
||||
### 매 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.
|
||||
|
||||
#### [유사 테스트 기법 (Similar Testing Techniques)]
|
||||
- [[Approval Testing / Snapshot Testing (승인/스냅샷 테스트)]]
|
||||
- 연결 이유: 캐릭터리제이션 테스트와 동일한 목적(기존 동작의 보존)과 방식(결과값 캡처 및 비교)을 공유하는 실무적 동의어이다 [2, 3].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 소프트웨어의 현재 동작을 스냅샷으로 저장하고, 변경 후의 상태와 비교하는 구체적인 구현 패턴 및 생태계의 도구들을 이해할 수 있다.
|
||||
### 매 응용
|
||||
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).
|
||||
|
||||
### Deeper Research Questions
|
||||
- 캐릭터리제이션 테스트(Characterization Tests)와 일반적인 단위 테스트(Unit Tests)의 본질적인 목적과 구현 방식의 가장 큰 차이는 무엇인가?
|
||||
- 레거시 코드 환경에서 캐릭터리제이션 테스트를 적용하기 위해 의존성을 끊고 접점(Seam)을 식별하는 구체적인 과정은 어떻게 진행되는가?
|
||||
- 시스템의 '실제 동작(what it actually does)'을 캡처할 때, 기존 코드에 내재된 버그나 비효율성은 어떻게 취급하고 이후에 어떻게 수정해야 하는가?
|
||||
- 승인 테스트(Approval Testing)나 스냅샷 테스트(Snapshot Testing) 도구를 실제 복잡하고 거대한 레거시 시스템에 적용할 때 발생하는 한계점은 무엇인가?
|
||||
- 마이클 페더스(Michael Feathers)가 제안한 '캐릭터리제이션 테스트 작성을 위한 휴리스틱(Heuristic)'은 구체적으로 어떤 기준과 절차로 구성되어 있는가?
|
||||
## 💻 패턴
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 복잡하고 이해하기 힘든 레거시 시스템의 함수나 클래스의 현재 반환값(상태)을 스냅샷 파일로 저장하고, 리팩토링을 수행한 뒤 변경 후의 결과가 저장된 스냅샷과 완벽히 일치하는지 비교하는 테스트 코드를 작성한다 [1, 2].
|
||||
- **System Design:** 강하게 결합되어 테스트가 불가능한 시스템에 대해 1차적인 캐릭터리제이션 안전망을 씌운 뒤, 객체 지향적이고 독립적인 모듈로 점진적인 아키텍처 재설계(Refactoring)를 진행하는 발판으로 사용한다 [2, 6].
|
||||
- **Operation / Maintenance:** 기존 기능의 변경 없이 버그 수정이나 성능 개선(유지보수)을 수행해야 할 때, 기존 시스템의 '실제 동작'이 훼손되지 않았음(회귀 버그가 발생하지 않았음)을 빠르고 확실하게 보장하는 용도로 활용한다 [2, 8].
|
||||
- **Learning Path:** 단위 테스트 작성법 학습 -> 레거시 코드의 문제점(의존성) 이해 -> 접점(Seam) 식별을 통한 의존성 분리 -> 캐릭터리제이션 테스트를 통한 안전망 구축 -> 본격적인 구조적 리팩토링 기법 적용의 순서로 학습한다 [1, 8].
|
||||
- **My Project Relevance:** 마감 기한이 촉박하고 기존 코드가 복잡하여 정규 단위 테스트를 면밀히 작성할 수 없는 프로젝트 모듈에서, 빠르고 신뢰할 수 있는 보호벽을 쳐 놓고 기능 추가나 코드 정리를 수행하고자 할 때 적용할 수 있다 [1, 2].
|
||||
### Feathers procedure (TypeScript + Jest)
|
||||
```typescript
|
||||
import { calculateInvoice } from './legacy';
|
||||
|
||||
### Adjacent Topics
|
||||
- [[Sprout & Wrap Techniques (스프라우트 & 랩 기법)]]
|
||||
- 확장 방향: 레거시 코드에 캐릭터리제이션 테스트조차 작성할 시간이 부족하거나 클래스가 너무 거대할 때, 기존 코드를 직접 수정하지 않고 완전히 분리된 위치에 새로운 테스트 가능한 코드를 싹 틔우거나(Sprout), 기존 메서드를 감싸서(Wrap) 새 로직을 안전하게 추가하는 우회 기법으로 확장이 가능하다 [9-11].
|
||||
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',
|
||||
});
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-03*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
// 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,
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Jest snapshot
|
||||
```typescript
|
||||
import { renderInvoiceHtml } from './render';
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
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.
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### ApprovalTests (Python)
|
||||
```python
|
||||
from approvaltests import verify
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
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.
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### Golden master with multiple inputs
|
||||
```python
|
||||
import json
|
||||
from pathlib import Path
|
||||
from legacy_pricing import compute_price
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
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
|
||||
- 부모: [[Software Testing]] · [[Legacy Code]]
|
||||
- 변형: [[Snapshot Testing]] · [[Approval Tests]] · [[Golden Master]]
|
||||
- 응용: [[Refactoring]] · [[Visual Regression]] · [[Migration Testing]]
|
||||
- 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 패턴 |
|
||||
|
||||
@@ -2,127 +2,179 @@
|
||||
id: wiki-2026-0508-choreography
|
||||
title: Choreography
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-8AE6A842]
|
||||
aliases: [Event Choreography, Saga Choreography]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [choreography, broker-topology, event-driven-architecture, saga-pattern, mediator-topology, architecture-principles]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [microservices, distributed-systems, events, saga]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-02
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: kafka-temporal
|
||||
---
|
||||
|
||||
# [[Choreography]]
|
||||
# Choreography
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
Choreography(안무)는 중앙 집중식 조정자(Central Coordinator)나 오케스트레이터 없이, 시스템의 구성 요소들이 자율적으로 서로 이벤트를 주고받으며 전체 워크플로우 흐름을 제어하는 방식입니다 [1, 2]. 주로 이벤트 기반 아키텍처(Event-Driven Architecture)의 브로커 토폴로지(Broker Topology)에서 활용되며, 마이크로서비스와 같은 분산 시스템 환경에서 서비스 간의 메시지 흐름을 안정적으로 관리하기 위해 Saga 패턴과 함께 사용되기도 합니다 [2, 3]. 각 컴포넌트가 독립적으로 반응하므로 결합도가 낮고 확장성과 반응성이 매우 뛰어나다는 특징을 가집니다 [1, 2].
|
||||
## 매 한 줄
|
||||
> **"매 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 의 핵심 선택지.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **자율적인 이벤트 흐름 제어**: Choreography 방식에서는 이벤트를 관리하고 통제하는 중앙의 이벤트 메디에이터(Mediator)가 존재하지 않습니다 [1, 2]. 대신, 구성 요소(서비스)가 시스템 전체에 이벤트를 브로드캐스트하면, 다른 구성 요소들이 이를 자율적으로 감지하여 처리하거나 무시하는 방식으로 동작합니다 [1].
|
||||
* **브로커 토폴로지(Broker Topology)와의 결합**: 이벤트 기반 아키텍처의 흐름 제어 방식 중 하나인 브로커 토폴로지의 근본적인 동작 원리가 바로 이 안무(Choreography) 방식입니다 [2]. 복잡한 중앙 오케스트레이션 없이, 다수의 서비스 간에 메시지를 발행 및 구독하는 과정을 통해 전체 워크플로우를 완수합니다 [1, 3].
|
||||
* **높은 비결합성(Decoupling) 및 시스템 확장성**: 중앙 통제가 없기 때문에 특정 컴포넌트가 전체 비즈니스 트랜잭션의 상태를 단독으로 소유하거나 알지 못합니다 [1]. 이로 인해 구성 요소 간의 결합도가 매우 낮게(Highly decoupled) 유지되며, 독립적인 컴포넌트의 확장성, 시스템의 빠른 응답성, 그리고 개별 모듈의 내결함성(Fault tolerance)이 크게 향상됩니다 [1, 2].
|
||||
* **Saga 패턴을 통한 분산 트랜잭션 관리**: 여러 서비스에 걸쳐 있는 비즈니스 프로세스에서 일관된 결과를 얻기 위해 Choreography 방식은 Saga 패턴과 결합하여(Choreographed Saga) 분산 명령과 메시지 흐름을 관리하는 데 사용됩니다 [3, 4].
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
* **에러 파악 및 복구의 어려움**: 중앙에서 워크플로우를 제어하지 않으므로 전체적인 프로세스 흐름을 한눈에 파악하기 어렵습니다. 또한 오류가 발생했을 때 이를 추적하고 자동으로 복구하는 메커니즘을 구현하는 것이 매우 까다롭습니다 [2, 5].
|
||||
* **분산 트랜잭션의 내재적 위험성**: 시스템에 실패한 작업을 재시작하거나 재실행(Replaying)하는 메커니즘이 기본적으로 내장되어 있지 않기 때문에 분산 트랜잭션 관리에 위험이 따릅니다 [1]. 따라서 오류 처리를 위한 수동 개입(Manual intervention) 전략을 반드시 신중하게 고려해야 합니다 [1].
|
||||
* **데이터 일관성(Data Inconsistency) 문제**: 컴포넌트들이 비동기적으로 자율 동작하는 구조 특성상, 일시적으로 시스템 내 데이터 불일치가 발생할 수 있는 주요 원인이 되기도 합니다 [1].
|
||||
### 매 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 |
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
### 매 패턴 종류
|
||||
- **Event-carried state transfer**: event 가 모든 필요 data 포함.
|
||||
- **Event notification**: event 는 trigger only, state 는 query.
|
||||
- **Saga choreography**: distributed transaction 의 compensating events.
|
||||
|
||||
#### [아키텍처 토폴로지 및 패턴]
|
||||
- [[Broker Topology]]
|
||||
- 연결 이유: Choreography 방식이 근간을 이루고 있는 이벤트 기반 아키텍처의 핵심 토폴로지입니다 [1, 2].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 중앙 조정자 없이 이벤트 채널(큐 등)과 프로세서만으로 이벤트를 브로드캐스팅하며 동작하는 분산 시스템의 구조적 원리를 이해할 수 있습니다 [1, 6].
|
||||
### 매 응용
|
||||
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).
|
||||
|
||||
- [[Event-Driven Architecture]]
|
||||
- 연결 이유: Choreography 방식이 구현되는 상위 아키텍처 패러다임으로, 비동기 이벤트를 통해 시스템이 상호작용합니다 [7, 8].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 상태 변화(이벤트)에 실시간으로 반응하며 확장성이 극대화되는 시스템 전체의 패러다임과 설계 방식을 파악할 수 있습니다 [7, 9].
|
||||
## 💻 패턴
|
||||
|
||||
- [[Saga Pattern]]
|
||||
- 연결 이유: Choreography 방식을 통해 여러 마이크로서비스 간의 분산 트랜잭션 및 메시지 흐름을 관리하기 위해 주로 사용되는 협업 패턴입니다 [3, 10].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 각 서비스가 로컬 트랜잭션을 수행하고, 이벤트를 발행하여 다음 단계를 트리거하는 방식(Eventual Consistency)으로 데이터 일관성을 관리하는 기술을 알 수 있습니다 [8, 10].
|
||||
### 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;
|
||||
}
|
||||
|
||||
#### [비교 및 대조 개념]
|
||||
- [[Mediator Topology]] (또는 Orchestration)
|
||||
- 연결 이유: Choreography의 대척점에 있는 방식으로, 중앙의 이벤트 메디에이터가 워크플로우를 오케스트레이션(Orchestration)하여 통제합니다 [1, 2].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 중앙 제어의 부재(Choreography)가 주는 이점(확장성)과 중앙 제어의 존재(Orchestration)가 주는 이점(강력한 에러 처리 및 트랜잭션 복구) 간의 트레이드오프를 명확히 비교할 수 있습니다 [1, 2].
|
||||
|
||||
### Deeper Research Questions
|
||||
- Choreography 방식에서 분산 시스템 간 트랜잭션 실패가 발생했을 때, 데이터의 최종 일관성(Eventual Consistency)을 효과적으로 복구하기 위한 보상 트랜잭션(Compensating Transaction)은 어떻게 설계해야 하는가?
|
||||
- 에러 발생 시 전체 워크플로우를 파악하기 어려운 Choreography의 치명적인 단점을 보완하기 위해, 분산 트레이싱(Distributed Tracing) 및 관측성(Observability) 도구를 어떻게 적용해야 하는가?
|
||||
- 중앙 집중형인 Orchestration(Mediator Topology) 방식과 비교하여 Choreography 방식이 구조적으로 더 적합한 특정 비즈니스 도메인이나 시스템 규모(트래픽, 서비스 수 등)는 무엇인가?
|
||||
- 마이크로서비스 생태계 내에서 Choreography 기반의 통신을 구현할 때, 이벤트 버전 관리(Event schema evolution)와 하위 호환성은 어떤 전략으로 유지해야 하는가?
|
||||
- 중앙 조정자가 없는 상태에서 비즈니스 워크플로우의 진행 상태와 이벤트 병목 현상을 실시간으로 모니터링할 수 있는 방법론은 무엇인가?
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 마이크로서비스 환경에서 각 서비스가 메시징 브로커(예: Kafka, RabbitMQ)를 통해 이벤트를 발행/구독(Publish-Subscribe)하게 함으로써, 다른 서비스의 비즈니스 로직이나 내부 구현과 철저히 분리되도록 코드를 작성합니다.
|
||||
- **System Design:** 트래픽 변동이 심하고 고도의 확장성이 최우선으로 요구되나 중앙 조정자로 인한 성능 병목(Bottleneck)이 우려될 때, 시스템 전체를 브로드캐스트 기반의 Choreography 워크플로우로 설계합니다.
|
||||
- **Operation / Maintenance:** 개별 마이크로서비스의 오류 격리(Fault isolation)에는 유리하지만 비즈니스 흐름 전체의 에러 파악은 매우 어렵습니다. 따라서 모든 이벤트에 상관관계 ID(Correlation ID)를 부여하여 분산된 구성 요소 전반의 흐름을 추적(Trace)할 수 있는 인프라 운영이 필수적입니다.
|
||||
- **Learning Path:** 이벤트 기반 아키텍처(EDA)의 비동기 메시징 기본 개념 학습 → 브로커(Broker)와 메디에이터(Mediator) 패턴의 장단점 비교 → 마이크로서비스 환경에서 Saga 패턴을 통한 Choreography 구현 및 에러 처리 메커니즘 학습으로 이어집니다.
|
||||
- **My Project Relevance:** 현재 진행하는 분산 애플리케이션이나 마이크로서비스 도입 시, 서비스 간 결합도를 최소화하여 자율성과 성능을 극대화할 것인지(Choreography), 에러 제어와 워크플로우 가시성을 위해 다소의 결합도를 감수할 것인지(Mediator/Orchestration)를 결정하는 전략적 판단 기준이 됩니다.
|
||||
|
||||
### Adjacent Topics
|
||||
- [[CQRS]] (Command Query Responsibility Segregation)
|
||||
- 확장 방향: 분산 아키텍처에서 Choreography 방식으로 이벤트를 구독하여 조회용(Read-only) 데이터베이스(또는 복제본)를 최신 상태로 동기화하는 등, 비동기 시스템의 조회 성능 최적화 기법으로 이해를 넓힐 수 있습니다 [4, 10].
|
||||
- [[Asynchronous Message Passing]]
|
||||
- 확장 방향: Choreography 패턴이 시스템 간 상호작용을 수행하는 핵심 통신 메커니즘으로, 동기적 통신 방식과의 차이점 및 메시지 큐 시스템의 활용 원리로 학습을 확장할 수 있습니다 [11].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
// 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 });
|
||||
});
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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),
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Shipping service
|
||||
```typescript
|
||||
kafka.consume('payment.succeeded', async (evt) => {
|
||||
const shipment = await shippingApi.create({ orderId: evt.orderId });
|
||||
await kafka.produce('shipment.created', { ...shipment });
|
||||
});
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
await processOrder(evt);
|
||||
}
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]]
|
||||
- 변형: [[Saga Pattern]] · [[Pub-Sub]]
|
||||
- 응용: [[Broker Topology]] · [[Event Sourcing]]
|
||||
- Adjacent: [[Orchestration]] · [[CQRS]] · [[Domain Events]]
|
||||
|
||||
## 🤖 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 패턴 |
|
||||
|
||||
@@ -2,95 +2,204 @@
|
||||
id: wiki-2026-0508-code-refactoring
|
||||
title: Code Refactoring
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-AUTO-WIKI-DEV-002]
|
||||
aliases: [Refactoring, Code Improvement, Fowler Refactoring]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [development, refactoring, code-quality, maintainability, technical-debt, p-reinforce]
|
||||
verification_status: applied
|
||||
tags: [refactoring, code-quality, fowler, ide, llm-refactor]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-01
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: Polyglot
|
||||
framework: IDE/AST-based-tools
|
||||
---
|
||||
|
||||
# [[Code Refactoring]]
|
||||
# Code Refactoring
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> "시스템의 겉보기 동작(Behavior)은 유지한 채 내부 구조를 개선하여, 인간에게는 더 읽기 쉽고 시스템에게는 더 변화에 유연하게 만드는 지속적인 코드 정제 작업."
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
리팩토링은 기술 부채를 관리하고 소프트웨어의 생명력을 유지하는 핵심 활동입니다.
|
||||
## 매 핵심
|
||||
|
||||
1. **목적의 분리 (Separation of Concerns)**:
|
||||
* **기능 추가와 리팩토링의 분리**: 새로운 기능 구현과 코드 구조 개선은 반드시 별도의 풀 리퀘스트(PR)로 진행해야 합니다. 섞일 경우 리뷰어의 인지 부하가 급증하고 검증의 정확도가 떨어집니다.
|
||||
* **스타일 수정의 독립성**: 포맷팅이나 명칭 변경과 같은 리팩토링도 기능 변경과 섞지 않는 것이 원칙입니다.
|
||||
2. **안전망 확보**:
|
||||
* 리팩토링의 전제 조건은 견고한 **자동화 테스트**입니다. 로직 개선 후에도 기존 기능이 완벽히 작동함을 증명할 수 있어야 합니다.
|
||||
3. **효율적 전략**:
|
||||
* 대규모 리팩토링은 한 번에 처리하기보다 200~400줄 단위로 잘게 쪼개어(Decomposition) 단계적으로 진행하는 것이 리뷰 품질과 속도 면에서 유리합니다.
|
||||
### 매 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**.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **리뷰 지연의 부작용**: 코드 리뷰 프로세스가 너무 느리면 개발자들은 리팩토링이나 코드 정리를 기피하게 되어 장기적으로 기술 부채가 누적됩니다. 빠른 리뷰 피드백 루프가 건강한 리팩토링 문화를 만듭니다.
|
||||
- **사후 비용 vs 사전 설계**: 개발 완료 후의 리팩토링은 비용이 많이 듭니다. 아키텍처 리뷰를 통한 사전 설계 검토(Shift-Left)가 대규모 리팩토링을 예방하는 가장 효율적인 정책입니다.
|
||||
### 매 disciplines
|
||||
- **Tests first**: 매 refactor 전 green test suite.
|
||||
- **Small steps**: 매 single refactor → run tests → commit.
|
||||
- **No mixing**: 매 behavior change 와 refactor 동시 X.
|
||||
- **Reversibility**: 매 step 별 git revert 가능.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- [[Technical Debt]]: 리팩토링이 상환하고자 하는 비용.
|
||||
- [[Automated Testing]]: 리팩토링을 가능하게 하는 안전망.
|
||||
- [[Code Health]]: 리팩토링의 궁극적인 지향점.
|
||||
- [[Single-purpose PR]]: 리팩토링 시 준수해야 할 PR 정책.
|
||||
- [[Architecture Review]]: 대규모 리팩토링을 예방하는 선제적 대응.
|
||||
---
|
||||
### 매 응용
|
||||
1. **Legacy modernization**: 매 strangler fig + extract.
|
||||
2. **Performance**: 매 inline hot function, extract slow path.
|
||||
3. **Test enabling**: 매 dependency 분리.
|
||||
4. **Onboarding**: 매 confusing code rename + decompose.
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
## 💻 패턴
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
### 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}")
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
# AFTER
|
||||
def print_owing(invoice):
|
||||
print_banner()
|
||||
outstanding = calculate_outstanding(invoice)
|
||||
print_details(invoice, outstanding)
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
def calculate_outstanding(invoice):
|
||||
return sum(o.amount for o in invoice.orders)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
def print_details(invoice, outstanding):
|
||||
print(f"name: {invoice.customer}")
|
||||
print(f"amount: {outstanding}")
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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);
|
||||
}
|
||||
}
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
// 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); } }
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Introduce Parameter Object
|
||||
```python
|
||||
# BEFORE
|
||||
def amount_invoiced(start_date, end_date, customer_id, currency, ...): ...
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
# AFTER
|
||||
@dataclass
|
||||
class InvoiceQuery:
|
||||
range: DateRange
|
||||
customer_id: str
|
||||
currency: str
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
def amount_invoiced(q: InvoiceQuery): ...
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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
|
||||
- 부모: [[Software_Engineering]] · [[Code_Quality]]
|
||||
- 변형: [[Strangler_Fig]] · [[Mikado_Method]]
|
||||
- 응용: [[Legacy_Modernization]] · [[Test_Driven_Development]]
|
||||
- Adjacent: [[Martin_Fowler]] · [[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 |
|
||||
|
||||
@@ -2,132 +2,187 @@
|
||||
id: wiki-2026-0508-combat-timeline-difficulty-scali
|
||||
title: Combat Timeline Difficulty Scaling
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [Combat Difficulty Curve, Encounter Scaling, Dynamic Difficulty Adjustment]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [uncategorized]
|
||||
source_trust_level: B
|
||||
confidence_score: 0.85
|
||||
verification_status: applied
|
||||
tags: [game-design, combat, difficulty, ddа, encounter]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: C#/Python
|
||||
framework: Game-engine-agnostic
|
||||
---
|
||||
|
||||
# 📈 Combat Timeline & Difficulty Scaling (전투 타임라인 및 난이도 조절 시스템)
|
||||
# Combat Timeline Difficulty Scaling
|
||||
|
||||
> **카테고리**: Skybound, Game Design, Software Architecture
|
||||
> **상태**: 🔵 구현 완료 (Implemented)
|
||||
> **최종 업데이트**: 2026-04-22
|
||||
## 매 한 줄
|
||||
> **"매 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 채택.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
## 📌 개요 (Overview)
|
||||
Skybound의 전투 시스템은 단순히 무작위로 적을 생성하는 것을 넘어, 시간 흐름에 따른 긴장감의 완급 조절(Difficulty Curve)과 성능 최적화(Staggered Spawn)를 동시에 달성하는 스크립트 기반 타임라인 시스템을 채택한다.
|
||||
### 매 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.
|
||||
|
||||
## 🛠️ 시스템 아키텍처 (Architecture)
|
||||
### 매 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. 데이터 레이어: `CombatTimeline.ts`
|
||||
- **StageMode**: `STANDARD`(15분) 및 `BLITZ`(8분) 모드 지원.
|
||||
- **DifficultyPhase**: 페이즈별 난이도 배율(`diffMult`), 스폰 간격 배율(`spawnIntervalMult`), 최대 개체수(`maxEnemyCount`) 정의.
|
||||
- **WaveTrigger**: 특정 시간(초)에 발생하는 스크립트 기반 웨이브. 적 유형, 밀도, 스파이크 여부, 화면 흔들림 효과 등을 포함.
|
||||
### 매 응용
|
||||
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%.
|
||||
|
||||
### 2. 제어 레이어: `StageDirectorSystem.ts` (v2.0)
|
||||
- **Time-Based Tick**: 매 프레임 타임라인을 체크하여 현재 페이즈와 활성화될 트리거를 수집.
|
||||
- **Intent Dispatching**: 페이즈 전환(`STAGE_TRANSITION`), 스크립트 스폰(`SCRIPTED_SPAWN`), 보상 발행(`PERMANENT_REWARD`) 등의 인텐트를 엔진에 전달.
|
||||
- **Death Trap Avoidance**: 스파이크(Spike) 구간 진입 30초 전, 플레이어의 레벨업을 돕기 위해 EXP 젬 밀도를 일시적으로 2배 강화(`EXP_DENSITY_BOOST`).
|
||||
## 💻 패턴
|
||||
|
||||
### 3. 실행 레이어: `SpawnerSystem.ts` (v2.0)
|
||||
- **Staggered Spawn Pattern**: 대량의 적 스폰 시 프레임 드랍을 방지하기 위해 `MAX_SWARM_BATCH`(6유닛)를 `SWARM_SPAWN_GAP`(3프레임) 간격으로 분산 생성.
|
||||
- **Hard Cap Protection**: 필드 내 총 적 개체수를 `MAX_ENEMIES_HARD_CAP`(30)으로 제한하여 시스템 부하 방지.
|
||||
### Phase-based encounter timeline
|
||||
```csharp
|
||||
public class BossEncounter : MonoBehaviour {
|
||||
enum Phase { Intro, Build, Climax, Enrage }
|
||||
Phase phase = Phase.Intro;
|
||||
float t;
|
||||
|
||||
## 💡 주요 설계 원칙 (Design Principles)
|
||||
void Update() {
|
||||
t += Time.deltaTime;
|
||||
var hpFrac = boss.HP / boss.MaxHP;
|
||||
var newPhase = phase;
|
||||
|
||||
### 1. 긴장감 곡선 (Tension Curve)
|
||||
- 무작위 스폰은 플레이어에게 지루함을 줄 수 있으므로, 명확한 'Spike' 구간과 'Recovery' 구간을 배치하여 도파민 분비를 최적화함.
|
||||
if (hpFrac < 0.25f) newPhase = Phase.Climax;
|
||||
else if (hpFrac < 0.60f) newPhase = Phase.Build;
|
||||
else if (t > 180f) newPhase = Phase.Enrage;
|
||||
|
||||
### 2. 성능 중심 설계 (Performance-First)
|
||||
- Object Pooling과 Staggered Spawn을 결합하여 모바일/웹 환경에서도 부드러운 전투 환경 제공.
|
||||
|
||||
### 3. UX 연속성 (UX Continuity)
|
||||
- 보스 처치 후 단순히 게임이 끝나는 것이 아니라, 영구 성장 시스템(`PERMANENT_REWARD`)과 연계하여 다음 플레이로의 동기를 부여함.
|
||||
|
||||
---
|
||||
**승인인**: AI 개발부장 코다리 🫡
|
||||
**관련 코드**: `StageDirectorSystem.ts`, `SpawnerSystem.ts`, `CombatTimeline.ts`
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts (Auto-Linked)
|
||||
* [[Architecture]]
|
||||
* [[Principles]]
|
||||
* [[Software_Architecture]]
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
|
||||
> *(TODO: 한 문장으로 핵심 통찰을 작성. "X는 Y 조건에서 Z 효과를 낸다" 구조 권장.)*
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
|
||||
**추출된 패턴:**
|
||||
> *(TODO)*
|
||||
|
||||
**세부 내용:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
|
||||
- **과거 데이터와의 충돌:** 없음
|
||||
- **정책 변화:** 없음
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
if (newPhase != phase) { OnPhaseEnter(newPhase); phase = newPhase; }
|
||||
ApplyPhaseModifiers(phase);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
```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),
|
||||
};
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
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)
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
def apply(self, enemy):
|
||||
enemy.hp *= self.scale
|
||||
enemy.dmg *= math.sqrt(self.scale) # damage scales softer
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]] · [[Boss_Phase_Design]]
|
||||
- 응용: [[Roguelike_Design]] · [[MMO_Raid_Design]] · [[Soulslike]]
|
||||
- Adjacent: [[Player_Telemetry]] · [[Game_Balance]] · [[Flow_Theory]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -2,130 +2,148 @@
|
||||
id: wiki-2026-0508-complex-event-processing-cep
|
||||
title: Complex Event Processing (CEP)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-CD492DA6]
|
||||
aliases: [CEP, Event Stream Processing, 복합 이벤트 처리]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [complex-event-processing-(cep), event-driven-architecture, simple-event-processing, event-stream-processing, internet-of-things-(iot), architecture-principles]
|
||||
confidence_score: 0.88
|
||||
verification_status: applied
|
||||
tags: [cep, streaming, event-driven, flink, esper]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-02
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: java
|
||||
framework: flink
|
||||
---
|
||||
|
||||
# [[Complex Event Processing (CEP)]]
|
||||
# Complex Event Processing (CEP)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
Complex Event Processing (CEP)는 다수의 단순하거나 일상적인 이벤트의 패턴을 분석하여, 보다 복잡한 이벤트가 발생했음을 추론하고 평가하는 이벤트 처리 방식이다 [1]. 인과적, 시간적, 공간적 상관관계를 바탕으로 여러 이벤트의 융합을 파악한 후 적절한 조치를 취하는 데 사용된다 [1]. 시간 창(time window)에 걸친 데이터 집계 및 패턴 매칭 등 실시간으로 고도화된 이벤트 처리가 요구될 때 핵심적인 역할을 한다 [2].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 Core 소스에 기반한 Core Content
|
||||
CEP는 성숙한 이벤트 기반 아키텍처(Event-Driven Architecture)에서 단순 이벤트 처리(Simple event processing), 이벤트 스트림 처리(Event stream processing)와 함께 흔히 사용되는 세 가지 주요 이벤트 처리 스타일 중 하나이다 [3].
|
||||
## 매 핵심
|
||||
|
||||
* **패턴 식별 및 집계:** CEP는 여러 이벤트 유형을 넘나들며 장기간에 걸쳐 발생하는 일련의 이벤트를 분석하여 패턴을 식별한다 [1]. 예를 들어, Azure Stream Analytics와 같은 기술을 사용하여 임베디드 디바이스에서 특정 시간 창(time window) 동안 수집된 판독값을 집계하고, 그 이동 평균이 임계값을 초과할 때 알림을 생성하는 방식으로 활용된다 [4].
|
||||
* **다차원적 상관관계 분석:** 이벤트 간의 상관관계는 인과적(causal), 시간적(temporal), 또는 공간적(spatial)일 수 있다 [1]. 여러 이벤트의 융합을 평가하여 복잡한 이벤트를 추론하며, 이를 위해 정교한 이벤트 해석기(interpreter), 이벤트 패턴 정의 및 매칭, 그리고 상관관계 기법의 적용이 필수적이다 [1].
|
||||
* **주요 활용 목적:** 주로 시스템이나 비즈니스상의 이상 징후(anomalies), 위협(threats), 그리고 기회(opportunities)를 감지하고 이에 즉각적으로 대응하기 위해 사용된다 [1].
|
||||
### 매 개념
|
||||
- **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).
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
* **제약 사항 및 기술적 복잡성:** CEP는 단순한 이벤트 처리와 달리, 복잡한 인과적/시간적/공간적 상관관계를 분석해야 하므로 정교한 이벤트 인터프리터와 이벤트 패턴 정의, 매칭 및 상관관계 분석 기술을 반드시 구현하고 도입해야 한다는 기술적 부담이 존재한다 [1].
|
||||
* **적합성의 한계:** 패턴 매칭이나 시간 단위의 데이터 집계와 같이 고도화된 복잡한 이벤트 처리가 필요한 경우에 적합하며 [2], 이러한 처리 방식이 불필요한 단순한 워크플로우를 가진 시스템에서는 아키텍처의 운영 오버헤드와 복잡성만 가중시킬 위험이 있다 [5].
|
||||
### 매 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.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
### 매 응용
|
||||
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.
|
||||
|
||||
#### [관계 유형 A (아키텍처/기반 기술)]
|
||||
* [[Event-Driven Architecture]]
|
||||
* 연결 이유: CEP는 이벤트 기반 아키텍처(EDA)가 제공하는 환경 내에서 활용되는 핵심적인 이벤트 처리 스타일 중 하나이기 때문이다 [3, 4].
|
||||
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: 이벤트의 생성자(Producer), 소비자(Consumer), 이벤트 채널 등의 분산 통신 인프라가 CEP의 패턴 매칭을 어떻게 뒷받침하는지 전체 구조를 파악할 수 있다 [4, 6].
|
||||
## 💻 패턴
|
||||
|
||||
#### [관계 유형 B (이벤트 처리 유형)]
|
||||
* [[Simple event processing]]
|
||||
* 연결 이유: CEP와 함께 성숙한 이벤트 기반 아키텍처를 구성하는 또 다른 주요 이벤트 처리 방식이기 때문이다 [3].
|
||||
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: 상태 변화에 대한 단순하고 즉각적인 다운스트림 조치(Simple)와, 장기간에 걸친 다수의 이벤트를 분석하는 방식(Complex) 간의 기능적 차이를 비교할 수 있다 [1, 3].
|
||||
* [[Event stream processing]]
|
||||
* 연결 이유: CEP와 병행하여 사용되는 방식으로, 일상적인 이벤트와 중요한 이벤트를 필터링하고 정보 구독자에게 스트리밍하는 역할을 수행한다 [7].
|
||||
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: 실시간 정보의 흐름이 CEP의 복잡한 상관관계 분석을 위한 데이터 파이프라인으로 어떻게 작용할 수 있는지 이해할 수 있다 [4, 7].
|
||||
### 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));
|
||||
|
||||
### Deeper Research Questions
|
||||
* CEP에서 다수의 이벤트를 처리할 때 발생하는 '시간적(temporal)' 및 '공간적(spatial)' 상관관계 매칭은 내부적으로 어떤 방식과 알고리즘을 통해 최적화되는가?
|
||||
* Event-Driven Architecture의 Broker 토폴로지와 Mediator 토폴로지 중 어떤 구조가 CEP의 정교한 패턴 분석 및 에러 핸들링에 더 유리하게 작용하는가?
|
||||
* 비즈니스 이상 징후나 보안 위협을 감지하기 위해 CEP 기술을 적용한 실제 산업 사례에서 아키텍처 구성과 이벤트 페이로드는 어떻게 설계되어 있는가?
|
||||
* Azure Stream Analytics와 같은 스트림 프로세서가 CEP를 구현할 때, 분산 환경에서의 '이벤트 순서 보장(Event ordering)'과 '최종 일관성(Eventual consistency)' 문제는 어떻게 해결되는가?
|
||||
* 이벤트 스트림 처리(Event stream processing)를 거친 대량의 데이터가 CEP 엔진으로 유입될 때 병목 현상을 방지하기 위한 큐(Queue) 관리 전략은 무엇인가?
|
||||
|
||||
### Practical Application Contexts
|
||||
* **Implementation:** Azure Stream Analytics와 같은 기술을 사용하여, 임베디드 디바이스에서 스트리밍되는 이벤트 데이터를 시간 창(time window) 기준으로 집계하고 특정 임계값 초과 여부를 감지하는 로직으로 구현한다 [4].
|
||||
* **System Design:** 다양한 형태의 단순/일상적 이벤트가 교차하고 장기간에 걸쳐 발생하는 시스템 환경에서, 이벤트 간의 인과적, 시간적, 공간적 상관관계를 평가할 수 있도록 설계에 반영해야 한다 [1].
|
||||
* **Operation / Maintenance:** 비즈니스 운영 시나리오에서 발생하는 이상 징후나 보안 위협을 식별하기 위해 정교한 이벤트 패턴을 지속적으로 정의, 매칭 및 최적화하는 유지보수 작업이 요구된다 [1].
|
||||
* **Learning Path:** 이벤트 기반 아키텍처의 기본 통신 원리를 익힌 후, 단일 이벤트 처리(Simple Event Processing)와 스트림 처리(Event Stream Processing)의 개념을 학습하고, 최종적으로 가장 복잡한 상관관계를 다루는 CEP 설계 기법으로 확장하는 경로가 적합하다 [1, 3, 7].
|
||||
* **My Project Relevance:** 실시간으로 발생하는 대규모 트래픽 및 센서 데이터 내에서 특정 행동 패턴이나 이상 징후(예: 금융 사기 탐지, IoT 디바이스 모니터링)를 즉각적으로 감지하고 대응해야 하는 시스템을 기획할 때 직접적으로 도입할 수 있다.
|
||||
|
||||
### Adjacent Topics
|
||||
* [[Internet of Things (IoT)]]
|
||||
* 확장 방향: 임베디드 디바이스 및 센서 등에서 폭발적으로 발생하는 실시간 데이터 스트림을 어떻게 수집하고, CEP를 적용하여 의미 있는 알림으로 변환할 수 있는지 물리적/네트워크 환경 맥락으로 확장이 가능하다 [4].
|
||||
* [[Microservices Architecture (MSA)]]
|
||||
* 확장 방향: 다수의 마이크로서비스 간에 독립적으로 발생하는 이벤트를 조합하여, 분산된 비즈니스 트랜잭션 내에서 발생하는 복잡한 흐름(Saga 패턴 등)을 어떻게 추적하고 패턴화할 수 있는지로 이해를 넓힐 수 있다 [8].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
|
||||
**추출된 패턴:**
|
||||
> *(TODO)*
|
||||
|
||||
**세부 내용:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
CEP.pattern(loginStream.keyBy(e -> e.userId), failedLogins)
|
||||
.select(match -> new Alert(match.get("first").get(0).userId))
|
||||
.addSink(alertSink);
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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)
|
||||
];
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Kafka Streams — sliding window aggregation
|
||||
```java
|
||||
KStream<String, Click> clicks = builder.stream("clicks");
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
clicks.groupByKey()
|
||||
.windowedBy(SlidingWindows.ofTimeDifferenceWithNoGrace(Duration.ofMinutes(5)))
|
||||
.count()
|
||||
.filter((k, count) -> count > 1000)
|
||||
.toStream()
|
||||
.to("anomalies");
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### Flink — session window
|
||||
```java
|
||||
stream.keyBy(e -> e.userId)
|
||||
.window(EventTimeSessionWindows.withGap(Time.minutes(30)))
|
||||
.aggregate(new SessionStats())
|
||||
.addSink(...);
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### Pattern with negation (NO heartbeat in 30s)
|
||||
```java
|
||||
Pattern.<HeartbeatEvent>begin("start")
|
||||
.notFollowedBy("missing")
|
||||
.where(e -> true)
|
||||
.within(Time.seconds(30));
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]]
|
||||
- 변형: [[Event Sourcing]] · [[CQRS]]
|
||||
- 응용: [[Fraud Detection]] · [[IoT Analytics]] · [[Real-Time Analytics]]
|
||||
- Adjacent: [[Apache Flink]] · [[Kafka Streams]] · [[Apache Pulsar]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -2,116 +2,183 @@
|
||||
id: wiki-2026-0508-complexity-theory
|
||||
title: Complexity Theory
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [Complex Systems, Complexity Science]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.85
|
||||
verification_status: applied
|
||||
tags: [complexity, systems, emergence, cynefin]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: agnostic
|
||||
framework: agnostic
|
||||
---
|
||||
|
||||
# [[Complexity Theory|Complexity Theory]]
|
||||
# Complexity Theory
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> "전체는 부분의 합보다 크다: 개별 요소들은 단순해 보이더라도, 이들이 얽히고설켜 상호작용할 때 발생하는 예측 불가능하고 비선형적인 패턴인 '복잡성'을 연구하는 현대 과학의 새로운 눈."
|
||||
## 매 한 줄
|
||||
> **"매 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 |
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
복잡계 이론(Complexity Theory)은 수많은 구성 요소가 서로 밀접하게 연관되어 질서와 혼돈 사이의 독특한 패턴을 만들어내는 시스템을 탐구합니다.
|
||||
### 매 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.
|
||||
|
||||
1. **핵심 개념**:
|
||||
* **Emergence (발현)**: 하위 수준의 단순한 규칙이 상위 수준의 지능적 패턴을 만듦. ([[Collective-Intelligence|Collective-Intelligence]]와 연결)
|
||||
* **Feedback Loops**: 시스템 내의 결과가 다시 원인이 되어 증폭(Positive)되거나 억제(Negative)되는 순환 구조.
|
||||
* **Self-Organization**: 외부의 지휘 없이도 스스로 새로운 질서를 찾아감.
|
||||
* **Non-linearity**: 원인의 작은 변화가 결과의 엄청난 차이를 가져옴 (Butterfly Effect).
|
||||
2. **적용 분야**:
|
||||
* 주식 시장, 기후 변화, 인간 뇌의 신경망, 거대 언어 모델의 창발 등.
|
||||
### 매 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).
|
||||
|
||||
- **추출된 패턴:** 알고리즘의 구체적인 성능을 넘어, 문제 자체가 가진 복잡도를 수치화하여 문제 해결의 전략적 가이드라인을 제시하는 분류 패턴.
|
||||
- **핵심 클래스:**
|
||||
- **P (Polynomial Time):** 효율적으로 해결 가능한 문제 (예: 정렬, 검색).
|
||||
- **NP (Nondeterministic Polynomial Time):** 답을 맞히기는 어렵지만, 주어진 답이 맞는지 확인하기는 쉬운 문제.
|
||||
- **NP-complete:** NP 문제 중 가장 어려운 문제들. 하나만 해결하면 모든 NP 문제를 해결할 수 있음 (예: SAT 문제).
|
||||
- **P vs NP:** 현대 전산학 최대의 난제. "확인이 쉬운 문제는 해결도 쉬운가?"에 대한 질문.
|
||||
- **의의:** 암호학(해독하기 힘든 문제 설계)과 대규모 데이터 처리 알고리즘 설계의 이론적 기반.
|
||||
### 매 응용 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).
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌**: 과거의 과학 정책은 문제를 쪼개서 분석하는 '환원주의 정책'이었으나, 현대 정책은 쪼개면 사라지는 시스템 전체의 성질을 분석하는 '전체론적 복잡계 정책'으로 패러다임을 전환함(RL Update).
|
||||
- **정책 변화(RL Update)**: 거대 AI 모델의 '창발 능력 정책'을 예측하고 제어하기 위해, 단순 성능 측정을 넘어 복잡계 이론을 적용한 '상전이(Phase Transition) 분석 정책'이 도입되고 있음.
|
||||
## 💻 패턴
|
||||
|
||||
---
|
||||
|
||||
- **과거 데이터와의 충돌:** 초기에는 '정답'을 찾는 알고리즘에 집중했으나, 복잡성 이론의 발달로 인해 완벽한 정답 대신 '근사해'를 찾는 휴리스틱의 정당성이 확보됨.
|
||||
- **정책 변화:** Antigravity 프로젝트는 에이전트의 작업 계획 수립 시, 해당 태스크가 NP-hard 수준의 복잡도를 가지는지 판단하여 전수 조사 대신 탐색 위주의 전략을 채택함.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- [[Emergence|Emergence]], [[Systems Thinking|Systems Thinking]], [[Collective-Intelligence|Collective-Intelligence]], Chaos Theory, [[Analysis|Analysis]]
|
||||
- **Modern Tech/Tools**: Agent-based modeling (NetLogo), Network [[Analysis|Analysis]] software,[[_system|system]] dynamics tools.
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- [[Algorithm-Complexity-Big-O|Algorithm-Complexity-Big-O]], [[Combinatorial-Optimization|Combinatorial-Optimization]], Turing-Machine-Foundations, Cryptography
|
||||
- **Raw Source:** 10_Wiki/Topics/AI/Complexity-Theory.md
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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"
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Probe → sense → respond (chaos engineering)
|
||||
```typescript
|
||||
// Netflix Chaos Monkey style — controlled probe of complex system
|
||||
import { ChaosClient } from '@netflix/chaos';
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
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'],
|
||||
});
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Reduce accidental complexity — replace shell with compiled tool
|
||||
```python
|
||||
# Accidental: bash script with 5 sed/awk/jq pipes
|
||||
# Essential: extract user emails from JSON
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
# After: simple, type-checked
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
emails = [
|
||||
user["email"]
|
||||
for user in json.loads(Path("users.json").read_text())
|
||||
if user.get("active")
|
||||
]
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]]
|
||||
- 변형: [[Cynefin]] · [[Promise Theory]] · [[Chaos Engineering]]
|
||||
- 응용: [[Distributed Systems]] · [[Microservices]] · [[SRE]]
|
||||
- Adjacent: [[No Silver Bullet]] · [[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 |
|
||||
|
||||
@@ -2,93 +2,215 @@
|
||||
id: wiki-2026-0508-component-library-architecture
|
||||
title: Component Library Architecture
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [Design System Architecture, UI Library Design]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [uncategorized]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [components, design-system, react, shadcn, radix]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: react-radix-shadcn
|
||||
---
|
||||
|
||||
# [[Component Library Architecture|Component Library Architecture]]
|
||||
# Component Library Architecture
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
컴포넌트 라이브러리 아키텍처는 확장 가능하고 유지보수가 용이한 프론트엔드 애플리케이션을 구축하기 위해 재사용 가능한 UI 컴포넌트를 설계하고 조직화하는 구조적 접근 방식입니다 [1, 2]. 이는 단순한 시각적 요소를 넘어, 컴포넌트 간의 상태 공유, 로직 분리, 아키텍처 패턴을 활용하여 일관성 있는 시스템을 구현하는 것을 목표로 합니다 [3-5]. 잘 설계된 아키텍처는 과도한 상태 전달([[Prop Drilling|Prop Drilling]])을 방지하고 높은 유연성을 제공하여 끊임없이 변화하는 제품 요구사항에 안전하게 대처할 수 있게 합니다 [1, 6-8].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **아토믹 디자인([[Atomic Design|Atomic Design]]) 방법론:** UI를 원자(Atoms), 분자(Molecules), 유기체(Organisms), 템플릿(Templates), 페이지(Pages) 등 5단계의 계층으로 나누어 구조화하는 멘탈 모델입니다 [2, 9, 10]. 이는 디자인 시스템의 일관성을 촉진하지만, 복잡한 비즈니스 로직과 결합될 때는 UI 라이브러리에만 아토믹 구조를 적용하고 애플리케이션 코드는 기능(Feature) 기반으로 분리하여 비즈니스 로직을 캡슐화하는 하이브리드 방식이 주로 권장됩니다 [11, 12].
|
||||
* **복합 컴포넌트([[Compound Components|Compound Components]]) 패턴:** 탭(Tabs)이나 아코디언(Accordion)과 같이 밀접하게 연관된 하위 컴포넌트들이 [[React Context|React Context]]를 통해 암시적으로 상태를 공유하는 패턴입니다 [13-15]. 무수히 많은 Prop을 하위로 계속 넘겨주는 대신, 컴포넌트 소비자가 직접 하위 요소를 조합할 수 있게 하여 레이아웃의 유연성을 극대화하고 API를 깔끔하게 유지합니다 [3, 6, 16, 17].
|
||||
* **헤드리스 컴포넌트([[Headless Components|Headless Components]]):** 접근성, 상태 관리, 비즈니스 로직 등 핵심 기능만 제공하고 시각적인 마크업과 스타일링은 전적으로 개발자에게 위임하는 방식입니다 [18, 19]. 주로 [[Tailwind CSS|Tailwind CSS]]와 결합하여 특정 프레임워크나 디자인 시스템에 종속되지 않는 고도로 맞춤화된 UI 라이브러리를 구축하는 데 사용됩니다 [18, 20].
|
||||
* **오버라이드 패턴([[Overrides Pattern|Overrides Pattern]]):** Uber의 Base Web 시스템 등에서 활용하는 아키텍처로, 컴포넌트 내부의 모든 하위 요소에 접근할 수 있는 식별자를 제공하여 스타일, 속성, 혹은 렌더링되는 컴포넌트 자체를 통째로 교체할 수 있게 합니다 [21-24]. 이를 통해 모든 엣지 케이스마다 새로운 Prop을 추가하여 발생하는 복잡성(Prop soup)을 방지하고 심층적인 커스터마이징을 지원합니다 [23, 24].
|
||||
* **기능 분할 설계([[Feature-Sliced Design|Feature-Sliced Design]], FSD) 및 모노레포:** 거대한 컴포넌트 라이브러리와 다수의 애플리케이션이 공존할 때, 단방향 의존성 흐름을 강제하는 구조입니다 [25-28]. Shared(공유 UI 기본 요소, 디자인 토큰 등), Entities, Features, Widgets, Pages 등의 계층으로 명확히 나누어 모노레포([[Turborepo|Turborepo]], Nx 등) 내에서 안정적이고 격리된 아키텍처를 유지할 수 있게 합니다 [27, 29-31].
|
||||
* **디자인 토큰([[Design Tokens|Design Tokens]]) 계층화:** 색상, 타이포그래피, 간격 등의 원시 값을 추상화하여 기본 토큰(Primitives), 시맨틱 토큰(Semantic), 컴포넌트 토큰(Component Tokens)의 3단계 계층 구조로 관리합니다 [32-35]. 이는 테마(예: 다크 모드)의 동적 전환을 용이하게 하고 라이브러리 전반의 시각적 일관성과 안전한 리팩토링을 보장합니다 [5, 36-38].
|
||||
## 매 핵심
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** [[Atomic Design|Atomic Design]], Compound Components, Headless Components, [[Design Tokens|Design Tokens]], [[Feature-Sliced Design|Feature-Sliced Design]]
|
||||
- **Projects/Contexts:** [[Uber Base Web|Uber Base Web]], Shopify Polaris, React Server Components (RSC, Tailwind CSS vs [[Styled Components|Styled Components]]
|
||||
- **Contradictions/Notes:** 복합 컴포넌트 패턴은 높은 유연성을 주지만 과용하면 소비자에게 너무 많은 통제권을 주어 UX나 접근성 등 구조적 일관성이 깨질 위험이 있습니다. 따라서 레이아웃이 고정되어 있는 단순한 버튼이나 배지 같은 컴포넌트에는 일반적인 Prop 기반 방식이 훨씬 적합합니다 [39-41]. 또한, 컴포넌트 스타일링 구현 시 Styled Components처럼 런타임에 스타일을 주입하는 방식은 동적 스타일링에 강력하나 [[Next.js 15|Next.js 15]]의 App Router 및 RSC 환경에서는 Context 부재로 인한 구조적 제약과 번들 사이즈 등 성능 비용이 따릅니다 [42-45]. 이 때문에 최신 프론트엔드 아키텍처는 정적 CSS 생성이 가능한 Tailwind CSS 또는 Zero-runtime 방식([[vanilla-extract|vanilla-extract]] 등)을 컴포넌트 라이브러리 구축에 더 권장하는 추세입니다 [46-49].
|
||||
### 매 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.
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-26*
|
||||
### 매 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.
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
### 매 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).
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
### 매 응용
|
||||
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).
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
## 💻 패턴
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
### Headless primitive (Radix)
|
||||
```typescript
|
||||
import * as Dialog from '@radix-ui/react-dialog';
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
|
||||
- **과거 데이터와의 충돌:** 없음
|
||||
- **정책 변화:** 없음
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
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>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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';
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
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' },
|
||||
},
|
||||
);
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
type Props = React.ButtonHTMLAttributes<HTMLButtonElement>
|
||||
& VariantProps<typeof buttonVariants>;
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
export function Button({ className, variant, size, ...rest }: Props) {
|
||||
return (
|
||||
<button
|
||||
className={cn(buttonVariants({ variant, size }), className)}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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" }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]]
|
||||
- 변형: [[Compound Components]] · [[Headless UI]]
|
||||
- 응용: [[shadcn-ui]] · [[Radix UI]] · [[Storybook]]
|
||||
- Adjacent: [[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 패턴 |
|
||||
|
||||
@@ -2,111 +2,193 @@
|
||||
id: wiki-2026-0508-component-based-architecture-cba
|
||||
title: Component Based Architecture (CBA)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [CBA, Component-Based Software Engineering, CBSE]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [uncategorized]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [architecture, components, modularity, reuse]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: react-vue-angular
|
||||
---
|
||||
|
||||
# [[Component-Based Architecture (CBA)|Component-Based Architecture (CBA]]
|
||||
# Component Based Architecture (CBA)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
컴포넌트 기반 아키텍처([[Component-Based Architecture|Component-Based Architecture]], CBA)는 독립적이고 모듈화된, 재사용 가능한 소프트웨어 컴포넌트들을 조립하여 애플리케이션을 구축하는 최신 소프트웨어 설계 패러다임입니다[1-3]. 레고 블록을 맞추듯 각 컴포넌트가 특정 기능을 수행하며, 명확히 정의된 인터페이스(API)를 통해 서로 통신합니다[2, 4]. 이 접근 방식은 소프트웨어를 처음부터 개발하는 대신 표준화된 부품을 재사용함으로써 유지보수성을 높이고 개발 속도를 앞당기며 뛰어난 확장성을 제공합니다[4-6].
|
||||
## 매 한 줄
|
||||
> **"매 시스템 = 매 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의 변형.
|
||||
|
||||
## 📖 Core 소스 Content
|
||||
## 매 핵심
|
||||
|
||||
* **컴포넌트의 정의 및 핵심 특징**
|
||||
컴포넌트는 특정 기능을 캡슐화한 재사용 가능하고 독립적인 소프트웨어 단위입니다[7]. 주요 특징으로는 내부 구현과 데이터를 숨기고 필요한 인터페이스만 노출하는 **캡슐화(Encapsulation)**, 여러 언어나 플랫폼 간에도 표준 인터페이스를 통해 통신할 수 있는 **상호 운용성([[Interoperability|InterOperability]])**, 더 큰 시스템을 구성하기 위해 쉽게 플러그인 할 수 있는 **조립성(Composability)**, 그리고 기존 기능을 손상시키지 않고 교체할 수 있는 **대체 가능성(Replaceability)**이 있습니다[8-13].
|
||||
### 매 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).
|
||||
|
||||
* **컴포넌트 기반 개발의 주요 장점**
|
||||
* **개발 속도 향상 및 비용 절감(Faster Time-to-Market):** 기존 컴포넌트를 재사용하여 반복적인 코딩을 방지함으로써 제품 출시를 가속화하고 개발 비용을 낮춥니다[14, 15].
|
||||
* **확장성([[Scalability|Scalability]]):** 트래픽이나 요구사항이 증가할 때 시스템 전체가 아닌 장바구니, 결제 등 특정 컴포넌트만 개별적으로 추가 및 확장할 수 있습니다[16-18].
|
||||
* **유지보수 및 병렬 개발(Maintainability & Collaboration):** 한 컴포넌트의 버그 수정이나 업데이트가 전체 시스템에 미치는 영향을 최소화합니다. 또한, 여러 팀이 서로 다른 컴포넌트(프론트엔드, 백엔드 등)를 동시에 개발할 수 있어 협업이 효율적입니다[14, 16, 18-20].
|
||||
### 매 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 로 명시).
|
||||
|
||||
* **설계 원칙 및 구현 방법**
|
||||
CBA 시스템을 구현할 때는 모듈성, 추상화, 그리고 역할에 따른 '관심사 분리([[_뇌와 팔다리의 분리_ - 관심사의 분리 (Separation of Concerns)|Separation of Concerns]])'를 원칙으로 삼아야 합니다[8, 21]. 시스템의 기능 및 비기능적 요구사항을 분석한 후 도메인 주도 설계(DDD) 등의 기법을 사용해 컴포넌트 경계를 식별합니다[22, 23]. 이후 명확한 API 및 통신 프로토콜(예: REST, gRPC 등)을 설계하고, 각각 독립적으로 개발 및 유닛 테스트를 진행한 뒤, CI/CD 파이프라인을 통해 통합 및 배포를 수행합니다[24-26].
|
||||
### 매 응용
|
||||
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).
|
||||
|
||||
* **구현 시 직면하는 한계 및 과제**
|
||||
* **초기 설계의 복잡성과 통합 오버헤드:** 시스템을 모듈화하고 인터페이스와 의존성을 명확히 정의하는 초기 계획 단계가 까다롭습니다[27-29]. 서로 다른 팀이 개발한 컴포넌트 간의 통신과 매끄러운 통합을 보장하는 것에도 오버헤드가 발생합니다[29, 30].
|
||||
* **성능 저하 및 의존성 관리:** 네트워크 호출이나 프로세스 간 통신 등 컴포넌트 상호작용으로 인해 성능 오버헤드와 지연(Latency)이 발생할 수 있습니다[27, 30, 31]. 또한, 다수의 컴포넌트가 다양한 버전의 라이브러리에 의존할 경우 버전 충돌 및 관리가 매우 복잡해집니다[31, 32].
|
||||
* **보안 및 과잉 엔지니어링 위험:** 각 컴포넌트의 업데이트 주기가 달라 최신화되지 않은 컴포넌트가 전체 시스템의 보안 취약점이 될 수 있으며[33], 유연성만을 추구하다 보면 시스템을 너무 잘게 쪼개어 과잉 엔지니어링(Over-engineering)으로 이어질 위험도 존재합니다[34].
|
||||
## 💻 패턴
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** Microservices Architecture, Service-Oriented Architecture (SOA), Monolithic Architecture, Object-Oriented Architecture
|
||||
- **Projects/Contexts:** React, Angular, Vue.js, PayPal, Spotify, Uber, Walmart
|
||||
- **Contradictions/Notes:** 소스에 따르면, 객체 지향 아키텍처(Object-Oriented Architecture)와 CBA는 원칙을 일부 공유하지만 차이가 있습니다. 객체 지향 아키텍처가 단일 애플리케이션 내에서 데이터와 동작을 캡슐화하는 데 중점을 둔다면, CBA는 여러 시스템 및 애플리케이션 전반에서 상호작용하고 재사용할 수 있는 독립적인 단위 생성을 강조합니다[35]. 또한 기존의 모놀리식 아키텍처(Monolithic Architecture)는 시스템 전체를 하나의 코드베이스로 묶어 확장 및 유지보수가 어렵지만, CBA는 느슨하게 결합된 모듈을 통해 독립적인 배포와 병렬 개발을 가능하게 합니다[36, 37].
|
||||
### React functional component
|
||||
```typescript
|
||||
type ButtonProps = {
|
||||
variant: 'primary' | 'ghost';
|
||||
onClick: () => void;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
|
||||
**추출된 패턴:**
|
||||
> *(TODO)*
|
||||
|
||||
**세부 내용:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
|
||||
- **과거 데이터와의 충돌:** 없음
|
||||
- **정책 변화:** 없음
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
export function Button({ variant, onClick, children }: ButtonProps) {
|
||||
return (
|
||||
<button
|
||||
className={`btn btn-${variant}`}
|
||||
onClick={onClick}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Web Component (framework-agnostic)
|
||||
```typescript
|
||||
class TodoItem extends HTMLElement {
|
||||
static observedAttributes = ['done', 'label'];
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
attributeChangedCallback(name: string, _old: string, value: string) {
|
||||
this.render();
|
||||
}
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
connectedCallback() {
|
||||
this.attachShadow({ mode: 'open' });
|
||||
this.render();
|
||||
}
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
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);
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### Composition over inheritance
|
||||
```typescript
|
||||
// Bad: deep inheritance
|
||||
class AdminButton extends IconButton extends Button { }
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
// 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]] · [[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 패턴 |
|
||||
|
||||
@@ -1,134 +1,32 @@
|
||||
---
|
||||
id: wiki-2026-0508-component-based-architecture
|
||||
title: Component Based Architecture
|
||||
title: Component-Based Architecture
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
canonical_id: self
|
||||
status: duplicate
|
||||
canonical_id: component-based-architecture-cba
|
||||
duplicate_of: "[[Component-Based Architecture (CBA)]]"
|
||||
aliases: []
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, component-architecture, cba]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
---
|
||||
|
||||
# [[Component-Based Architecture|Component-Based Architecture]]
|
||||
# Component-Based Architecture
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
컴포넌트 기반 아키텍처(Component-Based [[Architecture|Architecture]], CBA)는 소프트웨어 시스템을 모듈화되고 독립적이며 재사용 가능한 단위인 '컴포넌트(Component)'로 나누어 구축하는 설계 방법론입니다 [1, 2]. 레고 블록을 조립하듯 각 컴포넌트를 결합하여 크고 복잡한 애플리케이션을 완성할 수 있으며, 이로 인해 개발 속도와 시스템 확장성을 크게 향상시킵니다 [3, 4]. 각 컴포넌트는 내부 로직과 상태를 캡슐화하고 명확히 정의된 인터페이스를 통해서만 상호작용하도록 설계되어, 유지보수성과 팀 간의 협업 효율을 극대화합니다 [5, 6].
|
||||
> **이 문서는 [[Component-Based Architecture (CBA)]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
---
|
||||
## 핵심 요약
|
||||
- 동일 topic, suffix `(CBA)` 명시 version 매 canonical.
|
||||
- Component encapsulation, well-defined interface, composability 핵심.
|
||||
|
||||
컴포넌트 기반 아키텍처는 사용자 인터페이스(UI)를 버튼, 카드, 모달과 같이 어디서나 재사용할 수 있는 독립적인 블록(컴포넌트)으로 나누어 구축하는 설계 방식이다 [1, 2]. 이 접근법은 코드를 한 번만 작성하여 여러 곳에서 사용하게 함으로써 코드 중복을 줄이고 애플리케이션 전체의 UI 일관성을 유지하게 한다 [1]. 모던 웹 개발에서는 디자인 시스템, 캡슐화된 CSS 스타일링, 그리고 반응형 동작을 페이지 단위가 아닌 컴포넌트 단위로 결합하여 대규모 프로젝트의 유지보수성과 확장성을 극대화하는 데 핵심적인 역할을 한다 [3-5].
|
||||
## 🔗 Graph
|
||||
- 부모: [[Component-Based Architecture (CBA)]] (canonical)
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **핵심 원칙 및 특징:**
|
||||
- **모듈성 및 캡슐화 ([[Modularity|Modularity]] & Encapsulation):** 컴포넌트는 특정한 목적을 위해 기능과 데이터를 내부로 숨기고(캡슐화), 외부에 필요한 부분만 잘 정의된 인터페이스로 노출합니다 [5, 7].
|
||||
- **재사용성 및 독립성 (Reusability & Independence):** 한 번 개발된 컴포넌트는 수정 없이 여러 프로젝트에 재사용될 수 있으며, 전체 시스템을 파괴하지 않고 독립적으로 개발, 테스트, 배포 및 교체가 가능합니다 [8-10].
|
||||
- **상호운용성 ([[Interoperability|InterOperability]]):** 서로 다른 기술이나 플랫폼으로 구축된 컴포넌트라도 표준화된 인터페이스와 API를 통해 원활하게 통신하고 결합될 수 있습니다 [6, 11].
|
||||
|
||||
- **아키텍처의 주요 이점:**
|
||||
- **개발 속도 향상 및 비용 절감:** 기존 컴포넌트를 재사용하여 코드를 처음부터 다시 작성하는 수고를 덜어 제품 출시 기간(Time-to-Market)을 앞당깁니다 [12, 13].
|
||||
- **확장성 및 유지보수 용이성:** 전체 시스템을 재구성할 필요 없이 트래픽이나 요구사항에 따라 특정 컴포넌트만 독립적으로 확장하거나 업그레이드할 수 있으며, 버그 수정 시 다른 시스템에 미치는 영향을 최소화합니다 [8, 14-16].
|
||||
- **병렬 개발 (Parallel Development):** 시스템이 명확하게 나뉘어 있어 여러 개발 팀이 동시에 각기 다른 컴포넌트를 분담하여 작업할 수 있습니다 [8, 17].
|
||||
|
||||
- **설계 시 당면 과제 및 단점:**
|
||||
- **복잡성 및 의존성 관리:** 컴포넌트의 수가 증가할수록 컴포넌트 간의 상호작용, 호환성, 버전 관리 등 의존성을 통제하고 통합하는 것이 복잡해집니다 [18-20].
|
||||
- **성능 오버헤드:** 시스템을 지나치게 작은 컴포넌트로 나눌 경우(Over-engineering), 컴포넌트 간 통신(네트워크 호출 및 RPC 등)으로 인한 지연(Latency)과 오버헤드가 발생하여 성능을 저하시킬 수 있습니다 [18, 21, 22].
|
||||
- **보안 관리의 어려움:** 각 컴포넌트가 각기 다른 라이브러리와 업데이트 주기를 가질 경우, 제때 업데이트되지 않은 구식 컴포넌트가 전체 애플리케이션의 보안 취약점이 될 위험이 존재합니다 [23].
|
||||
|
||||
- **실제 활용 및 대안 아키텍처:**
|
||||
- **활용 사례:** 사용자 로그인, 결제 게이트웨이, 쇼핑카트와 같은 모듈이 독립적으로 필요한 전자상거래 플랫폼, CRM 시스템, 모바일 앱 등에서 활발히 사용됩니다 [24, 25]. 프론트엔드 라이브러리(React, Angular, Vue.js)뿐만 아니라 백엔드 플랫폼(Java EE, .NET 등)에서도 이 방식을 채택하며, PayPal, Walmart, Spotify, Uber 등의 기업들이 이 아키텍처를 도입해 확장성을 입증했습니다 [3, 26, 27].
|
||||
- **대안 아키텍처:** 프로젝트의 규모와 팀 구조에 따라 하나의 코드베이스로 구성된 Monolithic Architecture, 서비스 단위로 결합도를 낮춘 Microservices Architecture, 기업 환경에 맞춘 Service-Oriented Architecture (SOA), Layered Architecture 등과 비교되거나 혼합되어 사용됩니다 [28-31].
|
||||
|
||||
---
|
||||
|
||||
* **독립성과 재사용성의 원칙**
|
||||
컴포넌트는 주변의 DOM 구조에 의존하지 않고 독립적으로 기능할 수 있도록 설계되어야 한다 [2, 6]. React, Vue, Angular와 같은 현대 프레임워크는 이러한 컴포넌트 기반 아키텍처를 따르며, 사용자 정의 훅(Hooks)이나 컴포넌트 디렉터리 분리를 통해 프로젝트를 더욱 작고 깔끔하게 유지보수할 수 있도록 돕는다 [1, 6, 7].
|
||||
|
||||
* **컴포넌트 중심의 CSS 스타일링(Scoping) 전략**
|
||||
전통적인 CSS의 가장 큰 취약점인 전역 스코프(Global Scope) 문제를 해결하기 위해 컴포넌트 단위의 스타일링이 발전해 왔다.
|
||||
* **[[BEM (Block Element Modifier)|BEM (Block Element Modifier]]:** BEM의 'Block'은 독립적이고 재사용 가능한 컴포넌트를 의미하며, 스타일이 깊게 중첩되는 것을 방지하고 컴포넌트의 경계를 명확히 하여 모듈화를 이룬다 [2, 6, 8].
|
||||
* **[[CSS Modules|CSS Modules]] & CSS-in-JS:** 모던 자바스크립트 생태계에서는 빌드 타임에 고유한 클래스명을 생성하여 스타일 충돌을 방지하는 CSS Modules나, 컴포넌트 로직과 스타일을 동일한 공간에 위치시키는 CSS-in-JS([[styled-components|styled-components]] 등)를 통해 컴포넌트의 완벽한 캡슐화와 이동성(portability)을 확보한다 [5, 9-13].
|
||||
* **[[Tailwind CSS|Tailwind CSS]]:** 유틸리티 우선(Utility-first) 프레임워크인 Tailwind는 React 등의 컴포넌트 내부 JSX/HTML에 직접 스타일을 조합함으로써, 컴포넌트를 삭제할 때 스타일도 함께 제거되도록 하여 고아(orphaned) CSS가 남는 것을 방지한다 [14, 15].
|
||||
|
||||
* **컴포넌트 단위의 반응형 설계 ([[Container Queries|Container Queries]])**
|
||||
현대의 반응형 웹 디자인은 "페이지가 아닌 컴포넌트를 설계하라"는 원칙으로 진화했다 [3]. 기존의 미디어 쿼리는 브라우저의 뷰포트 크기에 의존했지만, **컨테이너 쿼리(Container Queries)**를 사용하면 컴포넌트가 자신이 배치된 부모 컨테이너의 가용 너비에 맞춰 스스로 레이아웃을 조정할 수 있다 [16-19]. 이는 반응형 동작을 페이지가 아닌 컴포넌트 고유의 속성으로 만들어, 컴포넌트가 사이드바나 전체 화면 어디에 배치되든 올바르게 동작하도록 한다 [4, 16, 20].
|
||||
|
||||
* **디자인 시스템과의 통합 ([[Design Tokens|Design Tokens]])**
|
||||
디자인 토큰은 글로벌 토큰, 의미론적(Alias) 토큰, 그리고 **컴포넌트 토큰(Component Tokens)**의 계층으로 구성된다 [21]. `--button-bg: var(--color-primary)`와 같이 특정 컴포넌트 전용으로 스코핑된 토큰을 사용하면, 전역 시스템의 일관성을 해치지 않으면서도 개별 컴포넌트의 스타일을 세밀하게 제어하고 다크 모드나 테마 변경에 유연하게 대응할 수 있다 [21-23].
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
No trade-offs available.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** [[Modularity|Modularity]], Encapsulation, Monolithic Architecture, Microservices Architecture, Service-Oriented Architecture (SOA)
|
||||
- **Projects/Contexts:** React, Angular, Vue.js 기반 프론트엔드 UI 구축, 전자상거래 플랫폼 및 CRM 시스템 설계, Java EE 및 .NET 엔터프라이즈 애플리케이션
|
||||
- **Contradictions/Notes:** 컴포넌트 기반 아키텍처는 유연성과 재사용성을 극대화하지만, 모듈화를 극대화하려는 목적으로 시스템을 너무 잘게 쪼개는 것(Over-engineering)은 오히려 통합 비용과 통신 오버헤드를 발생시키고 디버깅을 어렵게 만들 수 있으므로 적절한 세분화(Granularity) 수준을 결정하는 것이 핵심입니다 [18, 22, 32].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** [[BEM|BEM]], CSS Modules, CSS-in-JS, [[Tailwind CSS|Tailwind CSS]], 디자인 시스템(DesignSystems), [[Container Queries|Container Queries]]
|
||||
- **Projects/Contexts:** [[대규모 프론트엔드 프로젝트(Large Frontend Projects)|대규모 프론트엔드 프로젝트(Large Frontend Projects]], 모던 React/Vue 애플리케이션 구조
|
||||
- **Contradictions/Notes:** 컴포넌트 스타일링 방식에서 Tailwind CSS는 개발 속도를 높이고 컴포넌트와 스타일을 함께 관리할 수 있지만 JSX 마크업이 매우 길어질 수 있는 단점이 있다. 반면, CSS Modules나 [[SCSS|SCSS]]는 마크업을 깔끔하게 유지하고 복잡한 애니메이션을 다루기 좋으나, 스타일 파일과 컴포넌트 파일을 오가야 하는 컨텍스트 스위칭(Context switching) 비용이 발생하므로 프로젝트의 성격과 팀의 구성에 따라 적절한 선택이 필요하다 [12, 14, 15, 24, 25].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-26*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
|
||||
@@ -2,159 +2,260 @@
|
||||
id: wiki-2026-0508-compound-components
|
||||
title: Compound Components
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [Compound Component Pattern, React Compound Components]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.95
|
||||
verification_status: applied
|
||||
tags: [react, patterns, components, composition, context]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: react
|
||||
---
|
||||
|
||||
# [[Compound Components|Compound Components]]
|
||||
# Compound Components
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
컴파운드 컴포넌트(Compound Components) 패턴은 React에서 부모 컴포넌트와 자식 컴포넌트들이 암묵적인 상태와 동작을 공유하며 하나의 응집된 단위로 함께 작동하도록 하는 설계 패턴이다.[1, 2] 이 패턴을 사용하면 수많은 prop을 전달해야 하는 문제를 피하고, 개발자가 네이티브 HTML 요소를 사용하듯 유연하게 UI를 구성(compose)할 수 있다.[1, 3] 마치 레고 블록처럼 부모 컴포넌트가 기본 구조와 규칙을 제공하고 자식 컴포넌트들을 자유롭게 조립하여 확장 가능한 사용자 인터페이스를 구축할 수 있게 해준다.[4]
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **설계 철학 및 멘탈 모델의 전환**
|
||||
* 기존의 Prop 기반(Prop-Driven) API는 요구사항(레이아웃 변경, 조건부 동작 등)이 추가될 때마다 Prop이 폭발적으로 증가하여 유지보수가 어렵고 컴포넌트 내부가 파악하기 힘든 '블랙박스'가 되는 문제가 있습니다 [5-7].
|
||||
* 합성 컴포넌트는 이를 '구성 중심(Composition-Driven)' 모델로 전환하여, 컴포넌트는 상태와 규칙만 관리하고 레이아웃과 구조의 결정권은 이를 사용하는 소비자(Consumer)에게 일임합니다 [7, 8].
|
||||
## 매 핵심
|
||||
|
||||
* **[[React Context|React Context]]를 활용한 암시적 상태 공유**
|
||||
* 이 패턴의 핵심 기술은 React Context를 내부 상태 관리의 '계약(Contract)'으로 사용하는 것입니다 [9]. 부모(Root) 컴포넌트가 Context를 통해 상태를 제공하고, 하위 컴포넌트들은 [[Prop Drilling|Prop Drilling]] 없이 필요한 상태만 구독하여 동작합니다 [1, 10].
|
||||
* 내부 구현이 추상화되어 있으므로, 소비자는 내부가 어떻게 작동하는지 몰라도 하위 컴포넌트들을 자유롭게 조립할 수 있습니다 [9].
|
||||
### 매 problem solved
|
||||
- 단일 monolithic component 의 props explosion (`<Tabs items={...} renderTab={...} ...>`).
|
||||
- 매 caller 가 매 children 의 layout/order 를 control 의 X.
|
||||
- Slot composition 의 부재.
|
||||
|
||||
* **주요 장점**
|
||||
* **뛰어난 유연성과 가독성:** 특정 기능을 쉽게 포함하거나 제외할 수 있으며, 개발자는 하위 요소의 렌더링 순서와 구조를 자유롭게 재배치할 수 있습니다 [4, 7, 8].
|
||||
* **접근성(A11y) 자동화:** 컴포넌트 내부 Context에서 상태와 ID를 제어하므로, `aria-controls`나 `aria-labelledby` 같은 접근성 속성을 소비자가 수동으로 연결할 필요 없이 자동으로 처리할 수 있습니다 [11].
|
||||
### 매 solution
|
||||
- Parent 가 Context 로 shared state 의 publish.
|
||||
- Children 이 Context 를 consume — explicit prop drilling 의 X.
|
||||
- Children 의 component 가 namespace pattern (`Tabs.Tab`) 또는 separate exports.
|
||||
|
||||
* **성능 최적화 기법**
|
||||
* 복잡한 시스템이나 대규모 렌더링이 필요한 경우, 불필요한 리렌더링을 방지하기 위해 빈번하게 변경되는 상태와 정적인 구성을 각각 다른 Context로 분리(Split Contexts)하여 최적화할 수 있습니다 [12, 13].
|
||||
* 필요한 곳에만 하위 컴포넌트를 전략적으로 메모이제이션(Memoization)하여 성능을 유지합니다 [14].
|
||||
### 매 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).
|
||||
|
||||
* **사용 시 주의사항 및 한계**
|
||||
* 패턴을 구현하기 위해 초기에 작성해야 할 코드가 많아지고, Context 기반 렌더링 비용이 발생하며, 디버깅이 다소 까다로워질 수 있습니다 [11].
|
||||
* 버튼, 배지, 아바타, 아이콘처럼 구조가 단일하고 레이아웃이 고정된 컴포넌트에는 불필요한 추상화(Overusing)가 될 수 있으므로 피해야 합니다 [15, 16]. 탭, 아코디언, 모달, 드롭다운과 같이 레이아웃과 조립 방식이 다양한 복잡한 UI에 가장 적합합니다 [17-19].
|
||||
### 매 응용
|
||||
1. Tabs, Accordion, Disclosure.
|
||||
2. Menu, Dropdown, Combobox.
|
||||
3. Dialog, Drawer, Popover.
|
||||
4. Form fields with label/error/description.
|
||||
5. DataTable column children.
|
||||
|
||||
---
|
||||
## 💻 패턴
|
||||
|
||||
- **작동 원리와 개념**: 컴파운드 컴포넌트 패턴은 부모 컴포넌트를 여러 개의 작은 자식 컴포넌트로 쪼갠 후, 이들 간의 상호작용을 props나 Context API 등의 상태 관리 기법으로 통제하는 원리에 기반한다.[2] 부모 컴포넌트는 전체적인 상태를 관리하고 유연한 자식 컴포넌트(예: `<Modal.Header>`, `<Modal.Body>`, `<Modal.Footer>`)를 노출하여 사용자가 자연스럽게 UI를 조립할 수 있게 돕는다.[1]
|
||||
- **Props 전달의 한계 극복(Prop Soup 해결)**: 전통적인 컴포넌트 방식은 타이틀, 내용, 버튼 등 UI의 다양한 요소를 구현하기 위해 지나치게 많은 prop을 전달해야 하는 'Prop Soup' 문제를 유발하며, 이는 유지보수성과 재사용성을 떨어뜨린다.[3, 5] 컴파운드 패턴은 React의 특수한 `children` prop을 활용해 어떠한 HTML 구조나 JSX도 유연하게 수용함으로써 이러한 경직성을 해결한다.[6]
|
||||
- **서브컴포넌트의 캡슐화와 종속성**: 이 패턴에서 생성되는 서브컴포넌트들은 오직 부모 컴포넌트의 컨텍스트 내부에서만 의미를 가진다.[7] 부모 컴포넌트의 범위를 벗어나 독립적으로 존재하거나 사용되지 않는 헬퍼(helper) 컴포넌트로 설계되어 우발적인 오용을 방지하고 코드의 발견성을 높인다.[7]
|
||||
- **주요 적용 대상**: 이 패턴은 드롭다운, 모달, 탭, 테이블 등 자식 컴포넌트가 부모 컴포넌트의 로직에 의존하면서도 다양한 형태의 렌더링이 필요한 복잡한 UI 요소를 개발할 때 빛을 발한다.[2, 8, 9] ShadCN, Material UI, Radix UI와 같은 유명한 디자인 시스템 및 컴포넌트 라이브러리들이 이 패턴을 채택하고 있다.[8]
|
||||
### Context-based Tabs
|
||||
```typescript
|
||||
import { createContext, useContext, useId, useState } from 'react';
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
컴파운드 컴포넌트 패턴은 직관적이고 커스터마이징하기 쉬운 복잡한 API를 구축하는 데 훌륭한 장점을 제공하지만, 몇 가지 명확한 단점과 제약 사항이 존재한다.[10]
|
||||
- **상태 관리의 복잡성 증가**: 여러 컴포넌트가 상태를 공유해야 하므로 내부적인 상태 처리 로직이 단일 컴포넌트 구조보다 다소 복잡해질 수 있다.[11]
|
||||
- **서브컴포넌트의 오용 위험**: 서브컴포넌트는 부모 컴포넌트와 의미론적(semantically)으로 연결되어야 하므로 무작위로 부착해서는 안 된다.[12] 특히 서브컴포넌트만을 개별적으로 재수출(re-export)하는 것을 피해야 한다.[12] 만약 부모 컴포넌트의 컨텍스트 내에서 변경 사항이 생겼을 때, 개별 서브컴포넌트만 사용하는 소비자(consumer)가 이를 인지하지 못하면 치명적인 오류가 발생할 수 있다.[12]
|
||||
- **과도한 패턴 적용(Over-engineering) 경계**: 애플리케이션의 모든 컴포넌트를 컴파운드 컴포넌트 패턴으로 만들려고 시도해서는 안 된다.[12] 자식 컴포넌트의 렌더링 구조가 중요하고 소비자에게 유연성을 제공해야 하는 상황에서만 선택적으로 적용하는 것이 권장된다.[12]
|
||||
type TabsContextValue = {
|
||||
activeId: string;
|
||||
setActiveId: (id: string) => void;
|
||||
baseId: string;
|
||||
};
|
||||
const TabsContext = createContext<TabsContextValue | null>(null);
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** [[Render Props|Render Props]], Headless Components, Context API, [[Atomic Design|Atomic Design]]
|
||||
- **Projects/Contexts:** [[Radix UI|Radix UI]], Headless UI, [[MUI|MUI]]
|
||||
- **Contradictions/Notes:** 합성 컴포넌트는 매우 유연하고 강력한 패턴이지만, 하위 컴포넌트의 구성을 소비자가 자유롭게 바꿀 수 있기 때문에 의도치 않게 접근성이나 일관된 UX를 해칠 수 있습니다. 따라서 디자인 시스템에서는 안전한 조합의 경계(Safe composition [[Boundaries|Boundaries]])를 정의하고 문서화하는 것이 필수적입니다 [15, 17]. 또한 단순하고 고정된 레이아웃을 가진 컴포넌트에서는 일반적인 Prop 기반 접근법이 훨씬 간단하고 안전합니다 [16].
|
||||
function useTabs() {
|
||||
const ctx = useContext(TabsContext);
|
||||
if (!ctx) throw new Error('Tabs.* must be used inside <Tabs>');
|
||||
return ctx;
|
||||
}
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-26*
|
||||
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>;
|
||||
}
|
||||
|
||||
### Related Concepts
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
||||
#### [아키텍처 및 UI 설계 패턴]
|
||||
- [[Container and Presentational Pattern]]
|
||||
- 연결 이유: 컴파운드 컴포넌트가 UI 요소들을 논리적 그룹으로 묶는 패턴이라면, 컨테이너/프레젠테이셔널 패턴 역시 로직(상태 관리, 데이터 패칭)과 표현(UI 렌더링)을 분리하여 코드의 재사용성을 높이는 대표적인 React UI 설계 패턴이기 때문이다.[13-15]
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 관심사 분리(Separation of Concerns) 원칙을 적용하여 컴포넌트의 책임을 어떻게 나눌 것인가에 대한 거시적인 설계 전략.
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
||||
- [[Render Props]]
|
||||
- 연결 이유: 컴파운드 컴포넌트와 마찬가지로 부모 컴포넌트가 내부 상태를 자식에게 전달하되, 렌더링 구조의 통제권을 컴포넌트를 소비하는 측에 위임하여 동적인 렌더링을 가능하게 하는 유연한 UI 설계 패턴이기 때문이다.[16, 17]
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: React에서 컴포넌트 간 상태와 로직을 공유하고 UI 구조 결정을 소비자에게 이관하는 다양한 접근 방식과 그 유연성.
|
||||
|
||||
#### [상태 및 데이터 관리 도구]
|
||||
- [[Context API]]
|
||||
- 연결 이유: 컴파운드 컴포넌트 구조 내에서 부모 컴포넌트가 자식 컴포넌트들과 상태를 공유하고 관리할 때, 복잡한 Prop Drilling을 방지하기 위해 Context API가 내부적으로 널리 사용되기 때문이다.[2, 18, 19]
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 컴포넌트 트리 내에서 명시적인 prop 전달 없이 데이터를 효율적으로 공유하고 컴포넌트 그룹 내의 상태를 캡슐화하는 원리.
|
||||
|
||||
### Deeper Research Questions
|
||||
- 컴파운드 컴포넌트 패턴과 Render Props 패턴은 각각 어떠한 요구사항이 있을 때 도입하는 것이 더 적합하며, 두 패턴의 장점을 결합하여 사용할 수 있는 방법은 무엇인가?
|
||||
- Context API를 활용해 컴파운드 컴포넌트의 상태를 공유할 때 발생할 수 있는 자식 컴포넌트들의 불필요한 리렌더링(re-rendering) 문제는 어떠한 방식으로 최적화할 수 있는가?
|
||||
- ShadCN이나 Material UI 같은 대규모 디자인 시스템 라이브러리는 컴파운드 컴포넌트 패턴을 적용하면서 어떻게 내부 상태의 복잡성을 관리하고 API의 일관성을 유지하고 있는가?
|
||||
- React Server Components (RSC)의 도입으로 인해, 브라우저의 상태 및 상호작용에 의존하는 컴파운드 컴포넌트 패턴의 구현 방식에는 어떠한 구조적 변화나 제약이 따르는가?
|
||||
- 컴파운드 패턴의 서브컴포넌트를 부모와 분리하여 내보내지 말라는 원칙이, 대규모 프로젝트의 리팩토링이나 버전 업데이트 과정에서 구체적으로 어떤 안티패턴과 런타임 오류를 방지하는가?
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** React의 `children` prop이나 Context API를 사용하여 `Accordion`, `AccordionItem`처럼 부모 컴포넌트가 상태(예: `isOpen`)를 관리하고 자식 컴포넌트들이 이를 참조하여 동작을 결정하는 형태로 코드를 작성한다.[20, 21]
|
||||
- **System Design:** 조직 내에서 공통적으로 사용할 UI 컴포넌트 라이브러리나 디자인 시스템을 구축할 때, 사용자가 다양한 레이아웃 요구사항에 맞춰 컴포넌트를 조합할 수 있도록 유연한 설계를 제공하는 데 핵심적으로 사용된다.[8]
|
||||
- **Operation / Maintenance:** 수많은 기능을 하나의 컴포넌트에 몰아넣어 발생하는 과도한 prop 추가(Prop Soup)를 방지하므로, 새로운 UI 레이아웃이 필요할 때 기존 컴포넌트 내부 로직을 수정할 필요 없이 외부에서 렌더링 순서만 변경하여 유지보수 비용을 낮춘다.[5, 6, 22]
|
||||
- **Learning Path:** React에서 기본 함수형 컴포넌트 생성과 훅(`useState`, `useEffect`) 사용법을 숙지한 후, 재사용 가능하고 확장성 있는 고급 컴포넌트 아키텍처를 설계하는 단계에서 필수적으로 학습한다.[1, 23, 24]
|
||||
- **My Project Relevance:** 여러 페이지에서 모양은 다르지만 동일한 동작(열림/닫힘)을 수행하는 드롭다운, 모달, 아코디언 위젯을 개발해야 할 때, 이 패턴을 도입하여 하나의 강력한 컴포넌트로 모든 요구사항을 처리할 수 있다.[9, 20, 25, 26]
|
||||
|
||||
### Adjacent Topics
|
||||
- [[Custom Hooks]]
|
||||
- 확장 방향: 컴파운드 컴포넌트가 주로 UI의 조립과 유연한 렌더링 구조를 담당한다면, 복잡한 비즈니스 로직이나 API 호출 등은 Custom Hooks로 분리 추출하여 두 설계 패턴을 결합하는 클린 코드 전략으로 지식을 확장할 수 있다.[10, 27]
|
||||
- [[Higher-Order Components (HOCs)]]
|
||||
- 확장 방향: 로직을 재사용하는 또 다른 고급 React 패턴인 HOC와 비교하여, 컴파운드 컴포넌트가 해결하지 못하는 횡단 관심사(Cross-cutting Concerns, 예: 인증, 로깅) 처리에는 HOC가 어떻게 적용되는지 학습 범위를 넓힐 수 있다.[16, 28, 29]
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
|
||||
## 📌Brief 단기 요약
|
||||
합성 컴포넌트(Compound Components)는 여러 개의 연관된 하위 컴포넌트들이 암시적으로 상태를 공유하며 하나의 응집력 있는 단위로 동작하도록 설계하는 React 컴포넌트 패턴입니다 [1, 2]. 단일 컴포넌트에 수십 개의 Prop을 밀어 넣어 비대해지는 것을 방지하고, 기능과 책임을 여러 컴포넌트에 분산시킵니다 [3, 4]. 이는 HTML의 `<select>`와 `<option>` 태그처럼 직관적이고 선언적인 API를 형성하여 뛰어난 유연성과 재사용성을 제공합니다 [1, 4].
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
Tabs.List = List;
|
||||
Tabs.Trigger = Trigger;
|
||||
Tabs.Panel = Panel;
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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>
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Controlled variant
|
||||
```typescript
|
||||
type Props = {
|
||||
value?: string;
|
||||
defaultValue?: string;
|
||||
onValueChange?: (value: string) => void;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
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
|
||||
}
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### asChild slot pattern (Radix)
|
||||
```typescript
|
||||
import { Slot } from '@radix-ui/react-slot';
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
// 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]] · [[Slots]]
|
||||
- 응용: [[Component Library Architecture]] · [[Radix UI]] · [[shadcn-ui]]
|
||||
- Adjacent: [[React Context]] · [[A11y]] · [[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 패턴 |
|
||||
|
||||
@@ -2,129 +2,234 @@
|
||||
id: wiki-2026-0508-compute-shaders
|
||||
title: Compute Shaders
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [GPU Compute, GPGPU Shaders, WebGPU Compute]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [gpu, shaders, webgpu, parallel, wgsl, cuda]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: wgsl-glsl-cuda
|
||||
framework: webgpu-vulkan
|
||||
---
|
||||
|
||||
# [[Compute Shaders|Compute Shaders]]
|
||||
# Compute Shaders
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> 컴퓨트 셰이더(Compute Shaders)는 [[WebGPU|WebGPU]] 환경에서 지원되는 기능으로, CPU의 메인 스레드에서 수행되던 무거운 범용 연산 작업을 GPU로 오프로드하는 핵심 기술입니다 [1, 2]. GPU의 수천 개 코어를 활용한 병렬 처리를 통해 물리 시뮬레이션, 충돌 감지, 대규모 파티클 시스템 등의 작업 성능을 비약적으로 향상시킵니다 [2]. 또한 간접 그리기(Indirect Drawing) 기술과 결합하여 CPU의 개입 없이 가시성을 판별하고 화면을 그리는 완전한 GPU 주도 렌더링([[GPU-driven Rendering|GPU-driven Rendering]]) 파이프라인을 구축하는 데 사용됩니다 [3, 4].
|
||||
## 매 한 줄
|
||||
> **"매 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 본질.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
> 컴퓨트 셰이더(Compute Shaders)는 [[JavaScript|JavaScript]] 메인 스레드에서 수행되던 무거운 작업을 수천 개의 GPU 코어에서 병렬로 처리하도록 오프로드하는 범용 GPU 연산(general-Purpose GPU computation) 기술입니다 [1]. 주로 [[WebGPU|WebGPU]] 환경에서 사용되며, 파티클 시스템, 물리 시뮬레이션, 대규모 데이터 필터링 등의 CPU 병목 현상을 획기적으로 해결하여 렌더링 성능을 극대화하는 데 필수적인 역할을 합니다 [2-4].
|
||||
### 매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **범용 GPU 연산 및 성능 향상:** 컴퓨트 셰이더는 물리 시뮬레이션, 충돌 감지, 유체 시뮬레이션, 이미지 처리, 대규모 데이터 필터링, 절차적 지형 생성 등 복잡한 연산을 CPU 대신 GPU에서 병렬로 처리합니다 [2, 5-8]. 기존 CPU 기반 파티클 업데이트는 약 5만 개 수준에서 병목이 발생하지만, WebGPU 컴퓨트 셰이더를 활용하면 10만 개의 파티클을 2ms 이내에 업데이트하여 최대 150배의 성능 향상을 내며 수백만 개의 유닛을 처리할 수 있습니다 [9-12].
|
||||
* **GPU 주도 렌더링 및 컬링 (GPU-driven Rendering & Culling):** 간접 그리기(Indirect Drawing) 명령과 결합하여 극도로 효율적인 렌더링 파이프라인을 구성합니다 [4, 13]. 컴퓨트 셰이더가 모든 인스턴스에 대해 시야 절두체(Frustum) 및 오클루전(Occlusion) 컬링 판별을 수행하고, 화면에 보이는 객체 정보만 원자적 카운터(Atomic Counter)를 통해 간접 그리기 버퍼에 추가합니다 [3, 4, 14]. 이를 통해 CPU와 GPU 간의 데이터 동기화 지연과 명령 발행 오버헤드가 사실상 0에 수렴하게 됩니다 [4, 15].
|
||||
* **데이터 공유 및 메모리 최적화:** 읽기와 쓰기가 모두 가능한 스토리지 텍스처([[Storage|Storage]] Textures)를 활용해 GPU 기반 렌더링과 효과 처리를 유연하게 수행합니다 [6, 16]. 또한 스레드 간 데이터 공유가 필요한 경우, 반복 접근 패턴에서 전역 메모리보다 10~100배 더 빠른 작업 그룹 공유 메모리(Workgroup Shared [[memory|memory]])를 활용할 수 있습니다 [7, 13].
|
||||
* **고급 연산 기법 지원:** 컴퓨트 단계에서 메쉬 정점 변환을 처리하고 그 결과를 버퍼에 저장해 불필요한 중복 연산을 제거하는 '컴퓨트 스키닝(Compute Skinning)'이 가능해집니다 [12]. 또한 glTF 모델에 흔히 쓰이는 8비트/16비트 정수 데이터를 32비트 포맷으로 압축 해제하는 작업도 렌더링 파이프라인 외곽에서 효율적으로 수행할 수 있습니다 [12].
|
||||
* **동기화 및 파이프라인 제어 베스트 프랙티스:** 연산 의존성이 높은 씬을 Three.js에서 렌더링할 때는 `renderAsync`를 사용하여 렌더 패스가 시작되기 전에 컴퓨트 패스가 완전히 끝나도록 동기화해야 합니다 [17]. 성능 처리량을 극대화하기 위해서는 스테이징 버퍼(Staging Buffers)를 활용한 이중 버퍼링(Double-buffering)을 적용하는 것이 좋으며, 디스패치 사이에 `await mapAsync()`를 호출할 경우 GPU 파이프라인을 멈추게 만들 수 있으므로 지양해야 합니다 [18].
|
||||
### 매 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.
|
||||
|
||||
* **파티클 및 물리 시뮬레이션 처리 한계 돌파**
|
||||
기존 CPU 기반 파티클 업데이트는 일반적인 하드웨어에서 약 50,000개 부근에서 성능 병목에 도달하지만, WebGPU 컴퓨트 셰이더를 사용하면 이를 수백만 개 단위로 확장할 수 있습니다 [2, 3]. 예를 들어, CPU에서 프레임당 30ms가 소요되던 10,000개의 파티클 업데이트 작업을 컴퓨트 셰이더로 전환하면 100,000개의 파티클을 2ms 이내에 업데이트할 수 있어 약 150배의 성능 향상을 얻을 수 있습니다 [4]. 또한, 대규모 유체 시뮬레이션 및 물리 연산에도 탁월한 성능을 발휘합니다 [5, 6].
|
||||
### 매 응용
|
||||
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.
|
||||
|
||||
* **고급 데이터 처리 및 GPU 주도 렌더링([[GPU-driven Rendering|GPU-driven Rendering]])**
|
||||
컴퓨트 셰이더는 충돌 감지(Collision detection), 실시간 조명, 대규모 BIM 데이터셋의 실시간 필터링 등 다수의 데이터 스트림을 병렬로 처리하는 데 유용합니다 [1, 3, 4]. 실시간 편집이 가능한 대규모 절차적 지형(Procedural terrain)을 생성하거나 [6], 컴퓨트 셰이더의 출력을 기반으로 GPU가 렌더링 대상을 직접 결정하는 간접 그리기([[Indirect Draw|Indirect Draw]]s)를 수행하여 수백만 개의 인스턴스와 가시성 컬링(Culling)을 효율적으로 처리할 수 있습니다 [7, 8].
|
||||
## 💻 패턴
|
||||
|
||||
* **컴퓨트 스키닝 (Compute Skinning)**
|
||||
컴퓨트 셰이더는 컴퓨트 단계에서 메쉬 정점 변환을 처리하여 그 결과를 버퍼에 저장할 수 있게 해줍니다 [4]. 이렇게 저장된 데이터는 다수의 렌더링 패스에서 재사용할 수 있어 중복 계산을 없앨 수 있으며, 조립 과정을 보여주는 애니메이션 처리 등에 매우 효율적입니다 [4].
|
||||
### 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>;
|
||||
|
||||
* **핵심 구현 메커니즘 및 동기화 최적화**
|
||||
* **스토리지 텍스처([[Storage|Storage]] textures):** 일반 텍스처와 달리 읽기와 쓰기를 모두 허용하여 컴퓨트 셰이더 내에서 유체 시뮬레이션 및 이미지 처리 작업이 가능하게 합니다 [5, 9].
|
||||
* **작업 그룹 공유 메모리(Workgroup shared [[memory|memory]]):** 스레드 간 데이터 공유가 필요할 때 전역 메모리보다 10~100배 빠른 접근 속도를 제공합니다 [6, 7].
|
||||
* **렌더링 동기화 및 이중 버퍼링:** 컴퓨트 셰이더가 포함된 씬은 GPU 작업이 종속된 렌더링 패스 이전에 완료되도록 `renderAsync`를 사용하여 비동기 렌더링을 수행해야 합니다 [10]. 또한 성능을 높이려면 스테이징 버퍼(Staging buffers)를 활용한 이중 버퍼링(Double-buffering) 기법을 사용해야 하며, 파이프라인 지연을 방지하기 위해 디스패치 간에 `await mapAsync()` 사용을 피해야 합니다 [11].
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Graphics & Performance 분야의 자동 자산화 수행.
|
||||
|
||||
---
|
||||
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Graphics & Performance 분야의 자동 자산화 수행.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** `[[WebGPU|WebGPU]]`, `GPU-driven Rendering`, `Indirect Drawing`, `Storage Textures`, `[[Frustum Culling|Frustum Culling]]`
|
||||
- **Projects/Contexts:** `Three.js`, `Segments.ai`, `BIM Datasets`
|
||||
- **Contradictions/Notes:** 컴퓨트 셰이더는 엄청난 성능 향상을 제공하지만 구형 API인 [[WebGL|WebGL]]이나 WebGL 2에서는 지원되지 않아 WebGPU 환경이 필수적입니다 [1]. 또한 GPU 최적화를 제대로 다루지 못해 동기화 대기(`await mapAsync()`)를 남용할 경우, 오히려 GPU가 최대 60%의 시간 동안 유휴 상태(Idle)에 빠지는 병목 현상을 유발할 수 있습니다 [18].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-19*
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** [[WebGPU|WebGPU]], GPU-driven Rendering, [[TSL (Three Shader Language)|TSL (Three Shader Language]], Storage Textures
|
||||
- **Projects/Contexts:** Three.js WebGPURenderer, Native WebGPU, 대규모 건설/BIM 플랫폼 (Large-Scale Construction Viewers)
|
||||
- **Contradictions/Notes:** 컴퓨트 셰이더를 통한 GPU 병렬 연산은 압도적인 성능 향상을 가져오지만, 작업 디스패치 사이에 `await mapAsync()`를 무분별하게 사용하면 GPU 파이프라인이 멈추고 최대 60%의 시간 동안 GPU가 유휴 상태에 빠지는 성능 저하 역효과가 발생할 수 있으므로 주의해야 합니다 [11].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-19*
|
||||
|
||||
---
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
@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];
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### WebGPU dispatch (TypeScript)
|
||||
```typescript
|
||||
const adapter = await navigator.gpu.requestAdapter();
|
||||
const device = await adapter!.requestDevice();
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
const module = device.createShaderModule({ code: WGSL_SOURCE });
|
||||
const pipeline = device.createComputePipeline({
|
||||
layout: 'auto',
|
||||
compute: { module, entryPoint: 'main' },
|
||||
});
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
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;
|
||||
};
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
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,
|
||||
});
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
const bindGroup = device.createBindGroup({
|
||||
layout: pipeline.getBindGroupLayout(0),
|
||||
entries: [
|
||||
{ binding: 0, resource: { buffer: a } },
|
||||
{ binding: 1, resource: { buffer: b } },
|
||||
{ binding: 2, resource: { buffer: c } },
|
||||
],
|
||||
});
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
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]] · [[ML Inference]] · [[Particle Systems]]
|
||||
- Adjacent: [[Triton]] · [[MLX]] · [[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 |
|
||||
|
||||
@@ -2,121 +2,165 @@
|
||||
id: wiki-2026-0508-conceptual-integrity
|
||||
title: Conceptual Integrity
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-18536721]
|
||||
aliases: [Architectural Integrity, Brooks Conceptual Integrity]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [conceptual-integrity, software-architecture, implementation-separation, keeper-of-the-vision, "conway's-law", cognitive-engineering]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [architecture, design, brooks, mythical-man-month]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-02
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: agnostic
|
||||
framework: agnostic
|
||||
---
|
||||
|
||||
# [[Conceptual Integrity]]
|
||||
# Conceptual Integrity
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
Conceptual Integrity(개념적 무결성)는 소프트웨어 시스템의 아키텍처가 해당 시스템이 '무엇을' 해야 하며 '어떻게' 수행해야 하는지에 대한 전반적인 비전(overall vision)을 나타내야 한다는 개념입니다 [1]. 이 용어는 1975년 Fred Brooks의 저서인 『The Mythical Man-Month(맨먼스 미신)』에서 처음 소개되었습니다 [1]. 아키텍트가 시스템의 비전을 지키는 수호자 역할을 수행하여 추가되는 기능들이 아키텍처와 일관성을 유지하도록 보장하는 것이 핵심입니다 [1].
|
||||
## 매 한 줄
|
||||
> **"매 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 에 핵심 원칙으로 산다.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **개념의 기원 및 정의**: Conceptual Integrity는 Fred Brooks가 1975년에 출간한 책 『The Mythical Man-Month』에서 처음 도입된 용어로, 소프트웨어 아키텍처의 핵심 특성 중 하나로 꼽힙니다 [1]. 이는 시스템 설계 시 구조와 동작 방식에 있어 파편화되지 않은 하나의 일관된 비전을 가져야 함을 의미합니다 [1].
|
||||
* **비전과 구현의 엄격한 분리**: Conceptual Integrity를 달성하기 위해서는 아키텍처가 제시하는 시스템의 거시적인 비전이 실제 코드 수준의 세부 구현(implementation)과는 분리되어 다루어져야 합니다 [1].
|
||||
* **비전의 수호자로서의 아키텍트 역할**: 소프트웨어 아키텍트는 시스템 설계에서 '비전의 수호자(keeper of the vision)'라는 막중한 역할을 맡게 됩니다 [1]. 아키텍트는 시스템에 새로운 기능이 추가되거나 변경 사항이 발생할 때, 그것이 최초에 설정된 아키텍처의 비전과 동일한 선상에 있는지 철저히 확인하여 개념적 무결성을 보존해야 할 책임이 있습니다 [1].
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
소스에 관련 정보가 부족합니다.
|
||||
### 매 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."
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
### 매 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.
|
||||
|
||||
#### [아키텍처의 본질적 특성 (Architecture Characteristics)]
|
||||
- [[Software Architecture]]
|
||||
- 연결 이유: Conceptual Integrity는 훌륭한 소프트웨어 아키텍처가 갖추어야 할 주요 인지적, 구조적 특성 중 하나로 소개되기 때문입니다 [1, 2].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 소프트웨어 아키텍처가 단순한 구조적 청사진을 넘어, 시스템 전체를 아우르는 일관된 비전을 제시해야 한다는 본질적인 목적을 이해할 수 있습니다 [1].
|
||||
- [[Implementation Separation]]
|
||||
- 연결 이유: Conceptual Integrity를 유지하기 위한 전제 조건으로, 전체적인 시스템의 비전이 실제 구현과 명확히 분리되어야 한다고 명시되어 있기 때문입니다 [1].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 아키텍처 수준의 고차원적 의사결정 공간과 세부 구현 수준의 의사결정 공간이 어떻게 구분되어 시스템의 일관성을 유지하는지 이해할 수 있습니다 [1].
|
||||
### 매 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.
|
||||
|
||||
#### [아키텍트의 역할 (Role of Architect)]
|
||||
- [[Keeper of the Vision]]
|
||||
- 연결 이유: 아키텍트는 시스템에 대한 모든 추가 사항이 기존 아키텍처의 방향성과 일치하도록 감독하여 개념적 무결성을 지키는 핵심적인 역할을 수행하기 때문입니다 [1].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 소프트웨어 아키텍트가 프로젝트 수명주기 전반에 걸쳐 시스템의 설계 철학을 수호하기 위해 수행해야 하는 관리적 책임을 파악할 수 있습니다 [1].
|
||||
### 매 Tension
|
||||
- Conceptual integrity vs feature completeness.
|
||||
- Single architect vs distributed teams.
|
||||
- Stability vs evolution.
|
||||
|
||||
### Deeper Research Questions
|
||||
- Fred Brooks가 제안한 Conceptual Integrity를 다수의 독립적인 팀이 병렬로 개발을 진행하는 현대의 분산 아키텍처(예: 마이크로서비스 아키텍처) 환경에서 훼손 없이 유지하기 위한 구체적인 거버넌스 방법론은 무엇인가?
|
||||
- '비전의 수호자(Keeper of the vision)'로서 아키텍트의 역할이 애자일(Agile) 방법론이 추구하는 자율적이고 교차 기능적인 팀(Cross-functional team)의 성격과 어떻게 균형을 이룰 수 있는가?
|
||||
- 비전과 구현(Implementation)을 명확하게 분리하는 과정에서 발생할 수 있는 아키텍트와 개발자 간의 소통 단절이나 설계-구현 간의 괴리를 극복하는 커뮤니케이션 전략은 무엇인가?
|
||||
- 대규모 시스템이 진화함에 따라 Conceptual Integrity가 점진적으로 무너지는 현상(Architecture Erosion)을 조기에 탐지하고 측정할 수 있는 정량적 지표나 자동화된 도구는 무엇인가?
|
||||
- 시스템 인수합병(M&A) 등으로 인해 서로 다른 비전을 가진 두 개의 소프트웨어 시스템이 통합될 때, 새로운 Conceptual Integrity를 수립하기 위한 아키텍처적 접근 방식은 무엇인가?
|
||||
### 매 응용
|
||||
1. API design (REST resource model 의 일관성).
|
||||
2. Language design (Go, Elm).
|
||||
3. UI framework (SwiftUI, Jetpack Compose).
|
||||
4. CLI design (git, kubectl).
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 시스템 구현 단계에서 개발팀은 개별 기능이나 모듈을 작성할 때, 그것이 시스템 전체의 일관된 비전(무엇을, 어떻게 할 것인지)과 어긋나지 않도록 아키텍처 설계 가이드라인을 준수해야 합니다 [1].
|
||||
- **System Design:** 소프트웨어 시스템 초기 디자인 시, 아키텍처의 거시적인 방향성 및 구조적 비전을 세부 구현 사항과 명확하게 분리하여 정의하는 과정에 적용됩니다 [1].
|
||||
- **Operation / Maintenance:** 시스템 운영 및 유지보수 과정에서 새로운 요구사항이나 기능이 추가될 때, 아키텍트는 해당 변경 사항이 본래의 아키텍처 철학과 일치하는지 검토하여 시스템의 일관성을 지켜냅니다 [1].
|
||||
- **Learning Path:** 소프트웨어 아키텍트가 되기 위한 학습 과정에서, Fred Brooks의 고전문헌을 통해 소프트웨어 설계의 근본적인 철학과 아키텍트가 지녀야 할 책임 의식을 정립하는 방향으로 연결됩니다 [1].
|
||||
- **My Project Relevance:** 현재 진행 중인 프로젝트에서 소프트웨어 아키텍트 또는 테크 리드로서, 구성원들이 추가하는 코드가 프로젝트의 초기 아키텍처 비전을 훼손하지 않도록 방향성을 제시하고 감독하는 데 직결됩니다 [1].
|
||||
## 💻 패턴
|
||||
|
||||
### Adjacent Topics
|
||||
- [[Conway's Law]]
|
||||
- 확장 방향: Conceptual Integrity와 함께 소프트웨어 아키텍처를 형성하는 또 다른 인지적 제약(Cognitive constraints) 요소로서, 시스템을 설계하는 조직의 커뮤니케이션 구조가 시스템 설계 결과물에 미치는 영향을 탐구합니다 [1, 3].
|
||||
- [[Separation of Concerns]]
|
||||
- 확장 방향: 시스템 설계 시 복잡성을 줄이기 위한 전통적이고 핵심적인 원칙으로, 비전과 구현을 분리하는 Conceptual Integrity와 더불어 시스템 구조의 모듈성을 어떻게 달성할 수 있는지 연구합니다 [2].
|
||||
- [[Software Architecture Erosion]]
|
||||
- 확장 방향: 시간이 지남에 따라 아키텍처의 의도된 설계(비전)와 실제 구현 사이에 점진적인 격차가 발생하는 현상으로, Conceptual Integrity 유지가 실패했을 때 나타나는 증상 및 해결 방안(예: 리팩토링, 아키텍처 복구)으로 확장이 가능합니다 [4].
|
||||
### 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
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
// Same shape for charges, subscriptions, invoices, ...
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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;
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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)
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### Architecture Decision Records (ADRs) preserve integrity
|
||||
```markdown
|
||||
# ADR-007: All write APIs return the full resource
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
## Status
|
||||
Accepted
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 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]] · [[Mythical Man-Month]]
|
||||
- 변형: [[Convention over Configuration]] · [[Design Principles]]
|
||||
- 응용: [[API Design]] · [[Design Systems]] · [[ADR]]
|
||||
- Adjacent: [[Brooks Law]] · [[No Silver Bullet]] · [[Worse is Better]]
|
||||
|
||||
## 🤖 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 적용 |
|
||||
|
||||
@@ -2,120 +2,173 @@
|
||||
id: wiki-2026-0508-concurrent-rendering
|
||||
title: Concurrent Rendering
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [React Concurrent, Concurrent Mode, React 18 Concurrent]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [react, concurrent, rendering, scheduler, transitions]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: react
|
||||
---
|
||||
|
||||
# [[Concurrent Rendering|Concurrent Rendering]]
|
||||
# Concurrent Rendering
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
Concurrent Rendering(동시성 렌더링)은 메인 스레드를 블로킹하지 않고 UI의 여러 부분을 병렬로 렌더링할 수 있게 해주는 React의 핵심 아키텍처 기능입니다 [1]. 렌더링 작업을 '[[Time Slicing|Time Slicing]](시간 분할)'을 통해 작은 단위로 쪼개고 중요도에 따라 우선순위를 부여하여, 긴급한 사용자 입력에 반응하기 위해 렌더링을 일시 중지하거나 재개할 수 있습니다 [1, 2]. 이를 통해 무거운 연산 중에도 UI가 멈추지 않고 즉각적으로 반응하도록 하여 애플리케이션의 체감 성능을 극대화합니다 [3, 4].
|
||||
## 매 한 줄
|
||||
> **"매 render 매 interruptible, prioritizable, abandonable"**. React 18 (2022) 에 stable. Fiber architecture (2017) 의 결실. 2026 현재 React 19+ 의 default; `useTransition`, `useDeferredValue`, Suspense, streaming SSR, React Compiler 매 모든 것 위에 빌드.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
동시성 렌더링(Concurrent Rendering)은 React의 Fiber 아키텍처를 기반으로 메인 스레드를 동기적으로 차단하지 않고 렌더링 작업을 중단 및 재개할 수 있도록 하는 렌더링 방식입니다 [1, 2]. 이 기술은 전체 렌더링 작업을 작은 단위로 쪼개어 처리하는 타임 슬라이싱([[Time-Slicing|Time-Slicing]])을 통해, 긴급한 사용자 상호작용을 우선적으로 처리할 수 있도록 브라우저에 제어권을 양보합니다 [2-4]. 이를 통해 무거운 연산이 백그라운드에서 진행되는 동안에도 UI의 반응성을 부드럽게 유지할 수 있습니다 [4, 5].
|
||||
### 매 핵심 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **Fiber 아키텍처와 Work Loop**
|
||||
Concurrent Rendering은 React 16에서 처음 도입된 Fiber 아키텍처를 기반으로 작동합니다 [5, 6]. 기존의 단일 재귀 호출 기반 동기식 렌더링과 달리, 렌더링 작업을 'Fiber 노드'라는 작은 작업 단위(Unit of Work)로 분할합니다 [2, 7]. React는 Work Loop를 통해 이 트리를 점진적으로 순회하며, 각 작업 단위가 끝날 때마다 브라우저에 제어권을 양보(yield)하여 클릭과 같은 고우선순위 상호작용을 처리할 수 있는지 확인합니다 [8, 9].
|
||||
* **우선순위 기반 스케줄링 ([[Lane Model|Lane Model]])**
|
||||
동시성 작업의 우선순위는 'Lane'이라는 비트마스크 시스템을 통해 체계적으로 관리됩니다 [10, 11]. 타이핑이나 클릭처럼 사용자가 즉각적인 반응을 기대하는 긴급한 업데이트(Sync Lane)는 최우선으로 즉시 처리되며, 스크롤(InputContinuous Lane), 네트워크 응답(Default Lane), 백그라운드 렌더링(Idle Lane) 등은 각각 낮은 우선순위를 부여받아 스케줄링됩니다 [12-14]. 이 과정에서 렌더링 단계(Render phase)는 중단 가능(Interruptible)하므로, 더 높은 우선순위의 작업이 도착하면 기존의 렌더링 작업을 일시 중지, 폐기 또는 재시작할 수 있습니다 [15, 16].
|
||||
* **Concurrent Hooks 활용 (`[[useTransition|useTransition]]`, `[[useDeferredValue|useDeferredValue]]`)**
|
||||
[[React 18|React 18]] 및 19에서는 개발자가 동시성 렌더링을 직접 제어할 수 있는 훅을 제공합니다 [17, 18]. **`useTransition`**은 개발자가 상태 업데이트를 직접 긴급하지 않은 것(low-priority)으로 지정하여, 수천 개의 데이터 필터링 연산이 백그라운드에서 도는 중에도 사용자의 타이핑 입력이 즉시 반영되도록 돕습니다 [17, 19, 20]. **`useDeferredValue`**는 외부에서 전달받는 값 자체의 렌더링을 지연시켜, 새로운 결과가 준비될 때까지 UI가 동결되는 것을 막고 이전 결과를 표시하게 해줍니다 [19, 21].
|
||||
* **성능 최적화 메커니즘 (체감 성능 향상)**
|
||||
Concurrent Rendering의 핵심은 코드의 실제 연산 속도를 물리적으로 가속하는 것이 아닙니다 [3]. 무거운 연산이 즉각적인 사용자 피드백을 방해하지 않도록 처리 순서를 최적화하여 앱이 **"더 빠르게 느껴지게(feel faster)"** 만드는 데 목적이 있습니다 [3]. 이러한 비차단형(Non-[[Blocking|Blocking]]) 렌더링 방식은 사용자의 입력이 다음 화면 페인트로 이어지는 속도를 측정하는 핵심 웹 지표인 **INP(Interaction to Next Paint)**를 향상시키는 데 직접적으로 기여합니다 [21, 22].
|
||||
### 매 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.
|
||||
|
||||
- **Fiber 아키텍처와 작업 분할 (Time-Slicing)**
|
||||
기존의 동기식 스택 리컨실러(Stack Reconciler)가 메인 스레드를 길게 차단하여 UI가 멈추는 문제를 해결하기 위해, React 16부터 도입된 Fiber 아키텍처는 동시성 렌더링을 지원합니다 [1, 2]. 전체 렌더링 작업을 '작업 단위(unit of work)'인 Fiber 노드로 나누어 처리하며, 각 작업 후 브라우저에 제어권을 양보(yield)하여 더 높은 우선순위의 작업(예: 사용자 입력)이 있는지 확인합니다 [3, 6]. 렌더링 단계는 이렇게 중단과 재개가 가능하지만, 실제 DOM을 변경하는 커밋 단계는 동기적으로 처리됩니다 [7, 8].
|
||||
## 💻 패턴
|
||||
|
||||
- **우선순위 기반의 레인(Lane) 모델**
|
||||
동시성 렌더링은 '레인(Lane)'이라는 비트마스크 시스템을 통해 렌더링 작업의 우선순위를 관리합니다 [9, 10]. 클릭이나 타이핑 같은 사용자 상호작용은 가장 높은 우선순위(Sync Lane)로 즉시 처리되고, 화면에 보이지 않는 요소의 렌더링이나 무거운 데이터 업데이트는 낮은 우선순위(Idle 또는 Default Lane)로 미루어집니다 [9, 11].
|
||||
### useTransition — heavy filter
|
||||
```tsx
|
||||
function Search() {
|
||||
const [query, setQuery] = useState('');
|
||||
const [list, setList] = useState<Item[]>(allItems);
|
||||
const [isPending, startTransition] = useTransition();
|
||||
|
||||
- **[[React 18|React 18]]/19의 동시성 훅 (Concurrent Features)**
|
||||
`[[useTransition|useTransition]]`과 `[[useDeferredValue|useDeferredValue]]` 훅은 이 동시성 렌더링 모델을 직접적으로 활용합니다 [5]. `useTransition`은 대규모 목록 필터링과 같은 비긴급 상태 업데이트의 우선순위를 낮춰 입력 지연을 방지하며 [5, 12], `useDeferredValue`는 무거운 렌더링 계산이 필요한 값의 적용을 지연시킵니다 [12, 13].
|
||||
|
||||
- **동시성 하이드레이션 (Concurrent [[Hydration|Hydration]])**
|
||||
React 18부터는 하이드레이션 과정에도 동시성 렌더링이 적용됩니다 [14]. 거대한 덩어리의 하이드레이션 작업을 작은 조각으로 나누어 브라우저의 상호작용 처리를 방해하지 않게 하며, Suspense와 결합할 경우 사용자가 상호작용하는 UI 컴포넌트부터 우선적으로 하이드레이션하여 초기 로딩 성능(Total [[Blocking|Blocking]] Time)을 크게 개선합니다 [14, 15].
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
No trade-offs available.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** `[[Fiber Architecture|Fiber Architecture]]`, `Time Slicing`, `Lane Model`, `[[useTransition|useTransition]]`, `[[useDeferredValue|useDeferredValue]]`
|
||||
- **Projects/Contexts:** `[[React 18 & 19 Performance Optimization|React 18 & 19 Performance Optimization]]`
|
||||
- **Contradictions/Notes:** 소스에 따르면 `useTransition` 및 `useDeferredValue`와 같은 동시성 훅은 코드 자체의 속도를 높여주지는 않지만, 무거운 연산이 사용자 피드백을 방해하지 않도록 스케줄링하여 앱의 "체감 성능"을 개선하는 방식으로 작동한다는 점을 명확히 하고 있습니다 [3].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** [[React Fiber Architecture|React Fiber Architecture]], Time-Slicing, Lane Model, [[Reconciliation|Reconciliation]]
|
||||
- **Projects/Contexts:** React 18/19 Performance [[Optimization|Optimization]], Concurrent Hydration
|
||||
- **Contradictions/Notes:** 동시성 렌더링 기능(`useTransition`, `useDeferredValue` 등)은 애플리케이션의 실제 코드 실행 속도를 높이는 것이 아니라, 무거운 연산 중에도 긴급한 피드백을 방해하지 않도록 처리 순서를 조정함으로써 앱이 더 빠르게 "느껴지도록(feel faster)" 체감 성능을 향상시키는 역할을 합니다 [16].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
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} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### useDeferredValue
|
||||
```tsx
|
||||
function Page({ query }: { query: string }) {
|
||||
const deferred = useDeferredValue(query);
|
||||
return <ExpensiveResults query={deferred} />;
|
||||
}
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Suspense + use (React 19+)
|
||||
```tsx
|
||||
function UserProfile({ userPromise }: { userPromise: Promise<User> }) {
|
||||
const user = use(userPromise); // suspends if pending
|
||||
return <h1>{user.name}</h1>;
|
||||
}
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
<Suspense fallback={<Skeleton />}>
|
||||
<UserProfile userPromise={fetchUser(id)} />
|
||||
</Suspense>
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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>;
|
||||
}
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]] · [[Time Slicing]]
|
||||
- 응용: [[React Suspense]] · [[Streaming SSR]] · [[Next.js App Router]]
|
||||
- Adjacent: [[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 |
|
||||
|
||||
@@ -1,154 +1,168 @@
|
||||
---
|
||||
id: wiki-2026-0508-continuous-integration-ci
|
||||
title: Continuous Integration CI
|
||||
title: Continuous Integration (CI)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [CI, Continuous Integration, 지속적 통합]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
verification_status: applied
|
||||
tags: [ci, devops, automation, github-actions]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: yaml
|
||||
framework: github-actions
|
||||
---
|
||||
|
||||
# [[Continuous Integration (CI)|Continuous Integration (CI]]
|
||||
# Continuous Integration (CI)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> 지속적 통합(Continuous Integration, CI)은 소프트웨어 개발 수명 주기에서 코드 변경 사항이 발생할 때 이를 자동으로 검사하고 빌드하는 파이프라인입니다 [1, 2]. 개발자의 로컬 환경에서 우회될 수 있는 검사들을 강제하는 '안전망(Safety net)'이자 최종 권한(Final authority) 역할을 수행합니다 [2, 3]. CI 환경에서는 정적 애플리케이션 보안 테스트([[SAST|SAST]]), 린팅(Linting), 전체 테스트 스위트 실행 등을 통해 프로덕션 환경에 배포되기 전 코드의 품질과 보안을 엄격하게 관리합니다 [4, 5].
|
||||
## 매 한 줄
|
||||
> **"매 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 이 분 단위로 압축됨.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
Continuous Integration (CI)은 새로운 코드가 푸시(push)될 때마다 자동으로 테스트와 빌드 워크플로우를 실행하여 메인 브랜치의 안정성을 유지하는 소프트웨어 개발 관행입니다 [1, 2]. 이를 통해 "내 컴퓨터에서는 되는데(it works on my machine)"와 같은 환경 의존적인 문제를 방지하고, 병합(merge) 전에 버그를 조기에 발견할 수 있습니다 [2, 3]. 또한 잘 갖춰진 CI/CD 파이프라인과 테스트 환경은 새로운 개발자가 크고 복잡한 코드베이스를 더 빠르고 명확하게 이해하는 데 핵심적인 도움을 줍니다 [4].
|
||||
### 매 원칙
|
||||
- **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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **최종 검증 및 안전망(Safety Net) 역할:** 개발자가 로컬 환경에서 사용하는 Git 훅(예: [[Husky|Husky]], [[lint-staged|lint-staged]])은 `--no-verify` 명령어로 우회할 수 있으므로 코드 품질 정책에 대한 완벽한 강제성을 갖지 못합니다 [3]. 따라서 CI 파이프라인은 전체 코드에 대한 린팅(자동 수정 제외), 전체 테스트 스위트 실행, 타입 검사 및 빌드 검증을 우회 불가능하게 수행하는 안전망이자 최종 권한으로 작동합니다 [2, 4, 6].
|
||||
- **보안 및 품질 게이트(Quality [[Gates|Gates]]) 통합:** CI/CD 파이프라인에 SAST 도구(예: Snyk, [[SonarQube|SonarQube]], Qodana) 및 코드 품질 분석 도구를 통합하여 품질 검사를 빌드 프로세스의 자연스러운 일부로 만듭니다 [1, 7, 8]. 이를 통해 특정 심각도 임계값을 초과하는 보안 취약점이나 품질 기준에 미달하는 코드가 병합(Merge)되거나 배포되는 것을 자동으로 차단(Guardrail)할 수 있습니다 [1, 5, 9].
|
||||
- **병렬 검사 및 리뷰 파이프라인 설계:** Pull Request(PR)가 생성되면 CI 파이프라인은 린팅, 포맷팅 검증, 유닛 및 통합 테스트, 종속성 취약점 스캔 등의 사전 병합(Pre-Merge) 자동화 검사를 병렬로 실행합니다 [10]. 코드 변경 사항은 이러한 자동화 검사를 통과한 후에만 사람이 직접 수행하는 코드 리뷰로 라우팅되거나 병합이 활성화되도록 구성되어, 리뷰어의 인지적 부담을 줄이고 전체적인 소프트웨어 전송 속도를 높입니다 [8, 11, 12].
|
||||
- **CI 환경에서의 도구 실행 전략:** CI 서버에서 검사를 실행할 때는 로컬 환경을 위한 Git 훅 도구를 비활성화(`HUSKY=0` 등 설정)하고, 특정 파일만이 아닌 프로젝트에 필요한 실제 검사 명령어 전체를 직접 실행하도록 설정하는 것이 권장됩니다 [6, 13].
|
||||
### 매 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).
|
||||
|
||||
* **자동화된 테스트와 빌드 워크플로우를 통한 안정성 보장**: CI는 코드가 리포지토리에 푸시될 때 자동으로 테스트를 실행하는 역할을 합니다. 예를 들어 GitHub Actions와 같은 도구를 통해 CI를 구축하면, 메인 브랜치로 코드를 병합하기 전에 실패한 테스트를 수정하도록 강제하여 버그를 조기에 차단하고 코드의 안정성을 보장할 수 있습니다 [1-3].
|
||||
* **정적 코드 분석(SAST) 및 보안 도구의 결합**: 현대의 CI/CD 파이프라인은 단순히 빌드와 테스트만을 수행하는 것이 아니라, 다양한 코드 분석 도구(예: SonarQube, Semgrep, Cycode, Fortify 등)와 직접 통합되어 워크플로우 내에서 기능합니다 [5-7]. 코드가 병합되기 전 백그라운드에서 보안 취약점, 코딩 스타일 문제, 하드코딩된 비밀 키(Secret) 등을 자동으로 스캔하여 배포 속도 저하 없이 보안을 강화할 수 있습니다 [8, 9].
|
||||
* **마이크로서비스 아키텍처에서의 독립성 확보**: 마이크로서비스 아키텍처 환경에서는 각 서비스가 모놀리식 구조와 달리 자신만의 독립된 코드베이스와 CI/CD 파이프라인, 데이터 저장소를 가집니다 [10]. 이를 통해 특정 서비스에 대한 업데이트 및 배포가 다른 서비스에 영향을 미치지 않고 병렬적으로 신속하게 이루어질 수 있습니다 [10].
|
||||
* **코드베이스 이해 및 온보딩의 촉진**: 낯선 코드베이스를 파악해야 하는 상황에서, 양질의 테스트와 CI/CD 체계가 구축되어 있으면 개발자가 코드의 의도를 빠르게 이해할 수 있습니다 [4]. 코드의 기능이 테스트를 통해 CI 환경에서 지속적으로 검증되므로, 개발자는 코드가 어떻게 동작해야 하는지에 대한 명확한 기준을 얻을 수 있습니다 [4].
|
||||
## 💻 패턴
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
### 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
|
||||
|
||||
* **빌드/파이프라인 성능 저하 문제**: CI/CD 워크플로우에 무겁고 복잡한 정적 분석 도구(예: 대규모 엔터프라이즈용 Checkmarx 등)를 추가할 경우, 스캔 시간이 길어져 파이프라인 전체의 성능과 릴리스 속도에 악영향을 미칠 수 있습니다 [11]. 따라서 아무리 정확도가 높은 분석 도구라도 개발 및 릴리스 속도를 지속적으로 늦춘다면 오히려 득보다 실이 많을 수 있으므로 성능에 미치는 영향을 평가하여 도입해야 합니다 [12].
|
||||
* **오탐(False Positive)으로 인한 피로도**: CI/CD 파이프라인에서 실행되는 자동화된 분석 결과가 지나치게 많은 오탐을 발생시키면 개발자의 신뢰가 떨어지고 불필요한 리뷰 시간 낭비를 초래할 수 있습니다 [12].
|
||||
* **테스트 파일 구성의 복잡성**: 테스트 파일을 코드베이스 내에 모듈별로 뿔뿔이 흩어놓을 경우, CI/CD 파이프라인에서 모듈 간의 상호작용을 통합 테스트(Integration Testing)할 때 의존성 관리 및 실행 순서 보장 등에서 복잡성이 증가할 수 있습니다 [13, 14].
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** [[Static Application Security Testing (SAST)|Static Application Security Testing (SAST]], Code Review, Git Hooks, [[Quality Gates|Quality Gates]], [[Pull Request (PR)|Pull Request (PR]]
|
||||
- **Projects/Contexts:** [[TeamCity|TeamCity]], GitHub Actions, GitLab CI, Jenkins, [[Azure DevOps|Azure DevOps]]와 같이 코드 통합과 자동화 빌드를 관장하는 인프라 환경 [1, 9, 14].
|
||||
- **Contradictions/Notes:** 로컬 Git 훅(pre-commit 등)은 로컬 환경에서 빠른 피드백을 제공하여 시간을 절약하게 해주지만, 우회가 가능하므로 CI를 완전히 대체할 수 없으며 반드시 CI 파이프라인을 통한 최종 검증이 병행되어야 합니다 [2, 4, 15].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-18*
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
### Related Concepts
|
||||
|
||||
#### [소프트웨어 아키텍처 및 배포]
|
||||
- [[Microservices Architecture]]
|
||||
- 연결 이유: 대규모 시스템을 작은 비즈니스 도메인 단위로 나눈 구조로, 각 서비스가 자율성을 가지기 위해 독립적인 CI/CD 파이프라인을 운용하기 때문입니다 [10, 15].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: CI를 모놀리식 시스템 전체에 적용할 때와 개별 서비스에 적용할 때 배포의 민첩성이 어떻게 달라지는지 이해할 수 있습니다.
|
||||
|
||||
#### [품질 보증 및 분석 도구]
|
||||
- [[Static Application Security Testing (SAST)]]
|
||||
- 연결 이유: 코드가 CI 파이프라인에 푸시될 때 자동으로 실행되어, 실행 없이도(source-code level) 보안 취약점과 버그를 찾아내는 정적 분석 기술이기 때문입니다 [5, 16, 17].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: CI 단계를 활용하여 배포 전 코드 결함과 보안 문제를 조기에 발견하고 차단하는 자동화 프로세스 구축.
|
||||
|
||||
- [[GitHub Actions]]
|
||||
- 연결 이유: CI(Continuous Integration)를 자동화된 테스트 및 빌드 워크플로우로 구현하는 대표적인 플랫폼 도구입니다 [1-3].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 새로운 커밋이나 PR이 발생했을 때 트리거되어 개발자의 개입 없이 코드를 검증하는 실무적인 메커니즘.
|
||||
|
||||
### Deeper Research Questions
|
||||
|
||||
- 마이크로서비스 아키텍처에서 수십, 수백 개의 독립적인 CI/CD 파이프라인을 운영할 때, 일관된 보안 정책 및 코드 스타일 규칙을 어떻게 중앙 집중적으로 관리하고 강제할 수 있는가?
|
||||
- CI 파이프라인에 무거운 정적 보안 분석 도구를 연동할 경우 발생하는 스캔 속도 지연(bottleneck) 문제를 완화하고, 릴리스 속도와 보안성의 균형을 맞추기 위한 최적화 기법은 무엇인가?
|
||||
- 대규모 레거시 코드베이스 환경에 새로운 CI 파이프라인을 도입할 때, 잦은 빌드 실패와 오탐(False Positive)으로 인한 개발자 피로도를 최소화하는 점진적 적용 전략은 무엇인가?
|
||||
- 코드베이스 디렉토리 내 테스트 파일의 물리적인 위치(기능별 분산 배치 vs 중앙 테스트 디렉토리 집중)가 CI 파이프라인의 테스트 탐색(Test Discovery) 및 실행 효율성에 미치는 구조적 영향은 무엇인가?
|
||||
- 인공지능(AI) 기반 코드 리뷰 도구와 기존의 CI/CD 파이프라인(예: GitHub Actions)을 결합하여, 단순 구문 검사를 넘어 아키텍처 설계 결함을 병합 이전에 자동으로 식별하는 프로세스를 어떻게 구축할 수 있는가?
|
||||
|
||||
### Practical Application Contexts
|
||||
|
||||
- **Implementation:** GitHub Actions 등의 도구를 도입하여 레포지토리에 커밋이 올라올 때마다 작성된 단위 테스트(Unit Tests)와 보안 분석(SAST)이 자동으로 실행되고, 실패 시 병합(Merge)이 제한되도록 환경을 구현합니다 [1, 2, 5].
|
||||
- **System Design:** 소프트웨어 설계 시 마이크로서비스 아키텍처를 채택하여, 개별 서비스 단위로 CI/CD 파이프라인을 분리함으로써 시스템의 특정 부분에서 발생한 빌드 에러가 전체 서비스 배포를 블로킹하지 않도록 설계합니다 [10].
|
||||
- **Operation / Maintenance:** 새로운 기능 배포 시 CI 파이프라인을 통해 "내 로컬 환경에서는 되는데 운영 서버에서는 안 되는" 이슈를 근본적으로 방지하고, 메인 브랜치의 신뢰도를 높여 유지보수성을 극대화합니다 [2, 3].
|
||||
- **Learning Path:** 크고 복잡한 신규 코드베이스를 처음 파악하려는 학습자는, 코드를 눈으로만 읽기보다 CI 과정에 포함된 테스트 코드를 살피고 테스트 환경을 직접 가동하며 동적인 시스템의 의도를 파악하는 것이 유리합니다 [4].
|
||||
- **My Project Relevance:** 본 프로젝트의 버전 관리 및 품질 보증 체계에 적용하여 개발 주기를 단축시키고, PR 승인 전 필수 확인 조건(자동화된 린트, 테스트, 보안 스캔)으로 CI를 필수 도입하는 데 참고할 수 있습니다.
|
||||
|
||||
### Adjacent Topics
|
||||
|
||||
- [[Code Review]]
|
||||
- 확장 방향: CI 시스템이 자동화된 기계적 검증을 처리한다면, 코드 리뷰는 CI를 통과한 코드의 비즈니스적 문맥, 아키텍처적 타당성, 그리고 가독성 등을 사람이 판단하는 보완적인 영역으로 확장하여 연구할 수 있습니다 [9, 18, 19].
|
||||
- [[Application Security Posture Management (ASPM)]]
|
||||
- 확장 방향: 단순한 CI 파이프라인 스캐닝을 넘어 코드부터 클라우드 운영 환경 전체에 이르는 보안 가시성 관리 및 취약점 통합 대응 전략으로 확장할 수 있습니다 [20, 21].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
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
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Matrix build
|
||||
```yaml
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-24.04, macos-14, windows-2022]
|
||||
node: [20, 22]
|
||||
runs-on: ${{ matrix.os }}
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Affected-only (monorepo)
|
||||
```yaml
|
||||
- run: pnpm exec turbo run test --filter=...[origin/main]
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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: [ ... ]
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### Container-based test (testcontainers)
|
||||
```python
|
||||
# pytest with ephemeral postgres
|
||||
from testcontainers.postgres import PostgresContainer
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
def test_repo():
|
||||
with PostgresContainer("postgres:17") as pg:
|
||||
url = pg.get_connection_url()
|
||||
# run integration test against real DB
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]] · [[Software Engineering Practices]]
|
||||
- 변형: [[Continuous Delivery (CD)]] · [[Continuous Deployment]] · [[Trunk-Based Development]]
|
||||
- 응용: [[GitHub Actions]] · [[GitLab CI]] · [[Jenkins]]
|
||||
- Adjacent: [[Test Automation]] · [[Static Analysis]] · [[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 |
|
||||
|
||||
@@ -2,120 +2,228 @@
|
||||
id: wiki-2026-0508-control-points
|
||||
title: Control Points
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [Capture Points, KOTH, Domination]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.85
|
||||
verification_status: applied
|
||||
tags: [game-design, multiplayer, objectives, fps]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: csharp-gdscript
|
||||
framework: unity-godot-unreal
|
||||
---
|
||||
|
||||
# 통제점(Control Points)
|
||||
# Control Points
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
통제점(Control Points)은 최소 25명 이상의 플레이어로 구성된 동맹(Alliance)이 세계 지도 상의 경합 구역(Contestable Zones)에서 점령할 수 있는 거점입니다 [1]. 통제점을 성공적으로 점령하고 방어하면, 해당 동맹은 통제점의 레벨에 따라 다양한 수준의 석유 및 토륨 부스트 혜택을 얻게 됩니다 [2, 3]. 점령 과정은 NPC 기지 공격부터 시작하여 다른 동맹과의 제한된 전쟁(War) 및 서든 데스(Sudden Death) 단계에 이르는 치열한 전투로 구성됩니다 [3-5].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
거점(Control Points)은 월드 맵의 분쟁 가능 구역(Contestable Zones) 내에 위치하며, 점령 시 동맹(Alliance)에게 오일과 토륨 부스트 혜택을 제공하는 주요 군사적 목표물입니다 [1, 2]. 최소 25명 이상의 플레이어로 구성된 동맹만이 점령전에 참여할 수 있으며, NPC 기지를 파괴하는 것으로 본격적인 전쟁이 시작됩니다 [1, 2]. 이후 일정 횟수의 거점 파괴, 동맹 간의 전쟁(War) 단계, 서든 데스(Sudden Death) 등 엄격한 룰에 기반한 페이즈를 거쳐 최종적으로 구역 내에 생존한 기지의 유무에 따라 점령 동맹이 결정됩니다 [2-4].
|
||||
### 매 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 |
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **경합 구역과 통제점의 개념:** 통제점은 세계 지도의 특정 구역인 '경합 구역(Contestable Zones)' 내에 위치하는 NPC 기지입니다 [1, 3]. 모든 지도 구역에 전초기지나 요새가 있지만, 오직 경합 구역만이 통제점을 포함하고 있습니다 [1].
|
||||
- **점령을 위한 전투 및 진행 단계:** 통제점 점령은 여러 단계를 거쳐 이루어집니다.
|
||||
- **공격(Attacking) 및 공격받음(Under Attack) 단계:** 동맹이 경합 구역을 점령하기 위한 첫 번째 단계로, 통제점 자체인 NPC 기지를 공격해 물리쳐야 합니다 [3]. 이후 '공격받음' 상태로 전환되며, 제한된 시간 내에 통제점 레벨에 따라 요구되는 횟수만큼 기지를 격파해야 다음 단계로 넘어갈 수 있습니다 [3].
|
||||
- **전쟁(War) 단계:** 방어 동맹과 공격 동맹 간에 상반된 목표를 가지고 맞붙는 단계입니다 [4]. 방어 측은 경합 구역에서 모든 공격 동맹 구성원을 제거해야 하며, 공격 측은 전쟁 단계가 끝날 때까지 구역 내에 최소 1명의 동맹원 기지를 유지해야 합니다 [4]. 이 단계 동안 두 동맹은 다른 플레이어의 공격을 받지 않는 일종의 '철창 매치(cage match)'를 치르며, 패배한 기지는 구역 밖으로 '이동([[Shift|Shift]]ed)'되어 전쟁이 끝나거나 서든 데스 단계가 되기 전까지 돌아올 수 없습니다 [4].
|
||||
- **서든 데스(Sudden Death) 단계:** 전쟁 단계 종료 시점에도 공격 동맹 구성원이 구역 내에 남아있을 경우 발동됩니다 [5]. 방어 측이 공격 측 기지를 구역 밖으로 밀어낼 수 있는 마지막 기회이며, 한 번 밖으로 쫓겨나면 다시는 구역으로 들어올 수 없습니다 [5]. 서든 데스 종료 시 공격 측 기지가 하나라도 남아있다면 공격 동맹이 통제점을 최종적으로 차지하게 됩니다 [5].
|
||||
- **안전(Secured) 단계:** 통제점 전쟁의 최종 단계로, 이 기간 동안에는 다른 동맹이 통제점을 공격하여 경합 구역을 뺏기 위해 시도할 수 없습니다 [5].
|
||||
### 매 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 불가.
|
||||
|
||||
* **참여 조건 및 점령 혜택**
|
||||
거점(Control Points) 점령전에 참여하기 위해서는 최소 25명의 플레이어로 구성된 동맹(Alliance)에 소속되어야 합니다 [1]. 거점을 성공적으로 점령한 동맹은 해당 거점의 레벨에 따라 다양한 수준의 오일(Oil) 및 토륨(Thorium) 생산량 부스트 혜택을 받게 됩니다 [2].
|
||||
### 매 응용
|
||||
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).
|
||||
|
||||
* **점령전 진행 단계 (Phases of CP War)**
|
||||
점령전은 다음과 같은 여러 단계를 순차적으로 거치며 진행됩니다.
|
||||
* **초기 공격 (Attacking Control Points)**: 분쟁 가능 구역(Contestable Zone)을 차지하기 위해 동맹이 가장 먼저 해야 할 일은 구역 내에 있는 NPC 기지 형태의 거점 자체를 파괴하는 것입니다 [2].
|
||||
* **공격받음 (Under Attack) 단계**: NPC 기지를 무너뜨리면 거점은 'Under Attack' 상태가 됩니다 [2]. 이때 거점 레벨에 따라 요구되는 지정된 승리 횟수를 제한 시간 내에 달성해야만 다음 단계로 넘어갈 수 있습니다 [2].
|
||||
* **전쟁 (War) 단계**: 본격적으로 두 동맹이 분쟁 가능 구역 내에서 맞붙는 "케이지 매치(Cage Match)" 단계입니다 [3]. 이 기간에는 두 동맹을 제외한 다른 어떤 플레이어도 해당 구역의 기지를 공격할 수 없습니다 [3].
|
||||
* **방어 동맹의 목표**: 공격 동맹의 모든 멤버를 분쟁 가능 구역 밖으로 제거해야 합니다. 기지가 파괴된 플레이어는 구역 밖으로 '이동(shifted)'되며, 전쟁이 끝나거나 서든 데스 단계가 되기 전까지는 구역으로 복귀할 수 없습니다 [3].
|
||||
* **공격 동맹의 목표**: 전쟁 단계가 종료될 때까지 구역 내에 최소 1명 이상의 동맹 멤버 기지가 살아남아 있어야 합니다 [3].
|
||||
* **서든 데스 (Sudden Death) 단계**: 전쟁 단계가 끝날 때까지 구역 내에 공격 동맹의 기지가 남아있을 경우 발동됩니다 [4]. 방어 동맹이 공격 기지를 구역 밖으로 밀어낼 수 있는 마지막 기회이며, 이 단계에서 밖으로 밀려난 기지는 절대 다시 구역으로 복귀할 수 없습니다 [4]. 하나의 공격 기지라도 살아남는다면 공격 동맹이 거점을 차지하게 됩니다 [4].
|
||||
* **안전 확보 (Secured) 단계**: 거점 점령전의 최종 단계입니다 [4]. 이 기간 동안에는 다른 어떤 동맹도 해당 거점을 공격하거나 분쟁 가능 구역을 빼앗기 위해 시도할 수 없으며, 승리한 동맹은 다음 전투를 준비하며 휴식을 취할 수 있습니다 [4].
|
||||
## 💻 패턴
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- 신규 지식 자산화 (2026-04-27).
|
||||
- War Commander 전투 생태계 데이터 통합.
|
||||
### Unity C# — control point trigger
|
||||
```csharp
|
||||
using UnityEngine;
|
||||
using Unity.Netcode;
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** [[동맹(Alliances)|동맹(Alliances]], 토륨(Thorium), [[세계 지도(World Map)|세계 지도(World Map]]
|
||||
- **Projects/Contexts:** War Commander 전투 시스템 및 동맹 간 영토 지배 전략
|
||||
- **Contradictions/Notes:** 통제점 확보는 단순히 개별 기지의 전투력뿐만 아니라, 외부 세력의 개입이 차단된 상태('cage match')에서 동맹원들이 구역 내에 기지를 유지하거나 밀어내는 지정학적 기동 전략을 요구합니다 [2, 4].
|
||||
public class ControlPoint : NetworkBehaviour {
|
||||
public NetworkVariable<float> Progress = new(0f);
|
||||
public NetworkVariable<int> OwnerTeam = new(-1);
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-27*
|
||||
[SerializeField] private float captureRate = 10f; // pct/sec per attacker
|
||||
[SerializeField] private float maxRate = 20f;
|
||||
|
||||
---
|
||||
private readonly Dictionary<int, int> teamCount = new();
|
||||
|
||||
- **Related Topics:** [[동맹(Alliances)|동맹(Alliances)]], 토륨(Thorium)
|
||||
- **Projects/Contexts:** War Commander: Rogue Assault
|
||||
- **Contradictions/Notes:** 제공된 소스에서 설명하는 분쟁 가능 구역(Contestable Zones)과 거점(Control Points) 점령 시스템은 'War Commander: Rogue Assault' 헬프 센터의 데이터를 기반으로 합니다 [1]. 본가 'War Commander'의 200개 섹터를 둘러싼 동맹전(Clans & Alliances)과 맥락을 같이 하지만, 상세 전투 페이즈(War, Sudden Death 등)는 로그 어썰트(Rogue Assault)의 특정 시스템을 설명한 것임을 유의해야 합니다.
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-27*
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
private void FixedUpdate() {
|
||||
if (!IsServer) return;
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
var teams = new List<KeyValuePair<int,int>>(teamCount);
|
||||
teams.Sort((a, b) => b.Value.CompareTo(a.Value));
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
if (teams.Count == 0 || teams[0].Value == 0) return;
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
// Contested: top two teams equal & nonzero
|
||||
if (teams.Count > 1 && teams[0].Value == teams[1].Value) return;
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
var attacker = teams[0];
|
||||
var rate = Mathf.Min(maxRate, captureRate * Mathf.Sqrt(attacker.Value));
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Godot 4 / GDScript
|
||||
```gdscript
|
||||
extends Area3D
|
||||
class_name ControlPoint
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
@export var capture_rate: float = 10.0
|
||||
var progress: float = 0.0
|
||||
var owner_team: int = -1
|
||||
var team_in_zone: Dictionary = {}
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
func _physics_process(delta: float) -> void:
|
||||
if not multiplayer.is_server(): return
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
var top_team := -1
|
||||
var top_count := 0
|
||||
var contested := false
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
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
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
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
|
||||
- 부모: [[Multiplayer Game Design]] · [[Game Objectives]]
|
||||
- 변형: [[King of the Hill]] · [[Domination]] · [[Payload]]
|
||||
- 응용: [[Team Fortress 2]] · [[Overwatch]] · [[Battlefield]]
|
||||
- Adjacent: [[Server Authority]] · [[Lag Compensation]] · [[Spawn System]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -2,116 +2,177 @@
|
||||
id: wiki-2026-0508-control-systems-engineering
|
||||
title: Control Systems Engineering
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [control-systems, feedback-control, PID-control]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [control-systems, pid, mpc, feedback]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: python
|
||||
framework: do-mpc/control
|
||||
---
|
||||
|
||||
# Control[[_system|system]]s Engineering (제어 시스템 공학)
|
||||
# Control Systems Engineering
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> "원하는 목표 상태에 도달하도록 시스템을 설계하고 동적으로 수정하라" — 물리적 장치나 가상 에이전트가 외부 교란([[Noise|Noise]])에도 불구하고 목표 수치(Set-point)를 안정적으로 유지하게 만드는 공학적 프레임워크.
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
> "의도한 대로의 상태 유지: 복잡한 외부의 방해 속에서도, 시스템의 현재 상태를 목표치(Set-point)로 일정하게 유지하거나 정확한 경로로 유도하기 위해 끊임없이 '수정 명령'을 내리는 기술적 중추."
|
||||
### 매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **추출된 패턴:** 시스템의 출력을 입력으로 다시 되먹여(Feedback) 오차를 줄여나가는 '폐쇄 루프 제어(Closed-loop Control)' 패턴.
|
||||
- **세부 내용:**
|
||||
- **Open-loop vs Closed-loop:** 피드백 존재 여부에 따라 단순 명령 실행과 상태 기반 자동 수정을 구분.
|
||||
- **PID Control:** 비례(P), 적분(I), 미분(D) 항을 조합하여 오차를 빠르고 안정적으로 수렴시키는 범용 알고리즘.
|
||||
- **Stability [[Analysis|Analysis]]:** 시스템이 발산하지 않고 평형 상태를 유지할 수 있는지 수학적으로 검증.
|
||||
- **[[State-Space|State-Space]] Representation:** 복잡한 시스템의 상태를 행렬로 표현하여 다변수 제어를 가능하게 함.
|
||||
### 매 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.
|
||||
|
||||
제어 시스템 공학(Control-Systems-Engineering)은 동적 시스템의 거동을 제어하고 원하는 동작을 이끌어내기 위한 공학적 원리와 분석 방법을 다룹니다.
|
||||
## 💻 패턴
|
||||
|
||||
1. **핵심 구조 (Feedback Loop)**:
|
||||
* **Sensor**: 현재 상태(Output) 측정.
|
||||
* **Comparator**: 목표값과 현재값의 차이(Error) 계산.
|
||||
* **Controller**: 오차를 줄이기 위한 제어값 계산 (예: PID 제어).
|
||||
* **Actuator**: 시스템에 물리적/논리적 변화 가함.
|
||||
2. **왜 중요한가?**:
|
||||
* 자율주행차의 조향부터 원자로의 온도 조절, 로봇의 균형 잡기까지 현대 문명의 모든 '자동화'가 이 이론 위에 서 있기 때문임. (Automation와 연결)
|
||||
### 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
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 전통적인 고전 제어(루프 베이스)에서 현대의 AI 기반 지능형 제어(강화학습 베이스)로 패러다임이 융합되고 있음.
|
||||
- **정책 변화:** Antigravity 에이전트의 '목표 추적 루프' 설계 시, PID 제어의 감쇠(Damping) 원리를 적용하여 급격한 상태 변화를 억제함.
|
||||
|
||||
---
|
||||
|
||||
- **과거 데이터와의 충돌**: 과거에는 시스템의 모든 수학적 모델 정책을 완벽히 알아야 한다는 고전 제어(Classic Control) 정책이 주류였으나, 현대 정책은 모델을 몰라도 데이터로 배우는 '모델 프리 강화학습 정책(Model-free RL)'과 결합하여 훨씬 복합적인 제어 정책을 수행함(RL Update). ([[Reinforcement Learning (RL)|Reinforcement Learning (RL)]]와 연결)
|
||||
- **정책 변화(RL Update)**: 이제는 단순 물리 시스템 제어 정책을 넘어, 거대 AI 모델의 답변 정책([[Alignment|Alignment]])을 제어하거나 사회적 시스템의 변동성 정책을 제어하는 광의의 제어 정책으로 확장 중임.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Parent:** 10_Wiki/💡 Topics/AI
|
||||
- **Related:** [[Feedback-Control-Systems|Feedback-Control-Systems]], [[Robotics|Robotics]], System-Dynamics
|
||||
- **Raw Source:** 10_Wiki/Topics/AI/Control Systems Engineering.md
|
||||
|
||||
---
|
||||
|
||||
- Automation, [[Reinforcement Learning (RL)|Reinforcement Learning (RL)]], [[System-Theory|System-Theory]], [[Robotics|Robotics]], [[Efficiency|Efficiency]]
|
||||
- **Key Algorithms**: PID Control, Kalman Filter, Model Predictive Control (MPC).
|
||||
---
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
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
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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)
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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()
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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)
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]] · [[LQR]] · [[MPC]] · [[Adaptive-Control]]
|
||||
- 응용: [[Digital-Twin]] · [[Autopilot]] · [[Process-Control]]
|
||||
- Adjacent: [[Kalman-Filter]] · [[State-Estimation]] · [[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 |
|
||||
|
||||
@@ -2,128 +2,163 @@
|
||||
id: wiki-2026-0508-cosmos-플랫폼-netflix
|
||||
title: Cosmos 플랫폼 (Netflix)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [Netflix Cosmos, Cosmos Platform, Cosmos]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.85
|
||||
verification_status: applied
|
||||
tags: [netflix, media-processing, workflow, microservices]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: java
|
||||
framework: spring-boot
|
||||
---
|
||||
|
||||
# [[Cosmos 플랫폼 (Netflix)|Cosmos 플랫폼 (Netflix]]
|
||||
# Cosmos 플랫폼 (Netflix)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> Cosmos는 넷플릭스(Netflix)가 마이크로서비스, 비동기 워크플로우, 서버리스 함수의 장점을 결합하여 구축한 컴퓨팅 플랫폼이다 [1]. 기존 모놀리식 아키텍처인 'Reloaded'의 한계를 극복하고 관측성, 모듈성, 생산성, 지속적 배포(Continuous Delivery)를 향상시키기 위해 개발되었다 [2, 3]. 수 분에서 수년에 걸쳐 실행되는 복잡한 계층적 워크플로우 및 리소스 집약적인 알고리즘을 조율하는 데 최적화되어 있으며, 대규모 처리량과 지연 시간에 민감한 작업 부하를 모두 지원한다 [1].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
> 넷플릭스 코스모스 플랫폼(Netflix Cosmos)은 마이크로서비스의 장점과 비동기 워크플로우 및 서버리스 함수를 결합한 컴퓨팅 플랫폼이다 [1]. 이 플랫폼은 주로 수 분에서 수 년까지 지속될 수 있는 복잡하고 계층적인 워크플로우를 통해 조정되는 자원 집약적 알고리즘을 처리하는 데 사용된다 [1]. 기존의 모놀리식 아키텍처인 '리로디드(Reloaded)'의 한계를 극복하고 관찰성, 모듈성, 생산성, 자동화된 전송 능력을 향상시키기 위해 개발되었다 [2-4].
|
||||
### 매 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) 위 실행.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **배경 및 점진적 전환:** 넷플릭스의 기존 미디어 처리 시스템인 'Reloaded'는 개발팀 규모가 커짐에 따라 인프라와 애플리케이션 코드가 뒤섞이고 새로운 기능 배포가 지연되는 모놀리식 아키텍처의 한계를 겪었다 [2]. 이를 해결하기 위해 워크플로우 기반 미디어 특화 마이크로서비스 플랫폼인 Cosmos가 구축되었으며, 시스템을 완전히 교체할 때까지 기존 시스템 주위를 감싸며 새로운 시스템을 성장시키는 '스트랭글러 피그(Str[[ANGLE|ANGLE]]r fig) 패턴'을 도입하여 위험을 줄이면서 마이그레이션을 진행했다 [3, 4].
|
||||
* **다차원적 관심사의 분리 ([[_뇌와 팔다리의 분리_ - 관심사의 분리 (Separation of Concerns)|Separation of Concerns]]):** Cosmos는 로직을 API, 워크플로우, 서버리스 함수로 나누는 한편, 도메인 특화 애플리케이션 로직과 분산 컴퓨팅을 처리하는 플랫폼으로 분리하는 양방향 관심사 분리 원칙을 적용했다 [5]. 분산 처리를 담당하는 플랫폼은 세 가지 주요 하위 시스템과 이를 연결하는 큐잉 시스템으로 구성된다 [6].
|
||||
* **Optimus:** 외부 요청을 내부 비즈니스 모델로 매핑하는 API 계층이다 [6].
|
||||
* **Plato:** 비즈니스 규칙을 모델링하는 워크플로우 계층으로, 'Emirax'라는 도메인 특화 언어(DSL)를 사용하는 포워드 체이닝(forward chaining) 규칙 엔진을 기반으로 설계되었다 [6-8].
|
||||
* **Stratum:** 상태가 없으며 계산 집약적인 알고리즘을 실행하는 서버리스 계층이다 [6].
|
||||
* **Timestone:** 위의 하위 시스템들이 비동기적으로 통신할 수 있도록 돕는 대규모 저지연 우선순위 큐잉 시스템이다 [6].
|
||||
* **지연 시간 관리 및 활용 사례:** Cosmos는 서비스의 분해와 계층화를 지원하여 스튜디오에서 들어오는 미디어 소스를 처리하는 대규모 처리량 중심의 고위급 서비스인 'Tapas'와, 사용자 대면 작업으로 지연 시간에 민감한 'Sagan' 등의 다양한 서비스를 효율적으로 오케스트레이션한다 [9-12]. 수요 폭증 시 발생하는 지연 문제를 해결하기 위해 Stratum은 리소스 풀(Resource pools) 설정, 사전 확보된 웜 용량(Warm capacity), 컨테이너 시작 비용을 분산하는 마이크로 배치(Micro-batches), 작업의 우선순위(Priority) 지정 등의 전략을 활용한다 [13].
|
||||
### 매 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.
|
||||
|
||||
* **배경 및 개발 목적:** 넷플릭스는 기존의 모놀리식 미디어 처리 시스템인 '리로디드(Reloaded)'가 규모의 확장과 개발자 수의 증가로 인해 새로운 기능 배포를 지연시키고 운영 부담을 가중시키는 문제에 직면했다 [2, 3]. 이에 대응하여 관찰성(Observability), 모듈성([[Modularity|Modularity]]), 생산성(Productivity), 지속적 배포(Delivery)를 제공하는 워크플로우 중심의 미디어 특화 마이크로서비스 플랫폼인 코스모스를 구축하게 되었다 [4]. 기존 시스템을 점진적으로 안전하게 대체하기 위해 '스트랭글러 피그(str[[ANGLE|ANGLE]]r fig)' 패턴을 채택하였다 [5].
|
||||
## 💻 패턴
|
||||
|
||||
* **아키텍처 및 관심사의 분리 ([[_뇌와 팔다리의 분리_ - 관심사의 분리 (Separation of Concerns)|Separation of Concerns]]):** 코스모스는 애플리케이션과 플랫폼의 로직을 분리하여, 개발자가 분산 컴퓨팅의 세부 사항을 알 필요 없이 미디어 특화 추상화에 집중할 수 있게 한다 [6, 7]. 비즈니스 로직은 다음과 같은 세 가지 스케일 인식(scale-aware) 하위 시스템으로 나뉘어 관리된다 [6-8].
|
||||
* **옵티머스(Optimus):** 외부 요청을 내부 비즈니스 모델로 매핑하는 API 계층이다 [7, 8].
|
||||
* **플라토(Plato):** 비즈니스 규칙 모델링을 위한 워크플로우 계층으로, 'Emirax'라는 도메인 특화 언어를 사용하는 전방 추론(forward chaining) 규칙 엔진이다 [7-10].
|
||||
* **스트라툼(Stratum):** 무상태([[State|State]]less) 및 컴퓨팅 집약적인 함수를 실행하기 위한 서버리스 계층이다. 유연한 리소스 스케줄링을 지원하며 타이투스(Titus) 컨테이너 플랫폼 위에 구축되었다 [7, 8, 11].
|
||||
|
||||
* **비동기 통신 시스템:** 코스모스의 하위 시스템들은 대규모, 저지연 우선순위 대기열 시스템인 **타임스톤(Timestone)** 을 통해 서로 비동기적으로 통신한다 [7, 8].
|
||||
|
||||
* **지연 시간 및 처리량 관리:** 사용자 대면 서비스와 같은 지연 시간 민감(Latency-sensitive) 애플리케이션을 위해 스트라툼은 리소스 풀, 웜 커패시티(Warm capacity), 마이크로 배치(Micro-batches), 우선순위 설정을 통해 함수 실행 지연 시간을 관리한다 [12, 13]. 반면 리소스를 대량으로 소비하는 처리량 민감(Throughput-sensitive) 워크로드의 경우, 더 저렴한 '기회주의적(opportunistic)' 컴퓨팅 리소스를 활용할 수 있도록 유연하게 스케줄링한다 [11].
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
|
||||
---
|
||||
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** 마이크로서비스 (Microservices), 서버리스 컴퓨팅 (Serverless Computing), [[관심사의 분리 (Separation of Concerns)|관심사의 분리 (Separation of Concerns]]
|
||||
- **Projects/Contexts:** Reloaded, Optimus, Plato, Stratum, Timestone, Tapas, Sagan
|
||||
- **Contradictions/Notes:** "서버리스 함수를 조율하는 워크플로우를 트리거하는 마이크로서비스"라는 Cosmos의 프로그래밍 모델은 강력하지만, 단순한 애플리케이션에 적용하기에는 부가되는 복잡성이 이점보다 클 수 있다는 점이 지적된다 [14]. 또한, Cosmos 플랫폼 도입 당시 애플리케이션 개발자들은 일관성과 신뢰성을 획득하는 대신 일정한 유연성을 포기하는 방향으로 마인드셋을 전환해야 했다 [14].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-18*
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** 마이크로서비스 (Microservices), [[관심사의 분리 (Separation of Concerns)|관심사의 분리 (Separation of Concerns]], 서버리스 컴퓨팅 (Serverless Computing)
|
||||
- **Projects/Contexts:** 리로디드 (Reloaded), 타파스 (Tapas), 사간 (Sagan), 스트랭글러 피그 패턴 (Strangler fig pattern)
|
||||
- **Contradictions/Notes:** 소스에 따르면, 코스모스 서비스는 전형적인 마이크로서비스와 유사한 점이 있으나 완전히 같지는 않다. 일반적인 마이크로서비스가 무상태 비즈니스 로직을 가진 API로 요청 부하에 따라 자동 확장되는 반면, 코스모스는 다단계 워크플로우와 컴퓨팅 집약적인 비동기 서버리스 함수를 결합하고 있으며 큐(queue)의 크기에 따라 확장된다는 차이가 존재한다 [14].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-18*
|
||||
|
||||
---
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Optimus service (gRPC)
|
||||
```protobuf
|
||||
service EncodeService {
|
||||
rpc StartEncode(EncodeRequest) returns (EncodeResponse);
|
||||
rpc GetStatus(StatusRequest) returns (stream StatusUpdate);
|
||||
}
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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()
|
||||
));
|
||||
}
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### Idempotency key (function level)
|
||||
```java
|
||||
@CosmosFunction(idempotencyKey = "${input.movieId}-${input.bitrate}")
|
||||
public class EncodeFunction implements Function<EncodeReq, EncodeResp> { ... }
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 매 결정 기준
|
||||
| 상황 | 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]] · [[Workflow Orchestration]]
|
||||
- 변형: [[AWS Step Functions]] · [[Temporal]] · [[Argo Workflows]]
|
||||
- 응용: [[Netflix Encoding Pipeline]] · [[Conductor (Netflix)]]
|
||||
- Adjacent: [[Titus (Netflix)]] · [[Spinnaker]] · [[Reloaded (Netflix)]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -1,145 +1,171 @@
|
||||
---
|
||||
id: wiki-2026-0508-cross-cutting-concerns
|
||||
title: Cross Cutting Concerns
|
||||
title: Cross-Cutting Concerns
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-AUTO-C8FB6A]
|
||||
aliases: [Cross Cutting Concerns, AOP Concerns, 횡단 관심사]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [auto-reinforced]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [aop, architecture, separation-of-concerns]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-03
|
||||
github_commit: "[P-Reinforce] Continuous Worker - Cross-Cutting Concerns"
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: nestjs
|
||||
---
|
||||
|
||||
# [[Cross-Cutting Concerns|Cross-Cutting Concerns]]
|
||||
# Cross-Cutting Concerns
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
Cross-Cutting Concerns(횡단 관심사)는 로깅, 인증 및 인가, 예외 처리, 데이터 유효성 검사, 캐싱 등과 같이 애플리케이션의 여러 계층과 컴포넌트에 걸쳐 공통적으로 영향을 미치고 반복되는 보조적 요구사항을 의미한다 [1-4]. 핵심 비즈니스 로직(Core Concerns)으로부터 이러한 횡단 관심사를 효과적으로 분리하지 않으면 코드 중복(Scattering)과 강한 결합(Tangling)이 발생하여 시스템 유지보수성과 확장성이 크게 저하된다 [1, 5-7]. 따라서 현대 프레임워크와 아키텍처 설계에서는 관점 지향 프로그래밍(AOP)이나 미들웨어 패턴 등을 통해 이를 중앙 집중화하고 모듈화하는 것을 필수적인 원칙으로 삼는다 [2, 7-9].
|
||||
## 매 한 줄
|
||||
> **"매 module 매 흩어지는 functionality (logging, auth, tx) 의 횡단"**. AOP (Aspect-Oriented Programming, Kiczales 1997) 의 motivation. 2026 현재 NestJS interceptors, Spring AOP, OpenTelemetry auto-instrumentation, Sidecar (Istio) 매 modern realization.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **횡단 관심사의 본질과 문제점:**
|
||||
횡단 관심사는 특정 도메인 모듈에 국한되지 않고 시스템 전체에 걸쳐 광범위하게 적용되는 특성을 지닌다 [8]. 대표적인 예로 트랜잭션 관리, 분산 시스템에서의 동기화 처리, 에러 핸들링, 보안 및 모니터링 등이 있다 [5, 10-12]. 개발자가 시스템 초기 설계 단계에서 이를 명확히 분리할 수 있는 인프라적 지원을 고려하지 않으면, 애플리케이션의 거의 모든 함수에 `try-catch` 블록이나 로깅 코드가 반복적으로 삽입된다 [13-16]. 이는 단일 책임 원칙(SRP)과 DRY(Don't Repeat Yourself) 원칙을 심각하게 위반하는 결과를 낳는다 [14, 17, 18].
|
||||
## 매 핵심
|
||||
|
||||
* **프레임워크별 실전 구현 및 제어 패턴:**
|
||||
현대 소프트웨어 개발 프레임워크들은 횡단 관심사를 비즈니스 코드와 투명하게 분리하기 위한 각기 다른 메커니즘을 제공한다 [19, 20].
|
||||
* **Spring Boot (Java):** 서블릿 계층의 HTTP 요청 처리를 위한 Filter, 스프링 MVC 계층의 Interceptor, 그리고 서비스 로직의 메서드 단위 제어를 위한 관점 지향 프로그래밍(AOP)을 적극 활용한다 [19, 21-24]. 이를 통해 컨트롤러와 리포지토리 등의 비즈니스 로직을 건드리지 않고 횡단 관심사를 삽입할 수 있다 [23, 25].
|
||||
* **NestJS (Node.js):** Angular의 설계 철학을 바탕으로 미들웨어(Middleware), 가드(Guard), 인터셉터(Interceptor), 파이프(Pipe) 등 명확한 파이프라인 구조를 제공한다 [24, 26]. 또한 여러 기능에서 공통으로 필요한 기능(예: 예외 필터나 캐싱 유틸리티)을 `SharedModule`에 담아 `@Global()` 데코레이터와 함께 사용하여 의존성 주입을 간소화한다 [20, 26].
|
||||
* **Django (Python):** 미들웨어(Middleware), 데코레이터, 시그널(Signals) 메커니즘을 지원한다 [24, 27].
|
||||
### 매 정의
|
||||
- 단일 module 의 boundary 를 넘어 매 application 매 widely-scattered concern.
|
||||
- Tangled with business logic → SoC (Separation of Concerns) 위반.
|
||||
- Solution: 매 aspect, decorator, middleware, sidecar, interceptor 로 추출.
|
||||
|
||||
* **아키텍처 레벨의 해결 접근법:**
|
||||
코드 내 분리를 넘어 아키텍처 수준에서도 이를 고립시키기 위한 설계 패턴이 적용된다 [2, 7]. 클린 아키텍처(Clean Architecture)에서는 횡단 관심사를 핵심 비즈니스 규칙과 철저히 분리하여 인프라스트럭처(Infrastructure) 계층에서 처리하도록 강제한다 [2, 28]. 이 밖에도 헬퍼 함수 활용, 성숙한 써드파티 라이브러리 채택, 공통 인터페이스 라이브러리 사용, 혹은 상속(Base Class)을 통해 횡단 로직을 재사용하는 기법들이 상황에 맞게 적용된다 [29-33].
|
||||
### 매 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.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
* **AOP 및 데코레이터의 '마법'에 따른 디버깅 난이도 상승:**
|
||||
AOP 프레임워크나 데코레이터(Annotation)를 활용하면 비즈니스 로직이 매우 깔끔해진다는 장점이 있지만, 실행 흐름이 암시적이고 마법처럼 동작하기 때문에 새로 합류한 개발자가 시스템을 이해하기 어렵게 만든다 [20, 23, 34]. 로직이 의도치 않은 곳에서 실행될 때 그 원인을 추적하고 디버깅하는 난이도가 급격히 상승한다 [34].
|
||||
* **런타임 오버헤드 발생:**
|
||||
메서드를 호출할 때 런타임에 프록시 객체를 생성하여 요청을 가로채는 방식(예: C#의 Castle.DynamicProxy 등)은 성능 오버헤드를 유발한다 [35]. 극단적으로 응답성이 중요한 환경에서 모든 메서드 호출마다 로깅 프록시가 작동한다면 시스템 병목으로 작용할 수 있다 [35].
|
||||
* **상속(Base Class) 기반 공통 로직 관리의 제약:**
|
||||
상속 구조를 사용하여 로깅이나 인증 등의 관심사를 통합 관리하는 방식은 초기에 구현이 직관적이다 [33]. 하지만 대부분의 객체지향 언어는 다중 상속을 지원하지 않기 때문에, 로깅 기능만 필요한 클래스와 '로깅 및 인증'이 모두 필요한 클래스가 생길 경우 복잡한 상속 계층 트리를 양산하게 된다 [33]. 또한 모든 파생 클래스가 공통 인프라 의존성을 생성자로 전달해야 하는 설계 피로도를 초래한다 [33, 36].
|
||||
* **Django 시그널(Signals)의 부수 효과 안티 패턴:**
|
||||
Django 환경에서는 횡단 관심사 및 데이터 동기화 목적으로 시그널(Signals)이 자주 사용되나, 이는 코드 실행 흐름을 숨기고 파악하기 힘든 암시적 부수 효과(Side Effects)를 유발하여 대규모 프로젝트에서는 심각한 기술 부채를 초래하는 안티 패턴으로 꼽힌다 [27, 37].
|
||||
### 매 응용
|
||||
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.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
## 💻 패턴
|
||||
|
||||
#### [아키텍처/기반 기술]
|
||||
- [[Aspect-Oriented Programming (AOP)]]
|
||||
- 연결 이유: 횡단 관심사를 핵심 비즈니스 로직에서 모듈화하여 떼어내기 위해 고안된 주된 프로그래밍 패러다임이다.
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 객체 지향 프로그래밍(OOP)으로 완벽하게 해결되지 않는 코드 얽힘 문제를 프레임워크가 런타임 혹은 컴파일 타임에 어떻게 프록시를 씌워 해결하는지 근본적인 작동 원리를 파악할 수 있다 [19, 23, 30, 38-40].
|
||||
- [[Clean Architecture]]
|
||||
- 연결 이유: 횡단 관심사에 속하는 인프라적 요소(로깅, 인증 등)가 핵심 도메인 로직에 침투하지 않도록 경계를 나누는 시스템 구조 설계론이다.
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 왜 횡단 관심사가 비즈니스 규칙과 섞이지 않아야 하는지, 그리고 의존성 역전 원칙을 통해 어떻게 인프라 계층으로 이를 밀어낼 수 있는지에 대한 거시적인 설계 원칙을 이해할 수 있다 [2, 41, 42].
|
||||
|
||||
#### [구현/활용 도구]
|
||||
- [[Middleware & Interceptors]]
|
||||
- 연결 이유: 횡단 관심사를 애플리케이션의 HTTP 요청/응답 파이프라인에서 처리하기 위한 구체적이고 실전적인 프레임워크 단위의 구성 요소다.
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: NestJS, Spring Boot, ASP.NET Core 등 현대 웹 프레임워크에서 요청의 흐름을 가로채고, 조작하고, 모니터링하는 구체적인 실무 구현 방식을 이해할 수 있다 [19, 22, 24, 28, 43].
|
||||
- [[Dependency Injection (DI)]]
|
||||
- 연결 이유: 컴포넌트가 로거, 캐시 매니저와 같은 횡단 관심사 객체를 직접 생성(Hard-coupling)하지 않고 외부에서 제공받게 만드는 패턴이다.
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 애플리케이션 내의 횡단 관심사 로직들이 어떻게 서로 독립적으로 테스트 가능해지는지, 그리고 객체의 수명 주기(Life Cycle)가 어떻게 관리되는지 이해할 수 있다 [40, 44-46].
|
||||
|
||||
### Deeper Research Questions
|
||||
|
||||
- 단일 애플리케이션 아키텍처에서 마이크로서비스 및 분산 시스템 환경으로 전환될 때, 로깅과 분산 추적(Distributed Tracing) 같은 횡단 관심사는 네트워크 구간에서 어떻게 중앙 집중화되고 통제되는가?
|
||||
- Spring Boot의 Filter, Interceptor, AOP(@Aspect)는 요청 생명주기 내 구체적인 실행 시점과 타겟 객체의 접근 권한 측면에서 어떤 명확한 기술적 한계와 최적의 적용 사례를 갖는가?
|
||||
- 캐싱(Caching)을 횡단 관심사로서 비즈니스 로직과 분리 적용(예: Cache Aside 패턴)할 때 발생하는 데이터 무효화(Invalidation)와 정합성 문제는 아키텍처 수준에서 어떻게 효과적으로 통제될 수 있는가?
|
||||
- 성능에 민감한 백엔드 시스템에서 AOP 기반의 런타임 프록시 생성 및 리플렉션(Reflection) 비용을 최소화하기 위해 컴파일 타임 직조(Compile-time Weaving) 기법을 도입하는 것의 실효성 및 한계는 어떠한가?
|
||||
- Django 프레임워크 환경에서 횡단 관심사나 부가 동작 처리를 위해 시그널(Signals)을 사용할 때 발생하는 '실행 불투명성'을 극복하면서도 모듈 결합도를 낮출 수 있는 실무적 대안(예: 명시적인 서비스 레이어 패턴)은 어떻게 설계되는가?
|
||||
|
||||
### Practical Application Contexts
|
||||
|
||||
- **Implementation:** 비즈니스 함수 내부에서 직접 로거를 선언하거나 무분별한 `try-catch`로 에러를 처리하는 대신, C#의 커스텀 Attribute, Spring의 `@Aspect`, 혹은 NestJS의 Exception Filter를 구현하여 공통 동작을 깔끔하게 분리해 낸다 [13, 14, 23, 26].
|
||||
- **System Design:** 소프트웨어 초기 아키텍처 설계 과정부터 횡단 관심사(보안, 통신, 에러 처리 규약 등)를 도출하고 파이프라인의 어느 단계에서 이를 평가할지 명확히 정의함으로써, 개발자가 인프라스트럭처 걱정 없이 비즈니스 로직에만 몰입할 수 있는 기반 환경을 마련한다 [15, 16, 20].
|
||||
- **Operation / Maintenance:** 횡단 관심사 분리 기법을 통해 로깅 포맷, 성능 추적 지표(Metrics), 캐시 제어 방식이 애플리케이션 전 계층에서 일관성을 유지하도록 함으로써, 프로덕션 환경의 실시간 모니터링 가시성(Observability)과 디버깅 신뢰성을 확보한다 [47-49].
|
||||
- **Learning Path:** 특정 프레임워크(예: NestJS, Spring Boot)를 학습할 때 라우팅과 비즈니스 컨트롤러 작성을 넘어, 해당 프레임워크가 제공하는 횡단 관심사 제어 파이프라인(Filter -> Guard -> Interceptor -> Pipe 등)의 순서와 스펙을 심층적으로 파악하여 실무 능력을 갖춘다 [24, 43].
|
||||
- **My Project Relevance:** 현재 진행 중인 프로젝트 코드베이스 전반에서 중복으로 나타나는 권한 검사나 데이터 포맷 변환(DTO Validation) 로직을 식별하고, 이를 중앙집중화된 미들웨어나 인터셉터 계층으로 리팩터링하여 코드의 가독성과 테스트 용이성을 비약적으로 향상시킨다 [18, 50, 51].
|
||||
|
||||
### Adjacent Topics
|
||||
|
||||
- [[Design Patterns (디자인 패턴)]]
|
||||
- 확장 방향: 횡단 관심사를 효과적으로 설계하기 위해 자주 활용되는 특정 패턴(싱글톤, 프록시, 데코레이터 등)뿐 아니라, 전반적인 소프트웨어 구조와 컴포넌트 간 협력 방식을 유연하게 개선하는 객체지향 패턴 전체로 시야를 넓혀 학습한다.
|
||||
- [[Microservices Architecture (MSA)]]
|
||||
- 확장 방향: 단일 프로세스 안에서의 횡단 관심사가 아닌, 다수의 서비스 인스턴스가 통신하는 환경에서 Service Mesh나 API Gateway를 통해 인가, 로깅, 서킷 브레이커 등을 어떻게 글로벌하게 통제하는지에 대한 네트워크 관점의 인프라 패턴으로 확장한다.
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-03*
|
||||
---
|
||||
*Last updated: 2026-05-03*
|
||||
- Raw Source: 00_Raw/2026-05-03/Cross-Cutting Concerns.md
|
||||
---
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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 }))
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Spring AOP — `@Transactional`
|
||||
```java
|
||||
@Service
|
||||
public class OrderService {
|
||||
@Transactional
|
||||
public Order place(Order o) {
|
||||
repository.save(o);
|
||||
inventory.decrement(o.itemId);
|
||||
// throw → rollback
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Python decorator — caching
|
||||
```python
|
||||
from functools import lru_cache
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
@lru_cache(maxsize=1024)
|
||||
def expensive_lookup(key: str) -> Result:
|
||||
return db.query(key)
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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); }
|
||||
};
|
||||
}
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
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)]] · [[Middleware Pattern]] · [[Decorator Pattern]]
|
||||
- 응용: [[NestJS]] · [[Spring AOP]] · [[Istio]] · [[OpenTelemetry]]
|
||||
- Adjacent: [[Dependency Injection (의존성 주입)]] · [[Sidecar Pattern]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -1,130 +1,34 @@
|
||||
---
|
||||
id: wiki-2026-0508-cumulative-layout-shift-cls
|
||||
title: Cumulative Layout Shift CLS
|
||||
title: Cumulative Layout Shift (CLS)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
duplicate_of: none
|
||||
status: duplicate
|
||||
canonical_id: core-web-vitals
|
||||
duplicate_of: "[[Core-Web-Vitals]]"
|
||||
aliases: [cls, layout-shift]
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, performance, web-vitals]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
---
|
||||
|
||||
# [[Cumulative-Layout-Shift-CLS|Cumulative Layout Shift (CLS]]
|
||||
# Cumulative Layout Shift (CLS)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> Cumulative Layout Shift (CLS)는 웹 페이지가 로드되는 동안 레이아웃과 콘텐츠가 얼마나 예기치 않게 이동하는지를 측정하는 시각적 안정성(Visual Stability) 지표입니다 [1, 2]. 구글의 코어 웹 바이탈([[Core Web Vitals|Core Web Vitals]])을 구성하는 핵심 지표 중 하나로, 나중에 렌더링된 콘텐츠가 중요한 콘텐츠를 밀어내면서 발생하는 사용자 경험의 저하를 방지하기 위해 사용됩니다 [1, 2]. CLS 점수는 0.1 미만을 유지하는 것이 권장됩니다 [3].
|
||||
> **이 문서는 [[Core-Web-Vitals]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
---
|
||||
## 핵심 요약 (specialization aspects)
|
||||
- CLS 는 매 Core Web Vitals 의 stability metric — visible element 가 unexpectedly shift 한 amount 의 sum.
|
||||
- 매 target: CLS < 0.1 (good), < 0.25 (needs improvement).
|
||||
- 매 common causes: 매 image without dimensions, 매 ads/iframes, 매 web font swap (FOUT/FOIT), 매 dynamically injected content above fold.
|
||||
- 매 fix: `width`/`height` attributes, `aspect-ratio` CSS, `font-display: optional`, `min-height` placeholders, CSS `content-visibility`.
|
||||
|
||||
> "사용자가 읽거나 클릭하려는 순간 콘텐츠가 춤추듯 이동하는 '시각적 불안정성'을 제거하고, 0.08초 이내의 고정된 안정감을 제공하여 인지적 마찰을 차단하라" — 페이지의 전체 수명 동안 발생하는 예기치 않은 레이아웃 이동을 측정하는 [[Core Web Vitals|Core Web Vitals]]의 핵심 사용자 경험 지표.
|
||||
## 🔗 Graph
|
||||
- 부모: [[Core-Web-Vitals]] (canonical)
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **측정 기준 및 중요성:**
|
||||
CLS는 시각적 안정성을 측정하는 지표로, 페이지 로드 중 요소들의 위치가 변경되는 레이아웃 이동 현상을 수치화합니다 [1, 2]. 이상적이고 쾌적한 사용자 경험을 위해 CLS 점수는 0.1 미만이어야 하며, 0.25를 초과할 경우 상태가 매우 나쁜 것으로 간주되어 성능 개선이 필요합니다 [3]. LCP, INP와 함께 최적화되어야 하는 코어 웹 바이탈의 중요 요소입니다 [4].
|
||||
|
||||
* **주요 발생 원인 및 최적화 방법:**
|
||||
주로 앱 배너, 이미지, 광고, 임베드 요소 등이 화면에 나타나면서 기존에 렌더링된 콘텐츠를 아래로 밀어낼 때 발생합니다 [2, 5, 6]. 이를 방지하기 위해서는 이미지나 광고, 임베드 요소가 로드될 공간을 미리 확보(reserve space)해 두어야 하며, 기존에 있는 콘텐츠 위로 새로운 콘텐츠를 동적으로 삽입하는 것을 피해야 합니다 [6].
|
||||
|
||||
* **분석 및 디버깅:**
|
||||
[[Chrome DevTools|Chrome DevTools]]의 성능(Performance) 패널을 사용해 CLS의 원인을 파악하고 디버깅할 수 있습니다 [7].
|
||||
* 'Layout shifts' 트랙에서 레이아웃 이동은 보라색 다이아몬드로 표시되며, 시간상 근접성에 따라 클러스터 형태(보라색 선)로 그룹화됩니다 [7].
|
||||
* 이 다이아몬드나 'Worst cluster 1 shift' 항목을 클릭하면 어떤 DOM 요소가 이동에 영향을 받았는지 식별할 수 있으며, 마우스를 올리면 뷰포트 내에서 해당 요소가 하이라이트됩니다 [7, 8].
|
||||
|
||||
* **브라우저 지원 동향:**
|
||||
현재 구글을 중심으로 측정되고 있으나, 파이어폭스(Firefox)와 사파리(Safari)의 브라우저 호환성을 위한 [[Interop 2025|Interop 2025]] 프로젝트에는 CLS 지원이 계획되어 있지 않습니다 [9]. 다만, 차기 프로젝트인 [[Interop 2026|Interop 2026]]에 CLS를 포함하려는 제안이 존재합니다 [9].
|
||||
|
||||
---
|
||||
|
||||
- **추출된 패턴:** "Predictive Space Allocation and Visual Isolation" — 콘텐츠가 로드되기 전에 브라우저가 필요한 공간을 미리 예약하여, 데이터 로딩 전후의 시각적 불일치를 제로로 만드는 패턴.
|
||||
- **CLS 발생의 주요 원인:**
|
||||
- **Sizeless Images/Ads:** 크기가 지정되지 않은 이미지나 동적 광고가 로드되면서 주변 콘텐츠를 밀어냄.
|
||||
- **Dynamic Content Injection:** 배너나 툴팁이 기존 콘텐츠 위쪽에 갑자기 삽입됨.
|
||||
- **FOIT/FOUT:** 웹 폰트 로딩 지연으로 인한 텍스트 크기 및 줄바꿈 변경.
|
||||
- **CLS 최적화 전략:**
|
||||
- **Explicit Dimensions:** 모든 미디어 요소에 `width`, `height` 또는 `aspect-ratio` 명시.
|
||||
- **Placeholder Reservation:** 광고 및 동적 요소 슬롯에 `min-height`를 활용한 공간 확보.
|
||||
- **CSS Transform:** 위치 이동 애니메이션 시 레이아웃 재계산을 유발하지 않는 `transform` 속성 사용.
|
||||
- **Font Display:** `font-display: swap` 설정을 통해 텍스트 구조 변동 최소화.
|
||||
- **의의:** 시각적 안정성을 확보함으로써 오클릭(Misclick)을 방지하고, 검색 엔진 랭킹 점수를 높이며 사용자의 신뢰도를 향상시킴.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
|
||||
---
|
||||
|
||||
- **과거 데이터와의 충돌:** 과거에는 CLS 우수 기준이 0.1이었으나, 2025년 Google 정책 업데이트를 기점으로 0.08 미만(25% 강화)으로 더욱 엄격해짐.
|
||||
- **정책 변화:** Antigravity 프로젝트는 모든 UI 컴포넌트에 대해 'Zero Layout Shift' 정책을 강제하며, 빌드 타임에 이미지 크기 미지정 요소를 자동 검출하여 오류를 발생시키는 정책을 시행함.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** [[Core Web Vitals|Core Web Vitals]], Largest Contentful Paint (LCP), [[Interaction to Next Paint (INP)|Interaction to Next Paint (INP]]
|
||||
- **Projects/Contexts:** [[Chrome DevTools|Chrome DevTools]], [[Interop 2026|Interop 2026]]
|
||||
- **Contradictions/Notes:** CLS 수치는 기기의 해상도에 크게 의존하기 때문에 실제 방문자 데이터를 나타내는 현장(Field) 데이터와 개발자의 로컬(Local) 데이터 간에 차이가 발생하기 쉽습니다. 이러한 이유로 코어 웹 바이탈 지표 중에서도 에뮬레이션하여 측정하기 가장 까다로운 지표로 평가받습니다 [8].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-19*
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- [[Core-Web-Vitals|Core-Web-Vitals]], LCP-Largest-Contentful-Paint, INP-Interaction-to-Next-Paint, Web-Performance-Optimization, SEO-Foundations
|
||||
- **Raw Source:** 00_Raw/CLS (Cumulative Layout Shift).md
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
|
||||
@@ -2,92 +2,176 @@
|
||||
id: wiki-2026-0508-cyclomatic-complexity
|
||||
title: Cyclomatic Complexity
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [McCabe Complexity, Cyclomatic Number, 순환 복잡도]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [uncategorized]
|
||||
verification_status: applied
|
||||
tags: [code-quality, metrics, static-analysis, mccabe]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: python
|
||||
framework: ruff
|
||||
---
|
||||
|
||||
# [[Cyclomatic Complexity]]
|
||||
# Cyclomatic Complexity
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
Cyclomatic Complexity(순환 복잡도)는 소프트웨어 공학에서 코드의 복잡성을 평가하기 위해 사용되는 소프트웨어 측정 지표 중 하나입니다 [1]. 리팩토링의 결과와 품질을 평가하는 추상 구문 트리(AST) 기반 지표로 활용되며, 코드의 결합도 분석과 함께 사용됩니다 [2]. 성공적인 구조적 리팩토링을 거친 코드는 일반적으로 함수당 평균 순환 복잡도 수치가 감소하여 유지보수성이 향상되는 특징을 보입니다 [3, 4].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **리팩토링을 통한 복잡도 감소**: AI를 활용한 리팩토링 사례 연구에 따르면, 비대한 라우팅 레이어의 로직을 여러 기능별 전용 레이어로 모듈화하여 재분배한 결과 전체 함수의 수는 늘어났음에도 함수당 평균 순환 복잡도는 2.24에서 2.13으로 낮아졌으며, 라우팅 레이어 자체의 평균 복잡도는 1.97까지 하락했습니다 [3, 4].
|
||||
* **실증적 연구에서의 검증**: 마이크로소프트의 대규모 시스템(Windows 7) 진화 기록 분석에서도, 리팩토링이 우선적으로 집중된 상위 5%의 모듈은 나머지 95%의 일반 모듈에 비해 순환 복잡도(Cyclomatic complexity)를 비롯한 여러 복잡성 지표(Fan-in, Fan-out 등)를 더 큰 폭으로 감소시키는 것으로 확인되었습니다 [5, 6].
|
||||
* **품질 측정의 객관적 척도**: 순환 복잡도는 아키텍처의 의존성 분석과 같은 AST 기반 메트릭과 함께 사용되어, 변경된 코드가 단순히 재배치된 것을 넘어 실제적인 구조적 개선(예: 응집도 높은 자기 완결적 모듈로의 전환)을 이루었는지 검증하는 도구로 쓰입니다 [2, 3].
|
||||
* *(참고: 제공된 소스 내에 순환 복잡도를 계산하는 정확한 수학적 공식이나 구체적인 이론적 산출 기준에 대한 관련 정보는 부족합니다.)*
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
* **구성 요소 및 코드 라인 수(LOC) 증가**: 순환 복잡도를 낮추기 위해 응집도 높은 여러 개의 작은 모듈이나 함수로 논리를 분리하는 최적화를 거치면, 필연적으로 시스템 내 전체 함수 및 컴포넌트의 수는 증가하게 됩니다(예: 806개에서 1,022개로 증가) [3]. 결과적으로 개별 함수의 복잡도는 감소하지만 전체 코드 라인 수(LOC)와 파일 수는 오히려 증가하는 반대 급부(Trade-off)가 발생합니다 [7-9].
|
||||
* **다차원적인 평가의 필요성**: 순환 복잡도와 같은 지표가 개선되었다고 해서 소프트웨어 수정 비용이 모든 측면에서 줄어드는 것은 아닙니다. 리팩토링된 모듈은 복잡도 수치가 낮아지더라도, 구조적 변경으로 인해 수정 사항이 시스템 여러 곳에 흩어지는 '교차 절단 변경(crosscutting changes)'을 유발할 수 있으므로 단일 지표가 아닌 다차원적인 영향 평가가 반드시 수반되어야 합니다 [8, 9].
|
||||
### 매 계산
|
||||
- 각 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.
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-03*
|
||||
### 매 의미
|
||||
- **Test path 수** lower bound.
|
||||
- **Reading difficulty** proxy.
|
||||
- **Bug density correlation** — 매 empirical study.
|
||||
- **NOT** measure of correctness, performance, design quality.
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
### 매 응용
|
||||
1. CI gate — `max-complexity: 10` lint rule.
|
||||
2. Code review — high-CC function 매 split 요청.
|
||||
3. Refactoring target prioritization.
|
||||
4. Legacy modernization metric.
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
## 💻 패턴
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
|
||||
- **Parent:** [[10_Wiki/Topics]]
|
||||
- **Related:** *(TODO: 최소 2개)*
|
||||
- **Opposite / Trade-off:** *(TODO)*
|
||||
- **Raw Source:** 직접 입력
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Lint config (ruff, 2026)
|
||||
```toml
|
||||
# pyproject.toml
|
||||
[tool.ruff.lint]
|
||||
select = ["C90"] # mccabe
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
[tool.ruff.lint.mccabe]
|
||||
max-complexity = 10
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### ESLint
|
||||
```json
|
||||
{
|
||||
"rules": {
|
||||
"complexity": ["error", { "max": 10 }]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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');
|
||||
}
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
// 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; } }
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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
|
||||
- 부모: [[Code Quality Metrics]] · [[Static Analysis]]
|
||||
- 변형: [[Cognitive Complexity (Sonar)]] · [[Halstead Metrics]] · [[Maintainability Index]]
|
||||
- 응용: [[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 |
|
||||
|
||||
@@ -1,124 +1,32 @@
|
||||
---
|
||||
id: wiki-2026-0508-dom-document-object-model
|
||||
title: DOM(Document Object Model)
|
||||
title: DOM (Document Object Model)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
canonical_id: self
|
||||
status: duplicate
|
||||
canonical_id: dom
|
||||
duplicate_of: "[[DOM]]"
|
||||
aliases: []
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, dom, web]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
---
|
||||
|
||||
# [[DOM (Document Object Model)|DOM (Document Object Model]]
|
||||
# DOM (Document Object Model)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
[[DOM (Document Object Model)|DOM(Document Object Model]]은 브라우저가 수신한 HTML 문서 데이터를 파싱하여 생성하는 페이지 구조의 계층적 트리 표현입니다 [1-3]. 브라우저는 HTML 태그의 포함 관계를 바탕으로 부모 및 자식 노드의 트리를 형성하며, `<html>` 요소를 루트 노드로 갖습니다 [4, 5]. DOM은 페이지의 모든 콘텐츠 정보를 담고 있으며, 스타일 정보를 담은 CSSOM과 결합해 최종 화면 출력에 필요한 렌더 트리([[Render Tree|Render Tree]])를 형성하는 브라우저 렌더링 과정의 핵심 기반입니다 [6-8].
|
||||
> **이 문서는 [[DOM]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
---
|
||||
## 핵심 요약
|
||||
- 짧은 form `DOM` 매 canonical (filename convention).
|
||||
- Tree-based document representation, WHATWG Living Standard.
|
||||
|
||||
DOM(Document Object Model)은 브라우저가 HTML 마크업을 내부적으로 표현하기 위해 생성하는 계층적인 트리 구조의 객체 모델입니다 [1, 2]. 브라우저가 HTML 데이터를 수신하면서 점진적으로 생성하며, 웹 페이지의 모든 콘텐츠와 요소 간의 구조적 관계를 담고 있습니다 [1, 3, 4]. 자바스크립트([[JavaScript|JavaScript]]) 내의 다양한 API를 통해 DOM에 접근하고 이를 동적으로 조작할 수 있습니다 [2].
|
||||
## 🔗 Graph
|
||||
- 부모: [[DOM]] (canonical)
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **DOM 트리의 점진적 구축 (Incremental Construction)**
|
||||
브라우저는 네트워크를 통해 HTML 문서의 전체 데이터를 다 받기 전부터 점진적으로 DOM 트리를 구축할 수 있습니다 [1, 4]. 초기 14KB의 데이터 패킷이 수신되면 바이트를 문자로, 문자를 토큰(startTag 및 endTag 등)으로 변환한 뒤, 최종적으로 노드(Node)로 변환하여 트리를 조립합니다 [1, 4]. 이 점진적 생성 메커니즘 덕분에 네트워크 요청이 진행 중인 상태에서도 브라우저는 렌더링 준비를 시작할 수 있습니다 [9].
|
||||
|
||||
* **렌더링 파이프라인에서의 DOM과 CSSOM**
|
||||
DOM은 문서의 '콘텐츠'를 표현하는 반면, CSSOM은 해당 콘텐츠의 '스타일'을 정의하는 독립적인 트리 구조입니다 [9, 10]. 이 두 모델은 브라우저에 의해 결합되어 화면에 시각적으로 출력되어야 하는 노드만을 포함하는 '렌더 트리(Render Tree)'로 합성됩니다 [6, 11, 12]. 이 과정에서 `<script>`, `<meta>` 또는 `display: none`이 적용된 요소처럼 시각적 영향을 주지 않는 DOM 노드는 렌더 트리에서 제외됩니다 [8, 11-13].
|
||||
|
||||
* **크기와 복잡성이 성능에 미치는 영향**
|
||||
DOM 트리의 깊이와 생성된 노드의 개수는 웹 성능과 직결됩니다 [5, 9]. 노드의 수가 많아질수록 렌더 트리 합성, 레이아웃(Reflow), 페인트 단계에서 브라우저가 처리해야 할 계산의 양과 시간이 증가하여 애플리케이션의 성능이 저하될 수 있습니다 [5, 7, 9, 14]. 불필요한 래퍼를 줄이고 React Fragment 등을 사용하여 DOM 노드 수를 최소화하는 것이 성능 향상에 도움이 됩니다 [15].
|
||||
|
||||
* **DOM 조작의 비효율성과 최적화**
|
||||
[[JavaScript|JavaScript]]를 사용해 DOM을 직접 조작하고 크기나 위치 등을 변경하면, 브라우저는 문서 전체의 레이아웃(Reflow)과 페인트(Repaint) 과정을 다시 실행해야 하므로 처리 비용이 매우 높습니다 [16-18]. 이를 최적화하기 위해서는 사용된 DOM 노드나 속성값을 캐싱하고, DOM의 읽기 및 쓰기 작업을 분리하여 레이아웃 스래싱(Layout Thrashing)을 방지해야 합니다 [16, 19, 20]. React와 같은 프레임워크는 실제 DOM을 직접 수정하는 비효율성을 피하고자 메모리 내에 가벼운 사본인 가상 DOM([[Virtual DOM|Virtual DOM]])을 생성하여 조작을 추상화합니다 [17, 21, 22].
|
||||
|
||||
---
|
||||
|
||||
- **DOM 생성 과정 (DOM Construction Process)**
|
||||
브라우저는 서버로부터 HTML 문서를 수신하면 즉시 파싱(Parsing)을 시작합니다 [5]. 이 과정은 전체 문서가 도착하기를 기다리지 않고 점진적(incremental)으로 이루어집니다 [1]. 수신된 데이터(바이트)는 문자로 변환되고, 이후 토큰(tokens)으로 변환된 다음 최종적으로 노드(nodes)로 변환되어 계층적인 DOM 트리를 형성합니다 [1, 6]. 시작 태그(startTag)와 종료 태그(endTag) 사이에 다른 태그들이 포함되는 방식으로 노드 간의 계층 구조가 정의됩니다 [6].
|
||||
|
||||
- **트리 구조와 구성 (Tree Structure and Composition)**
|
||||
DOM 트리는 문서의 콘텐츠를 묘사하며, `<html>` 요소가 트리 구조의 첫 번째 요소이자 루트(root) 노드가 됩니다 [4]. 다른 요소 안에 중첩된 요소들은 자식 노드(child nodes)가 되어 트리 내부에서 각 요소의 관계와 계층을 반영합니다 [4]. 생성된 DOM 트리는 이후 스타일 정보를 담고 있는 [[CSSOM(CSS Object Model)|CSSOM(CSS Object Model]]과 결합하여 화면에 그려질 요소를 결정하는 렌더 트리([[Render Tree|Render Tree]])를 구축하는 데 사용됩니다 [7, 8].
|
||||
|
||||
- **성능에 미치는 영향 (Performance Implications)**
|
||||
DOM 트리의 깊이와 복잡성은 브라우저의 성능과 직결됩니다 [9]. DOM에 존재하는 노드의 수가 많아질수록 렌더 트리 생성, 레이아웃(Layout), 페인트(Paint)와 같은 중요 렌더링 경로([[Critical Rendering Path|Critical Rendering Path]])의 후속 작업에 소요되는 시간과 연산 부담이 커지게 됩니다 [3, 4, 9].
|
||||
|
||||
- **직접적인 DOM 조작의 한계 (Limitations of Direct DOM Manipulation)**
|
||||
자바스크립트 등을 통해 DOM을 직접 변경하는 작업은 브라우저의 레이아웃(Reflow)과 페인트 단계를 지속적으로 트리거하기 때문에 본질적으로 속도가 느리고 비용이 많이 듭니다 [10]. 애플리케이션이 복잡해질 경우 여러 노드를 개별적으로 업데이트하면 중복 연산이 발생하며, 이는 React와 같은 프레임워크가 가상 DOM([[Virtual DOM|Virtual DOM]])을 도입하게 된 핵심 배경이 되었습니다 [10].
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
No trade-offs available.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** CSSOM (CSS Object Model), [[Render Tree|Render Tree]], Virtual DOM, [[Critical Rendering Path (CRP)|Critical Rendering Path (CRP]], Reflow (Layout), Repaint
|
||||
- **Projects/Contexts:** 프론트엔드 성능 최적화(DOM 접근 최소화 및 렌더링 파이프라인 관리), React의 렌더링 엔진 구조 및 재조정([[Reconciliation|Reconciliation]]) 과정 이해 [6, 17, 23, 24].
|
||||
- **Contradictions/Notes:** DOM 구축은 HTML을 파싱하면서 '점진적(incremental)'으로 이루어지지만, CSSOM 구축은 렌더링을 차단(render-[[Blocking|Blocking]])하며 점진적으로 처리되지 않는다는 구조적 차이가 있습니다 [1, 7, 9].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** [[CSSOM(CSS Object Model)|CSSOM(CSS Object Model]], Critical Rendering Path(CRP), Render Tree, [[Virtual DOM|Virtual DOM]], Reflow / Repaint
|
||||
- **Projects/Contexts:** 브라우저 렌더링 과정 ([[Browser|Browser]] Rendering Process), 프론트엔드 성능 최적화 및 React의 Virtual DOM 도입 배경 이해 [7, 10, 11]
|
||||
- **Contradictions/Notes:** 소스 간의 모순된 정보는 없습니다. 참고로 DOM의 생성은 점진적(incremental)으로 진행되어 문서를 파싱하는 동안에도 화면을 그리기 시작할 수 있지만, [[CSSOM|CSSOM]]의 생성은 렌더링을 차단(render-[[Blocking|Blocking]])한다는 점에서 두 모델의 구축 방식에 차이가 있습니다 [3, 9].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
|
||||
+145
-127
@@ -1,153 +1,171 @@
|
||||
---
|
||||
id: wiki-2026-0508-dom
|
||||
title: DOM
|
||||
title: DOM (Document Object Model)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [DOM, Document Object Model, DOM Tree]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.95
|
||||
verification_status: applied
|
||||
tags: [dom, web, browser, html, javascript]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: javascript
|
||||
framework: browser
|
||||
---
|
||||
|
||||
# [[DOM 요소 조작 및 타입 좁히기|DOM 요소 조작 및 타입 좁히기]]
|
||||
# DOM (Document Object Model)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> DOM 요소 조작 시에는 타입스크립트의 타입 좁히기(Type Narrowing) 기술을 통해 타입 안정성을 확보하는 것이 중요합니다. 타입 좁히기란 코드 흐름 분석을 사용하여 포괄적인 타입(유니온 타입 등)을 구체적인 단일 타입으로 줄여나가는 과정입니다 [1-3]. DOM 요소를 다루거나 구조가 명확하지 않은 데이터를 처리할 때, 타입 단언(`as`), 사용자 정의 타입 가드, `typeof` 및 `instanceof` 연산자 등을 활용하여 안전하게 타입을 좁혀 조작할 수 있습니다 [4-6].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
> 주어진 소스에는 DOM 요소 조작의 구체적인 방법론이나 원리에 대한 내용이 포함되어 있지 않아 소스에 관련 정보가 부족합니다. 제공된 문서들에서는 DOM 요소를 다룰 때 TypeScript의 타입 단언(`as`)을 사용하는 상황이나, 사용자 입력을 DOM에 추가하기 전 XSS 공격을 방어하기 위해 텍스트를 소독(sanitize)해야 한다는 보안 및 타입 안정성 측면에서의 단편적인 예시만 확인됩니다 [1-3].
|
||||
### 매 구조
|
||||
- **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.
|
||||
|
||||
[[DOM (Document Object Model)|DOM(Document Object Model]]은 브라우저가 수신한 HTML 문서를 구문 분석하여 구성하는 문서의 구조와 콘텐츠를 나타내는 계층적 트리 구조입니다 [1-3]. 이는 브라우저의 렌더링 과정인 크리티컬 렌더링 패스(CRP)에서 CSSOM과 결합하여 화면에 그려질 렌더 트리(Render Tree)를 생성하는 핵심 기초가 됩니다 [4-6]. [[JavaScript|JavaScript]]를 통한 직접적인 DOM 조작은 레이아웃(Reflow)과 페인트 작업을 유발해 성능을 저하시키므로, 최신 프레임워크인 React는 이를 최적화하기 위해 [[Virtual DOM|Virtual DOM]]을 활용합니다 [7].
|
||||
### 매 mutation
|
||||
- `appendChild`, `insertBefore`, `removeChild`, `replaceChild` (legacy).
|
||||
- `append`, `prepend`, `before`, `after`, `replaceWith`, `remove` (modern).
|
||||
- `cloneNode(deep)`.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
**DOM 요소 조작 시 타입 단언(`as`)의 활용**
|
||||
* DOM 요소로 작업하며 타입을 좁혀야 할 때, 타입 단언(`as`) 연산자가 주로 활용됩니다 [5].
|
||||
* 타입 단언은 런타임 검증을 마쳤거나 DOM 조작과 같이 불가피한 상황에서 컴파일러에게 특정 타입임을 강제할 때 사용합니다 [5, 7]. 하지만 개발자가 잘못 판단할 경우 컴파일러가 에러를 잡지 못해 런타임 오류로 이어질 수 있으므로 사용에 매우 주의해야 합니다 [7, 8].
|
||||
### 매 응용
|
||||
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).
|
||||
|
||||
**DOM 요소 삽입과 브랜디드 타입(Branded Types)을 통한 보안**
|
||||
* 사용자의 입력값을 DOM의 `innerHTML` 등에 직접 추가하는 것은 XSS 공격에 노출될 수 있는 위험한 방식입니다 [9].
|
||||
* 이를 방어하기 위해 브랜디드 문자열 타입(Branded String Types)을 사용하여, 데이터가 DOM에 추가되기 전에 반드시 정제(Sanitized) 과정을 거쳤음을 타입 시스템 차원에서 강제할 수 있습니다 [9].
|
||||
* 또한, 유효하지 않은 잉여 속성(예: 'hello')을 DOM 객체로 전달할 경우 React와 같은 라이브러리에서는 경고를 발생시킬 수 있으므로 정확한 타입 지정이 중요합니다 [10].
|
||||
## 💻 패턴
|
||||
|
||||
**타입 좁히기(Type Narrowing)의 주요 기법**
|
||||
* **`typeof` 및 `instanceof` 연산자:** `typeof`를 사용해 "string", "number", "boolean" 등의 원시 타입을 확인하거나, `instanceof`를 사용해 생성자 프로토타입의 인스턴스인지를 확인하여 타입을 좁힙니다 [4, 6].
|
||||
* **`in` 연산자 및 판별 속성(Discriminant Property):** 객체 내에 특정 속성이 존재하는지 `in` 키워드로 확인하거나, 식별 가능한 유니온([[Discriminated Unions|Discriminated Unions]]) 패턴에서 공통 리터럴 타입 필드(예: `kind` 또는 `type`)를 `switch` 문으로 비교하여 해당 블록 내의 타입을 안전하게 좁힙니다 [1, 3, 4, 11].
|
||||
* **타입 서술어(Type Predicates):** 반환 타입에 `is` 키워드를 사용하여(예: `value is Positive`), 함수가 `true`를 반환할 때 조건문 내부에서 매개변수가 특정 타입으로 좁혀지도록 타입 시스템에 알립니다 [6, 12].
|
||||
* **단언 함수(Assertion Functions):** 입력된 값이 기대한 타입이 아닐 경우 에러를 던지도록 작성된 함수입니다. 이 함수를 통과한 이후의 코드는 해당 값이 특정 타입이 확실함을 타입 시스템이 인지하여 타입을 좁히게 됩니다 [13, 14].
|
||||
|
||||
---
|
||||
|
||||
소스에 관련 정보가 부족합니다.
|
||||
|
||||
제공된 소스에서 DOM 조작과 관련해 부분적으로 도출할 수 있는 내용은 다음과 같습니다:
|
||||
|
||||
* **DOM 조작과 타입 단언(`as`):** TypeScript 환경에서 DOM 요소를 조작하거나 타입 추론이 어려운 외부 데이터를 다룰 때, 개발자가 런타임 유효성을 확인하여 타입에 대해 확신이 있다면 `as` 키워드를 사용하여 타입을 단언할 수 있습니다 [2]. 주로 DOM 요소의 타입을 구체적으로 좁혀야(narrow) 할 때(예: 특정 HTML 요소로 단언할 때) 제한적으로 `as`의 사용이 고려됩니다 [3].
|
||||
* **DOM 추가 시 보안(XSS) 유의사항:** 사용자의 입력값을 검증 없이 DOM(예: `innerHTML`)에 직접 쓰는 것은 보안상 매우 위험한 방식입니다 [1]. 악의적인 코드가 주입되는 XSS(크로스 사이트 스크립팅) 공격을 막기 위해, DOM에 데이터를 추가하기 전에 반드시 텍스트를 소독(sanitize)해야 합니다 [1]. TypeScript의 브랜디드 타입(Branded Types)을 활용하면 소독된 문자열과 소독되지 않은 문자열의 타입을 구분할 수 있어, 안전하게 처리된 문자열만 DOM에 삽입되도록 타입 시스템 수준에서 강제할 수 있습니다 [1, 4].
|
||||
|
||||
---
|
||||
|
||||
* **DOM 트리의 점진적 구축:** 브라우저는 HTML 응답을 받으면 바이트(bytes)를 문자, 토큰(token), 노드(node)로 변환하는 과정을 거쳐 DOM 트리를 구성합니다 [3, 8, 9]. HTML의 시작 태그와 종료 태그는 노드 간의 부모, 자식, 형제 관계와 같은 계층 구조를 정의하며, `<html>` 요소가 문서 트리의 루트 노드가 됩니다 [3, 9]. DOM의 구축은 점진적(incremental)으로 이루어지기 때문에, 브라우저는 데이터를 수신하는 도중에도 트리를 구축할 수 있습니다 [8, 9].
|
||||
* **렌더 트리(Render Tree)의 형성:** DOM은 페이지의 '콘텐츠'를 담고 있으며, 페이지의 '스타일'을 담고 있는 [[CSSOM(CSS Object Model)|CSSOM(CSS Object Model]]과 결합하여 렌더 트리를 완성합니다 [5, 6, 10, 11]. 이 렌더 트리는 화면에 실제로 그려지는 가시적인 노드만을 포함하며, `<head>` 태그나 `display: none` 스타일이 적용된 DOM 노드는 렌더 트리에 포함되지 않습니다 [4, 5, 12, 13].
|
||||
* **DOM 조작과 렌더링 성능([[Reflow & Repaint|Reflow & Repaint]]):** DOM 노드의 수가 많고 깊이가 깊을수록 레이아웃 및 페인트와 같은 후속 렌더링 단계에 걸리는 연산 부담이 크게 증가합니다 [2, 3, 10, 14]. 또한, JavaScript로 DOM의 구조를 추가/삭제하거나 크기, 위치 속성을 변경하면 브라우저는 화면의 레이아웃을 다시 계산하는 Reflow(또는 Layout)를 실행하고, 이어 픽셀을 다시 그리는 Repaint 단계를 거치게 되어 막대한 연산 비용이 발생합니다 [7, 14-17].
|
||||
* **성능 최적화 및 접근 최소화 방법:** DOM 조작으로 인한 성능 저하를 막기 위해 DOM 노드나 속성값을 변수에 캐싱(Caching)하여 재사용하거나, 연산을 반복문 외부로 빼내어 DOM 상호작용 횟수를 최소화해야 합니다 [18, 19]. 특히, DOM 값을 읽는 작업(Phase 1)과 수정하는 작업(Phase 2)을 교차로 수행하는 레이아웃 스래싱([[Layout Thrashing|Layout Thrashing]])을 방지하도록 코드를 분리하는 것이 중요합니다 [19-21].
|
||||
* **React의 Virtual DOM 도입 배경:** 위와 같은 직접적인 DOM 조작의 비효율성을 극복하기 위해 React는 메모리상에 존재하는 가벼운 복사본인 Virtual DOM(VDOM)을 도입했습니다 [7, 22]. 상태가 변경되면 React는 새로운 Virtual DOM을 생성하고 이전과 비교(Diffing/[[Reconciliation|Reconciliation]])하여 변경된 최소한의 부분만을 실제 DOM에 반영함으로써 렌더링 성능을 극대화합니다 [7, 22, 23].
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
|
||||
---
|
||||
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** Type Narrowing, Type Assertions, [[Discriminated Unions|Discriminated Unions]], Branded Types
|
||||
- **Projects/Contexts:** 안전한 DOM 조작 및 데이터 정제, React 컴포넌트 Props 처리
|
||||
- **Contradictions/Notes:** 타입 단언(`as`)은 DOM 요소를 다루며 타입을 좁힐 때 유용하고 흔하게 사용되지만 [5], 런타임 동작에는 영향을 주지 않으므로 타입 에러를 우회하여 잘못된 코드를 통과시킬 위험이 있습니다. 따라서 가능한 한 `satisfies`나 사용자 정의 타입 가드 등 더 안전한 방식을 우선적으로 고려하는 것이 좋습니다 [7, 8, 15].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-18*
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** [[타입 단언 (Type Assertions)|타입 단언(Type Assertions]], 브랜디드 타입(Branded Types)
|
||||
- **Projects/Contexts:** 안전한 TypeScript 프론트엔드 개발 및 XSS 방어
|
||||
- **Contradictions/Notes:** 소스에 DOM 요소 조작의 본질적인 원리나 구체적인 API(예: 순수 자바스크립트 DOM API)에 대한 정보가 절대적으로 부족하므로 "소스에 관련 정보가 부족합니다."
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-18*
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** [[Virtual DOM|Virtual DOM]], CSSOM, Render Tree, [[Reflow 및 Repaint|Reflow 및 Repaint]], [[Critical Rendering Path (CRP)|Critical Rendering Path (CRP]]
|
||||
- **Projects/Contexts:** [[React 렌더링 최적화|React 렌더링 최적화]], 브라우저 렌더링 과정, [[웹 성능 가이드(Web Performance)|웹 성능 가이드(Web Performance]]
|
||||
- **Contradictions/Notes:** DOM의 구축은 HTML 데이터를 수신함과 동시에 '점진적(incremental)'으로 이루어지며 렌더링을 차단하지 않는 반면, 스타일을 정의하는 CSSOM의 구축은 후속 규칙이 이전 규칙을 덮어쓸 수 있기 때문에 완전히 구문 분석될 때까지 렌더링을 차단(render-[[Blocking|Blocking]])한다는 점에서 작동 방식의 차이가 있습니다 [2, 8-10].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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);
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Event delegation
|
||||
```javascript
|
||||
list.addEventListener('click', (e) => {
|
||||
const item = e.target.closest('.item');
|
||||
if (!item || !list.contains(item)) return;
|
||||
handleClick(item.dataset.id);
|
||||
});
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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 });
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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);
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### Range & Selection
|
||||
```javascript
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(el);
|
||||
const text = range.toString();
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]] · [[Browser Architecture]]
|
||||
- 변형: [[Virtual DOM]] · [[Shadow DOM]] · [[Incremental DOM]]
|
||||
- 응용: [[React]] · [[Web Components]] · [[Playwright]]
|
||||
- Adjacent: [[CSSOM]] · [[Event Loop (Browser)]] · [[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 |
|
||||
|
||||
@@ -2,145 +2,183 @@
|
||||
id: wiki-2026-0508-dora-metrics
|
||||
title: DORA Metrics
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [dora, four-keys, accelerate-metrics]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [dora, devops, metrics, delivery-performance]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: sql
|
||||
framework: github-actions/grafana
|
||||
---
|
||||
|
||||
# [[DORA Metrics (소프트웨어 전달 성과 지표)|DORA Metrics (소프트웨어 전달 성과 지표]]
|
||||
# DORA Metrics
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
DORA(DevOps Research and Assessment) 지표는 소프트웨어 개발 조직의 전달(Delivery) 성능과 운영 효율성을 측정하는 글로벌 표준 기준입니다 [1]. 코드 리뷰의 속도와 효율성은 DORA 지표에 직결되며, 빠른 리뷰 주기를 유지하는 엘리트(Elite) 팀은 그렇지 않은 팀보다 50% 더 높은 딜리버리 성과를 보입니다 [2]. DORA 지표는 배포 빈도, 변경 리드 타임, 서비스 복구 시간, 변경 실패율의 4가지 핵심 지표를 통해 조직의 역량을 객관적으로 진단합니다 [3].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
> "엘리트 개발 팀의 성적표: 단순히 '얼마나 많이 만드는가'가 아니라, '얼마나 빠르고 안전하게 사용자에게 가치를 전달하는가'를 4가지 핵심 숫자로 입증하여 조직의 생산성 격차를 시각화하는 강력한 리트머스 시험지."
|
||||
### 매 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: 0–5%.
|
||||
4. **Mean Time to Restore (MTTR)** — incident detection → resolution. Elite: < 1 hour.
|
||||
5. **Reliability** (added 2021/2022 reports) — meeting/exceeding SLO targets.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **4대 핵심 지표 (Four Key Metrics):**
|
||||
1. **배포 빈도 (Deployment Frequency):** 코드가 프로덕션에 얼마나 자주 배포되는가? (엘리트 팀: 하루에 수회 이상) [3]
|
||||
2. **변경 리드 타임 (Lead Time for Changes):** 코드가 커밋된 후 프로덕션에 배포되기까지 걸리는 시간 (엘리트 팀: 1시간 미만) [3]
|
||||
3. **서비스 복구 시간 (Time to Restore Service):** 장애 발생 시 서비스가 복구되는 데 걸리는 시간 (엘리트 팀: 1시간 미만) [3]
|
||||
4. **변경 실패율 (Change Failure Rate):** 배포 후 장애나 수정이 필요한 비율 (엘리트 팀: 0~15%) [3]
|
||||
* **코드 리뷰 속도와의 상관관계:** 코드 리뷰 처리 속도는 소프트웨어 전달 성과를 결정짓는 핵심 요인입니다 [2]. 리뷰가 지연되면 리드 타임이 길어지고 병목이 발생하여 전체 생산성이 저하됩니다.
|
||||
* **엘리트 성과자(Elite Performers)의 실천 기준:**
|
||||
* **풀 리퀘스트(PR) 크기:** 인지 부하를 줄이기 위해 모든 PR을 400줄(LOC) 이하로 유지함 [3, 5].
|
||||
* **첫 리뷰 시간:** PR 생성 후 1시간 이내에 첫 리뷰가 수행됨 [5].
|
||||
* **리뷰 완료 시간:** 6시간 이내에 전체 리뷰 및 승인이 완료됨 [3, 5].
|
||||
* **품질 게이트 통합:** 코드 리뷰 체크리스트에 변경 사항이 배포 파이프라인이나 DORA 지표 측정에 미치는 영향을 점검하는 항목을 포함하는 것이 권장됩니다 [1].
|
||||
### 매 performance bands (2024 report)
|
||||
- **Elite** — frequent deploys, < 1 day LT, 0–5% CFR, < 1h MTTR.
|
||||
- **High** — weekly–monthly, 1 day–1 week, 0–10%, < 1 day.
|
||||
- **Medium** — monthly–6m, 1 week–1 month, 0–15%, < 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.
|
||||
|
||||
DORA Metrics는 Google의 DevOps [[Research|Research]] and [[Assessment|Assessment]](DORA) 팀이 수천 개의 기업을 조사하여 정립한 소프트웨어 개발 및 배포 성과 측정 지표입니다.
|
||||
## 💻 패턴
|
||||
|
||||
1. **4대 핵심 지표**:
|
||||
* **Deployment Frequency (배포 빈도)**: 제품을 얼마나 자주 배포하는가? (속도)
|
||||
* **Lead Time for Changes (변경 리드 타임)**: 코드 커밋부터 배포까지 얼마나 걸리는가? (효율)
|
||||
* **Change Failure Rate (변경 실패율)**: 배포 실패로 인해 장애가 발생할 확률. (신뢰성)
|
||||
* **Failed Service Restoration Time (복구 소요 시간)**: 장애 발생 시 복구까지 걸리는 시간. (복구력)
|
||||
2. **왜 중요한가?**:
|
||||
* 속도와 안정성을 상충 관계(Trade-off)가 아닌, 상호 보완 관계로 정의하여 '엘리트 그룹'으로 가기 위한 정량적 목표 정책을 제시하기 때문임. ([[Efficiency|Efficiency]]와 연결)
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
* **속도 vs 철저함:** 엘리트 기준(6시간 이내 완료)을 무리하게 추구할 경우, 코드 리뷰가 피상적으로 흐르거나 보안 결함을 놓칠 위험이 있습니다 [6, 7].
|
||||
* **니트피킹(Nit-picking)의 함정:** 사소한 스타일 교정에 집착하여 리뷰 시간을 지연시키면 리드 타임이 악화됩니다 [8]. 스타일 검사는 자동화 도구에 위임하고, 리뷰어는 아키텍처 및 핵심 로직에 집중하여 속도와 철저함의 균형을 맞춰야 합니다 [10].
|
||||
* **데이터 오염:** 지표 달성 자체에만 매몰되면 개발자가 PR을 인위적으로 쪼개거나 품질을 희생하는 등 수치가 실제 생산성을 대변하지 못하게 될 수 있습니다.
|
||||
|
||||
---
|
||||
|
||||
- **과거 데이터와의 충돌**: 과거에는 단순히 LOC(코드 라인 수)나 커밋 수 정책으로 개발자 성과를 측정했으나, DORA 정책은 '가치 전달의 흐름 정책(Flow)' 중심의 측정 정책이 조직의 성공과 직결됨을 증명함(RL Update).
|
||||
- **정책 변화(RL Update)**: 최근에는 4대 지표 정책에 '안정성 정책' 외에 '운영 효율성 정책'을 시각화하는 5번째 지표(Reliability)를 추가하여 서비스 가용성 정책을 더욱 정밀하게 관리하는 추세임. (Reliability와 연결)
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
* **Review-Speed Benchmarks**: DORA 데이터를 기반으로 리뷰 속도를 엘리트, 우수, 수용 가능 수준으로 구분하여 정량 평가하는 기준입니다.
|
||||
* **Pull Request Size Limits (PR 크기 제한**: 엘리트 등급의 리뷰 속도 달성을 위한 선제 조건으로, 리뷰어의 인지 부하를 최소화합니다.
|
||||
* **Automation in Code Review (코드 리뷰 자동화**: 기계적 검증을 자동화하여 인간 리뷰어가 고차원적 가치 창출(지식 공유 등)에 집중하게 돕습니다.
|
||||
* **Software Delivery Performance**: DORA 지표가 궁극적으로 측정하고자 하는 소프트웨어 전달 역량의 종합적 성과입니다.
|
||||
|
||||
### Deeper Research Questions
|
||||
* 지리적으로 분산된 글로벌 팀이 DORA의 '첫 리뷰 1시간 이내' 기준을 달성하기 위해 비동기 협업 및 알림(Notification) 시스템을 어떻게 최적화해야 하는가?
|
||||
* 리뷰 속도 단축을 위해 SAST와 같은 보안 도구가 CI/CD 파이프라인의 병목이 되지 않도록 스캔 정책을 어떻게 유연하게 설계해야 하는가?
|
||||
* 레거시 시스템 마이그레이션과 같이 PR을 작게 쪼개기 어려운 상황에서 DORA 지표의 속도 벤치마크를 어떻게 합리적으로 조정(Normalization)할 것인가?
|
||||
* DORA 지표 개선이 실제 비즈니스 가치(매출, 고객 만족도 등)로 연결되는 정량적 상관관계를 어떻게 입증할 수 있는가?
|
||||
* 코드 리뷰어 할당 알고리즘을 개선하여 특정 리뷰어에게 쏠리는 병목을 해소하고 팀 전체의 DORA 성과를 균등하게 높이는 방법은 무엇인가?
|
||||
|
||||
### Practical Application Contexts
|
||||
* **Implementation:** 모든 PR을 400 LOC 미만으로 분할하여 제출함으로써 리뷰어의 빠른 승인을 유도합니다 [3, 11].
|
||||
* **System Design:** 린팅, 포맷팅, 테스트 단계를 자동화하여 리뷰어가 기계적 결함 검토에 시간을 낭비하지 않도록 파이프라인을 설계합니다.
|
||||
* **Operation / Maintenance:** 주기적으로 '첫 리뷰까지 걸리는 시간'의 75백분위수를 추적하여 팀의 딜리버리 역량을 관리합니다 [13].
|
||||
* **Learning Path:** 신속한 응답 문화를 조성하고, 리뷰 피드백 루프 자체가 주니어 개발자의 성장을 돕는 교육 기회가 되도록 운영합니다.
|
||||
* **My Project Relevance:** 현재 팀의 평균 리드 타임과 배포 빈도 데이터를 추출하여 DORA 벤치마크와 비교 진단하고 병목 구간을 개선합니다.
|
||||
|
||||
### Adjacent Topics
|
||||
* **DevOps Culture**: DORA 지표가 효과를 발휘하기 위해 전제되어야 할 팀의 심리적 안전감과 실험 정신 등 문화적 측면으로 확장됩니다.
|
||||
* **Cycle Time (TTR**: PR 생성부터 병합까지의 전체 주기를 측정하고 관리하는 실무적 지표 체계입니다.
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
---
|
||||
|
||||
- [[Efficiency|Efficiency]], [[Reliability|Reliability]], [[Scalability|Scalability]], Standard-Operating-Procedure, [[Management|Management]], [[Strategic-Planning|Strategic-Planning]]
|
||||
- **Category**: Elite, High, Medium, Low performers.
|
||||
---
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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;
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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)\"}"
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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;
|
||||
}
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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;
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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);
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### Grafana dashboard panel (PromQL-style)
|
||||
```promql
|
||||
# Deployment frequency (deploys per day per service)
|
||||
sum by (service) (rate(deployments_total{env="production"}[7d])) * 86400
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
# 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]]
|
||||
- 변형: [[SPACE-Framework]] · [[Engineering-Metrics]]
|
||||
- 응용: [[Trunk-Based-Development]] · [[Continuous-Integration]] · [[SRE]]
|
||||
- Adjacent: [[Accelerate-Book]] · [[Apache-DevLake]] · [[SLO-Engineering]] · [[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 |
|
||||
|
||||
@@ -2,118 +2,169 @@
|
||||
id: wiki-2026-0508-deepreadonly
|
||||
title: DeepReadonly
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [deep-readonly, recursive-readonly, immutable-type]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [typescript, type-utility, immutability]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: typescript-5.x
|
||||
---
|
||||
|
||||
# [[DeepReadonly|DeepReadonly]]
|
||||
# DeepReadonly
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> DeepReadonly는 TypeScript에서 객체의 모든 중첩된 프로퍼티에 재귀적으로 `readonly`를 적용하여 데이터 구조 전체를 완전한 불변(immutable) 상태로 만드는 사용자 정의 유틸리티 타입이다 [1, 2]. 기본 내장된 `Readonly<T>` 유틸리티가 객체의 최상위 속성만 보호하는 얕은(shallow) 불변성만을 제공한다는 한계를 극복하기 위해 고안되었다 [1-3]. 상태 관리나 설정 객체와 같이, 객체 생성 이후 내부의 단 하나의 속성도 수정되지 않아야 함을 엄격하게 보장해야 할 때 주로 사용된다 [1, 4].
|
||||
## 매 한 줄
|
||||
> **"매 `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.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
> 재귀적 불변성(DeepReadonly)은 TypeScript에서 최상위 속성뿐만 아니라 중첩된 내부 객체까지 모두 불변(immutable) 상태로 만드는 커스텀 유틸리티 타입 기법입니다 [1-3]. 내장 `Readonly<T>` 타입이나 `readonly` 수식어가 제공하는 얕은(shallow) 수준의 보호 한계를 극복하기 위해 매핑 타입과 조건부 타입을 결합하여 구현합니다 [1, 3-5]. 전체 데이터 구조의 변경을 방지하여 트리 구조나 복잡한 중첩 데이터를 다루는 상태 관리 및 설정 객체 등에서 데이터 무결성을 보장하는 강력한 방어책 역할을 합니다 [1, 3].
|
||||
### 매 vs Readonly
|
||||
- `Readonly<T>` — 매 top-level only. 매 `obj.nested.mutate = X` 가 still allowed.
|
||||
- `DeepReadonly<T>` — 매 every level 의 recursive freeze.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **얕은 불변성의 한계 극복:** TypeScript가 기본으로 제공하는 `Readonly<T>` 타입은 객체의 최상위 수준(top-level) 프로퍼티만 읽기 전용으로 제어한다 [1, 2]. 따라서 내부의 중첩된 객체는 여전히 수정 가능한 상태로 남게 되어 데이터 오염의 위험이 존재하는데, 깊은 수준의 불변성을 강제하기 위해서는 `DeepReadonly` 타입이 필요하다 [1-3].
|
||||
- **재귀적 구현 방식:** `DeepReadonly`는 매핑 타입(Mapped Types)과 조건부 타입(Conditional Types)을 결합하여 재귀적으로 정의된다 [4]. 일반적으로 `type DeepReadonly<T> = { readonly [P in keyof T]: DeepReadonly<T[P]> };`와 같은 형태로 작성되어, 중첩된 데이터 트리 구조의 모든 하위 속성에 `readonly` 수식어가 빠짐없이 적용되도록 만든다 [1, 2, 4].
|
||||
- **적용 및 가용성:** 이 타입은 데이터 무결성을 최우선으로 하는 프론트엔드 아키텍처나 복잡한 시스템에서 예기치 않은 데이터 변경을 차단하는 강력한 방패 역할을 수행한다 [4]. 하지만 `DeepReadonly`는 현재 TypeScript 언어 자체에 내장되어 있지 않다 [5]. 따라서 개발자가 프로젝트 내에서 직접 재귀적 유틸리티 타입을 선언하거나, `ts-essentials`와 같이 이를 제공하는 서드파티 라이브러리를 가져와 사용해야 한다 [5].
|
||||
### 매 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).
|
||||
|
||||
- **얕은 불변성의 한계:** TypeScript의 내장 `Readonly<T>` 유틸리티 타입이나 기본적인 `readonly` 수식어는 객체의 최상위(top-level) 속성만 읽기 전용으로 만든다 [1, 2, 5]. 이로 인해 중첩된 객체(nested objects)나 배열의 깊은 내부 속성들은 여전히 변경 가능한(mutable) 상태로 남아 예기치 않은 데이터 오염에 취약해진다 [1, 2, 5].
|
||||
- **DeepReadonly의 동작 원리:** 이러한 한계를 극복하기 위해 모든 내부 계층을 보호할 수 있는 `DeepReadonly` 재귀적 타입(Recursive Type)을 정의한다 [1, 2]. 이 타입은 매핑 타입(Mapped Types)과 조건부 타입(Conditional Types)을 결합하여 구성하며, 객체의 프로퍼티를 순회하며 중첩된 모든 속성에 재귀적으로 `readonly`를 강제하여 전체 구조를 동결시킨다 [1, 3].
|
||||
- **구현 및 라이브러리 의존성:** `DeepReadonly`는 현재 TypeScript 언어에 기본적으로 내장된 유틸리티 타입이 아니다 [6]. 따라서 시스템 무결성을 위해 개발자가 직접 재귀적 헬퍼 타입을 정의하거나, `ts-essentials`와 같이 이를 제공하는 외부 라이브러리에 의존해야 한다 [6]. 반대로 불변성을 해제해야 하는 경우에는 `Mutable` 헬퍼 타입을 만들어 모든 속성의 `readonly`를 제거할 수도 있다 [2, 7].
|
||||
- **핵심 활용 사례:** 트리 구조나 복잡한 중첩 데이터를 다룰 때 단 하나의 속성도 변경되지 않도록 보장한다 [1, 3]. 생성 후 구조가 수정되어서는 안 되는 설정 객체(Configuration objects), 상태 관리 아키텍처, 그리고 데이터 무결성이 치명적으로 중요한 금융 시스템 등에서 필수적인 보호 요소로 자리 잡고 있다 [1, 3, 8].
|
||||
## 💻 패턴
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
### Basic DeepReadonly
|
||||
```ts
|
||||
type DeepReadonly<T> = T extends (...args: any[]) => any
|
||||
? T
|
||||
: T extends object
|
||||
? { readonly [K in keyof T]: DeepReadonly<T[K]> }
|
||||
: T;
|
||||
|
||||
---
|
||||
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** [[readonly|readonly]], Readonly<T>, Mapped Types, Conditional Types
|
||||
- **Projects/Contexts:** [[상태 관리(State Management)|상태 관리(State Management]], 설정 객체(Configuration Objects), ts-essentials
|
||||
- **Contradictions/Notes:** 깊은 수준의 불변성을 보장하는 기능이 실무적으로 널리 요구되었음에도 불구하고 `DeepReadonly`는 TypeScript에 공식적으로 기본 내장되어 있지 않다는 점이 특징적이다 [5]. 이로 인해 추가적인 구현이나 외부 라이브러리 의존성이 요구된다 [5].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-18*
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** [[Readonly 유틸리티 타입|Readonly]], 매핑 타입 (Mapped Types), 조건부 타입 (Conditional Types), 유틸리티 타입 (Utility Types)
|
||||
- **Projects/Contexts:** ts-essentials, 프론트엔드 상태 관리 ([[State|State]] [[Management|Management]]), 설정 객체 (Configuration objects)
|
||||
- **Contradictions/Notes:** `Readonly<T>`는 기본 제공되나 `DeepReadonly`는 TypeScript에 내장되어 있지 않다는 점이 특징입니다 [6]. 또한 런타임에 성능 오버헤드를 일으키는 `Object.freeze()`의 얕은 동결과 달리, 이 방식은 컴파일 타임에 타입 레벨에서만 불변성을 검사하고 강제하므로 훨씬 효율적입니다 [5].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-18*
|
||||
|
||||
---
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
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
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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;
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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;
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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>;
|
||||
}
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### `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']
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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;
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
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]] · [[DeepWritable]]
|
||||
- 응용: [[Redux-State]] · [[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 |
|
||||
|
||||
@@ -2,132 +2,161 @@
|
||||
id: wiki-2026-0508-dependencies-의존성
|
||||
title: Dependencies (의존성)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [npm-dependencies, package-dependencies, supply-chain]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [uncategorized]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [dependencies, npm, semver, supply-chain]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: javascript
|
||||
framework: npm/pnpm
|
||||
---
|
||||
|
||||
# [[Dependencies (의존성)]]
|
||||
# Dependencies (의존성)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
의존성(Dependencies)은 하나의 코드 조각(모듈, 클래스, 메서드 등)이 기능하기 위해 다른 코드 조각이나 외부 리소스에 의존하는 관계를 의미합니다 [1-3]. 테스트가 누락된 레거시 코드 등에서 강하게 결합된 의존성은 코드를 이해하고 수정하며 테스트하기 어렵게 만드는 주요 원인이 됩니다 [3, 4]. 성공적이고 안전한 리팩토링과 시스템 아키텍처의 지속 가능성을 확보하기 위해서는 이러한 불필요한 의존성을 식별하고 끊어내는 작업이 필수적입니다 [4-6].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 Core 대Content
|
||||
* **의존성의 문제점과 레거시 코드:** 클래스나 패키지 간의 건강하지 못한 의존성은 코드의 부패를 초래합니다 [7]. 특히 레거시 코드에서는 데이터베이스 연결, 외부 서버 API 호출, 복잡한 매개변수 등 다루기 힘든 의존성 때문에 코드를 테스트 환경에서 격리하여 실행하는 것이 매우 어렵습니다 [3, 4]. 마이클 페더스(Michael Feathers)는 코드를 안전하게 변경하기 위해 가장 먼저 해결해야 할 과제로 '의존성 끊기(Breaking Dependencies)'를 꼽았습니다 [6].
|
||||
* **의존성 분리 전략 - 접점(Seams)의 활용:** 기존 레거시 코드에 테스트를 추가하고 의존성을 제거하기 위해 '접점(Seam)'이라는 개념이 활용됩니다 [4, 8]. 접점이란 소스 코드를 직접 편집하지 않고도 프로그램의 동작을 변경할 수 있는 지점을 뜻합니다 [4, 9]. 이를 통해 프로덕션 코드의 변경 없이 테스트 시에만 가짜 객체(Mock)를 주입하여 외부 의존성을 우회하고 독립적인 단위 테스트를 수행할 수 있습니다 [4, 10].
|
||||
* **모듈 간 의존성 관리와 아키텍처 개선:** 대규모 소프트웨어 시스템에서 리팩토링의 핵심 목표는 모듈 간의 바람직하지 않은 의존성을 줄이는 것입니다 [5, 11]. 마이크로소프트 윈도우 7(Windows 7)의 리팩토링 사례 연구에 따르면, 집중적인 리팩토링을 거친 모듈들은 모듈 간 의존성 수가 유의미하게 감소하였으며, 이는 전체적인 시스템 복잡도를 낮추고 병렬 개발의 효율성을 극대화하는 결과를 가져왔습니다 [5, 12].
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
* **'객체 통째로 넘기기(Preserve Whole Object)' 리팩토링의 부작용:** 긴 매개변수 목록을 줄이기 위해 여러 데이터 값을 넘기는 대신 해당 데이터가 포함된 전체 객체를 넘기는 리팩토링을 수행할 수 있습니다 [13]. 하지만 이 방식을 사용하면 호출되는 메서드가 원래는 몰라도 되었을 '전체 객체'에 대해 새로운 의존성을 가지게 됩니다 [14]. 이러한 새로운 의존성이 전체 의존성 구조를 망가뜨리거나 복잡하게 만든다면, 해당 리팩토링 기법은 피해야 합니다 [14].
|
||||
* **의존성 분리의 높은 비용:** 소프트웨어의 설계가 얼마나 훌륭한지와 무관하게, 기존 프로젝트에서 클래스를 분리하고 의존성을 끊어내어 테스트 가능한 상태로 만드는 작업은 상당한 시간과 노력을 필요로 합니다 [15].
|
||||
* **잘못된 추상화의 위험:** 중복을 피하고자 성급하게 리팩토링하여 잘못된 추상화를 도입할 경우, 새로운 요구사항이 등장함에 따라 코드를 맞추기 위해 오히려 의존성이 더 꼬이게 되고 결과적으로 유지보수 비용이 증가할 수 있습니다 [16].
|
||||
### 매 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.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
### 매 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.
|
||||
|
||||
#### [아키텍처/기반 기술]
|
||||
- [[Seams (접점)]]
|
||||
- 연결 이유: 소스코드를 변경하지 않고도 의존성을 끊고 동작을 바꿀 수 있게 해주는 핵심 개념이기 때문입니다 [8, 9].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 의존성이 강한 레거시 코드를 어떻게 테스트 가능한 단위로 격리할 수 있는지 그 메커니즘(객체 접점, 전처리 접점, 링크 접점)을 구체적으로 파악할 수 있습니다 [17-19].
|
||||
- [[Legacy Code (레거시 코드)]]
|
||||
- 연결 이유: 테스트가 없고 의존성 문제로 인해 변경하기 가장 어려운 상태의 코드를 의미하기 때문입니다 [4, 20].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 의존성이 극도로 얽힌 환경에서 왜 리팩토링보다 의존성 제거와 테스트 도입이 우선되어야 하는지 실무적 맥락을 이해할 수 있습니다 [6].
|
||||
### 매 Lockfile
|
||||
- **pnpm-lock.yaml** / **package-lock.json** / **yarn.lock**: 매 exact resolved versions + integrity hashes.
|
||||
- 매 `npm ci` 사용 (매 install 가 X) — 매 lockfile 강제, deterministic install.
|
||||
- 매 commit 의 must.
|
||||
|
||||
#### [구현/활용 도구]
|
||||
- [[Mock Objects (가짜 객체)]]
|
||||
- 연결 이유: 의존성을 성공적으로 끊어낸 후(접점 확보 후), 실제 의존성을 대체하여 테스트 환경을 구성하는 도구이기 때문입니다 [4].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 복잡한 외부 리소스(DB, 외부 서비스 등)에 대한 의존성을 어떻게 통제 가능한 상태로 시뮬레이션할 수 있는지 파악할 수 있습니다 [4, 21].
|
||||
- [[Preserve Whole Object (객체 통째로 넘기기)]]
|
||||
- 연결 이유: 코드를 단순화하는 리팩토링 기법임과 동시에, 잘못 사용하면 새로운 의존성을 창출하는 양날의 검이기 때문입니다 [14].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 데이터 전달 방식의 최적화가 시스템의 의존성 결합도(Coupling)에 어떤 영향을 미치는지 이해하고 설계의 트레이드오프를 평가할 수 있습니다 [14].
|
||||
### 매 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 됨.
|
||||
|
||||
### Deeper Research Questions
|
||||
- 레거시 시스템에서 테스트를 추가하기 위해 의존성을 끊을 때, '접점(Seams)'의 세 가지 주요 유형(Object Seams, Preprocessing Seams, Link Seams)은 각각 어떤 프로그래밍 언어 환경과 상황에서 가장 효과적으로 적용될 수 있는가? [17-19]
|
||||
- 양방향 연관관계를 단방향으로 변경(Change Bidirectional Association to Unidirectional)하여 의존성을 줄일 때 고려해야 할 시스템 아키텍처적 제약 사항과 데이터 동기화 문제는 무엇인가? [22]
|
||||
- 마이크로소프트 윈도우 7(Windows 7) 사례와 같이 대규모 시스템에서 모듈 간 의존성을 정량적으로 분석하고 리팩토링으로 이를 낮추었을 때, 이것이 실제 상용 환경의 결함 발생률(Post-release Defects) 감소에 미치는 구체적인 인과관계는 무엇인가? [11, 23]
|
||||
- 리팩토링 시 '객체 통째로 넘기기(Preserve Whole Object)'를 통해 감소하는 매개변수 목록의 가독성 이점과, 새롭게 증가하는 클래스 간 의존성의 부작용 비용을 어떻게 정량적 혹은 정성적으로 비교 평가할 것인가? [14]
|
||||
- 의존성이 심하게 얽혀 도저히 테스트를 작성하기 힘든 환경에서 '스프라우트 메서드(Sprout Method)'를 적용하는 것이, 기존 의존성 구조를 건드리지 않으면서도 안전하게 신규 기능을 테스트하는 데 어떤 방식으로 기여하는가? [24, 25]
|
||||
## 💻 패턴
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 매개변수 전달 구조를 리팩토링할 때, 데이터를 낱개로 보낼지 객체 전체로 보낼지를 결정하는 기준으로 해당 객체 간의 '의존성 증가'가 시스템에 미칠 영향을 평가하여 코드를 구현합니다. [14]
|
||||
- **System Design:** 초기 시스템 아키텍처 및 클래스를 설계할 때, 상호작용하는 모듈 사이에 과도한 결합이 발생하지 않도록 의존성을 관리하며 향후 '접점(Seam)'을 통한 대체와 확장이 가능한 유연한 구조를 마련합니다. [5, 8]
|
||||
- **Operation / Maintenance:** 기존의 복잡한 레거시 코드를 유지보수하고 기능을 추가해야 할 때, 프로덕션 코드를 직접 수정하기 전에 의존성을 분리하고 가짜 객체를 주입하여 안전한 테스트 하네스(Test Harness)를 먼저 구축합니다. [4, 6]
|
||||
- **Learning Path:** 리팩토링 원칙 학습 -> 코드 냄새(Code Smells) 식별 -> 의존성 분리 및 접점(Seams) 활용 -> 테스트 주도 리팩토링(TDD) -> 지속 가능한 아키텍처 유지의 순서로 학습을 전개합니다. [6, 26]
|
||||
- **My Project Relevance:** 현재 진행 중인 프로젝트에서 기능 추가 시 기존 코드가 얽혀 테스트가 불가능하다면, 기능 개발을 멈추고 데이터베이스나 외부 API와 같은 강한 의존성을 분리하는 '준비적 리팩토링(Preparatory Refactoring)'부터 수행해야 합니다. [3, 27]
|
||||
|
||||
### Adjacent Topics
|
||||
- [[Test-Driven Development (TDD)]]
|
||||
- 확장 방향: 테스트를 코드 작성 전에 미리 작성함으로써, 처음부터 외부 의존성이 낮고 격리가 쉬운(테스트하기 좋은) 유연한 아키텍처 설계로 이어지는 과정을 확장하여 학습할 수 있습니다. [28, 29]
|
||||
- [[Technical Debt (기술 부채)]]
|
||||
- 확장 방향: 무분별한 의존성 방치 및 더러운 코드(Dirty Code)의 축적이 향후 유지보수와 기능 확장 시 비용을 얼마나 기하급수적으로 증가시키는지 그 경제적 영향을 연구할 수 있습니다. [6, 30]
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-03*
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
|
||||
**추출된 패턴:**
|
||||
> *(TODO)*
|
||||
|
||||
**세부 내용:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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" }
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### pnpm 의 strict install
|
||||
```bash
|
||||
# CI 의 deterministic install
|
||||
pnpm install --frozen-lockfile
|
||||
# 매 lockfile mismatch 시 error.
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
# 매 audit
|
||||
pnpm audit --audit-level=high
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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 }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### SBOM 생성 (CycloneDX)
|
||||
```bash
|
||||
npx @cyclonedx/cyclonedx-npm --output-file sbom.json
|
||||
# 매 SLSA / EU CRA compliance 의 사용.
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### Known-good integrity check
|
||||
```bash
|
||||
# 매 npm install 후 lockfile integrity 검증
|
||||
pnpm install --frozen-lockfile --prefer-offline
|
||||
# Subresource integrity 가 lockfile 에 자동 record.
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]] · [[Build-Systems]]
|
||||
- 변형: [[Monorepo]] · [[npm-workspaces]] · [[pnpm-catalogs]]
|
||||
- 응용: [[Dependency-Analysis]] · [[SBOM]] · [[License-Compliance]]
|
||||
- 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 |
|
||||
|
||||
@@ -2,90 +2,174 @@
|
||||
id: wiki-2026-0508-dependency-injection-의존성-주입
|
||||
title: Dependency Injection (의존성 주입)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [DI, Dependency Injection, IoC, Inversion of Control]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [uncategorized]
|
||||
confidence_score: 0.93
|
||||
verification_status: applied
|
||||
tags: [di, ioc, design-pattern, spring, nestjs]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: nestjs
|
||||
---
|
||||
|
||||
# [[Dependency Injection (의존성 주입)]]
|
||||
# Dependency Injection (의존성 주입)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
의존성 주입(Dependency Injection)은 프로그램의 규모가 커짐에 따라 모듈 간의 의존성을 리팩토링할 때 서비스 로케이터(Service Locator)와 함께 도입할 수 있는 설계 패턴입니다 [1]. 이 패턴은 여러 팀에서 제공하는 모듈들을 동적으로 결합할 수 있게 해주어, 개발자가 전체 시스템을 다 이해하지 않고도 작은 부분을 수정할 수 있도록 돕습니다 [1]. 그 외 구체적인 개념에 대해서는 소스에 관련 정보가 부족합니다.
|
||||
## 매 한 줄
|
||||
> **"매 의존성 매 외부 주입, 직접 생성 X"**. IoC 의 가장 흔한 구현. Martin Fowler (2004) 가 명명. 2026 현재 Spring (Java), NestJS (Node), Angular, dagger (Android), wire (Go) 매 mainstream; testability + decoupling 의 backbone.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **모듈 의존성 리팩토링의 일환:** 프로그램이 성장함에 따라 모듈을 분리하는 것은 필수적이며, 프레젠테이션-도메인-데이터(Presentation-Domain-Data) 계층화를 활용해 프로그램을 나눈 뒤 모듈 간의 의존성을 해결하는 과정에서 의존성 주입 패턴이 활용될 수 있습니다 [1].
|
||||
* **다양한 언어에서의 적용:** 이 패턴은 자바(Java)나 클래스 개념이 없는 자바스크립트(JavaScript) 스타일 등 각기 다른 프로그래밍 언어 환경에 모두 적용될 수 있으나, 언어의 특성에 따라 그 구현 형태는 다르게 나타납니다 [1].
|
||||
* 그 외 상세한 동작 원리나 구체적 구현 사례에 대해서는 소스에 관련 정보가 부족합니다.
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
소스에 관련 정보가 부족합니다.
|
||||
### 매 형태 (3 종류)
|
||||
- **Constructor injection** — 생성자 매 dependency 받음. 매 immutable, 매 권장.
|
||||
- **Setter injection** — setter 매 dependency 받음. optional dep 에 적합.
|
||||
- **Field injection** — 매 framework 의 reflection. simple 하지만 testability ↓.
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-03*
|
||||
### 매 benefit
|
||||
- **Testability** — mock 매 쉽게 inject.
|
||||
- **Decoupling** — concrete impl 의 unaware.
|
||||
- **Lifecycle 관리** — singleton, request-scoped, transient.
|
||||
- **Configuration centralization** — DI container 의 wiring.
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
### 매 응용
|
||||
1. Spring `@Autowired`, `@Component`.
|
||||
2. NestJS `@Injectable()` + module providers.
|
||||
3. Angular `providedIn: 'root'`.
|
||||
4. Go: 매 manual 또는 google/wire codegen.
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
## 💻 패턴
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
### NestJS — constructor injection
|
||||
```typescript
|
||||
@Injectable()
|
||||
export class UserService {
|
||||
constructor(
|
||||
private readonly repo: UserRepository,
|
||||
private readonly logger: Logger,
|
||||
) {}
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
async find(id: string) {
|
||||
this.logger.log(`finding ${id}`);
|
||||
return this.repo.findById(id);
|
||||
}
|
||||
}
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
|
||||
- **Parent:** [[10_Wiki/Topics]]
|
||||
- **Related:** *(TODO: 최소 2개)*
|
||||
- **Opposite / Trade-off:** *(TODO)*
|
||||
- **Raw Source:** 직접 입력
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
@Module({
|
||||
providers: [UserService, UserRepository, Logger],
|
||||
exports: [UserService],
|
||||
})
|
||||
export class UserModule {}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Spring Boot — constructor injection (no `@Autowired` needed)
|
||||
```java
|
||||
@Service
|
||||
public class OrderService {
|
||||
private final PaymentGateway gateway;
|
||||
private final OrderRepository repo;
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
public OrderService(PaymentGateway gateway, OrderRepository repo) {
|
||||
this.gateway = gateway;
|
||||
this.repo = repo;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Token / interface binding (NestJS)
|
||||
```typescript
|
||||
export const PAYMENT_GATEWAY = Symbol('PAYMENT_GATEWAY');
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
@Module({
|
||||
providers: [
|
||||
{ provide: PAYMENT_GATEWAY, useClass: StripeGateway },
|
||||
],
|
||||
exports: [PAYMENT_GATEWAY],
|
||||
})
|
||||
export class PaymentModule {}
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
@Injectable()
|
||||
class CheckoutService {
|
||||
constructor(@Inject(PAYMENT_GATEWAY) private gw: PaymentGateway) {}
|
||||
}
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### Factory provider (async, e.g. DB connection)
|
||||
```typescript
|
||||
{
|
||||
provide: 'DATABASE_CONNECTION',
|
||||
useFactory: async (config: ConfigService) => {
|
||||
return await createPool({ url: config.get('DB_URL') });
|
||||
},
|
||||
inject: [ConfigService],
|
||||
}
|
||||
```
|
||||
|
||||
### Manual DI (Go, wire-style)
|
||||
```go
|
||||
// wire.go (codegen)
|
||||
func InitializeApp() *App {
|
||||
repo := NewUserRepo(NewDB())
|
||||
svc := NewUserService(repo)
|
||||
return NewApp(svc)
|
||||
}
|
||||
```
|
||||
|
||||
### Test with mock (vitest)
|
||||
```typescript
|
||||
const mockRepo: UserRepository = {
|
||||
findById: vi.fn().mockResolvedValue({ id: '1', name: 'A' }),
|
||||
};
|
||||
const service = new UserService(mockRepo, mockLogger);
|
||||
expect(await service.find('1')).toEqual({ id: '1', name: 'A' });
|
||||
```
|
||||
|
||||
### Modern: TC39 decorators + Reflect.metadata (2026)
|
||||
```typescript
|
||||
@injectable()
|
||||
class EmailService {
|
||||
@inject(SMTP_CLIENT) private smtp!: SmtpClient;
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Spring/Java | `@Component` + constructor injection |
|
||||
| Node.js/TS, full framework | NestJS module providers |
|
||||
| Frontend (Angular) | `providedIn: 'root'` |
|
||||
| Go | manual or `google/wire` |
|
||||
| Tiny app, no framework | manual constructor — DI 불필요 |
|
||||
|
||||
**기본값**: constructor injection, framework-managed singleton. Field injection 매 피하기.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Inversion of Control]] · [[SOLID]] (D)
|
||||
- 변형: [[Service Locator]] · [[Factory Pattern]]
|
||||
- 응용: [[Spring Framework]] · [[NestJS]] · [[Angular]]
|
||||
- Adjacent: [[Cross-Cutting Concerns]] · [[Aspect-Oriented Programming (AOP)]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: provider wiring 생성, mock 매 test 자동 생성, refactor field→constructor injection.
|
||||
**언제 X**: lifecycle / scope decision 매 architectural taste 필요.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Service Locator** — DI 와 혼동, dep 매 hidden.
|
||||
- **Field injection 남용** — test 시 reflection 필요, 매 fragile.
|
||||
- **Circular dep** — A→B→A. forwardRef 로 hack 보다 redesign.
|
||||
- **God container** — singleton 매 200개. module boundary 무시.
|
||||
- **`new` in business logic** — DI 의 의미 없음.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Fowler 2004 *Inversion of Control Containers and the Dependency Injection Pattern*, NestJS docs 2026).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — full content with NestJS/Spring/Go patterns |
|
||||
|
||||
@@ -2,244 +2,31 @@
|
||||
id: wiki-2026-0508-dependency-injection
|
||||
title: Dependency Injection
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
canonical_id: self
|
||||
status: duplicate
|
||||
canonical_id: dependency-injection-uijonseong-juip
|
||||
duplicate_of: "[[Dependency Injection (의존성 주입)]]"
|
||||
aliases: []
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, dependency-injection, design-pattern]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
---
|
||||
|
||||
# [[Dependency-Injection|Dependency-Injection]] (의존성 주입)
|
||||
# Dependency Injection
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> "직접 사러 가지 말고, 배달받아 써라." 객체가 필요한 의존 객체를 스스로 생성하지 않고, 외부에서 주입받음으로써 코드 간의 결합도를 낮추고 테스트 용이성을 극대화하는 디자인 패턴이다.
|
||||
> **이 문서는 [[Dependency Injection (의존성 주입)]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
---
|
||||
## 핵심 요약 (specialization aspects)
|
||||
- 매 영문 표제 variant.
|
||||
- 매 patterns / DI containers / framework-specific (Angular, NestJS, Spring) 의 매 canonical 에 통합.
|
||||
|
||||
**의존성 주입(Dependency Injection, DI)**은 객체 지향 프로그래밍에서 객체 간의 결합도를 낮추기 위해 사용되는 설계 패턴입니다. 객체가 내부에서 필요한 의존 객체를 직접 생성(new)하지 않고, 인터페이스를 통해 외부(프레임워크나 컨테이너)로부터 주입받는 방식을 의미합니다. 이는 SOLID 원칙 중 하나인 **의존성 역전 원칙(DIP)**을 실현하는 핵심 메커니즘으로, 코드의 유연성, 재사용성, 그리고 테스트 용이성을 획기적으로 향상시킵니다.
|
||||
## 🔗 Graph
|
||||
- 부모: [[Dependency Injection (의존성 주입)]] (canonical)
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
> 의존성 주입(Dependency Injection, DI)은 모듈이 필요로 하는 의존성 객체를 내부에서 직접 생성하지 않고 외부로부터 제공(주입)받도록 설계하는 소프트웨어 패턴입니다 [1, 2]. 이 기법은 시스템 컴포넌트 간의 결합도를 낮추어 코드의 모듈화를 촉진하며 [2, 3], 궁극적으로 애플리케이션의 유지보수성과 테스트 용이성을 크게 향상시키는 데 목적이 있습니다 [3, 4].
|
||||
|
||||
---
|
||||
|
||||
의존성 주입(Dependency Injection, DI)은 상위 계층이 하위 계층의 인스턴스를 직접 생성하는 대신, 외부에서 의존성을 "주입"하여 구성 요소 간의 결합도를 낮추는 소프트웨어 엔지니어링 기법이다 [1]. 핵심 비즈니스 로직을 변경하지 않고도 종속성을 관리하거나 특정 구현체를 쉽게 교체할 수 있게 해준다 [2]. 의존성 역전 원칙(DIP)을 달성하기 위한 대표적인 구현 방법으로 사용되며, 애플리케이션의 테스트 용이성과 유지보수성을 크게 향상시킨다 [2, 3].
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **The Core Concept**:
|
||||
- 클래스 내부에서 `new Service()`를 호출하는 순간, 그 클래스는 해당 서비스에 강하게 결합(Coupled)된다.
|
||||
- DI는 생성자(Constructor)나 메서드 인자를 통해 외부에서 구현체를 전달받는다.
|
||||
- **Benefits**:
|
||||
- **TeStability**: 실제 DB 대신 가짜(Mock) 객체를 주입하여 단위 테스트 가능.
|
||||
- **Flexibility**: 코드 수정 없이 실행 시점에 구현체 교체 가능.
|
||||
- **Maintenance**: 의존성 관리가 한곳(Container)으로 집중되어 구조 파악이 용이.
|
||||
- **Types**: Constructor Injection, Setter Injection, Interface Injection.
|
||||
|
||||
---
|
||||
|
||||
### 1. 주요 주입 방식
|
||||
* **생성자 주입 (Constructor Injection):** 객체 생성 시점에 의존성을 주입받는 방식으로, 필드를 `final/readonly`로 유지할 수 있어 불변성을 보장하고 가장 권장되는 방식입니다.
|
||||
* **세터 주입 (Setter Injection):** 객체 생성 후 세터 메서드를 통해 의존성을 주입합니다. 선택적 의존성이 있거나 실행 중에 변경이 필요할 때 사용합니다.
|
||||
* **인터페이스 주입 (Interface Injection):** 주입을 담당하는 인터페이스를 통해 의존성을 제공받습니다. (상대적으로 사용 빈도가 낮음)
|
||||
|
||||
### 2. 제어의 역전 (IoC)과의 관계
|
||||
DI는 **제어의 역전(Inversion of Control)**을 실현하는 구체적인 방법 중 하나입니다. 객체의 생성 주기와 의존성 조립의 권한을 객체 자신이 아닌 외부의 **IoC 컨테이너**(Spring의 ApplicationContext, NestJS의 Module 등)로 위임함으로써 개발자는 비즈니스 로직에만 집중할 수 있게 됩니다.
|
||||
|
||||
### 3. 실무 설계 패턴 (Frameworks)
|
||||
* **NestJS:** `@Injectable()`과 모듈 시스템을 통해 강력한 DI 컨테이너를 제공합니다. TypeScript의 타입을 토큰으로 활용하여 의존성을 자동 연결합니다.
|
||||
* **Spring Boot:** `@Autowired`나 생성자 주입을 통해 Bean 간의 의존성을 관리합니다.
|
||||
* **Riverpod (Flutter):** 상태 관리 기능에 DI를 결합하여 컴파일 타임 안정성을 제공하고 위젯 트리 외부에서 의존성을 안전하게 제공합니다.
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- **결합도 감소 및 모듈화 촉진**
|
||||
의존성 주입은 모듈 간 상호작용 시 한 모듈이 다른 모듈의 인스턴스를 직접 생성하지 않고 외부에서 제공받는 방식을 취합니다 [1, 2]. 이러한 방식은 컴포넌트들을 디커플링(decoupling)하여 핵심 로직을 변경하지 않고도 구현체를 교체하거나 의존성을 쉽게 관리할 수 있게 해줍니다 [3].
|
||||
- **의존성 역전 원칙(DIP) 구현의 핵심**
|
||||
객체 지향 프로그래밍의 핵심 설계 원칙 중 하나인 '의존성 역전 원칙(Dependency [[Inversion|Inversion]] Principle)'은 상위 모듈이 하위 모듈에 직접 의존하지 않고 둘 다 추상화에 의존해야 함을 명시합니다 [5]. 의존성 주입은 이 원칙을 실제로 구현하는 주된 수단으로 사용되며, Java의 Spring이나 ASP.NET Core와 같은 프레임워크들은 내장된 DI 컨테이너를 통해 의존성 주입을 훨씬 쉽게 구현할 수 있도록 지원합니다 [6].
|
||||
- **소프트웨어 아키텍처에서의 활용**
|
||||
- **계층형 아키텍처(Layered [[Architecture|Architecture]]):** 상위 계층이 하위 계층을 직접 인스턴스화하는 대신 외부에서 의존성을 주입받게 하여, 계층 간의 느슨한 결합(loose coupling)을 이끌어냅니다 [1].
|
||||
- **클린 아키텍처(Clean Architecture):** 내부 계층에 정의된 인터페이스(포트)에 대해 외부 계층이 구체적인 구현(어댑터)을 제공합니다. 이때 런타임에 의존성 주입을 사용하여 컴포넌트들을 연결함으로써, 핵심 비즈니스 로직이 특정 프레임워크나 도구에 결합되지 않도록 방지합니다 [7]. 또한 의존성 주입기를 활용해 모든 의존성이 내부를 향하도록 의존성 규칙을 관리할 수 있습니다 [8].
|
||||
- **테스트 용이성(TeStability) 확보**
|
||||
하드 코딩된 의존성은 구현 세부 사항과 강하게 결합하여 코드를 외부 환경으로부터 고립시켜 단위 테스트를 불가능하게 만들거나 어렵게 합니다 [4, 9]. 따라서 외부 시스템 없이 모듈을 독립적으로 테스트하고, 필요에 따라 목(Mock)과 같은 테스트 더블(Test Double)로 의존성을 대체하기 위해서는 의존성 주입의 사용이 필수적으로 권장됩니다 [4, 10].
|
||||
|
||||
---
|
||||
|
||||
* **구성 요소의 분리(Decoupling)와 유지보수성**: DI 프레임워크를 활용하면 시스템의 구성 요소들을 서로 분리(decouple)할 수 있다 [2]. 이를 통해 핵심 로직을 건드리지 않고도 의존성을 관리하거나 새로운 구현체로 대체하기가 훨씬 수월해지며, 결과적으로 시스템의 테스트 가능성(Testability)과 유지보수성이 현저히 향상된다 [2].
|
||||
* **의존성 역전 원칙(DIP)의 실현**: 상위 수준 모듈이 하위 수준 모듈에 직접 의존하지 않고 양쪽 모두 추상화(abstractions)에 의존해야 한다는 '의존성 역전 원칙(Dependency Inversion Principle)'은 주로 의존성 주입(DI)을 통해 구현된다 [3]. Java의 Spring이나 ASP.NET Core에 내장된 DI 컨테이너와 같은 프레임워크를 사용하면 구성 요소를 쉽게 분리하여 이 원칙을 적용할 수 있다 [4].
|
||||
* **계층형 아키텍처(Layered Architecture) 내에서의 역할**: 계층 간의 엄격한 통신을 강제하고 종속성을 관리하기 위해 DI를 구현한다 [1]. 상위 계층이 하위 계층의 객체를 직접 생성하는 방식 대신, 외부 소스로부터 의존성이 주입되게 함으로써 결합도를 느슨하게 만든다 [1].
|
||||
* **클린 아키텍처(Clean Architecture)와의 결합**: 비즈니스 로직을 외부의 데이터베이스나 웹 프레임워크로부터 격리시키는 클린 아키텍처에서 DI는 필수적으로 사용된다 [5, 6]. 내부 계층에서 인터페이스(포트)를 정의하고 외부 계층이 구체적인 구현체(어댑터)를 제공하도록 설계한 뒤, 런타임 시점에 의존성 주입을 사용해 이 구성 요소들을 연결한다 [6].
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- DI 프레임워크(Spring, NestJS 등)를 과도하게 사용하면 의존성 그래프가 너무 복잡해져 런타임 성능에 영향을 주거나 디버깅이 어려워지는 'DI 지옥'에 빠질 수 있다. 객체 간의 관계가 명확할 때는 과도한 추상화보다 직관적인 구성을 고려해야 한다.
|
||||
|
||||
---
|
||||
|
||||
### ✅ Benefits
|
||||
* **낮은 결합도:** 객체 간의 직접적인 참조가 줄어들어 특정 구현체가 변경되어도 이를 사용하는 코드를 수정할 필요가 없습니다.
|
||||
* **테스트 용이성:** 실제 DB나 API 객체 대신 Mock(가짜) 객체를 외부에서 주입하여 독립적인 단위 테스트가 가능합니다.
|
||||
* **유지보수성:** 객체의 생성 로직이 한곳(Composition Root)에 모여 있어 시스템 구성 파악이 용이합니다.
|
||||
|
||||
### ⚠️ Challenges
|
||||
* **초기 복잡성:** 단순한 프로젝트에서는 인터페이스 정의와 프레임워크 설정 등이 오버헤드가 될 수 있습니다 (Overkill).
|
||||
* **런타임 오류:** 의존성이 런타임에 주입되므로, 설정 오류로 인한 주입 실패를 컴파일 시점에 발견하기 어려울 수 있습니다 (단, 최신 프레임워크는 이를 상당 부분 개선함).
|
||||
* **코드 추적의 어려움:** 객체 생성 로직이 외부에 감추어져 있어, 코드를 처음 읽는 개발자가 실제 어떤 클래스가 사용되는지 파악하기 위해 미로를 헤매는 현상(The Hidden Maze)이 발생할 수 있습니다.
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
|
||||
---
|
||||
|
||||
DI 메커니즘 자체로 인해 발생하는 런타임 오버헤드, 디버깅 복잡성 등의 구체적인 기술적 제약 사항이나 부작용에 대해서는 **소스에 관련 정보가 부족합니다**.
|
||||
|
||||
다만, DI를 포함한 SOLID 원칙 및 아키텍처 패턴을 코드베이스에 적용할 때 따르는 설계적 측면의 제약(Trade-off)과 요구 사항은 다음과 같습니다:
|
||||
* **숙련도 및 프레임워크 의존성**: DI를 원활하게 구현하기 위해서는 Spring이나 ASP.NET Core와 같은 전용 DI 프레임워크 기술에 의존해야 하며, 이를 능숙하게 다룰 수 있는 숙련된 개발자(Skilled developers)가 필요하다 [4, 7].
|
||||
* **선행 설계 작업의 증가**: 핵심 구현 코드를 작성하기 전에 컴포넌트가 무엇을 해야 하는지 정의하는 '인터페이스 설계'를 먼저 수행해야 하는 설계 규율(design discipline)이 강제된다 [4, 7].
|
||||
* **구현 복잡도(Implementation Complexity)**: 컴포넌트의 책임을 분리하고 추상화하는 과정은 초기 설계 및 리팩토링 단계에서 중간에서 높음(Medium-High) 수준의 작업 복잡도와 설계 훈련을 요구한다 [7].
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- Related: [[의존성 역전 (Dependency Inversion)|Dependency-[[Inversion]]-Principle]] , Inversion-of-Control (IoC)
|
||||
- Pattern: Factory-Method-Pattern
|
||||
|
||||
---
|
||||
|
||||
### Related Concepts
|
||||
* [[Dependency_Inversion_Principle]]: DI가 추구하는 근본적인 객체지향 설계 원칙입니다.
|
||||
* [[Hexagonal_Architecture]]: 도메인 포트에 외부 어댑터를 주입할 때 DI를 필수로 사용합니다.
|
||||
* [[Inversion_of_Control]]: 객체의 생명 주기를 프레임워크에 위임하는 상위 개념입니다.
|
||||
|
||||
### Practical Application Contexts
|
||||
* **Unit Testing:** 테스트 환경에서 Mock Repository를 주입하여 비즈니스 로직을 검증합니다.
|
||||
* **Polyglot Infrastructure:** 설정 파일만 변경하여 SQL DB 어댑터를 NoSQL DB 어댑터로 교체합니다.
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** [[의존성 역전 원칙 (Dependency Inversion Principle)|의존성 역전 원칙 (Dependency Inversion Principle]], 느슨한 결합 (Loose Coupling), 관심사의 분리 ([[_뇌와 팔다리의 분리_ - 관심사의 분리 (Separation of Concerns)|Separation of Concerns]], [[테스트 용이성 (Testability)|테스트 용이성 (Testability]]
|
||||
- **Projects/Contexts:** [[클린 아키텍처 (Clean Architecture)|클린 아키텍처 (Clean Architecture]], 계층형 아키텍처 (Layered Architecture), [[Spring Framework|Spring Framework]], ASP.NET Core
|
||||
- **Contradictions/Notes:** 제공된 모든 소스는 의존성 주입이 모듈 간의 결합도를 낮추고 테스트 용이성을 극대화한다는 점에서 일치된 견해를 보이고 있으며, 코드의 설계 단계부터 하드 코딩을 지양하고 의존성 주입을 염두에 둘 것을 공통적으로 강조하고 있습니다 [2, 9].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-18*
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
### Related Concepts
|
||||
|
||||
#### [설계 원칙 (Design Principles)]
|
||||
- [[의존성 역전 원칙 (Dependency Inversion Principle, DIP)]]
|
||||
- 연결 이유: DI는 고수준 모듈과 저수준 모듈 간의 결합을 끊기 위해 추상화에 의존하게 만드는 DIP 원칙을 코드로 구현하는 직접적인 수단이다 [3].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 왜 인터페이스를 구현체보다 먼저 설계해야 하는지, 그리고 DI가 어떻게 코드의 유연성을 확보하는지 그 근본적인 철학을 이해할 수 있다 [3, 4].
|
||||
|
||||
- [[관심사의 분리 (Separation of Concerns, SoC)]]
|
||||
- 연결 이유: 시스템을 겹치지 않는 별개의 기능 섹션으로 분할하여 복잡도를 낮추는 SoC를 실무적으로 효과적으로 적용하기 위한 핵심 전략 중 하나가 DI 프레임워크를 활용하는 것이다 [2, 8].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 의존성 주입이 궁극적으로 모듈성(Modularity)을 높이고 시스템 복잡도를 줄이는 거시적 설계 목표와 어떻게 맞닿아 있는지 파악할 수 있다 [2, 8].
|
||||
|
||||
#### [아키텍처 및 구현 기술 (Architectures & Frameworks)]
|
||||
- [[클린 아키텍처 (Clean Architecture)]]
|
||||
- 연결 이유: 비즈니스 로직(내부)과 프레임워크/데이터베이스(외부)를 격리하기 위한 의존성 규칙을 런타임에 최종적으로 완성시키는 도구가 바로 DI이다 [5, 6].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 포트(인터페이스)와 어댑터(구현체)가 코드 구조 내에서 분리되어 있을 때, 어떻게 이들이 실제 애플리케이션 실행 시 결합되는지 그 연결 고리를 이해할 수 있다 [6].
|
||||
|
||||
- [[DI 프레임워크 (Spring, ASP.NET Core)]]
|
||||
- 연결 이유: 의존성 주입을 수동으로 관리하는 대신, 시스템 차원에서 자동으로 객체를 생성하고 주입해 주는 실질적인 구현 도구들이다 [4].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 코드베이스 내부에서 종속성 관계를 자동으로 조립하고 분리(decouple)하는 구체적인 프레임워크의 동작 방식을 이해할 수 있다 [4].
|
||||
|
||||
### Deeper Research Questions
|
||||
- 의존성 주입 시 인터페이스와 구체 클래스(Concrete Implementation)를 연결하는 설정 정보는 대규모 코드베이스의 어느 계층(혹은 모듈)에 위치하는 것이 가장 이상적인가?
|
||||
- 런타임에 동적으로 의존성이 주입되는 환경에서, 상향식(Bottom-Up) 코드베이스 탐색 시 데이터 흐름과 의존 관계를 어떻게 효과적으로 역추적할 수 있는가?
|
||||
- 의존성 주입 프레임워크(예: Spring)를 과도하게 사용할 때 발생할 수 있는 '코드 가독성 저하'나 '디버깅의 어려움'을 해결하기 위한 구조적 접근법은 무엇인가?
|
||||
- 마이크로서비스 아키텍처(MSA)에서 각 독립된 서비스 내부의 DI 컨테이너 구성은 모놀리식 아키텍처와 비교하여 어떤 차별화된 설계 전략을 가져야 하는가?
|
||||
- 테스트 자동화를 위해 단위 테스트에서 모의 객체(Mock Objects)를 의존성 주입으로 제공할 때, 테스트 커버리지를 높이는 가장 효율적인 인터페이스 분리 전략은 무엇인가?
|
||||
|
||||
### Practical Application Contexts
|
||||
|
||||
- **Implementation:** 클래스 개발 시 내부에서 사용할 의존 객체를 직접 `new` 키워드로 생성하지 않고, 생성자나 설정자를 통해 주입받도록 코드를 작성한다. 또한, 코드 구현에 앞서 인터페이스를 먼저 정의하여 의존성의 유연함을 확보한다 [1, 4].
|
||||
- **System Design:** 소프트웨어 아키텍처를 계층형(Layered) 또는 클린 아키텍처로 구성할 때, 하위 계층의 변경이 상위 계층에 영향을 미치지 않도록 계층 간 통신 경계 인터페이스를 구축하고 이를 DI로 연결하도록 설계한다 [1, 6].
|
||||
- **Operation / Maintenance:** 데이터베이스 기술 교체나 새로운 외부 API 연동이 필요할 때, 핵심 비즈니스 로직 모듈은 그대로 유지한 채 DI 컨테이너의 설정만 수정하여 외부 어댑터 구현체를 교체함으로써 유지보수 비용을 최소화한다 [2, 5, 6].
|
||||
- **Learning Path:** SOLID 원칙 중 SRP(단일 책임 원칙) 적용을 시작으로 인터페이스 설계법을 익히고, DIP의 개념을 숙지한 뒤, Spring이나 ASP.NET Core 등의 DI 프레임워크의 사용법을 학습하는 순서로 확장해 나간다 [4].
|
||||
- **My Project Relevance:** 복잡한 시스템의 '코드베이스 읽기 지식'을 확보하기 위해 소스 코드를 탐색할 때, 객체가 직접 생성되지 않고 주입되는 패턴(DI)을 인지함으로써, 정적 코드만으로는 보이지 않는 런타임 시점의 결합 구조와 전체 실행 제어 흐름(Control Flow)을 정확히 해독하고 역추적하는 데 필수적이다 [2, 4].
|
||||
|
||||
### Adjacent Topics
|
||||
- [[테스트 가능성 (Testability)]]
|
||||
- 확장 방향: DI가 어떻게 모의 객체(Mock)나 스텁(Stub) 주입을 용이하게 만들어 단위 테스트를 격리된 환경에서 안전하고 완벽하게 수행할 수 있도록 돕는지 확장하여 조사한다 [1, 2].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
|
||||
## 💡 Adjacent Topics
|
||||
* [[NestJS]]: DI를 기반으로 아키텍처를 강제하는 대표적인 Node.js 프레임워크입니다.
|
||||
* [[Composition_Root]]: 애플리케이션 진입점에서 모든 객체 의존성을 조립하는 지점입니다.
|
||||
* [[Service_Locator_Pattern]]: DI와 유사하지만 객체가 직접 저장소를 호출하여 의존성을 찾는, 지양해야 할 안티패턴입니다.
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
|
||||
@@ -2,164 +2,174 @@
|
||||
id: wiki-2026-0508-dependency-analysis
|
||||
title: Dependency Analysis
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [dep-analysis, dependency-graph, code-dependency-tools]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [tooling, dependencies, static-analysis]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: javascript
|
||||
framework: madge/depcheck/knip
|
||||
---
|
||||
|
||||
# [[시스템 의존성 분석과 모듈 간 결합도 관리 (Dependency Analysis)]]
|
||||
# Dependency Analysis
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
의존성 분석은 소프트웨어 시스템 내의 다양한 컴포넌트, 모듈, 서비스 또는 패키지 간의 상호작용과 결합 관계를 식별하고 매핑하는 과정입니다 [1-3]. 이는 대규모 코드베이스에서 단일 변경 사항이 다른 시스템에 미치는 파급 효과(Impact)를 이해하고, 아키텍처의 경계를 파악하는 데 필수적입니다 [4, 5]. 개발자는 의존성 분석을 통해 순환 참조를 방지하고, 구조적 결함을 리팩토링하며, 신규 개발자의 온보딩과 코드 독해 속도를 가속화할 수 있습니다 [6-9].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **시스템 영향도 및 파급 효과 분석**
|
||||
복잡한 시스템에서 특정 컴포넌트의 변경은 의존성을 가진 다른 서비스에 예기치 않은 오류를 유발할 수 있습니다 [4, 5]. 의존성 분석은 모듈이나 서비스 간의 데이터 흐름과 호출 스택을 추적하여 이러한 통합 위험(Integration risks)과 파괴적 변경(Breaking changes)을 사전에 식별합니다 [1, 2, 4]. 특히 마이크로서비스 환경에서는 크로스 리포지토리(Cross-repository) 수준의 의존성 추적이 시스템의 안정성을 유지하는 핵심이 됩니다 [1, 10].
|
||||
## 매 핵심
|
||||
|
||||
* **아키텍처 규칙과 의존성 방향의 통제**
|
||||
대규모 코드베이스는 계층형(Layered) 아키텍처, 클린(Clean) 아키텍처, 헥사고날(Hexagonal) 아키텍처 등 고유의 아키텍처 스타일을 따릅니다 [3, 11]. 이러한 구조에서 가장 중요한 것은 의존성의 방향입니다 [12, 13]. 예를 들어, 클린 아키텍처의 '의존성 규칙(Dependency Rule)'에 따르면 모든 의존성은 시스템의 핵심인 비즈니스 엔티티와 유즈케이스 계층을 향해 안쪽으로만 향해야 합니다 [12-14]. 코드베이스를 읽을 때 외부 프레임워크나 UI 로직이 코어 비즈니스 로직에 스며들지 않았는지 의존성 방향을 분석하여 아키텍처의 부패 여부를 진단할 수 있습니다 [3, 11, 14].
|
||||
### 매 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.
|
||||
|
||||
* **순환 의존성(Cyclic Dependencies) 방지와 모듈성**
|
||||
서로 다른 폴더나 모듈이 서로를 양방향으로 참조하는 순환 의존성은 시스템의 모듈성과 독립성을 크게 훼손합니다 [6, 7]. 예를 들어, A 프로젝트의 코드가 B 프로젝트에 의존하고, B가 다시 A의 테스트 코드에 의존한다면 독립적인 모듈로 볼 수 없습니다 [6]. 의존성 분석을 통해 이러한 순환 고리를 시각적으로 파악하고, 관심사 분리(Separation of Concerns) 및 캡슐화 원칙을 적용하여 의존성을 단방향으로 리팩토링해야 합니다 [7].
|
||||
### 매 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.
|
||||
|
||||
* **시각화 도구 및 AI 자동화 도입**
|
||||
코드베이스 맵(Codebase Maps)이나 시스템 아키텍처 다이어그램(예: C4 모델의 컨테이너/컴포넌트 다이어그램)은 코드의 의존성을 색상과 화살표로 시각화하여 파악을 돕습니다 [2, 8, 15, 16]. 최근에는 Augment Code, Cody, Greptile과 같은 AI 기반 도구가 도입되어 수십만 개의 파일을 인덱싱하고 크로스 리포지토리 간의 아키텍처 의존성을 자동으로 매핑하고 추적합니다 [1, 10, 17].
|
||||
### 매 응용
|
||||
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.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
* **과도한 추상화의 복잡성 비용:** 의존성을 분리하기 위해 의존성 주입(Dependency Injection)과 인터페이스를 적극 도입하면 모듈 간 결합도는 낮아지지만, 추상화의 깊이가 깊어져 코드의 직관적인 독해를 방해할 수 있습니다 [18, 19]. 때로는 약간의 중복이 과도한 추상화보다 가독성 면에서 유리할 수 있습니다 [20].
|
||||
* **분석 도구의 성능 한계:** C++과 같이 규모가 크고 헤더 파일의 중첩 및 재귀적 포함(Recursive Includes)이 심한 레거시 시스템에서는 의존성이 폭발적으로 증가하여 IDE나 분석 도구(예: Intellisense)의 인덱싱 속도를 저하시키고 마비시킬 수 있습니다 [21-23]. 대형 코드베이스를 AI로 초기 인덱싱할 때도 수 시간이 소요되는 제약이 있습니다 [24].
|
||||
* **아키텍처 표류(Architectural Drift):** 수동으로 작성된 의존성 맵이나 아키텍처 다이어그램은 코드가 진화함에 따라 실제 구현과 멀어지는 현상을 겪게 됩니다 [25]. 의존성 정보를 실시간 코드로 동기화하는 도구를 사용하지 않으면, 오히려 잘못된 의존성 정보를 기반으로 개발을 진행할 위험이 있습니다 [25-27].
|
||||
## 💻 패턴
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- [[Software_Supply_Chain_Security]]: 프로젝트 내부 의존성을 넘어 외부 라이브러리의 보안 의존성을 관리하는 영역.
|
||||
- [[Clean_Architecture]]: 의존성 방향을 통제하여 비즈니스 로직을 보호하는 대표적 아키텍처.
|
||||
- [[Refactoring]]: 의존성 분석 결과를 바탕으로 수행되는 구조 개선 활동.
|
||||
### Madge 의 circular detection
|
||||
```bash
|
||||
npx madge --circular --extensions ts,tsx src/
|
||||
# 매 circular 가 있으면 fail.
|
||||
|
||||
---
|
||||
|
||||
### Related Concepts
|
||||
|
||||
#### [아키텍처 및 설계 원칙]
|
||||
- [[의존성 역전 원칙 (Dependency Inversion Principle)]]
|
||||
- 연결 이유: SOLID 설계 원칙의 핵심으로, 상위 모듈이 하위 모듈에 의존하지 않고 두 계층 모두 추상화(인터페이스)에 의존해야 함을 정의합니다 [28].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 클린 아키텍처에서 코어 비즈니스 로직을 프레임워크나 데이터베이스로부터 보호하기 위해 의존성 방향을 어떻게 통제하는지 깊이 이해할 수 있습니다 [12, 13].
|
||||
|
||||
- [[순환 의존성 (Cyclic Dependencies)]]
|
||||
- 연결 이유: 두 개 이상의 모듈이 서로를 참조하여 모듈의 독립성을 해치는 구조적 결함으로, 의존성 분석 시 우선적으로 해결해야 할 대상입니다 [6, 7].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 의존성을 리팩토링할 때 관심사 분리(Separation of Concerns)와 캡슐화를 통해 문제를 어떻게 해결할 수 있는지 파악할 수 있습니다 [7].
|
||||
|
||||
- [[관심사 분리 (Separation of Concerns)]]
|
||||
- 연결 이유: 시스템을 뚜렷하고 겹치지 않는 기능 섹션으로 분할하여 모듈 간 의존성을 최소화하는 소프트웨어 공학의 기본 원칙입니다 [7, 29].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 계층형 아키텍처 및 마이크로서비스에서 역할과 책임을 어떻게 나누고 결합도를 낮추는지 논리적 기반을 이해할 수 있습니다 [7, 30, 31].
|
||||
|
||||
#### [구현 및 분석 도구]
|
||||
- [[의존성 주입 (Dependency Injection)]]
|
||||
- 연결 이유: 컴포넌트 간의 의존성을 직접 생성하지 않고 외부 프레임워크 등을 통해 주입받음으로써 결합도를 낮추는 구체적인 구현 패턴입니다 [18, 19, 32].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 의존성 역전 원칙(DIP)을 실제 코드로 구현하고, 단위 테스트의 용이성을 확보하는 방법을 배울 수 있습니다 [18, 19].
|
||||
|
||||
- [[코드베이스 맵 (Codebase Maps)]]
|
||||
- 연결 이유: 코드베이스 내 주요 파일과 의존 패키지 간의 관계를 색상 코딩 및 화살표로 시각화하여 시스템의 아키텍처를 보여주는 도구입니다 [8, 33].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 복잡한 저장소에서 코어 로직과 외부 의존성(Imports/Packages)을 시각적으로 어떻게 분리하고 파악하여 온보딩 속도를 높이는지 알 수 있습니다 [8, 34, 35].
|
||||
|
||||
### Deeper Research Questions
|
||||
- 마이크로서비스(Microservices) 아키텍처에서 여러 개의 분산된 리포지토리에 걸친 크로스 리포지토리(Cross-repository) 의존성을 어떻게 효과적으로 매핑하고 분석할 수 있는가?
|
||||
- C/C++ 프로젝트에서 발생하는 방대한 헤더 파일 포함(Includes) 문제를 해결하고, 의존성 분석 도구의 성능(인덱싱 속도 등)을 최적화하기 위한 모범 사례는 무엇인가?
|
||||
- 클린 아키텍처의 엄격한 '의존성 규칙(Dependency Rule)'을 강제하고 위반을 탐지하기 위해 CI/CD 파이프라인에 정적 분석 도구를 어떻게 통합할 수 있는가?
|
||||
- Augment Code나 Cody와 같은 LLM 기반 AI 도구는 기존의 정적 의존성 분석 도구(SAST/SCA)가 지닌 한계를 어떤 방식으로 극복하고 아키텍처 컨텍스트를 제공하는가?
|
||||
- 애자일 환경에서 코드가 지속적으로 변경됨에 따라 발생하는 의존성 다이어그램의 '아키텍처 표류(Architectural Drift)' 현상을 방지할 수 있는 자동화 및 동기화 전략은 무엇인가?
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 신규 기능을 추가하거나 레거시 코드를 수정할 때, 기존 모듈이 의존하는 패키지 트리와 인터페이스를 추적하여 부수 효과(Side-effects)나 연쇄 장애를 방지하는 설계 및 코딩에 적용됩니다.
|
||||
- **System Design:** 소프트웨어 설계 단계에서 C4 모델의 컨테이너 및 컴포넌트 다이어그램을 활용하여 서브시스템 간 통신 흐름과 외부 API, 데이터베이스에 대한 의존성 방향을 규정합니다.
|
||||
- **Operation / Maintenance:** 레거시 코드베이스의 기술적 부채를 해결하기 위해 순환 참조를 색출하여 끊어내고, 코드 리뷰 시 인터페이스를 통하지 않은 잘못된 의존성 주입이 없는지 영향도 분석(Impact Analysis)을 수행합니다.
|
||||
- **Learning Path:** 신규 엔지니어가 코드베이스에 온보딩할 때, 진입점(Entry point)에서 시작하여 하향식(Top-Down)으로 데이터가 어떤 모듈과 의존성을 거쳐 흐르는지 시각적 투어(Codebase Tour)를 통해 파악하는 데 활용됩니다.
|
||||
- **My Project Relevance:** 거대한 소스 코드나 낯선 프레임워크 환경을 분석할 때, 개별 코드 라인이 아닌 모듈 간의 연결 구조를 파악함으로써 코드베이스를 빠르고 정확하게 독해(Reading Codebase)하기 위한 기반 지식입니다.
|
||||
|
||||
### Adjacent Topics
|
||||
- [[소프트웨어 아키텍처 다이어그램 (Software Architecture Diagrams)]]
|
||||
- 확장 방향: 분석된 의존성을 UML, C4 모델 등의 시각적 형태로 문서화하여 다양한 이해관계자(개발자, PM 등)와 아키텍처를 소통하는 방법으로 확장.
|
||||
- [[소프트웨어 구성 분석 (Software Composition Analysis, SCA)]]
|
||||
- 확장 방향: 프로젝트 내부 의존성뿐만 아니라 오픈소스 라이브러리와 같은 외부 의존성(Third-party Dependencies)에 포함된 보안 취약점이나 라이선스 리스크를 분석하는 영역으로 확장.
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
|
||||
## 1. 개요
|
||||
의존성 분석(Dependency Analysis)은 소프트웨어 시스템 내의 다양한 컴포넌트, 모듈, 패키지 간의 상호작용과 연결 관계를 식별하고 평가하는 과정이다. 시스템의 복잡도가 증가함에 따라 개별 모듈이 다른 모듈에 얼마나 강하게 결합되어 있는지(Coupling), 그리고 한 곳의 변경이 시스템 전체에 어떤 파급 효과(Impact)를 미치는지를 파악하는 것은 안정적인 설계와 유지보수를 위해 필수적이다.
|
||||
|
||||
## 2. 핵심 분석 대상 및 기법
|
||||
- **의존성 방향성 (Dependency Direction)**: 상위 계층이 하위 계층에 의존하는지, 혹은 의존성 역전 원칙(DIP)을 통해 추상화에 의존하고 있는지 분석하여 아키텍처 건전성 평가.
|
||||
- **순환 의존성 (Cyclic Dependencies)**: 모듈 A가 B를 참조하고, B가 다시 A를 참조하는 등의 고리 구조를 식별. 이는 모듈의 독립성을 해치고 테스트와 배포를 어렵게 만드는 주된 요인임.
|
||||
- **영향도 분석 (Impact Analysis)**: 특정 함수나 클래스를 수정했을 때, 해당 요소를 참조하고 있는 모든 상위 호출자(Callers)와 관련 모듈을 추적하여 연쇄 장애 리스크 판단.
|
||||
- **시각화 맵 (Dependency Mapping)**: 코드베이스 맵이나 그래프 도구를 활용하여 복잡한 모듈 간의 연결 구조를 한눈에 볼 수 있도록 시각화.
|
||||
|
||||
## 3. 엔지니어링 가치
|
||||
- **시스템 복잡성 제어**: 엉킨 의존성 실타래를 풀어내어 시스템을 더 작고 관리 가능한 단위로 분해할 수 있는 근거 제공.
|
||||
- **안정적인 리팩토링 및 변경**: 변경의 영향 범위를 사전에 완벽히 파악함으로써, 코드 수정 시 발생하는 예상치 못한 부작용(Side-effects) 최소화.
|
||||
- **모듈의 재사용성 향상**: 결합도가 낮은 독립적인 모듈을 설계하여 다른 프로젝트나 서비스에서도 쉽게 재사용할 수 있는 기반 마련.
|
||||
- **온보딩 가속화**: 전체적인 시스템 구조와 데이터 흐름을 의존성 맵을 통해 보여줌으로써 신규 개발자가 거대한 코드베이스에 빠르게 적응하도록 도움.
|
||||
|
||||
## 4. 트레이드오프 및 주의사항
|
||||
- **추상화의 비용**: 의존성을 줄이기 위해 과도하게 인터페이스를 도입하고 계층을 나누면, 실제 로직을 파악하기 위해 여러 파일을 넘나들어야 하는 인지적 부하(Cognitive Load) 발생 가능.
|
||||
- **분석 도구의 오버헤드**: 수십만 줄 이상의 거대 코드베이스에서 실시간으로 의존성 트리를 갱신하는 것은 IDE 성능 저하나 인덱싱 지연을 유발할 수 있음.
|
||||
- **아키텍처 표류 (Drift)**: 코드는 계속 변하는데 의존성 문서나 다이어그램이 최신화되지 않으면, 잘못된 정보를 바탕으로 위험한 설계 결정을 내릴 수 있음.
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
- **정보 상태**: 검증 완료 (Verified)
|
||||
- **출처 신뢰도**: A
|
||||
- **검토 이유**: 소프트웨어의 모듈성과 확장성을 확보하기 위해 복잡하게 얽힌 시스템 구조를 객관적으로 분석하고 결합도를 관리하기 위한 아키텍처적 기반 정립.
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
npx madge --image graph.svg src/
|
||||
# 매 SVG 의 visualization.
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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' } },
|
||||
};
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
```bash
|
||||
depcruise --config .dependency-cruiser.cjs src/
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Knip (unused exports/files/deps)
|
||||
```jsonc
|
||||
// knip.json
|
||||
{
|
||||
"entry": ["src/index.ts", "src/cli.ts"],
|
||||
"project": ["src/**/*.{ts,tsx}"],
|
||||
"ignoreDependencies": ["husky"]
|
||||
}
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
```bash
|
||||
npx knip
|
||||
# 매 unused files, unused exports, unused deps 의 list.
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### Turborepo prune (monorepo)
|
||||
```bash
|
||||
turbo prune --scope=@acme/web --docker
|
||||
# 매 web 의 deps 만 가진 minimal package.json 의 emit — Docker layer cache 의 efficient.
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]]
|
||||
- 변형: [[Madge]] · [[dependency-cruiser]] · [[Knip]]
|
||||
- 응용: [[Monorepo]] · [[Dead-Code-Elimination]] · [[Architecture-Tests]]
|
||||
- Adjacent: [[Dependencies]] · [[Bundlers]] · [[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 |
|
||||
|
||||
@@ -2,107 +2,168 @@
|
||||
id: wiki-2026-0508-digital-twin
|
||||
title: Digital Twin
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [digital-twin, virtual-replica, cyber-physical-system]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [digital-twin, iot, simulation, cps]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: python
|
||||
framework: NVIDIA-Omniverse/Azure-Digital-Twins
|
||||
---
|
||||
|
||||
# [[Digital_Twin|Digital Twin]] Interfaces
|
||||
# Digital Twin
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> 물리적 실체와 디지털 가상물을 실시간 데이터 혈류로 연결하여 예측 가능한 미래를 설계하는 인터페이스 기술.
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
게임 산업과 경제 설계에서 디지털 트윈은 복잡한 시스템, 개념 및 아이디어를 쉽게 검증하고 소통할 수 있도록 돕는 '플레이 가능한 시뮬레이션 모델'을 의미한다 [1]. 출시 후 실제 게임에서 발생하는 텔레메트리 데이터(JSON)를 시뮬레이션 모델에 입력하여 현실과 모델 사이의 간극을 좁히는 방식으로 작동한다 [2]. 이를 통해 개발자는 시간의 흐름에 따른 게임 시스템의 동작을 관찰하고 플레이어의 미래 행동을 효과적으로 예측할 수 있다 [1, 2].
|
||||
### 매 3-tier
|
||||
- **Digital Model** — 매 static representation, 매 sync X.
|
||||
- **Digital Shadow** — 매 one-way sync (physical → digital).
|
||||
- **Digital Twin** — 매 bidirectional sync (digital → physical control 의 가능).
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **추출된 패턴:** IoT 센서 데이터의 가상화 매핑 및 실시간 렌더링을 통한 물리-가상 동기화 패턴.
|
||||
- **세부 내용:**
|
||||
- 고해상도 3D 모델링과 실시간 텔레메트리의 결합.
|
||||
- 시뮬레이션을 통한 장애 예측 및 선제적 유지보수 UI.
|
||||
- 데이터 시각화를 넘어선 가상 환경에서의 물리적 조작성 확보.
|
||||
### 매 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.
|
||||
|
||||
* **미래 예측 및 격차 축소**: 디지털 트윈은 라이브 서비스([[LiveOps|LiveOps]]) 환경에서 강력한 예측 도구로 기능한다. 게임 출시 후 실제 플레이어들로부터 수집되는 텔레메트리 데이터를 시뮬레이션 모델에 주입(Data Ingestion)함으로써 현실의 게임플레이와 가상의 수학적 모델 사이의 오차를 줄이고 미래의 경제적 변화와 행동을 예측한다 [2].
|
||||
* **가시성과 동적 분석 제공**: 정적인 스프레드시트나 솔버 기반의 분석과 달리, 디지털 트윈은 버튼 클릭 한 번으로 시간에 따른 게임 시스템의 동작을 모든 세부 수준에서 관찰할 수 있게 해준다 [1].
|
||||
* **개발 효율성 증대 및 리스크 회피**: 게임의 디지털 트윈이 한 번 구축되면, 실제 코드를 작성하거나 새로운 빌드를 배포하지 않고도 즉각적으로 변경 사항을 적용할 수 있다 [1]. 또한, 라이브 서버의 실제 플레이어를 대상으로 경제 실험을 진행하는 위험을 감수할 필요 없이 다양한 '만약의 시나리오(What-if scenarios)'를 안전하게 탐색하고 단 몇 분 만에 귀중한 데이터 인사이트를 도출할 수 있다 [1].
|
||||
## 💻 패턴
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 정적인 3D 모델에서 살아 움직이는 '데이터 기반 생명체'로의 개념 진화.
|
||||
- **정책 변화:** 구조적 연결성(w2) 관점에서 [[3D_Web_HMI|3D_Web_HMI]]와의 기술적 통합 시너지 분석.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Parent:** 10_Wiki/💡 Topics/Graphics
|
||||
- **Related:** [[3D_Web_HMI|3D_Web_HMI]], [[IoT|IoT]], Predictive-Maintenance
|
||||
- **Raw Source:** 00_Raw/2026-04-20/Digital Twin Interfaces.md
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** [[마키네이션(Machinations)|마키네이션(Machinations]], 게임 경제 설계(Game Economy Design), 시뮬레이션(Simulation), [[라이브옵스(Live-ops)|라이브옵스(LiveOps]]
|
||||
- **Projects/Contexts:** [[데이터 기반 수익화 전략 분석 및 가상 경제 시스템 검증 프로젝트|데이터 기반 수익화 전략 분석 및 가상 경제 시스템 검증 프로젝트]]
|
||||
- **Contradictions/Notes:** 소스 내에서 상충되는 정보는 없으나, 정적이고 이상적인 스프레드시트 기반의 접근 방식과 대비하여 디지털 트윈이 동적 시스템을 모니터링하고 리스크 없이 게임 밸런싱을 수행하는 데 훨씬 효율적이라는 점이 지속적으로 강조된다 [1, 2].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-28*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### MQTT → twin update (Python)
|
||||
```python
|
||||
import paho.mqtt.client as mqtt
|
||||
from azure.digitaltwins.core import DigitalTwinsClient
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
dt = DigitalTwinsClient("https://factory.api.weu.digitaltwins.azure.net", credential)
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
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)
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
c = mqtt.Client()
|
||||
c.on_message = on_msg
|
||||
c.connect("mqtt.factory.local", 1883)
|
||||
c.subscribe("factory/+/telemetry")
|
||||
c.loop_forever()
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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')
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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
|
||||
- 부모: [[IoT-Architecture]] · [[Cyber-Physical-Systems]]
|
||||
- 변형: [[Asset-Twin]] · [[Process-Twin]] · [[System-Twin]]
|
||||
- 응용: [[Predictive-Maintenance]] · [[Sim-to-Real]] · [[Smart-City]]
|
||||
- Adjacent: [[OpenUSD]] · [[OPC-UA]] · [[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 |
|
||||
|
||||
@@ -2,125 +2,206 @@
|
||||
id: wiki-2026-0508-discriminated-unions
|
||||
title: Discriminated Unions
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [Tagged Unions, Sum Types, Algebraic Data Types, ADT]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.95
|
||||
verification_status: applied
|
||||
tags: [typescript, types, functional, type-narrowing]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: type-system
|
||||
---
|
||||
|
||||
# [[Discriminated Unions|Discriminated Unions]]
|
||||
# Discriminated Unions
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> Discriminated Unions(또는 식별 가능한 유니온, 태그된 유니온)은 서로 다른 데이터 형태를 구분하기 위해 공통된 리터럴 속성(판별자, Discriminant)을 사용하는 TypeScript의 패턴입니다 [1-3]. 일반적인 유니온 타입과 달리, 컴파일러가 판별자 속성을 확인하여 타입을 자동으로 안전하게 좁힐 수(Narrowing) 있게 해줍니다 [4-6]. 이를 통해 유효하지 않은 상태의 표현을 원천적으로 차단하고, 모든 가능한 경우를 처리하도록 강제하는 완전성 검사(Exhaustiveness checking)를 구현할 수 있습니다 [3, 7, 8].
|
||||
## 매 한 줄
|
||||
> **"매 한 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.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
> "타입의 확실한 이름표: 여러 가능한 데이터 형태 중 '현재 어떤 형태인지'를 명확한 구분자(Tag)로 박제하여, 조건문 안에서 컴파일러가 타입을 완벽하게 추론하게 만들고 런타임 에러의 가능성을 원천 봉쇄하는 견고한 방패."
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **작동 원리 및 특징**
|
||||
Discriminated Union은 객체들이 공통으로 가지는 식별자 필드(주로 `kind`, `type`, `status` 같은 문자열 리터럴)를 활용하여 구성됩니다 [2-4]. 이 공통 속성을 기반으로 TypeScript의 코드 흐름 분석이 진행되며, 특정 브랜치에서 타입을 명확하게 좁혀줍니다 [3, 4, 9]. 이는 런타임 오버헤드가 전혀 추가되지 않는 컴파일 타임 전용 구조입니다 [10].
|
||||
|
||||
* **주요 장점**
|
||||
가장 큰 장점은 올바르지 않은 조합의 상태(Invalid [[State|State]]s)를 코드로 표현할 수 없게 만들어 구조적으로 버그를 방지한다는 것입니다 [1, 7, 11]. 또한 `switch` 문과 `never` 타입을 결합하면 모든 유니온 케이스가 처리되었는지 컴파일러가 확인하는 '완전성 검사(Exhaustive checking)'가 가능합니다 [3, 12-14]. 유니온에 새로운 타입 멤버가 추가되었을 때 이를 누락한 코드를 즉각적인 컴파일 에러로 포착해 내므로 유지보수성이 크게 향상됩니다 [3, 8].
|
||||
|
||||
* **사용 사례 (Use Cases)**
|
||||
API 응답 데이터 처리, 폼(Form) 핸들링, Redux 스타일의 리듀서(Reducer), 라우터 상태 관리, 그리고 상태 머신(State Machine) 패턴을 모델링하는 데 매우 적합합니다 [7, 15-17]. 복잡한 상태를 표현해야 할 때는 다중 판별자(Multiple Discriminants)를 두거나 유니온을 중첩(Nested)하는 방식으로도 활용할 수 있습니다 [15, 16].
|
||||
|
||||
* **주의사항 및 베스트 프랙티스**
|
||||
판별자로는 항상 문자열 리터럴 타입을 사용하는 것이 권장되며, 모든 브랜치에 걸쳐 일관된 판별자 속성을 포함해야 합니다 [12, 16, 18]. 타입을 좁힐 때는 `instanceof` 연산자를 사용하는 대신 반드시 판별자 속성을 확인해야 합니다 [18]. 단, 아주 거대한 코드베이스에서 과도하게 복잡한 유니온 타입을 사용하면 TypeScript의 컴파일 속도가 느려질 수 있으며, 깊게 중첩될 경우 에러 메시지를 파악하기 어려워질 수 있으므로 주의해야 합니다 [10].
|
||||
|
||||
---
|
||||
|
||||
구별된 공용체(Discriminated-Unions, Tagged Unions)는 공통된 문자열 리터럴 속성(Discriminant)을 사용하여 여러 타입 중 하나를 안전하게 선택하는 패턴입니다.
|
||||
|
||||
1. **3대 조건**:
|
||||
* **Union of Types**: 여러 타입이 결합된 합집합 타입.
|
||||
* **Discriminant Property**: 각 타입에 공통으로 존재하는 리터럴 속성 (예: `type: 'success' | 'error'`).
|
||||
* **Type Guarding**: `switch`나 `if` 문을 통해 해당 속성을 검사하면, 블록 내부에서 해당 타입으로만 자동 축소(Narrowing).
|
||||
2. **왜 중요한가?**:
|
||||
* 에러 핸들링 시 `status` 값에 따라 `data`가 있을지 `error`가 있을지 컴파일러가 정확히 알게 하여, 정의되지 않은 속성 접근 정책(Undefined errors)을 막기 때문임. ([[Reliability|Reliability]]와 연결)
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
|
||||
---
|
||||
|
||||
- **과거 데이터와의 충돌**: 과거 자바스크립트 정책은 'duck typing'에 의존하여 런타임에 일일이 `if(data)` 등을 체크해야 했으나, TS 정책은 구별된 공용체 정책을 통해 '컴파일 타임'에 모든 경로 정책을 검증함(RL Update).
|
||||
- **정책 변화(RL Update)**: 이제는 단순 에러 처리를 넘어, 복잡한 상태 머신 정책(FSM)이나 Redux 액션 타입 정책 등을 정의하는 표준 아키텍처 패턴 정책으로 자리 잡음. ([[State-Space|State-Space]]와 연결)
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** [[Union Types|Union Types]], Type Narrowing, Exhaustiveness Checking, Literal Types, never type
|
||||
- **Projects/Contexts:** React State [[Management|Management]], State Machine Pattern, API Response Handling, Redux Reducers
|
||||
- **Contradictions/Notes:** Discriminated Union 패턴은 타입 안정성과 예측 가능성을 크게 높여주지만, 유니온 타입이 지나치게 복잡해지거나 깊은 중첩 구조를 가지게 되면 오히려 TypeScript의 컴파일 성능을 저하시키고 에러 메시지의 가독성을 떨어뜨리는 부작용(단점)을 유발할 수 있습니다 [10].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-18*
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- [[Reliability|Reliability]], [[State-Space|State-Space]], [[Technical-Architecture|Technical-Architecture]], [[Logic|Logic]], [[Complexity-Theory|Complexity-Theory]]
|
||||
- **Key Concept**: Algebraic Data Types (ADT).
|
||||
---
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 매 anatomy
|
||||
```typescript
|
||||
type Result<T, E> =
|
||||
| { kind: "ok"; value: T }
|
||||
| { kind: "err"; error: E };
|
||||
// ^^^^^^^^^^^ 매 discriminant — 매 string / number / boolean literal.
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 매 narrowing rules
|
||||
- 매 discriminant 의 literal 의 must.
|
||||
- 매 `switch` / `if` 매 변수 의 narrow.
|
||||
- 매 exhaustive check 의 `never` 의 leverage.
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 매 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.
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 매 응용
|
||||
1. Result / Option / Either monads.
|
||||
2. State machine state.
|
||||
3. Redux / xstate action / event.
|
||||
4. API response variants.
|
||||
5. AST node types.
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
## 💻 패턴
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### Pattern 1: Result / Either
|
||||
```typescript
|
||||
type Result<T, E = Error> =
|
||||
| { ok: true; value: T }
|
||||
| { ok: false; error: E };
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
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]] · [[Rust Enums]] · [[F# DU]]
|
||||
- 응용: [[Result Type]] · [[State Machine]] · [[Redux Actions]] · [[Zod]]
|
||||
- Adjacent: [[Pattern Matching]] · [[Exhaustiveness Checking]] · [[ts-pattern]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -2,120 +2,190 @@
|
||||
id: wiki-2026-0508-distributed-systems-fallacies
|
||||
title: Distributed Systems Fallacies
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-3031BBF7]
|
||||
aliases: [Fallacies of Distributed Computing, 8 Fallacies, Deutsch Fallacies]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [distributed-systems-fallacies, event-driven-architecture, microservices-architecture, peer-to-peer-(p2p)-architecture, event-driven-architecture, architecture-principles]
|
||||
verification_status: applied
|
||||
tags: [distributed-systems, architecture, networking, reliability]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-02
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: polyglot
|
||||
framework: distributed-systems
|
||||
---
|
||||
|
||||
# [[Distributed Systems Fallacies]]
|
||||
# Distributed Systems Fallacies
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
분산 컴퓨팅의 오류(Distributed Systems Fallacies)는 **소프트웨어 개발 및 배포에 있어 심각한 문제를 야기할 수 있는 일련의 오해나 잘못된 가정들**을 의미합니다 [1]. 제공된 소스에 따르면, 이벤트 기반 아키텍처(Event-Driven Architecture)와 같은 분산 시스템 패턴이 특히 이러한 분산 컴퓨팅의 오류에 취약한 것으로 나타납니다 [1]. (추가적인 상세 정의에 대해서는 소스에 관련 정보가 부족합니다.)
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
**소스에 관련 정보가 부족합니다.**
|
||||
## 매 핵심
|
||||
|
||||
(제공된 소스에서는 이벤트 기반 아키텍처가 "분산 컴퓨팅의 오류(fallacies of distributed computing)"에 취약하며, 이것이 소프트웨어 개발과 배포에 중대한 문제를 일으킬 수 있는 오해들이라는 단일 문장의 사실만 간략히 언급되어 있습니다 [1]. 구체적으로 어떤 오류들이 존재하는지, 원리는 무엇인지에 대한 상세한 설명은 포함되어 있지 않습니다.)
|
||||
### 매 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.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
**소스에 관련 정보가 부족합니다.**
|
||||
### 매 왜 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.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
분산 컴퓨팅의 오류에 대한 직접적인 세부 정보는 부족하지만, 소스에 명시된 내용과 분산 시스템 구조의 특성을 바탕으로 연결되는 개념은 다음과 같습니다.
|
||||
### 매 응용
|
||||
1. Microservices design — 매 call graph 의 latency budget 산정.
|
||||
2. Cross-region replication — 매 split-brain / eventual consistency 의 plan.
|
||||
3. Edge computing — 매 intermittent connectivity 의 first-class.
|
||||
|
||||
#### [아키텍처/기반 기술]
|
||||
- [[Event-Driven Architecture]]
|
||||
- 연결 이유: 소스에서 **이벤트 기반 아키텍처가 분산 컴퓨팅의 오류에 직접적으로 취약하다**고 명시하고 있기 때문입니다 [1].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 분산된 컴포넌트 간에 비동기적으로 이벤트를 전달할 때, 시스템 인프라나 네트워크 통신에 대한 잘못된 가정이 데이터 손실, 순서 뒤섞임, 에러 핸들링의 어려움 등 어떤 치명적 문제로 이어지는지 파악할 수 있습니다 [1-3].
|
||||
## 💻 패턴
|
||||
|
||||
- [[Microservices Architecture]]
|
||||
- 연결 이유: 마이크로서비스 역시 여러 서비스가 네트워크를 통해 통신(Interprocess communication)하는 분산 시스템 모델이므로, 분산 컴퓨팅의 복잡성과 한계에 직면하기 때문입니다 [4].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 분산 환경에서의 네트워크 혼잡, 데이터 일관성(Data Consistency) 유지, 디버깅의 어려움 등 분산 컴퓨팅 환경이 갖는 현실적인 제약과 위험성을 배울 수 있습니다 [4, 5].
|
||||
|
||||
- [[Peer-to-Peer (P2P) Architecture]]
|
||||
- 연결 이유: 중앙 서버 없이 각 노드가 클라이언트이자 서버 역할을 동시에 수행하는 완전한 분산 네트워크 모델이기 때문입니다 [6].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 분산 시스템에서 중앙 통제 없이 데이터 일관성을 확보하고 보안을 유지하는 것이 얼마나 복잡한지 등 분산 컴퓨팅의 설계적 난제를 이해할 수 있습니다 [7].
|
||||
|
||||
### Deeper Research Questions
|
||||
- 분산 컴퓨팅의 오류(Fallacies of Distributed Computing)를 구성하는 구체적인 오해(Misconceptions)들은 무엇이며, 이들이 소프트웨어 배포 시 유발하는 치명적인 문제는 각각 무엇인가?
|
||||
- 이벤트 기반 아키텍처(EDA)를 설계할 때, 분산 컴퓨팅의 오류를 방지하거나 완화하기 위해 어떤 네트워크 통신 기준이나 에러 핸들링 기법을 적용해야 하는가?
|
||||
- 마이크로서비스 아키텍처의 서비스 간 통신(Interprocess communication) 환경에서 분산 컴퓨팅 오류가 데이터 일관성에 미치는 영향은 무엇인가?
|
||||
- 분산 시스템에서 발생할 수 있는 데이터 손실 오류를 막기 위해 언급된 '클라이언트 승인 모드(Client acknowledge mode)'와 '최종 참여자 지원(Last participant support)'의 상세 작동 원리는 무엇인가?
|
||||
- 초기 아키텍처 설계 단계에서 분산 네트워크의 신뢰성이나 대기 시간(Latency)에 대한 오해를 바로잡기 위해 아키텍트가 취해야 할 설계 프로세스는 무엇인가?
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 소스에 관련 정보가 부족합니다.
|
||||
- **System Design:** 분산 시스템(특히 이벤트 기반 아키텍처)을 설계할 때, **네트워크나 분산 인프라 환경에 대한 막연한 오해를 배제**하고 잠재적이고 치명적인 개발/배포 실패를 방지하는 설계 기준으로 활용됩니다 [1].
|
||||
- **Operation / Maintenance:** 소스에 관련 정보가 부족합니다.
|
||||
- **Learning Path:** 소스에 관련 정보가 부족합니다.
|
||||
- **My Project Relevance:** 소스에 관련 정보가 부족합니다.
|
||||
|
||||
### Adjacent Topics
|
||||
- [[Event-Driven Architecture]]
|
||||
- 확장 방향: 분산 컴퓨팅의 오류에 취약한 시스템이 직면하는 한계를 이해하고, 이를 극복하기 위한 데드 레터 큐(DLQ), 오류 처리 프로세서 등 구체적 회복 탄력성(Resiliency) 설계 전략으로 확장.
|
||||
- [[Microservices Architecture]]
|
||||
- 확장 방향: 분산된 컴포넌트 간의 상호작용에서 발생하는 네트워크 복잡성과 분산 트랜잭션 오류(Fallacies)가 미치는 운영상 한계 및 보완책 연구.
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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");
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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) {}
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
async function getUser(id: string) {
|
||||
return dbLimit(() => db.users.findOne({ id }));
|
||||
}
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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;
|
||||
}
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]]
|
||||
- 응용: [[Microservices Architecture]] · [[Service Mesh]]
|
||||
- Adjacent: [[Resilience Patterns]] · [[Chaos Engineering]] · [[Circuit Breaker Pattern]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -2,124 +2,207 @@
|
||||
id: wiki-2026-0508-distributed-tracing
|
||||
title: Distributed Tracing
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-8AEC7FF0]
|
||||
aliases: [distributed-tracing, opentelemetry-tracing, request-tracing]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [distributed-tracing, microservices-architecture, serverless-architecture, event-driven-architecture, observability, devops-environment]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [observability, tracing, opentelemetry, jaeger]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-02
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: opentelemetry/tempo
|
||||
---
|
||||
|
||||
# [[Distributed Tracing]]
|
||||
# Distributed Tracing
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
분산 추적(Distributed Tracing)은 마이크로서비스, 서버리스, 사이드카, 이벤트 기반 아키텍처와 같은 분산 시스템에서 여러 컴포넌트나 서비스를 거쳐 전파되는 요청과 트랜잭션의 흐름을 모니터링, 추적 및 디버깅하기 위한 핵심 관측성(Observability) 패턴입니다 [1-4]. 이 패턴은 공유된 호출 콜스택(Call context)이 없는 탈동조화된 환경에서 특정 오류의 근본 원인이나 성능 병목 지점을 명확히 파악할 수 있도록 돕습니다 [5, 6].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **분산 시스템의 디버깅 한계 극복**: 마이크로서비스, 서버리스, 이벤트 기반 아키텍처 등에서는 단일 비즈니스 트랜잭션이 여러 독립적인 생산자(Producers)와 소비자(Consumers) 또는 수많은 함수 파편들로 나뉘어 비동기적으로 실행됩니다 [4, 5]. 컴포넌트 간 호출 컨텍스트가 공유되지 않기 때문에 기존의 로컬 디버깅 방식으로는 에러나 예기치 않은 동작의 원인을 찾기 매우 어렵습니다 [4, 5]. 예를 들어 50개 이상의 서비스나 여러 사이드카(Sidecar) 간에 얽힌 요청 흐름을 쫓기 위해서는 분산 추적이 필수적으로 요구됩니다 [1, 2].
|
||||
- **관측성(Observability) 확보의 수단**: 분산 추적은 로그 집계(Log aggregation), 애플리케이션 메트릭, 헬스 체크 API 등과 함께 분산 환경의 가시성을 확보하는 핵심 관측성 패턴 중 하나입니다 [3]. 시스템이 주로 API 중심으로 구동되는 점을 활용해 API 호출을 추적함으로써 성능 문제를 식별하고, 문제가 발생한 트랜잭션 내에서 특정 마이크로서비스가 수행한 역할을 정확히 파악할 수 있습니다 [6].
|
||||
- **상관관계 ID(Correlation ID) 활용**: 분산 추적을 구현하기 위해서는 시스템 내의 모든 이벤트 및 API 페이로드에 '상관관계 ID(Correlation ID)'를 포함하여 전달해야 합니다 [5]. 이를 통해 다운스트림(Downstream) 소비자와 로깅 시스템이 서로 개별적으로 실행된 연관 작업들을 단일 추적 경로(Trace)로 연결할 수 있습니다 [5].
|
||||
- **초기 설계의 중요성**: 이미 컴포넌트가 분리되어 운영 중인 분산 시스템에 관측성을 사후에 끼워 넣는(Retrofitting) 작업은 구조적으로 매우 어렵습니다 [5]. 따라서 분산 추적을 위한 계측(Instrumentation)은 시스템 설계 초기 단계부터 반드시 계획되어야 합니다 [5].
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
분산 추적을 시스템에 도입하고 유지하는 것은 추가적인 인지적 부하(Cognitive load)와 인프라 오버헤드를 발생시킵니다 [4]. 이를 효과적으로 관리하려면 강력한 관측성 도구와 에러 모니터링 플랫폼을 별도로 구축하고 운영해야 합니다 [4].
|
||||
또한, 시스템의 모든 구성 요소가 연결성을 잃지 않도록 '상관관계 ID(Correlation ID)'를 지속적으로 전달해야 하므로 각 서비스 개발 시 추가적인 계측(Instrumentation) 노력이 요구됩니다 [5]. 만약 이러한 추적 기능과 가시성을 시스템 설계 초기부터 반영하지 않고 개발 후반부에 사후 도입(Retrofitting)하려고 시도할 경우, 그 복잡성과 어려움은 기하급수적으로 증가합니다 [5].
|
||||
### 매 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).
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
### 매 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.
|
||||
|
||||
#### [분산 아키텍처 패턴 (Distributed Architecture Patterns)]
|
||||
- [[Microservices Architecture]]
|
||||
- 연결 이유: 대규모 마이크로서비스 아키텍처에서는 50개 이상의 서비스가 얽혀 통신하므로, 디버깅을 위해 분산 추적이 필수적으로 요구됩니다 [1].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 독립적인 데이터베이스와 서비스를 가진 환경에서 분산된 요청을 추적하는 근본적인 이유와 복잡성을 이해할 수 있습니다 [3].
|
||||
- [[Serverless Architecture]]
|
||||
- 연결 이유: 서버리스 환경은 비즈니스 로직이 다수의 독립된 함수로 파편화되므로 에러를 추적하기 위해 분산 추적 도구가 필요합니다 [4].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 비동기적으로 트리거되는 일회성 함수들 사이에서 요청의 흐름을 파악하는 과제를 이해할 수 있습니다 [4].
|
||||
- [[Event-Driven Architecture]]
|
||||
- 연결 이유: 이벤트 기반 아키텍처는 생산자와 소비자가 완전히 분리되어 비동기적으로 동작하므로 상관관계 ID를 포함한 이벤트 추적이 필수적입니다 [5].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 직접적인 API 호출이 아닌 메시지와 이벤트 채널을 통해 상태가 전달될 때 분산 추적이 어떻게 단일 트랜잭션을 재구성하는지 파악할 수 있습니다 [5].
|
||||
### 매 응용
|
||||
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).
|
||||
|
||||
#### [운영 및 가시성 패턴 (Operational / Visibility Patterns)]
|
||||
- [[Observability]]
|
||||
- 연결 이유: 분산 추적은 마이크로서비스 및 탈동조화된 시스템에서 시스템 상태를 파악하기 위한 전체 관측성 패턴의 하위 요소입니다 [3].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 분산 추적, 메트릭, 로그 집계가 결합되어 어떻게 블랙박스 같은 분산 시스템의 내부 상태를 투명하게 만드는지 이해할 수 있습니다 [3, 5, 6].
|
||||
## 💻 패턴
|
||||
|
||||
### Deeper Research Questions
|
||||
- 이벤트 기반 아키텍처(Event-Driven Architecture)에서 분산 추적을 구현하기 위해 시스템 전반에 상관관계 ID(Correlation ID)를 누락 없이 전달하는 가장 효과적인 기술적 접근법은 무엇인가?
|
||||
- 마이크로서비스 아키텍처에 분산 추적과 같은 관측성(Observability) 도구를 도입할 때 발생하는 인프라 오버헤드와 네트워크 지연을 어떻게 최소화할 수 있는가?
|
||||
- 사이드카 패턴(Sidecar Pattern)을 활용할 때, 메인 애플리케이션의 코어 로직 수정 없이 사이드카 계층에서 분산 추적(Distributed tracing)을 대행 처리하는 설계 원리는 무엇인가?
|
||||
- 분산 시스템에서 발생하는 에러 처리(Error handling) 로직과 분산 추적 시스템은 어떻게 상호작용하여 관리자에게 근본 원인(Root cause)을 보고하는가?
|
||||
- 사후 도입(Retrofitting)이 어려운 분산 추적 기능을 시스템 설계의 초기 단계부터 내재화(Built-in)하기 위해 아키텍트가 고려해야 할 필수 체크리스트는 무엇인가?
|
||||
### 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';
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 비즈니스 트랜잭션이 시작되는 최초 지점에서 고유한 상관관계 ID(Correlation ID)를 생성하고, 모든 다운스트림 컴포넌트(API, 이벤트 메시지 등)에 이를 전달하도록 코드 레벨의 계측(Instrumentation)을 구현해야 합니다 [5].
|
||||
- **System Design:** 마이크로서비스, 서버리스, 사이드카 패턴 등 분산 아키텍처를 채택할 때, 설계 초기부터 필수 관측성 패턴(Observability Pattern)으로 분산 추적을 아키텍처에 포함시켜야 통제 불능 상태를 막을 수 있습니다 [1, 2, 5].
|
||||
- **Operation / Maintenance:** 운영 중인 분산 애플리케이션에서 성능 저하나 오류가 발생했을 때, 추적 ID를 기반으로 어떤 특정 서비스나 함수에서 병목 또는 예외가 발생했는지 시각적으로 파악하여 신속한 문제 해결(Troubleshooting)을 수행합니다 [4, 6].
|
||||
- **Learning Path:** 단일 모놀리식 애플리케이션의 로컬 디버깅 경험에서 출발하여, 분산 시스템의 디버깅 한계를 인지한 후, 관측성(Observability)의 3요소(추적, 로깅, 메트릭)를 학습하고 최종적으로 분산 추적 기술을 실제 아키텍처에 적용하는 과정으로 연결됩니다.
|
||||
- **My Project Relevance:** 소스에 관련 정보가 부족합니다. (현재 질문 및 제공된 소스 데이터에는 사용자의 구체적인 프로젝트나 환경 맥락이 명시되어 있지 않습니다.)
|
||||
|
||||
### Adjacent Topics
|
||||
- [[Log Aggregation]]
|
||||
- 확장 방향: 분산 추적 데이터를 기반으로 각 서비스에 흩어진 로그들을 중앙에서 수집하고 분석하여 전체적인 가시성을 완성하는 방법론으로 확장 [3].
|
||||
- [[Sidecar Architecture Pattern]]
|
||||
- 확장 방향: 마이크로서비스 통신 사이에서 분산 추적 정보 생성 및 전달(텔레메트리 데이터 수집 등)을 돕는 메커니즘을 제공하는 서비스 메시(Service Mesh) 및 사이드카 패턴의 역할 조사 [2, 7].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
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();
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Manual span (TypeScript)
|
||||
```ts
|
||||
import { trace, SpanStatusCode } from '@opentelemetry/api';
|
||||
const tracer = trace.getTracer('orders');
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
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();
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
provider = TracerProvider()
|
||||
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter(endpoint="otel-collector:4317")))
|
||||
trace.set_tracer_provider(provider)
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
app = FastAPI()
|
||||
FastAPIInstrumentor.instrument_app(app)
|
||||
HTTPXClientInstrumentor().instrument()
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]]
|
||||
- 변형: [[Jaeger]] · [[Tempo]] · [[Honeycomb]] · [[Zipkin]]
|
||||
- 응용: [[SLO-Engineering]] · [[Performance-Debugging]] · [[Service-Mesh]]
|
||||
- Adjacent: [[OpenTelemetry]] · [[Logs]] · [[Metrics]] · [[Profiles]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -2,91 +2,211 @@
|
||||
id: wiki-2026-0508-distributed-system-type-safety
|
||||
title: Distributed System Type Safety
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-Reinforce-AUTO-DSTS-001]
|
||||
aliases: [cross-service-types, contract-types, schema-driven-types]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.94
|
||||
tags: [auto-reinforced, Distributed-Systems, type-safety, contract, Architecture, Reliability, api-design]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [distributed-systems, type-safety, contracts, codegen]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-04-20
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: gRPC/OpenAPI/tRPC
|
||||
---
|
||||
|
||||
# [[Distributed-System-Type-Safety|Distributed-System-Type-Safety]]
|
||||
# Distributed System Type Safety
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> "국경을 넘는 지능의 약속: 수많은 서버와 서비스가 얽힌 분산 환경에서, 데이터가 네트워크를 타고 이동하더라도 처음의 약속(Type)이 깨지지 않았음을 기술적으로 보장하여 전체 시스템의 '논적적 정합성'을 유지하는 기술."
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
분산 시스템 타입 안전성(Distributed-System-Type-Safety)은 서로 다른 네트워크 노드 간에 주고받는 데이터가 사전에 정의된 데이터 구조(Type)를 엄격히 준수함을 보장하는 것입니다.
|
||||
## 매 핵심
|
||||
|
||||
1. **구현 전략**:
|
||||
* **Shared Contracts**: IDL(Interface Definition Language)을 사용하여 서비스 간 규약을 정의 (gRPC, GraphQL, Protobuf). ([[Schema|Schema]]와 연결)
|
||||
* **Automatic Code Generation**: 중앙의 스키마 파일을 읽어 각 언어(JS, Go, Java 등)의 타입 코드를 자동 생성. ([[Efficiency|Efficiency]]와 연결)
|
||||
* **Runtime Validation**: 데이터가 서버에 도착하자마자 실제 타입과 일치하는지 Zod 등을 통해 검층.
|
||||
2. **왜 중요한가?**:
|
||||
* 분산 환경에서는 한쪽 서비스의 타입 변경이 수천 개의 연결된 서비스를 '침묵의 에러(Silent failure)'로 빠뜨릴 수 있기 때문임.
|
||||
### 매 problem
|
||||
- 매 service A 의 type 변경 → 매 service B 가 silently break.
|
||||
- 매 JSON 의 매 stringly-typed wire — 매 runtime error.
|
||||
- 매 versioning 가 매 hard.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌**: 과거에는 단순 문자열(JSON) 통신 정책에 의존하여 런타임 에러 정책이 잦았으나, 현대 정책은 'End-to-End Type Safety 정책'을 통해 클라이언트부터 백엔드까지 연결된 타입 체인 정책을 형성함(RL Update). (Reliability와 연결)
|
||||
- **정책 변화(RL Update)**: 이제는 단순 데이터 타입 정책을 넘어, 버전 관리 정책(Versioning)과 하위 호환성 정책(Compatibility)을 타입 시스템 정책 내에서 자동으로 추적하는 스마트 계약형 인프라 정책으로 진화 중임.
|
||||
### 매 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.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- [[Schema|Schema]], [[Efficiency|Efficiency]], [[Reliability|Reliability]], [[Technical-Architecture|Technical-Architecture]], Standard-Operating-Procedure
|
||||
- **Key Tools**: gRPC, tRPC, GraphQL, Zod, Protocol Buffers.
|
||||
---
|
||||
### 매 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).
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
## 💻 패턴
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
### Buf + Protobuf workflow
|
||||
```bash
|
||||
# buf.yaml
|
||||
version: v2
|
||||
modules: [{ path: proto }]
|
||||
breaking: { use: [FILE] }
|
||||
lint: { use: [STANDARD] }
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
# CI 의 breaking-change check
|
||||
buf breaking --against '.git#branch=main'
|
||||
buf generate
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
```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);
|
||||
}
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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.
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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;
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
// 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' });
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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' } } });
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]] · [[GraphQL]] · [[tRPC]] · [[OpenAPI]]
|
||||
- 응용: [[Microservices]] · [[Event-Driven-Architecture]] · [[BFF-Pattern]]
|
||||
- Adjacent: [[Schema-Registry]] · [[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 |
|
||||
|
||||
@@ -2,157 +2,32 @@
|
||||
id: wiki-2026-0508-distributed-computing
|
||||
title: Distributed Computing
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
canonical_id: self
|
||||
status: duplicate
|
||||
canonical_id: distributed-systems
|
||||
duplicate_of: "[[Distributed-Systems]]"
|
||||
aliases: []
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, distributed-systems]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
---
|
||||
|
||||
# [[Distributed Computing]]
|
||||
# Distributed Computing
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
소프트웨어 아키텍처는 크게 모놀리식(Monolithic) 아키텍처와 분산 아키텍처(Distributed Architecture) 두 가지 주요 유형으로 분류된다 [1]. 분산 컴퓨팅 패턴은 데이터 처리와 저장, 그리고 애플리케이션의 워크로드를 여러 대의 서버나 노드로 분할하여 처리하는 구조를 말한다 [2], [3]. 공간 기반 아키텍처(Space-based Architecture), 마이크로서비스, 클라이언트-서버, P2P, 브로커 패턴 등 다양한 아키텍처 패턴이 이러한 분산 컴퓨팅의 원리를 기반으로 설계되어 대규모 트래픽, 동시성 및 확장성 문제를 해결하는 데 사용된다 [2], [4], [5], [6], [7].
|
||||
> **이 문서는 [[Distributed-Systems]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
---
|
||||
## 핵심 요약 (specialization aspects)
|
||||
- "Distributed Computing" 매 historical term — 매 grid/HPC computing 의 emphasis.
|
||||
- "Distributed Systems" 매 broader term — 매 networked services, consensus, replication 의 cover.
|
||||
- 매 modern usage 의 두 terms 매 interchangeable, 매 canonical 의 Distributed-Systems.
|
||||
|
||||
> "한 대의 거대한 컴퓨터 대신, 수만 대의 작은 컴퓨터가 하나의 목표를 위해 협력하게 하라" — 네트워크로 연결된 여러 대의 컴퓨터 자원을 활용하여, 단일 시스템으로는 처리 불가능한 대규모 연산이나 데이터를 병렬적으로 처리하는 기술 체계.
|
||||
## 🔗 Graph
|
||||
- 부모: [[Distributed-Systems]] (canonical)
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **분산 컴퓨팅 기반의 주요 아키텍처 패턴**
|
||||
* **공간 기반 아키텍처 (Space-Based Architecture):** 클라우드 기반 또는 튜플 공간 아키텍처라고도 불리며, 여러 인스턴스에 애플리케이션 워크로드를 분산시켜 높은 트래픽과 확장성 문제를 해결하는 분산 컴퓨팅 패턴이다 [2]. 중앙 데이터베이스 병목 현상을 피하기 위해 여러 서버의 RAM에 데이터를 저장하는 인메모리 데이터 그리드(IMDG)를 활용하여 노드 간 데이터를 효율적으로 공유한다 [8].
|
||||
* **클라이언트-서버 및 피어-투-피어 (P2P):** 클라이언트-서버 패턴은 자원과 데이터 관리를 중앙 서버가 담당하고 여러 클라이언트가 네트워크를 통해 이에 분산 접속하는 구조다 [5], [9]. 반면, 탈중앙화된 피어-투-피어(P2P) 아키텍처는 모든 노드(피어)가 동등한 권한을 갖고 클라이언트와 서버 역할을 동시에 수행하며, 중앙 서버 없이 서로 직접 자원을 공유하는 분산 네트워크 모델이다 [10], [7].
|
||||
* **마이크로서비스 아키텍처 (Microservices Architecture):** 거대한 단일 애플리케이션을 작고 독립적으로 배포 가능한 개별 서비스들의 집합으로 분할하는 패턴이다 [4], [11]. 각 서비스는 분산된 환경에서 자체 프로세스를 실행하며 API와 같은 가벼운 메커니즘을 통해 상호 통신한다 [12], [11].
|
||||
* **브로커 및 마스터-슬레이브 패턴:** 브로커(Broker) 아키텍처는 분산 시스템 내에서 분리된 컴포넌트 간의 통신과 조정을 중앙 브로커가 관리하여 유연성을 높인다 [13], [6]. 마스터-슬레이브(Master-Slave) 아키텍처는 분산 컴퓨팅 환경에서 마스터 컴포넌트가 여러 슬레이브 컴포넌트에 작업을 분배하고 병렬 처리 및 부하 분산을 수행하도록 돕는 패턴이다 [14], [15].
|
||||
|
||||
---
|
||||
|
||||
- **추출된 패턴:** 거대한 문제를 작은 조각으로 나누어 분산된 노드에 할당하고, 각 노드의 결과물을 다시 통합(Aggregation)하여 최종 해답을 도출하는 분할 정복(Divide and Conquer) 패턴.
|
||||
- **핵심 요소:**
|
||||
- **Parallelism:** 데이터 병렬화(Data Parallel) 및 모델 병렬화(Model Parallel)를 통한 학습 속도 향상.
|
||||
- **Concurrency Control:** 여러 노드가 동시에 데이터에 접근할 때 정합성 유지.
|
||||
- **Fault Tolerance:** 일부 노드에 장애가 생겨도 전체 시스템이 중단되지 않도록 설계 (CAP 정리 참고).
|
||||
- **Communication Overhead:** 노드 간 데이터를 주고받는 통신 비용을 최소화하는 것이 성능의 핵심.
|
||||
- **주요 프레임워크:** Apache Spark, Ray, Horovod, Kubernetes.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
* **강력한 확장성과 고가용성 (장점):** 분산 컴퓨팅을 활용하는 아키텍처는 수요에 따라 독립적인 서비스나 노드를 수평적으로 추가하여 유기적인 확장이 가능하다 [2], [16], [17]. 또한, 분산된 노드들이 작업을 나누어 처리하므로 단일 장애점(SPOF)을 제거하거나 최소화하여 시스템의 내결함성(Fault Tolerance)과 회복 탄력성을 극대화할 수 있다 [10], [6].
|
||||
* **복잡한 분산 운영 및 디버깅 (단점):** 분산 시스템을 설계, 구현, 관리하는 것은 단일(Monolithic) 시스템보다 기하급수적으로 복잡하다 [18], [17]. 독립적인 서비스들 간의 복잡한 상호작용으로 인해 분산 작업의 흐름을 이해하고 문제를 추적, 디버깅하는 것이 매우 어렵다 [19], [20], [21].
|
||||
* **네트워크 지연과 데이터 일관성 한계 (단점):** 분산된 컴포넌트 및 서비스 간의 통신은 네트워크를 경유해야 하므로 네트워크 지연(Latency)과 데이터 전송 오버헤드가 발생한다 [20], [22], [17]. 또한 각 서비스나 노드가 자체 데이터를 가질 경우, 강한 일관성(ACID)을 유지하기 어려우며 최종 일관성(Eventual Consistency) 모델이나 Saga 패턴 같은 복잡한 트랜잭션 관리를 도입해야 하는 제약이 따른다 [23], [21], [24].
|
||||
* **분산 컴퓨팅의 오류 위험:** 이벤트 기반 설계 등 분산 컴퓨팅의 원리를 따르는 아키텍처는 네트워크가 항상 신뢰할 수 있다고 가정하는 등의 '분산 컴퓨팅의 오류(Fallacies of distributed computing)'에 취약하며, 이러한 잘못된 가정은 소프트웨어 구현 및 배포 시 심각한 문제를 초래할 수 있다 [25].
|
||||
|
||||
---
|
||||
|
||||
- **과거 데이터와의 충돌:** 단순한 서버-클라이언트 구조에서, 수만 개의 GPU가 긴밀하게 동기화되어 거대 언어 모델을 학습시키는 초거대 분산 컴퓨팅 시대로 진화.
|
||||
- **정책 변화:** Antigravity 프로젝트는 향후 수조 개의 지식 노드를 처리하기 위해 Ray와 같은 최신 분산 프레임워크를 기반으로 지식 가드닝 에이전트의 연산 인프라를 확장할 계획임.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
|
||||
#### [분산 시스템 아키텍처 패턴]
|
||||
* [[Space-based Architecture Pattern]]
|
||||
* 연결 이유: 고부하 분산 처리를 위해 중앙 데이터베이스를 배제하고 메모리 공간을 공유하는 가장 대표적인 분산 컴퓨팅 패턴이기 때문이다 [2], [26].
|
||||
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: 분산 시스템에서 데이터베이스 병목을 회피하기 위한 인메모리 데이터 그리드(IMDG)의 원리와 높은 트래픽 환경에서의 수평적 확장 방법 [8], [27].
|
||||
* [[Peer-to-Peer Architecture Pattern]]
|
||||
* 연결 이유: 클라이언트-서버와 대비되는 극단적인 분산 네트워크 형태로, 모든 노드가 서버이자 클라이언트 역할을 분담하기 때문이다 [10], [28].
|
||||
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: 중앙 통제 없이 네트워크의 참여자가 늘어날수록 컴퓨팅 자원과 확장성이 증가하는 유기적 확장성과 탈중앙화 시스템의 결함 허용성 [10], [29].
|
||||
* [[Microservices Architecture Pattern]]
|
||||
* 연결 이유: 현대 소프트웨어 생태계에서 분산 컴퓨팅 패러다임을 비즈니스 애플리케이션 구조로 가장 흔히 구체화한 아키텍처 패턴이기 때문이다 [4], [11].
|
||||
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: 분산된 개별 서비스들이 어떻게 독립적인 배포 파이프라인을 가지고 동작하며, 분산 트랜잭션(Saga 등)이나 분산 쿼리를 어떻게 조율하는지에 대한 실무적 해결책 [4], [24].
|
||||
|
||||
#### [분산 환경의 통신 및 제어 구조]
|
||||
* [[Broker Architecture Pattern]]
|
||||
* 연결 이유: 분리된 컴포넌트 간의 분산된 요청과 메시징을 연결하고 라우팅해 주는 중앙 조정 역할을 수행하기 때문이다 [13], [6].
|
||||
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: 마이크로서비스 또는 이벤트 기반 분산 시스템에서 결합도를 낮추고 비동기 메시지 기반의 통신을 가능하게 하는 네트워크 미들웨어의 작동 원리 [30], [6].
|
||||
* [[Master-Slave Architecture Pattern]]
|
||||
* 연결 이유: 분산 컴퓨팅 시스템에서 워크로드 분산과 병렬 처리, 데이터 복제를 구현할 때 널리 쓰이는 기본 아키텍처이기 때문이다 [31], [15].
|
||||
* 이 개념을 통해 더 깊게 이해할 수 있는 부분: 중앙 조정자(마스터)를 통해 하위 노드(슬레이브)에 작업을 동시 할당함으로써 성능과 신뢰성을 향상시키는 방법 [31], [32].
|
||||
|
||||
### Deeper Research Questions
|
||||
|
||||
* 마이크로서비스나 공간 기반 아키텍처 같은 분산 컴퓨팅 환경에서 데이터 무결성을 유지하기 위해 ACID 트랜잭션 대신 활용되는 최종 일관성(Eventual Consistency)과 Saga 패턴의 구체적인 작동 원리와 그 한계는 무엇인가? [21], [24]
|
||||
* 분산 환경 내의 독립적인 서비스들 간 통신을 위해 적용되는 브로커(Broker)와 메디에이터(Mediator) 토폴로지는 시스템의 결합도와 성능 최적화에 어떠한 트레이드오프를 발생시키는가? [33], [34]
|
||||
* 이벤트 기반 아키텍처를 도입할 때 마주하게 되는 '분산 컴퓨팅의 오류(Fallacies of Distributed Computing)'는 소프트웨어 엔지니어링 과정에서 어떠한 설계적 부채나 장애로 이어질 수 있는가? [25]
|
||||
* P2P(Peer-to-Peer) 분산 네트워크 아키텍처는 클라이언트-서버 모델이 가지는 갑작스러운 부하(High Load) 문제를 어떤 유기적인 자원 공유 메커니즘을 통해 해결하는가? [35], [36]
|
||||
* 네트워크 지연과 서비스 간의 통신 복잡성이 존재하는 분산 마이크로서비스 아키텍처에서, 분산 트레이싱(Distributed Tracing) 및 시스템 가시성(Observability)을 확보하기 위한 최적의 방안은 무엇인가? [37], [38]
|
||||
|
||||
### Practical Application Contexts
|
||||
|
||||
* **Implementation:** 애플리케이션을 구현할 때, 단일 코드베이스가 아닌 네트워크를 통해 통신하는 여러 개의 모듈이나 서비스로 작업을 분할하고 비동기 메시징 및 원격 프로시저 호출(RPC)을 적용하여 분산 환경을 구축한다 [4], [13].
|
||||
* **System Design:** 시스템 디자인 시 폭발적인 사용자 트래픽이나 높은 데이터 처리량이 예상될 때, 모놀리식 구조의 한계를 벗어나고자 마이크로서비스, P2P, 또는 공간 기반 아키텍처와 같은 분산 컴퓨팅 패턴을 전략적으로 채택해야 한다 [2], [39].
|
||||
* **Operation / Maintenance:** 개별 분산 컴포넌트의 유연한 확장은 가능하지만, 수많은 노드나 서비스 간 통신 장애 시 디버깅이 어렵기 때문에 중앙 집중형 로깅, 분산 추적, 그리고 서비스 메쉬(Service Mesh) 등 고도화된 운영/모니터링 체계가 필수적이다 [37], [40].
|
||||
* **Learning Path:** 소프트웨어 아키텍처 학습에 있어서, 초기의 단일(Monolithic) 또는 계층형 아키텍처를 이해한 뒤, 이들이 분산 시스템으로 분리되면서 겪는 상태 관리, 통신 패턴, 그리고 데이터 일관성의 난제들을 학습하는 심화 과정으로 이어진다 [24], [1].
|
||||
* **My Project Relevance:** '아키텍처 패턴 지식'을 탐구함에 있어, 시스템의 확장성 및 대규모 동시성 처리를 위해 분산 컴퓨팅 개념이 적용된 아키텍처(EDA, MSA, Space-based 등)가 어떻게 시스템 설계의 트레이드오프(성능 vs 복잡도)를 결정하는지 핵심 지식으로 활용해야 한다 [41], [42].
|
||||
|
||||
### Adjacent Topics
|
||||
|
||||
* [[Event-Driven Architecture]]
|
||||
* 확장 방향: 분산 컴퓨팅 시스템 내에서 개별 컴포넌트나 노드들이 강하게 결합되지 않도록, 비동기적인 '이벤트'를 매개체로 하여 통신하고 반응하는 구조적 접근법으로 조사를 확장할 수 있다 [43], [44].
|
||||
* [[Serverless Architecture]]
|
||||
* 확장 방향: 분산된 인프라(서버)의 관리 책임 자체를 클라우드 제공자에게 위임하고, 필요할 때마다 동적으로 컴퓨팅 자원을 할당받아 작은 기능(Function) 단위로 실행하는 차세대 클라우드 분산 아키텍처 기술로 연결해 알아볼 수 있다 [45], [46].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
---
|
||||
|
||||
- [[Parallel-Computing|Parallel-Computing]], [[CAP-Theorem|CAP-Theorem]],[[_system|system]]-Design-for-AI-Scale, [[GPU-Architecture|GPU-Architecture]]
|
||||
- **Raw Source:** 10_Wiki/Topics/AI/Distributed-Computing.md
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
|
||||
@@ -2,90 +2,220 @@
|
||||
id: wiki-2026-0508-downshift
|
||||
title: Downshift
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [downshift-js, useCombobox, useSelect]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [uncategorized]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [react, ui, accessibility, combobox, hooks]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: react
|
||||
---
|
||||
|
||||
# [[Downshift|Downshift]]
|
||||
# Downshift
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
Down[[Shift|Shift]]는 React 환경에서 `useCombobox()`와 같은 기능을 제공하는 헤드리스 컴포넌트([[Headless Components|Headless Components]]) 라이브러리의 대표적인 예시입니다 [1]. 이 라이브러리는 컴포넌트의 내부 상태와 로직만을 노출하고, 실제 UI 마크업의 형태는 개발자가 전적으로 정의하도록 위임합니다 [1]. 이를 통해 특정 디자인에 얽매이지 않고 접근성 높은 UI 라이브러리를 구축할 수 있도록 돕습니다 [1].
|
||||
## 매 한 줄
|
||||
> **"매 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).
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **헤드리스 컴포넌트(Headless Components) 패턴:** Downshift는 UI 마크업 없이 로직만을 제공하는 헤드리스 컴포넌트의 특징을 잘 보여줍니다 [1]. 개발자는 Downshift가 제공하는 로직을 바탕으로 자신이 원하는 대로 시각적 요소를 구현할 수 있습니다 [1].
|
||||
* **로직과 마크업의 완벽한 분리:** 상태 및 동작 로직을 UI 마크업과 철저히 분리하기 때문에 구성 요소의 조합성(Composability)이 매우 뛰어납니다 [1].
|
||||
* **뛰어난 확장성과 호환성:** 특정한 스타일이나 마크업을 강제하지 않으므로 어떠한 디자인 시스템과도 완벽하게 호환되며, 프레임워크에 구애받지 않는(framework-agnostic) 확장 가능한 컴포넌트를 구축하는 데 매우 적합합니다 [1].
|
||||
## 매 핵심
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** [[Headless Components|Headless Components]], React Component Patterns, [[Accessible UI Libraries|Accessible UI Libraries]]
|
||||
- **Projects/Contexts:** [[Design Systems|DesignSystems]], 확장 가능하고 유지보수하기 쉬운 프론트엔드 UI 컴포넌트 아키텍처 구축 [1].
|
||||
- **Contradictions/Notes:** 소스에 관련 정보가 부족합니다.
|
||||
### 매 무엇 의 solve
|
||||
- 매 native `<select>` 의 styling 의 unable.
|
||||
- 매 custom dropdown 의 매 keyboard / screen reader / focus management 의 hard.
|
||||
- 매 ARIA roles (`combobox`, `listbox`, `option`) 의 correctly wire.
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-26*
|
||||
### 매 API 종류
|
||||
- `useCombobox` — 매 typeahead 의 search input + dropdown.
|
||||
- `useSelect` — 매 native select replacement (no input).
|
||||
- `useMultipleSelection` — 매 tag / chip selection.
|
||||
- Render-prop `<Downshift>` — 매 legacy, 매 hooks 권장.
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
### 매 핵심 state
|
||||
- `isOpen` — dropdown open?
|
||||
- `highlightedIndex` — 매 keyboard hover.
|
||||
- `selectedItem` — 매 chosen value.
|
||||
- `inputValue` — 매 typed text.
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
### 매 응용
|
||||
1. Autocomplete / type-ahead search.
|
||||
2. Country / timezone picker.
|
||||
3. Multi-select tag input (with `useMultipleSelection`).
|
||||
4. Async-loading dropdowns.
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
## 💻 패턴
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
### Pattern 1: Basic useCombobox
|
||||
```tsx
|
||||
import { useCombobox } from "downshift";
|
||||
import { useState } from "react";
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
const ALL = ["apple","banana","cherry","date","elderberry"];
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
export function FruitCombo() {
|
||||
const [items, setItems] = useState(ALL);
|
||||
const cb = useCombobox({
|
||||
items,
|
||||
onInputValueChange: ({ inputValue }) => {
|
||||
setItems(ALL.filter(f => f.includes(inputValue?.toLowerCase() ?? "")));
|
||||
},
|
||||
});
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
|
||||
- **과거 데이터와의 충돌:** 없음
|
||||
- **정책 변화:** 없음
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
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>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Pattern 2: Async items (debounced)
|
||||
```tsx
|
||||
import { useCombobox } from "downshift";
|
||||
import { useState, useEffect } from "react";
|
||||
import { useDebouncedValue } from "./hooks";
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
export function UserPicker() {
|
||||
const [query, setQuery] = useState("");
|
||||
const debounced = useDebouncedValue(query, 250);
|
||||
const [items, setItems] = useState<User[]>([]);
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
useEffect(() => {
|
||||
if (!debounced) return;
|
||||
fetch(`/api/users?q=${debounced}`).then(r => r.json()).then(setItems);
|
||||
}, [debounced]);
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
const cb = useCombobox({
|
||||
items,
|
||||
itemToString: u => u?.name ?? "",
|
||||
onInputValueChange: ({ inputValue }) => setQuery(inputValue ?? ""),
|
||||
});
|
||||
// 매 render UI 동일 패턴.
|
||||
}
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### Pattern 3: Multi-select with chips
|
||||
```tsx
|
||||
import { useCombobox, useMultipleSelection } from "downshift";
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
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]]
|
||||
- 변형: [[Radix UI]] · [[Headless UI (Tailwind Labs)]] · [[Ariakit]] · [[React Aria]]
|
||||
- 응용: [[Combobox Pattern]] · [[Autocomplete]]
|
||||
- Adjacent: [[ARIA Authoring Practices]] · [[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 |
|
||||
|
||||
@@ -2,120 +2,166 @@
|
||||
id: wiki-2026-0508-dynamic-systems-development-meth
|
||||
title: Dynamic Systems Development Method (DSDM)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-11CDF5FD]
|
||||
aliases: [DSDM, Atern, AgilePF]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [dynamic-systems-development-method-(dsdm), agile-software-development, up-front-design, software-architecture, scrum, process-methodology]
|
||||
source_trust_level: B
|
||||
confidence_score: 0.85
|
||||
verification_status: applied
|
||||
tags: [agile, methodology, project-management, architecture]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-02
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: methodology
|
||||
framework: agile
|
||||
---
|
||||
|
||||
# [[Dynamic Systems Development Method (DSDM)]]
|
||||
# Dynamic Systems Development Method (DSDM)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
DSDM은 애자일(Agile) 소프트웨어 개발 방법론 및 프레임워크 중 하나입니다 [1, 2]. 이 방법론은 '기반(Foundations)' 단계를 의무화하여 '딱 필요한 만큼(just enough)'의 아키텍처 기반을 구축하도록 함으로써 사전 설계(up-front design)와 민첩성(agility) 사이의 균형을 맞춥니다 [2]. 주어진 소스에 관련 정보가 부족하여, 상세한 정의와 원리를 파악하는 데는 한계가 있습니다.
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **애자일과 아키텍처의 균형:** 소프트웨어 아키텍처를 수립할 때 지나치게 많은 사전 설계(big design up front)를 수행하는 것에 대해 애자일 소프트웨어 개발 지지자들 사이에서 우려가 제기되곤 합니다 [2]. DSDM은 이러한 사전 설계와 민첩성 사이의 트레이드오프(trade-off) 균형을 맞추기 위해 고안된 방법론 중 하나입니다 [2].
|
||||
* **Foundations 단계:** DSDM은 프로젝트 초기에 'Foundations'라는 단계를 의무화합니다 [2]. 이 단계에서는 과도한 설계를 지양하고 프로젝트 진행에 '딱 필요한 정도의(just enough)' 아키텍처 토대만을 마련합니다 [2].
|
||||
* 소스에 관련 정보가 부족합니다. (상세한 프로세스나 구조적 원리에 대한 추가 정보가 소스에 포함되어 있지 않습니다.)
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
* 소스에 관련 정보가 부족합니다.
|
||||
* (단, 주어진 소스에 따르면 DSDM 자체가 시스템의 민첩성(agility)을 확보하면서도 필수적인 사전 설계(up-front design)를 수행해야 한다는 트레이드오프를 해결하기 위한 목적을 가지고 도입됨을 알 수 있습니다 [2].)
|
||||
### 매 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.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
### 매 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.
|
||||
|
||||
#### [소프트웨어 개발 패러다임]
|
||||
- [[Agile software development]]
|
||||
- 연결 이유: DSDM은 애자일 소프트웨어 개발 방법론의 일종으로 언급됩니다 [2].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 요구사항의 빠른 변화에 대응하면서도 아키텍처적 안정성을 확보하는 방법.
|
||||
### 매 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.
|
||||
|
||||
- [[Up-front design]]
|
||||
- 연결 이유: DSDM은 지나친 사전 설계(big design up front)를 지양하고 적절한 타협점을 찾기 위해 활용됩니다 [2].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 초기 설계의 적정선('just enough')과 소프트웨어 시스템 유연성 간의 관계.
|
||||
### 매 Roles
|
||||
- **Business Sponsor / Visionary / Ambassador** — 매 business side.
|
||||
- **Technical Coordinator / Solution Developer / Tester** — 매 dev side.
|
||||
- **Project Manager / Team Leader** — 매 facilitation.
|
||||
|
||||
### Deeper Research Questions
|
||||
(제공된 소스에 정보가 제한적이므로, 이를 기반으로 확장할 수 있는 심층 질문을 작성했습니다.)
|
||||
### 매 응용
|
||||
1. Government / regulated projects — 매 audit trail required.
|
||||
2. Fixed-deadline launches — 매 features 의 flex.
|
||||
3. Hybrid waterfall→agile transitions.
|
||||
|
||||
- DSDM의 'Foundations' 단계에서 규정하는 '딱 필요한 정도(just enough)'의 아키텍처 기반은 구체적으로 어떤 기준으로 결정되는가?
|
||||
- DSDM은 Scrum이나 XP 등 다른 애자일 방법론과 비교하여 아키텍처 설계 단계에서 어떤 차별점을 가지는가?
|
||||
- 초기 아키텍처 토대가 부족할 경우 발생할 수 있는 아키텍처 침식(Architecture erosion)을 DSDM은 어떤 제어 장치를 통해 방지하는가?
|
||||
- DSDM을 대규모 엔터프라이즈 아키텍처(Enterprise Architecture) 환경에 적용할 때 발생할 수 있는 한계점은 무엇인가?
|
||||
- 소스에 관련 정보가 부족합니다.
|
||||
## 💻 패턴
|
||||
|
||||
### Practical Application Contexts
|
||||
|
||||
- **Implementation:** 소스에 관련 정보가 부족합니다.
|
||||
- **System Design:** 애자일 환경에서 소프트웨어 시스템을 설계할 때, 사전 설계와 민첩성의 균형을 맞추기 위해 초기 아키텍처 'Foundations' 단계를 도입하는 방식으로 적용할 수 있습니다 [2].
|
||||
- **Operation / Maintenance:** 소스에 관련 정보가 부족합니다.
|
||||
- **Learning Path:** 소스에 관련 정보가 부족합니다.
|
||||
- **My Project Relevance:** 소스에 관련 정보가 부족합니다.
|
||||
|
||||
### Adjacent Topics
|
||||
|
||||
- [[Software Architecture]]
|
||||
- 확장 방향: DSDM은 소프트웨어 아키텍처 설계 시 사전 설계의 정도를 조절하는 맥락에서 중요한 방법론으로 논의됩니다 [2].
|
||||
- [[Scrum]], [[XP]], [[Kanban]]
|
||||
- 확장 방향: DSDM과 함께 소프트웨어 개발 생명주기(SDLC)를 지원하는 다양한 애자일 방법론 및 프레임워크들로, 각 방법론이 아키텍처를 다루는 방식을 비교 연구할 수 있습니다 [1].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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
|
||||
}
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
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";
|
||||
}
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### Pattern 4: Modeling — high level only
|
||||
```mermaid
|
||||
flowchart LR
|
||||
User[(User)] --> API
|
||||
API --> Auth
|
||||
API --> Order
|
||||
Order --> Payment[(Stripe)]
|
||||
Order --> DB[(Postgres)]
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 매 결정 기준
|
||||
| 상황 | 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]] · [[Software Project Management]]
|
||||
- 변형: [[Scrum]] · [[Extreme Programming (XP)]] · [[SAFe]]
|
||||
- 응용: [[MoSCoW Prioritization]] · [[Timeboxing]]
|
||||
- Adjacent: [[Lean Software Development]] · [[Shape Up]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -1,120 +1,191 @@
|
||||
---
|
||||
id: wiki-2026-0508-e-commerce-platforms
|
||||
title: E commerce Platforms
|
||||
title: E-commerce Platforms
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [ecommerce, online-store-platform, headless-commerce]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [ecommerce, shopify, stripe, headless]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: shopify-hydrogen/medusa/stripe
|
||||
---
|
||||
|
||||
# [[E-commerce Platforms|E-commerce Platforms]]
|
||||
# E-commerce Platforms
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
E-commerce Platforms(이커머스 플랫폼)은 제품 카탈로그, 장바구니, 결제 처리 등의 기능을 제공하여 온라인 상거래를 지원하는 시스템입니다 [1, 2]. 이 시스템의 핵심은 검색 엔진 최적화(SEO)를 통한 제품 발견, 빠른 페이지 로딩을 통한 구매 전환율 향상, 그리고 재고 및 가격 변동을 반영하는 최신 데이터의 유지입니다 [3-5]. 소스 자료에 따르면, 이커머스 플랫폼은 성능과 확장성을 극대화하기 위해 SSR(서버 사이드 렌더링), ISR(점진적 정적 재생성)과 같은 최적화된 웹 렌더링 전략과 컴포넌트 기반 아키텍처(CBA)를 적극적으로 채택합니다 [2, 6].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
전자상거래 플랫폼은 제품 카탈로그, 재고 관리, 결제 시스템 등을 처리하기 위해 고도의 확장성과 렌더링 최적화가 요구되는 복잡한 웹 시스템입니다 [1-3]. 검색 엔진 최적화(SEO)와 빠른 페이지 로딩 속도, 그리고 장바구니와 같은 동적 상호작용 간의 균형을 맞추는 것이 핵심 목표입니다 [1, 4, 5]. 이를 달성하기 위해 현대의 전자상거래 플랫폼은 SSR, ISR, SSG와 같은 다양한 렌더링 전략과 컴포넌트 기반 아키텍처(CBA)를 적극적으로 활용합니다 [6-8].
|
||||
### 매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **이커머스 플랫폼을 위한 웹 렌더링 전략 (Web Rendering Strategies):**
|
||||
* **SSR (Server-Side Rendering):** 이커머스 플랫폼의 제품 목록 페이지, 카테고리 탐색 및 개별 제품 상세 페이지에 가장 이상적인 렌더링 방식 중 하나입니다 [3]. 서버에서 제품의 세부 정보, 가격, 구매 버튼이 포함된 완전한 HTML을 즉시 제공하므로, 자바스크립트 로딩을 기다릴 필요 없이 사용자에게 콘텐츠를 보여주어 구매 전환율을 크게 향상시킵니다 [5]. 또한 훌륭한 SEO를 제공하여 제품 검색 노출에 유리하며, 항상 최신의 실시간 데이터를 요구하는 결제(Checkout) 페이지에 적합합니다 [3, 7].
|
||||
* **SSG (Static Site Generation):** 제품 라인이 변동 없이 안정적이고 콘텐츠 업데이트 주기가 규칙적인 제품 카탈로그 페이지에 적용될 수 있습니다 [8].
|
||||
* **ISR (Incremental Static Regeneration):** 이커머스 플랫폼에 최적의 균형(성능과 최신성)을 제공하는 고도화된 접근 방식입니다 [4, 6]. 대규모 제품 카탈로그를 초고속으로 로딩하는 동시에, 전체 사이트를 다시 빌드하는 오버헤드 없이 백그라운드에서 재고 정보와 가격을 주기적으로 업데이트하여 최신 상태로 유지할 수 있습니다 [4, 6, 9].
|
||||
### 매 PSP / payments
|
||||
- **Stripe** — global default, broad APM coverage.
|
||||
- **Adyen** — enterprise / omnichannel.
|
||||
- **PayPal/Braintree, Klarna, Afterpay, Apple/Google Pay** — APMs.
|
||||
- **Crypto / stablecoin** — Coinbase Commerce (niche).
|
||||
|
||||
* **컴포넌트 기반 아키텍처 적용 ([[Component-Based Architecture|Component-Based Architecture]]):**
|
||||
* 이커머스 플랫폼은 제품 목록(Product listings), 결제 게이트웨이(Payment gateways), 장바구니(Shopping c[[Arts|Arts]]), 고객 리뷰 모듈 등 명확히 분리된 기능을 가진 재사용 가능한 소프트웨어 컴포넌트들의 조립으로 구축됩니다 [2].
|
||||
* 이러한 모듈식 접근 방식을 통해 비즈니스가 확장됨에 따라 새로운 결제 옵션을 추가하거나 제품 추천 기능을 갱신해야 할 때, 플랫폼 전체에 중단을 일으키지 않고 특정 컴포넌트만 쉽게 교체하거나 확장할 수 있는 유연성을 확보합니다 [2, 10].
|
||||
### 매 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.
|
||||
|
||||
---
|
||||
## 💻 패턴
|
||||
|
||||
* **전자상거래를 위한 최적의 렌더링 전략:**
|
||||
* **서버 사이드 렌더링 (SSR):** 제품 목록 페이지, 카테고리 탐색 및 개별 제품 상세 뷰에 이상적입니다. 강력한 검색 엔진 가시성(SEO)을 보장하고 클라이언트 측의 처리 지연 없이 제품의 가격과 재고 등을 즉각적으로 렌더링하여 사용자 경험과 전환율을 향상시킵니다 [1].
|
||||
* **점진적 정적 재생성 (ISR):** 빠른 제품 페이지 로딩 속도를 제공하면서도 전체 사이트를 다시 빌드할 필요 없이 재고 정보 및 가격을 최신 상태로 유지할 수 있어 대규모 전자상거래 플랫폼에 완벽한 균형을 제공합니다 [4, 6, 7].
|
||||
* **정적 사이트 생성 (SSG):** 실시간 재고 변경보다는 예약된 빌드 프로세스를 통해 제품 정보가 주로 업데이트되는 안정적인 제품 카탈로그 페이지에 유리합니다 [9, 10].
|
||||
* **클라이언트 사이드 렌더링 (CSR):** 소셜 미디어나 전자상거래 웹사이트처럼 고도의 상호 작용이 필요한 애플리케이션에 부분적으로 사용됩니다 [5].
|
||||
|
||||
* **전자상거래에서의 컴포넌트 기반 아키텍처 (CBA) 활용:**
|
||||
* 전자상거래 플랫폼은 제품 목록, 결제 게이트웨이, 장바구니, 고객 리뷰 모듈과 같은 개별 기능을 독립적인 컴포넌트로 구축하여 아키텍처의 모듈화와 재사용성을 극대화합니다 [2, 3].
|
||||
* 트래픽 급증 시 전체 애플리케이션이 아닌 쇼핑 카트 컴포넌트와 같은 특정 인스턴스만 추가하여 원활한 운영을 유지하는 등 뛰어난 확장성을 제공합니다 [8].
|
||||
* 마케팅 캠페인이나 시즌별 프로모션에 맞춰 기본 비즈니스 기능을 손상시키지 않고 다양한 테마를 적용하여 사이트의 디자인을 신속하게 변경할 수 있습니다 [11].
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
No trade-offs available.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** [[Server-Side Rendering (SSR)|Server-Side Rendering (SSR]], Incremental Static Regeneration (ISR), Component-Based Architecture, Search Engine Optimization (SEO
|
||||
- **Projects/Contexts:** 대규모 트래픽을 처리하면서도 검색 엔진 노출을 극대화하고 실시간 재고/가격 변동을 반영해야 하는 프론트엔드 웹 성능 최적화 및 렌더링 아키텍처 구축 맥락 [3, 4, 7].
|
||||
- **Contradictions/Notes:** 제공된 소스는 이커머스 플랫폼의 백엔드 비즈니스 로직이나 운영 모델보다는 주로 프론트엔드의 화면 렌더링 최적화(SSR/ISR)와 아키텍처(컴포넌트화) 측면에 초점을 맞추고 있어, 결제 시스템의 내부 동작 원리 등에 대해서는 소스에 관련 정보가 부족합니다.
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** [[Server-Side Rendering (SSR)|Server-Side Rendering (SSR]], Incremental Static Regeneration (ISR), Component-Based Architecture (CBA
|
||||
- **Projects/Contexts:** 제품 카탈로그 및 장바구니 시스템 (Product Catalogs and Shopping C[[Arts|Arts]])
|
||||
- **Contradictions/Notes:** 소스 [5]에서는 높은 수준의 상호작용이 필요한 전자상거래 웹사이트에 CSR이 흔히 사용된다고 언급합니다. 하지만 다른 소스들은 검색 엔진 최적화(SEO)와 최신 데이터 제공의 중요성 때문에 제품 탐색 및 세부 페이지에는 SSR 또는 ISR을 사용하는 것이 훨씬 이상적이고 필수적이라고 강조합니다 [1, 4, 7].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-25*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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);
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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 });
|
||||
}
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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 } });
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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();
|
||||
}
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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,
|
||||
})),
|
||||
});
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]] · [[Payments]]
|
||||
- 변형: [[Headless-Commerce]] · [[Composable-Commerce]] · [[Marketplace-Platform]]
|
||||
- 응용: [[Shopify-Hydrogen]] · [[Medusa]] · [[commercetools]]
|
||||
- Adjacent: [[Stripe]] · [[Adyen]] · [[Algolia]] · [[Sanity]] · [[Avalara]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -2,109 +2,202 @@
|
||||
id: wiki-2026-0508-eve-온라인-eve-online
|
||||
title: EVE 온라인(EVE Online)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [EVE Online, EVE, CCP Games]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [game-design, mmo, sandbox, virtual-economy, distributed-systems]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: stackless-python
|
||||
framework: tranquility
|
||||
---
|
||||
|
||||
# [[EVE 온라인(EVE Online)|EVE 온라인(EVE Online]]
|
||||
# EVE 온라인(EVE Online)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
EVE 온라인(EVE Online)은 우주를 배경으로 하는 다중 접속 역할 수행 게임(MMORPG)이다 [1]. 수십만 명의 플레이어가 단일 서버에 접속하는 거대한 규모를 자랑하며, 경험치 획득 대신 실시간으로 스킬을 훈련하는 독특한 캐릭터 성장 방식을 채택하고 있다 [1, 2]. 특히 플레이어 간의 거래와 시장 메커니즘을 중심으로 고도로 정교화된 가상 경제 시스템을 운영하는 것이 핵심적인 특징이다 [3, 4].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
이브 온라인(EVE Online)은 수십만 명의 플레이어를 단일 서버에 수용하여 상호작용하게 하는 우주 배경의 대규모 다중 사용자 온라인 역할 수행 게임(MMORPG)이다 [1, 2]. 전통적인 경험치 획득이 아닌 실시간 스킬 훈련 기반의 성장 방식을 제공한다 [1]. 또한 플레이어 주도적인 가상 경제 시스템을 구축하고 있으며, 인플레이션 제어를 위해 정교한 하드 싱크(Hard Sinks) 메커니즘을 적용한 대표적인 성공 사례로 꼽힌다 [3, 4].
|
||||
### 매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **단일 서버 기반의 거대 생태계:** 일반적인 MMORPG가 서버당 수천 명 수준으로 인원을 제한하는 것과 달리, EVE 온라인은 수십만 명의 플레이어가 동일한 서버에 수용되며 6만 명 이상이 동시 접속하여 상호작용하는 거대한 단일 세계를 구축하고 있다 [2].
|
||||
* **실시간 스킬 훈련을 통한 대안적 성장:** 캐릭터 성장을 위해 몬스터 사냥이나 퀘스트를 통해 경험치 포인트를 모으는 전통적인 방식에서 벗어나, 실시간(real-time)으로 스킬을 훈련하여 능력을 발전시키는 대안적인 성장(Progression) 메커니즘을 사용한다 [1].
|
||||
* **플레이어 주도의 정교한 경제 시스템:** 게임 내 경제는 철저히 플레이어의 활동과 아이템 시장(마켓) 거래를 기반으로 굴러간다 [4, 5].
|
||||
* **비율 기반의 하드 싱크(Hard Sinks)를 통한 인플레이션 제어:** 게임 내 통화량의 지속적인 증가(인플레이션)를 제어하고 경제 수명 주기 전반에 걸쳐 균형을 유지하기 위해 고도화된 장치들을 사용한다 [3]. 구체적으로 5~15%에 달하는 경매장 거래 수수료나 아이템 가치에 연동되는 수리비와 같이 백분율(%)을 기반으로 작동하는 영구적 재화 소멸 시스템(하드 싱크)을 적용하여 가상 경제의 구조적 무결성을 유지한다 [3].
|
||||
### 매 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.
|
||||
|
||||
- **플레이어 주도형 경제 시스템 (Player-driven Economy):** 이브 온라인은 경제 시스템이 철저히 플레이어의 활동을 기반으로 작동하는 구조적 특징을 지닌다 [4].
|
||||
- **비율 기반의 하드 싱크(Hard Sinks) 메커니즘:** 게임 경제 설계 시 플레이어의 자산 규모가 거대해짐에 따라 고정된 비용의 재화 소모(예: 고정된 NPC 상점 구매가)는 인플레이션 억제 기능을 상실하기 쉽다 [3]. 이를 방지하기 위해 이브 온라인은 5~15%에 달하는 경매장 수수료나 가치 연동형 장비 수리비와 같이 '백분율 기반의 하드 싱크'를 전략적으로 채택하고 있다 [3]. 이는 경제 수명 주기 전반에 걸쳐 유통 통화량을 직접적으로 줄이고 재화의 가치를 방어하는 데 필수적인 역할을 한다 [3].
|
||||
- **대규모 단일 서버 아키텍처:** 다른 일반적인 MMORPG들이 서버당 수천 명을 수용하는 다중 서버 구조를 띠는 것과 대조적으로, 이브 온라인은 수십만 명의 플레이어가 단일 서버 공간에 존재하며 6만 명 이상이 동시에 플레이하는 등 막대한 규모의 상호작용과 경제 활동이 하나의 세계에서 이루어지는 환경을 제공한다 [2].
|
||||
- **실시간 성장 모델 (Real-time Progression):** 전투나 퀘스트를 통한 경험치 축적(Grinding)을 통해 레벨업하는 보편적 방식과 달리, 이브 온라인은 현실 시간의 흐름(Real-time)에 따라 스킬을 훈련하는 대안적인 성장 시스템을 사용하여 플레이어들에게 독창적인 목표 달성 방식을 제공한다 [1].
|
||||
## 💻 패턴
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
No trade-offs available.
|
||||
### 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
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** [[MMORPG 영속적 세계와 자원 관리|MMORPG]], 하드 싱크 (Hard Sinks), 인플레이션 제어, [[플레이어 기반 경제|플레이어 기반 경제]]
|
||||
- **Projects/Contexts:** 가상 경제 시스템의 구조적 무결성 설계, 알비온 온라인 (동일한 플레이어 경제 기반 게임 사례
|
||||
- **Contradictions/Notes:** 소스의 분석에 따르면, 대부분의 전통적인 MMORPG가 경험치를 통해 레벨을 올리는 성장 구조를 가지는 것과 대조적으로, EVE 온라인은 실시간 스킬 훈련이라는 이질적인 방식을 채택하여 게임 진행의 척도를 다르게 정의하고 있다 [1].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-29*
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** [[MMORPG 영속적 세계와 자원 관리|MMORPG]], 하드 싱크 (Hard Sinks), 플레이어 기반 경제 (Player-driven Economy
|
||||
- **Projects/Contexts:** [[알비온 온라인(Albion Online)|알비온 온라인 (Albion Online]] (이브 온라인과 유사하게 정교한 경제 시스템과 백분율 기반의 하드 싱크를 사용하는 MMORPG 사례)
|
||||
- **Contradictions/Notes:** 소스에 관련 정보가 부족합니다. (이브 온라인의 경제 시스템과 관련된 상반된 주장이나 비판점에 대한 구체적인 내용은 소스에 포함되어 있지 않습니다.)
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-29*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
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)
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Per-system node assignment
|
||||
```python
|
||||
SYSTEM_NODES = {} # system_id -> node_id
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
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)
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
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())
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
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],
|
||||
}
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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
|
||||
- 부모: [[MMO-Design]] · [[Game-Architecture]]
|
||||
- 변형: [[Sandbox-Games]] · [[Single-Shard-MMO]]
|
||||
- 응용: [[Virtual-Economy]] · [[Distributed-Simulation]] · [[Player-Politics]]
|
||||
- Adjacent: [[Stackless-Python]] · [[Time-Dilation]] · [[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 |
|
||||
|
||||
@@ -2,138 +2,187 @@
|
||||
id: wiki-2026-0508-enabling-point-활성화-지점
|
||||
title: Enabling Point (활성화 지점)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [Activation Point, Enabling Constraint, Trigger Point]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [uncategorized]
|
||||
source_trust_level: B
|
||||
confidence_score: 0.8
|
||||
verification_status: applied
|
||||
tags: [architecture, design, leverage-point, evolutionary-architecture]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: methodology
|
||||
framework: architecture
|
||||
---
|
||||
|
||||
# [[Enabling Point (활성화 지점)]]
|
||||
# Enabling Point (활성화 지점)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
Enabling Point(활성화 지점)는 소프트웨어 프로그램 내에서 접점(Seam)을 이용해 어떤 동작을 사용할지 결정을 내릴 수 있는 장소를 의미합니다 [1]. 레거시 코드에 테스트를 추가하기 위해 소스 코드를 직접 수정하지 않고도 동작을 변경해야 하는데, 이때 프로덕션 코드 외부나 인터페이스에서 변화를 주어 특정 동작을 대체할 수 있게 만드는 지점이 바로 활성화 지점입니다 [2]. 이를 통해 기존 프로덕션 코드의 동작과 분리하여 시스템의 의존성을 안전하게 끊고 리팩토링할 수 있는 기반을 제공합니다 [1-3].
|
||||
## 매 한 줄
|
||||
> **"매 작은 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.
|
||||
|
||||
## 📖 Core 소스 Content
|
||||
**활성화 지점의 정의와 역할**
|
||||
* 모든 접점(Seam)은 반드시 활성화 지점을 갖습니다 [1, 2].
|
||||
* 접점이 프로그램 내에서 코드를 편집하지 않고도 동작을 변경할 수 있는 '위치'라면, 활성화 지점은 테스트용 동작을 사용할지 프로덕션용 동작을 사용할지 **'결정을 내리는 곳'**입니다 [1].
|
||||
* 소스 코드는 프로덕션과 테스트 환경에서 동일해야 하므로, 접점을 활용하기 위해서는 반드시 다른 어딘가(활성화 지점)에서 변화를 주어야만 합니다 [2].
|
||||
## 매 핵심
|
||||
|
||||
**접점(Seam) 유형별 활성화 지점의 형태**
|
||||
* **전처리 접점 (Preprocessing Seams):** 코드가 컴파일되기 전에 텍스트를 교체하는 방식입니다 [4]. 이 접점의 활성화 지점은 **전처리기 지시자(preprocessor define, 예: `TESTING` 매크로 정의)**를 켜거나 끄는 곳이 됩니다 [2, 5].
|
||||
* **링크 접점 (Link Seams):** 이 접점의 활성화 지점은 항상 **프로그램 텍스트 외부**에 존재합니다 [6]. 예를 들어, 빌드 스크립트, 배포 스크립트, makefile의 설정이나 Java의 클래스패스(classpath) 환경 변수가 활성화 지점이 되어, 프로덕션 라이브러리 대신 테스트용 라이브러리를 연결하도록 결정합니다 [6-8].
|
||||
* **객체 접점 (Object Seams):** 객체 지향 언어에서 가장 널리 사용되는 접점입니다 [6]. 어떤 객체를 넘길지 결정할 수 있는 **메서드의 인수 목록(argument list)**이나, 프로덕션 객체를 생성할지 테스트용 서브클래스(Mock/Fake)를 생성할지 결정하는 **객체 생성 위치(instantiation point)**가 활성화 지점이 됩니다 [5, 9].
|
||||
### 매 무엇 / 무엇 X
|
||||
- **무엇**: 매 explicit 한 future-flexibility hook (interface / event / config flag / plugin).
|
||||
- **무엇 X**: 매 speculative generality (YAGNI 위반) — 매 enabling point 의 cheap / minimal.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
* **가시성 저하:** 전처리 접점과 링크 접점은 활성화 지점이 소스 코드 텍스트 외부(예: 매크로 정의, makefile, 빌드 스크립트)에 존재하기 때문에 변경 사항을 눈치채기 어려울 수 있습니다 [3, 6].
|
||||
* **유지보수의 어려움:** 외부 환경에 의존하는 활성화 지점(링크/전처리 접점)을 이용한 테스트는 상대적으로 명시적이지 않아 유지보수하기 까다로울 수 있습니다 [3].
|
||||
* **적용의 우선순위:** 객체 지향 언어에서는 가장 명시적이고 관리하기 쉬운 **객체 접점(Object Seams)을 우선적으로 사용**하는 것이 좋습니다 [3]. 전처리 접점과 링크 접점은 의존성이 시스템 전반에 너무 넓게 퍼져 있어 더 나은 대안이 없는 불가피한 경우에만 제한적으로 사용하는 것이 권장됩니다 [3].
|
||||
### 매 indicator
|
||||
- 매 small abstraction 의 매 large optionality 의 unlock.
|
||||
- 매 reversible decision 의 keep — 매 매 one-way door 의 avoid.
|
||||
- 매 cost-of-change 의 grow before it's added.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
### 매 종류
|
||||
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.
|
||||
|
||||
#### [관계 유형 A (핵심 개념/이론)]
|
||||
- [[Seam (접점)]]
|
||||
- 연결 이유: 활성화 지점은 접점을 실제로 동작하게 만들기 위해 반드시 짝을 이루어 존재하는 필수 개념입니다 [1, 2].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 코드를 직접 수정하지 않고도 소프트웨어의 특정 부분의 동작을 변경하거나 격리할 수 있는 근본적인 메커니즘을 이해할 수 있습니다.
|
||||
### 매 응용
|
||||
1. Strangler fig migration — 매 facade 의 enabling point.
|
||||
2. Plugin systems (VSCode, Obsidian, Backstage).
|
||||
3. Multi-tenant SaaS — 매 tenant-scoped extension.
|
||||
|
||||
#### [관계 유형 B (구현/테스트 기법)]
|
||||
- [[Object Seam (객체 접점)]]
|
||||
- 연결 이유: 객체 지향 환경에서 활성화 지점(매개변수나 객체 생성부)을 위치시키기에 가장 권장되는 안전한 접점 유형입니다 [3, 6].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 다형성을 활용하여 테스트용 객체를 주입하고 의존성을 끊어내는 구체적인 설계 기법을 배울 수 있습니다.
|
||||
- [[Link Seam (링크 접점)]]
|
||||
- 연결 이유: 클래스패스나 빌드 스크립트 등 프로그램 코드 외부를 활성화 지점으로 사용하여 의존성을 끊는 기술입니다 [6, 7].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 컴파일 및 링킹 단계에서 테스트 환경을 분리하는 빌드 시스템 수준의 대체 전략을 이해할 수 있습니다.
|
||||
- [[Preprocessing Seam (전처리 접점)]]
|
||||
- 연결 이유: 매크로(`#define` 등)를 활성화 지점으로 삼아 컴파일 전 단계에서 코드를 교체하는 방법입니다 [2, 4, 5].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: C/C++ 같은 언어에서 테스트용 빌드를 별도로 구축하는 조건부 컴파일 및 코드 치환 기술을 이해할 수 있습니다.
|
||||
## 💻 패턴
|
||||
|
||||
### Deeper Research Questions
|
||||
- 객체 접점의 활성화 지점을 시스템에 안전하게 도입하기 위한 최적의 리팩토링 기법(예: Parameterize Constructor, Extract and Override Call 등)은 어떤 기준에 따라 선택해야 하는가?
|
||||
- 링크 접점의 활성화 지점을 활용할 때, 테스트 환경과 실제 프로덕션 환경 간의 빌드 구성 차이로 인해 발생할 수 있는 잠재적 결함을 어떻게 최소화할 수 있는가?
|
||||
- 전처리 접점의 활성화 지점을 과도하게 사용할 경우 발생하는 코드 가독성 저하와 유지보수성 하락 문제를 완화할 수 있는 관리 기법은 무엇인가?
|
||||
- 극도로 얽혀있는 레거시 시스템에서 여러 계층의 활성화 지점을 동시에 관리하고 추적해야 할 때, 이를 효과적으로 시각화하고 문서화하는 전략은 무엇인가?
|
||||
- 객체 지향 패러다임을 지원하지 않는 언어(예: C 언어)에서 활성화 지점을 식별하고 적용하기 위해 활용할 수 있는 아키텍처적 접근 방식은 무엇인가?
|
||||
### 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>;
|
||||
}
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 테스트하기 까다로운 레거시 코드를 테스트 하네스(Test Harness) 안으로 가져오기 위해, 활성화 지점을 찾아 가짜 객체(Fake Object)나 스텁(Stub)을 주입하여 원래의 소스 코드 수정 없이 안전하게 격리합니다 [2, 10].
|
||||
- **System Design:** 소프트웨어 설계 시 메서드의 매개변수나 생성자 등을 통해 명시적인 활성화 지점을 마련해 두면, 향후 컴포넌트의 동작을 쉽게 교체하고 테스트하기 용이한 유연한 시스템(Testable Architecture)을 구축할 수 있습니다 [9].
|
||||
- **Operation / Maintenance:** 빌드 스크립트, Makefile, 클래스패스(Classpath) 등의 외부 환경을 활성화 지점으로 관리함으로써, 프로덕션 환경의 코드를 오염시키지 않고 격리된 테스트 환경을 효과적으로 유지보수할 수 있습니다 [6, 7].
|
||||
- **Learning Path:** '레거시 코드의 복잡성 이해' -> '의존성 끊기의 필요성 인식' -> '접점(Seam) 식별' -> '적절한 활성화 지점(Enabling Point) 파악 및 적용' -> '안전망(테스트) 구축 및 리팩토링'의 순서로 개발 역량을 향상시킬 수 있습니다 [1, 3, 11].
|
||||
- **My Project Relevance:** 현재 다루고 있는 시스템 중 결합도가 높아 테스트 작성이 불가능한 모듈에 대해 접점과 활성화 지점을 찾아내고, 이를 통해 의존성을 분리하여 자동화된 테스트를 작성하는 데 직접적인 지침으로 활용할 수 있습니다.
|
||||
class StripeProvider implements PaymentProvider { /* ... */ }
|
||||
class TossProvider implements PaymentProvider { /* ... */ }
|
||||
|
||||
### Adjacent Topics
|
||||
- [[Dependency Injection (의존성 주입)]]
|
||||
- 확장 방향: 객체 접점의 활성화 지점(예: 생성자, 세터, 매개변수)을 통해 의존성을 주입하고 관리하는 현대적 디자인 패턴 및 프레임워크 기술 체계로의 학습 확장.
|
||||
- [[Mock Objects (가짜 객체)]]
|
||||
- 확장 방향: 활성화 지점을 통해 시스템에 주입되어, 실제 의존성을 안전하게 대체하고 다양한 시나리오에 대한 테스트를 가능하게 하는 테스트 더블(Test Double) 생성 및 활용 기법으로의 확장.
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-03*
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
|
||||
**추출된 패턴:**
|
||||
> *(TODO)*
|
||||
|
||||
**세부 내용:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
// service 의 매 PaymentProvider 만 의 know
|
||||
class CheckoutService {
|
||||
constructor(private payments: PaymentProvider) {}
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Pattern 2: Event hook
|
||||
```typescript
|
||||
type Hook<T> = (ctx: T) => Promise<void>;
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
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); }
|
||||
}
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
// 매 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));
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### Pattern 3: Feature flag (LaunchDarkly-style)
|
||||
```typescript
|
||||
import { flags } from "./flags";
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
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.
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]] · [[Evolutionary Architecture]]
|
||||
- 변형: [[Leverage Point (Meadows)]] · [[Seam (Working Effectively with Legacy Code)]]
|
||||
- 응용: [[Strangler Fig Pattern]] · [[Plugin Architecture]] · [[Feature Flags]]
|
||||
- Adjacent: [[Hexagonal Architecture]] · [[Fitness Function]] · [[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 |
|
||||
|
||||
@@ -2,85 +2,31 @@
|
||||
id: wiki-2026-0508-enterprise-software-architecture
|
||||
title: Enterprise Software Architecture
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
canonical_id: self
|
||||
aliases: [P-Reinforce-AI-SOFTWARE-ARCH]
|
||||
duplicate_of: none
|
||||
status: duplicate
|
||||
canonical_id: enterprise-software-engineering
|
||||
duplicate_of: "[[Enterprise-Software-Engineering]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.98
|
||||
tags: ["Architecture|[Architecture", Enterprise, _systemsDesign, DistributedSystems]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-04-20
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, enterprise, architecture]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
---
|
||||
|
||||
# [[Enterprise-Software-Architecture|Enterprise-Software-Architecture]] (엔터프라이즈 소프트웨어 아키텍처)
|
||||
# Enterprise Software Architecture
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> "비즈니스의 복잡도를 다루는 최상위 설계 도면." 개별 기능의 구현보다 시스템 간의 관계, 확장성, 가용성, 보안 등 거시적 관점에서 엔터프라이즈 급 요구사항을 충족시키기 위한 구조화 전략이다.
|
||||
> **이 문서는 [[Enterprise-Software-Engineering]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **Layered Architecture**: 관심사 분리를 통한 계층화 (Data, Service, Presentation).
|
||||
- **Message-Oriented Middleware**: 시스템 간 비동기 결합 및 데이터 정합성 보장.
|
||||
- **Legacy Integration**: 과거의 시스템(Mainframe 등)과 최신 플랫폼을 연결하는 어댑터 및 브리지 설계.
|
||||
- **Compliance & Security**: 규제 준수(GDPR, ISMS 등)를 고려한 데이터 접근 제어 설계.
|
||||
## 핵심 요약 (specialization aspects)
|
||||
- 매 architecture 측면 — TOGAF / Zachman / C4 / DDD bounded context.
|
||||
- 매 engineering 측면 (lifecycle / governance / SDLC) 의 매 canonical 에 통합.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- 과거의 무거운 SOA(Service Oriented Architecture)에서 MSA(Microservices Architecture)로 주류가 이동했으나, 최근에는 서비스 과분절로 인한 운영 비용 급증을 경고하는 'Macro-services' 또는 'Modular Monolith'로의 회귀 흐름도 존재한다. 중요한 것은 유행이 아니라 비즈니스 도메인의 복잡도에 맞는 적정 기술의 선택이다.
|
||||
## 🔗 Graph
|
||||
- 부모: [[Enterprise-Software-Engineering]] (canonical)
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- Related: Domain-Driven-Design (DDD) , [[Distributed-Systems|Distributed-Systems]]
|
||||
- Patterns: Sidecar-Pattern , CQRS
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
|
||||
@@ -2,143 +2,31 @@
|
||||
id: wiki-2026-0508-eugen-systems
|
||||
title: Eugen Systems
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
canonical_id: self
|
||||
status: duplicate
|
||||
canonical_id: eugen-systems-modding-manual
|
||||
duplicate_of: "[[Eugen Systems 모딩 매뉴얼]]"
|
||||
aliases: []
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, game-dev, modding, eugen]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
---
|
||||
|
||||
# Eugen Systems 모딩 매뉴얼
|
||||
# Eugen Systems
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
Eugen Systems의 WARNO 모딩 매뉴얼은 플레이어가 게임 소스 코드를 직접 수정하지 않고도 게임 내 데이터 포맷인 NDF(Neutral Data Format) 파일을 편집하여 새로운 유닛, 무기, 사단 등을 추가하거나 밸런스를 변경할 수 있도록 돕는 지침이다 [1, 2]. 게임 설치 폴더에 포함된 공식 매뉴얼(Modding Manual, NDF Reference Manual) 및 커뮤니티가 제공하는 가이드와 툴(Warno Mod Editor 등)을 기반으로 모딩이 이루어진다 [3, 4]. 이를 통해 사용자들은 유닛의 기초적인 통계부터 3D 모델(Depiction) 및 덱 편제에 이르기까지 폭넓은 데이터 수정 작업을 수행할 수 있다 [1, 5, 6].
|
||||
> **이 문서는 [[Eugen Systems 모딩 매뉴얼]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
---
|
||||
## 핵심 요약
|
||||
- Eugen Systems: 매 French RTS studio (Wargame, Steel Division, WARNO).
|
||||
- 매 modding manual은 NDF script + Wargame Modding Suite 중심.
|
||||
|
||||
Eugen Systems??Wargame ?쒕━利? Steel Division, 洹몃━怨?[[WARNO|WARNO]]瑜?媛쒕컻???꾨옉?ㅼ쓽 寃뚯엫 媛쒕컻 ?ㅽ뒠?붿삤?낅땲??[1-3]. ?대뱾? WARNO?먯꽌 ?낆옄?곸씤 Iriszoom ?붿쭊怨?NDF(Neutral Data Format) ?ㅽ겕由쏀듃 ?몄뼱瑜?寃고빀??'?곗씠??湲곕컲 ?ㅺ퀎(Data-Driven Design)' 泥좏븰??援ы쁽?덉뒿?덈떎 [4, 5]. ?대? ?듯빐 ?됱쟾 ?쒕???援곗궗 援먮━? ?λ퉬 ?쒖썝???뺢탳???곗씠???꾪궎?띿쿂濡?移섑솚?섏뿬 源딆씠 ?덇퀬 ?꾩떎?곸씤 ?꾨? ?꾩닠 ?쒕??덉씠???섍꼍???쒓났?섍퀬 ?덉뒿?덈떎 [4].
|
||||
## 🔗 Graph
|
||||
- 부모: [[Eugen Systems 모딩 매뉴얼]] (canonical)
|
||||
|
||||
---
|
||||
|
||||
Eugen Systems의 WARNO는 1987년 소련 강경파의 쿠데타를 기점으로 1989년에 제3차 세계대전이 발발했다는 가상의 '냉전기 열전(Cold War Gone Hot)' 시나리오를 배경으로 합니다 [1, 2]. 이 가상 시나리오는 실제 역사적 사단 편제표(TO&E)를 철저한 데이터 구조로 치환하여 게임 내 규칙으로 적용한 데이터 기반 설계를 특징으로 합니다 [2]. 더 나아가, 독자적인 NDF(Neutral Data Format) 시스템을 통해 소스코드 수정 없이도 게임 데이터를 제어할 수 있게 하여, 커뮤니티 주도의 분석 도구 및 모드(Mod) 개발이 활발히 이루어지는 개방적인 생태계를 구축했습니다 [2, 3].
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **모딩 초기 설정 (Initial Setup):** WARNO의 모딩은 게임의 `Mods` 폴더 내에 있는 `CreateNewMod.bat` 파일을 실행하여 모드 이름을 인수로 입력함으로써 시작된다 [7, 8]. 성공적으로 실행되면 `CommonData`, `GameData` 폴더와 모드 생성 및 관리를 위한 다양한 배치 파일(`GenerateMod.bat`, `UpdateMod.bat` 등)이 생성된다 [6, 9]. Eugen Systems는 모딩의 기초를 다룬 'Modding Manual'과 NDF 언어의 구조를 설명하는 'NDF Reference Manual' PDF 파일을 게임 폴더 내에 함께 제공하여 모더들을 지원하고 있다 [4].
|
||||
|
||||
* **필요 도구 (Tools):** NDF 파일을 수정하기 위해 Sublime Text, NotePad++ 같은 텍스트 편집기와 고유 식별자 생성을 위한 GUID 생성기가 필수적이다 [6, 10]. 또한 커뮤니티에서 개발한 통합 솔루션인 Warno Mod Editor(WME)를 활용하면 필수적인 NDF 편집과 GUID 생성을 한 번에 편리하게 처리할 수 있다 [3, 11].
|
||||
|
||||
* **데이터 파일 편집 (NDF 파일 수정):**
|
||||
* **사단 및 덱 편제:** `Divisions.ndf` 파일에서 특정 사단에 할당된 유닛 카드 리스트를 추가하거나 변경할 수 있으며, `DivisionRules.ndf`에서 숙련도(Veterancy)에 따른 유닛 가용성을 세부적으로 설정한다 [6, 12, 13]. 덱의 활성화 포인트와 슬롯 비용은 `DivisionCostMatrix.ndf`에서 변경 가능하다 [14].
|
||||
* **유닛 및 무기 속성:** 유닛의 시야, 비용, 전진 배치(Forward Deployment) 특성 등은 `UniteDescriptor.ndf`에서, 무장 및 탄약 적재량은 `WeaponDescriptor.ndf`에서, 관통력이나 피해량 같은 핵심 전투 속성은 `Ammunition.ndf`에서 수정한다 [2, 15]. 관통력 등을 수정할 때는 특정한 데미지 유형 인덱스(예: DamageFamily_ap)를 상호 참조하는 방식을 취한다 [16].
|
||||
* **시각적 묘사 (Depictions):** 게임 내 3D 모델(`.fbx` 파일), 사운드, 시각 효과 등을 렌더링하기 위해서는 `DepictionVehicles.ndf`, `DepictionAlternatives.ndf`(LOD 품질 설정용), `GeneratedDepictionGhosts.ndf`(배치 단계의 투명 모델), `UnitCadavreDescriptor.ndf`(파괴된 유닛 잔해) 등의 다양한 NDF 파일들을 편집하고 상호 연결하는 복잡한 과정이 필요하다 [5, 17, 18].
|
||||
|
||||
---
|
||||
|
||||
* **Iriszoom ?붿쭊怨??쒓컖?겶룸Ъ由ъ쟻 ?곗씠???듯빀:** Eugen Systems??R.U.S.E.遺??諛쒖쟾?쒖폒 ???낆옄?곸씤 Iriszoom ?붿쭊??理쒖떊 踰꾩쟾??WARNO???곸슜?덉뒿?덈떎 [6, 7]. ???붿쭊? 臾쇰━ 湲곕컲 ?뚮뜑留?PBR) ?쒖뒪?쒖쓣 ?꾩엯?섏뿬 ?ъ쭏???앸퀎?깆쓣 ?믪씠怨? ?꾩감 ?좏룺?대굹 ?щ━肄ν꽣 濡쒗꽣 鍮꾩궛 媛숈? ?숈쟻 ?뚭눼 ?쒖뒪?쒖씠 ?좊떅??臾쇰━???곹깭 ?곗씠?곗? 吏곸젒 ?곕룞?섎룄濡??ㅺ퀎?섏뿀?듬땲??[6-9]. ?먰븳, ???щ줈誘명꽣 ?⑥쐞???꾨왂???쒖빞遺??媛쒕퀎 ?좊떅 ?⑥쐞???꾩닠???쒖젏源뚯? 留ㅻ걚?쎄쾶 ?곌껐?섎뒗 媛蹂??LOD ?쒖뒪?쒖쓣 吏?먰빀?덈떎 [7, 9].
|
||||
* **[[NDF (Neutral Data Format)|NDF (Neutral Data Format]] 湲곕컲???곗씠???꾪궎?띿쿂:** WARNO??紐⑤뱺 ?쇰━???ㅺ퀎??NDF?쇰뒗 Eugen Systems???낆옄?곸씤 ?띿뒪??湲곕컲 ?ㅽ겕由쏀듃 ?몄뼱濡?援ъ텞?섏뼱 ?덉뒿?덈떎 [5]. ???쒖뒪?쒖? 寃뚯엫 肄붾뱶? ?곗씠?곕? ?꾧꺽??遺꾨━?섎?濡? 媛쒕컻?먮굹 紐⑤뜑(Modder)???뚯뒪 肄붾뱶瑜?嫄대뱶由ъ? ?딄퀬??`UniteDescriptor.ndf`??`Ammunition.ndf` 媛숈? ?뚯씪???섏젙?섏뿬 ?좊떅???깅뒫, 紐낆쨷瑜? ?κ컩 ???섏쿇 媛쒖쓽 ?띿꽦??議곕┰ 諛?愿由ы븷 ???덉뒿?덈떎 [5, 10].
|
||||
* **?붾젅硫뷀듃由?Telemetry) 湲곕컲??諛몃윴??** Eugen Systems??而ㅻ??덊떚???⑥닚 ?щ줎?대굹 遺덈쭔???꾨땶, ?붾젅硫뷀듃由щ? ?듯빐 ?섏쭛?섎뒗 ?ㅼ젣 ?곗씠???좊떅 ?좏깮瑜? ?밸쪧, ???곗뒪 鍮꾩쑉, ?됯퇏 ?앹〈 ?쒓컙 ??瑜?遺꾩꽍?섏뿬 寃뚯엫 諛몃윴?ㅻ? ?뺣??섍쾶 議곗젙?⑸땲??[11, 12]. 媛앷??곸씤 吏?쒕? 諛뷀깢?쇰줈 NDF ?뚯씪 ?댁쓽 ?ъ씤??鍮꾩슜, 臾댁옣 ?몃? ?ㅽ럺, ?뱀꽦(Trait) ?곗씠?곕? ?섏젙?⑥쑝濡쒖뜥 ?꾩닠 ?앺깭怨꾩쓽 洹좏삎??留욎땅?덈떎 [12, 13].
|
||||
* **?щ떒(Division) ?쒖뒪???꾩엯???듯븳 ?꾨왂???쒖빟???곗씠?고솕:** ?댁쟾 Wargame ?쒕━利덉쓽 ?먯쑀濡쒖슫 ???쒖뒪?쒓낵 ?щ━, WARNO?먮뒗 ??궗???щ떒 ?몄젣??TO&E)??湲곕컲???쒖뒪?쒖쓣 梨꾪깮?덉뒿?덈떎 [4]. ?대뒗 ?꾨꼍???좊떅留?紐⑥쑝??鍮꾪쁽?ㅼ쟻??硫뷀?瑜?諛⑹??섍퀬, 媛??щ떒蹂??щ’ 媛?⑹꽦(Availability) 諛?鍮꾩슜 ??怨좎쑀??媛뺤젏怨??쎌젏 ?곗씠?곕? 媛뺤젣?⑥쑝濡쒖뜥 ?꾩닠??源딆씠? 諛몃윴?ㅻ? ?μ긽?쒗궎????븷???⑸땲??[14-16].
|
||||
|
||||
---
|
||||
|
||||
* **가상 냉전 시나리오의 데이터적 구현**
|
||||
* WARNO의 배경은 1987년 미하일 고르바초프에 반대하는 소련 강경파의 쿠데타로 인해 1989년 NATO와 바르샤바 조약기구 간의 전면전이 발발하는 대체 역사입니다 [1].
|
||||
* 이 허구의 시나리오를 현실감 있게 통제하기 위해, 게임은 실제 군대의 사단 편제표(TO&E)를 핵심 데이터 규칙으로 내재화했습니다 [2].
|
||||
* 이를 통해 무제한적인 유닛 조합 대신, 특정 사단이라는 거대한 데이터 군집이 지닌 역사적, 교리적 강점과 약점을 반영하도록 설계되었습니다 [2, 4].
|
||||
|
||||
* **NDF 기반의 개방형 모딩 아키텍처**
|
||||
* 게임의 모든 물리적, 기술적 논리는 NDF(Neutral Data Format)라는 Eugen Systems의 독자적인 텍스트 기반 스크립트 언어로 정의되어 있습니다 [2].
|
||||
* NDF는 게임 코드와 데이터 값을 엄격히 분리하여, 모더(Modder)들이 `UniteDescriptor.ndf`, `WeaponDescriptor.ndf`, `Divisions.ndf` 등의 파일만 텍스트 편집기로 수정하여도 유닛의 성능, 명중률, 가용성 등을 세밀하게 변경할 수 있도록 지원합니다 [2, 5].
|
||||
* Eugen Systems는 사용자를 위해 `CreateNewMod.bat` 등의 배치 파일과 모딩 매뉴얼, NDF 참조 가이드를 제공하여 손쉽게 모드 환경을 구축할 수 있게 돕고 있습니다 [3, 5].
|
||||
|
||||
* **데이터 민주화와 커뮤니티 생태계 확장**
|
||||
* NDF 파일의 구조적 접근성 덕분에 커뮤니티는 숨겨진 게임 내부 수치를 파싱하여 War-Yes, Warno-Armory와 같은 정밀한 데이터 분석 웹사이트와 툴을 자체적으로 개발할 수 있었습니다 [2, 6, 7].
|
||||
* 또한, 흩어진 NDF 속성들의 의미와 핵심 게임 메커니즘을 문서화하기 위해 WARNO-DATA와 같은 광범위한 오픈소스 위키 프로젝트가 진행되기도 했습니다 [2, 8].
|
||||
* 이러한 생태계의 개방성은 모든 무기 데이터를 실제 현실의 제원값으로 치환하고 시뮬레이션 경제를 재설계한 'RebsFRAGO'와 같은 고도의 현실주의 모드(Realism Mod)가 탄생하는 기술적 근간이 되었습니다 [2, 9].
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
No trade-offs available.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** `[[NDF (Neutral Data Format)|NDF (Neutral Data Format)]]`, `Warno Mod Editor (WME)`, `[[Iriszoom 엔진|Iriszoom 엔진]]`
|
||||
- **Projects/Contexts:** `[[WARNO-DATA Wiki|WARNO-DATA Wiki]]`, `RebsFRAGO 모드 프로젝트`
|
||||
- **Contradictions/Notes:** 모딩 중 동일한 유닛을 같은 사단 덱 내에 중복해서 추가할 경우, 충돌이 발생하여 정상적으로 모드가 생성되지 않는다는 점에 주의해야 한다 [14]. 또한, 모드 생성 시 나타나는 코드 오류 메시지가 주로 프랑스어로 출력되므로, 번역기를 사용하여 편집 실수를 파악하고 대처해야 할 수 있다 [15].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-28*
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** Iriszoom Engine, NDF (Neutral Data Format), Telemetry, [[사단 시스템 (Division System)|Division System]]
|
||||
- **Projects/Contexts:** [[WARNO|WARNO]], Steel Division 2, Wargame Series
|
||||
- **Contradictions/Notes:** Wargame ?쒕━利덉쓽 ?쒗븳 ?녿뒗 ???쒖뒪?쒖쓣 ?좏샇?섎뒗 ?쇰? ?좎??ㅼ? ?щ떒 ?쒖뒪?쒖씠 ?좎????좏깮沅뚭낵 李쎌쓽?깆쓣 ?쒗븳?쒕떎怨?鍮꾪뙋?섏?留?[17, 18], Eugen Systems 諛??ㅼ닔???좎??ㅼ? ?щ떒 ?쒖뒪?쒖씠 紐⑤뱺 吏꾩쁺???묎컳? 媛뺣젰???좊떅?쇰줈 梨꾩슦??硫뷀?瑜?諛⑹??섍퀬, ?⑥뵮 ?ㅼ콈濡?퀬 諛몃윴???덈뒗 ??궗???꾩닠 ?섍꼍???쒓났?쒕떎怨?諛섎컯?섎ʼn ?由쏀빀?덈떎 [14-16, 19].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-28*
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** [[NDF (Neutral Data Format)|NDF (Neutral Data Format)]], [[사단 편제표 (TO&E)|사단 편제표 (TO&E)]], [[데이터 기반 설계|데이터 기반 설계]]
|
||||
- **Projects/Contexts:** [[WARNO-DATA 프로젝트|WARNO-DATA 프로젝트]], [[RebsFRAGO 모드|RebsFRAGO 모드]], [[War-Yes 및 Warno-Armory 도구|War-Yes 및 Warno-Armory 도구]]
|
||||
- **Contradictions/Notes:** 게임의 전체적인 배경은 1989년 3차 세계대전이라는 완전한 허구의 시나리오를 따르고 있지만, 그 전장을 채우는 부대 편제와 유닛의 성능은 철저하게 실제 역사적 데이터(TO&E 등)를 바탕으로 한 데이터 아키텍처에 의해 엄격하게 통제되고 있어 허구와 현실성이 공존하고 있습니다 [1, 2, 4].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-28*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
|
||||
@@ -2,125 +2,195 @@
|
||||
id: wiki-2026-0508-event-mediator
|
||||
title: Event Mediator
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-F81E0CF7]
|
||||
aliases: [Mediator Pattern, Event Bus]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [event-mediator, event-driven-architecture, broker-topology, message-queues, bpm-engine-/-bpel, architecture-principles]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [architecture, design-pattern, event-driven, decoupling]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-02
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: nodejs
|
||||
---
|
||||
|
||||
# [[Event Mediator]]
|
||||
# Event Mediator
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
이벤트 메디에이터(Event Mediator)는 이벤트 기반 아키텍처(Event-Driven Architecture)의 메디에이터 토폴로지(Mediator Topology) 내에서 이벤트의 흐름을 통제하고 워크플로우를 중앙에서 오케스트레이션(Orchestration)하는 핵심 구성 요소이다 [1, 2]. 다수의 단계가 필요한 복잡한 상황에서 각 프로세서가 수행할 명령을 지정된 채널로 전달하며, 비즈니스 프로세스의 상태를 유지하고 에러 처리 및 복구(재시작) 기능을 제공하는 것이 특징이다 [1-3]. 반면, 모든 흐름을 중앙에서 제어하기 때문에 성능 병목이나 단일 장애점이 될 위험이 존재한다 [1, 2].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **중앙 집중식 워크플로우 제어:** 이벤트 메디에이터는 이벤트 큐(Event Queue)로부터 초기 이벤트(Initiating Event)를 수신한 후, 비즈니스 프로세스를 구현하기 위해 단계를 조정한다 [4]. 이벤트 핸들러가 처리 완료 메시지를 보내면, 메디에이터는 이를 바탕으로 조건부(conditional) 또는 반복적(iterative) 논리를 적용해 다음 단계를 결정하고 후속 처리 이벤트(Processing Event)를 발송한다 [4].
|
||||
* **명령(Command) 기반의 오케스트레이션:** 시스템 전체에 이벤트를 브로드캐스트하는 브로커(Broker) 토폴로지와 달리, 지정된 채널(주로 메시지 큐)을 통해 특정 명령 형태의 이벤트를 디스패치한다 [1]. 즉, 이벤트 메디에이터 구조에서의 이벤트는 단순한 상태 변화의 알림이 아니라 반드시 실행되어야 할 '명령'으로 취급된다 [5].
|
||||
* **상태 유지 및 강력한 에러 복구:** 이벤트 메디에이터는 비즈니스 프로세스의 상태를 유지(maintain the state)할 수 있어, 에러가 발생했을 때 이를 복구하고 프로세스를 재시작(restart)할 수 있는 능력을 제공한다 [1, 2]. 이를 통해 분산 환경에서 더욱 정교한 에러 핸들링과 향상된 데이터 일관성을 확보할 수 있다 [1].
|
||||
* **도메인별 분산 및 확장 구현:** 단일 메디에이터 구성뿐만 아니라 고객, 브라우징, 주문, 재고 등 문제 도메인별로 다수의 메디에이터를 분할 구현하여 부하에 따라 독립적으로 확장성을 확보하고 신뢰성을 높일 수 있다 [4]. 단순한 제어 로직은 일반 코드로, 복잡한 제어나 긴 실행 시간이 필요한 워크플로우는 BPEL(Business Process Execution Language)이나 BPM(Business Process Management) 엔진과 같은 도구를 사용하여 제어한다 [6].
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
* **성능 병목 및 단일 장애점(SPOF) 위험:** 메디에이터가 모든 워크플로우와 이벤트 흐름을 중앙에서 제어하고 조정하기 때문에, 트래픽이 집중될 경우 메디에이터 자체가 성능의 병목(bottleneck) 현상을 유발하거나 시스템의 신뢰성을 위협하는 단일 장애점이 될 위험이 존재한다 [1, 2].
|
||||
* **컴포넌트 간 결합도(Coupling) 증가:** 중앙 집중형 오케스트레이션 방식을 따르므로, 처리기(Consumer/Handler)들이 메디에이터의 명령을 인식해야 하며 프로세스 제어를 위한 일정 수준의 결합이 수반되어 전체적으로 컴포넌트 간 결합도가 증가한다 [1, 2, 7].
|
||||
* **상대적으로 낮은 확장성:** 브로커 토폴로지와 같이 각 구성 요소가 극도로 느슨하게 결합되어 자율적으로 이벤트를 처리하는 방식에 비해, 메디에이터 병목 등으로 인해 상대적인 시스템 확장성과 성능 한계가 낮다 [2].
|
||||
### 매 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.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
### 매 동기 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).
|
||||
|
||||
#### [관계 유형 A (아키텍처/기반 기술)]
|
||||
- [[Event-Driven Architecture]]
|
||||
- 연결 이유: 이벤트 메디에이터가 핵심 오케스트레이션 역할을 수행하는 최상위 아키텍처 패턴이기 때문이다 [8, 9].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 이벤트를 비동기적으로 생성하고 감지하여 처리하는 분산 시스템 전반의 동작 원리와 유연성을 이해할 수 있다 [8, 10].
|
||||
- [[Broker Topology]]
|
||||
- 연결 이유: 중앙 조정자인 메디에이터 없이 컴포넌트들이 브로드캐스트된 이벤트를 자율적으로 처리하는(안무 방식) 상반된 토폴로지이기 때문이다 [1, 2, 10].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 중앙 통제형(오케스트레이션) 방식과 분산 통제형(안무) 방식의 장단점(결합도, 에러 처리, 확장성)을 비교 및 대조하여 분석할 수 있다 [2, 5].
|
||||
### 매 응용
|
||||
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.
|
||||
|
||||
#### [관계 유형 B (구현/활용 도구)]
|
||||
- [[Message Queues]]
|
||||
- 연결 이유: 이벤트 메디에이터가 다음 작업을 수행할 소비자(이벤트 핸들러)에게 명령(이벤트)을 디스패치할 때 지정하는 주요 통신 채널 기술이기 때문이다 [1].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 이벤트의 비동기적 버퍼링 및 전달을 통한 시스템의 부하 분산과 안정성 확보 메커니즘을 배울 수 있다 [4, 11].
|
||||
- [[BPM Engine / BPEL]]
|
||||
- 연결 이유: 메디에이터에서 에러 처리와 조건부 논리 제어 등 복잡도가 높은 비즈니스 로직을 구현할 때 활용하는 언어 및 실행 엔진이기 때문이다 [6].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 복잡한 조건부 처리, 동적 경로 결정 및 긴 실행 시간(Long-running)을 가지는 워크플로우 관리 기법을 이해할 수 있다 [6].
|
||||
## 💻 패턴
|
||||
|
||||
### Deeper Research Questions
|
||||
- 오케스트레이션(Orchestration) 방식의 메디에이터 패턴과 안무(Choreography) 방식의 브로커 패턴을 비즈니스 복잡도에 따라 하이브리드 형태로 어떻게 결합할 수 있는가?
|
||||
- 이벤트 메디에이터가 상태를 유지(Stateful)하면서도 대규모 트래픽 하에서 성능 병목이나 단일 장애점(SPOF)이 되는 것을 피하기 위한 스케일링 전략이나 기술 구조는 무엇인가?
|
||||
- 메디에이터 토폴로지 환경에서 단계 중 에러 발생 시, 중앙 메디에이터는 어떠한 방식으로 프로세스를 재시작(restart)하고 보상 트랜잭션(Compensating Transaction)을 지시하는가?
|
||||
- 이벤트 메디에이터 내부의 로직을 일반 코드로 직접 구현하는 방식과 BPEL 등의 DSL(Domain Specific Language)을 활용하는 방식 사이의 선택 기준과 각각의 유지보수 이점은 무엇인가?
|
||||
- 단일 시스템 내에서 문제 도메인별로 다수의 이벤트 메디에이터를 분할할 때, 초기 이벤트 큐에서 각 메디에이터로 이벤트를 분류 및 라우팅하는 효율적인 구조는 어떻게 설계해야 하는가?
|
||||
### Typed Event Bus (TypeScript)
|
||||
```typescript
|
||||
type EventMap = {
|
||||
'user.signup': { userId: string; email: string };
|
||||
'order.placed': { orderId: string; total: number };
|
||||
'cache.invalidate': { key: string };
|
||||
};
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 복잡한 비즈니스 로직 및 에러 처리 구현이 요구될 경우, Apache Camel, Spring Integration과 같은 메시징 인프라나 jBPM 같은 BPM 실행 엔진을 사용하여 워크플로우를 통제하는 메디에이터를 직접 구현한다.
|
||||
- **System Design:** 아키텍처 설계 시, 에러 복구와 프로세스의 상태 보존이 필수적인 워크플로우 구간(예: 다단계 금융 결제, 복잡한 재고 처리 등)을 식별하고 이 부분에 메디에이터 토폴로지를 적용해 데이터 일관성을 확보한다.
|
||||
- **Operation / Maintenance:** 운영 측면에서 중앙 이벤트 메디에이터 자체가 성능의 병목이나 단일 장애점이 될 수 있으므로, 해당 메디에이터 컴포넌트의 이중화 구성과 집중적인 상태 모니터링(Observability) 체계를 관리한다.
|
||||
- **Learning Path:** 이벤트 기반 아키텍처의 기본 원리와 브로커 토폴로지의 느슨한 결합을 먼저 학습한 뒤, 분산 시스템에서의 에러 핸들링과 워크플로우 통제 필요성에 따라 메디에이터 토폴로지의 구조적 특징과 한계를 순차적으로 학습한다.
|
||||
- **My Project Relevance:** 여러 서비스에 걸쳐 비동기적으로 실행되는 복잡한 비즈니스 프로세스 프로젝트를 진행할 때, 특정 단계의 실패 시 전체 프로세스 롤백 혹은 재시작을 중앙에서 조율해야 하는 관리 오케스트레이터의 도입을 검토할 때 참고한다.
|
||||
class EventMediator<M> {
|
||||
private handlers = new Map<keyof M, Set<(p: any) => void | Promise<void>>>();
|
||||
|
||||
### Adjacent Topics
|
||||
- [[Microservices Architecture]]
|
||||
- 확장 방향: 독립적으로 배포된 다수의 마이크로서비스 간에 걸쳐진 분산 트랜잭션 관리와 프로세스 조정을 위해 이벤트 메디에이터를 어떻게 효율적으로 통합할 것인지 연구한다.
|
||||
- [[Saga Pattern]]
|
||||
- 확장 방향: 분산 환경에서 ACID 트랜잭션 대신 최종 일관성(Eventual Consistency)을 보장하기 위한 오케스트레이션 기반 SAGA 패턴 구현 시, 중앙 메디에이터의 보상 트랜잭션 제어 기법을 심층 학습한다.
|
||||
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);
|
||||
}
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
const bus = new EventMediator<EventMap>();
|
||||
bus.on('user.signup', async ({ userId, email }) => {
|
||||
await sendWelcomeEmail(email);
|
||||
});
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Mediator with Request/Response (MediatR-style)
|
||||
```typescript
|
||||
interface IRequest<TResponse> { __response?: TResponse }
|
||||
interface IHandler<TReq extends IRequest<TRes>, TRes> {
|
||||
handle(req: TReq): Promise<TRes>;
|
||||
}
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
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); }
|
||||
}
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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 });
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### Middleware Pipeline
|
||||
```typescript
|
||||
type Middleware<E> = (event: E, next: () => Promise<void>) => Promise<void>;
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
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]] · [[Message-Bus]]
|
||||
- 응용: [[CQRS]] · [[Saga-Pattern]] · [[Microservices]]
|
||||
- Adjacent: [[Event-Sourcing]] · [[Domain-Events]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -1,133 +1,196 @@
|
||||
---
|
||||
id: wiki-2026-0508-event-stream-processing
|
||||
title: Event stream processing
|
||||
title: Event Stream Processing
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-777ED71E]
|
||||
aliases: [Stream Processing, ESP, Streaming Analytics]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [event-stream-processing, event-driven-architecture, complex-event-processing, event-sourcing, apache-kafka, architecture-principles]
|
||||
confidence_score: 0.93
|
||||
verification_status: applied
|
||||
tags: [streaming, kafka, flink, real-time, data-engineering]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-02
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: polyglot
|
||||
framework: kafka-flink
|
||||
---
|
||||
|
||||
# [[Event stream processing]]
|
||||
# Event Stream Processing
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
이벤트 스트림 처리(Event stream processing)는 일반적인 이벤트와 주요 이벤트를 식별하고, 이를 실시간으로 수집하여 스트림 프로세서에 연속적으로 공급하는 이벤트 기반 아키텍처의 핵심 데이터 처리 방식이다 [1, 2]. 데이터 스트리밍 플랫폼을 파이프라인으로 활용하여 시스템 내외부의 실시간 정보 흐름을 주도하며, 기업의 즉각적인 의사 결정을 가능하게 한다 [1, 2]. 대규모 데이터와 높은 처리량이 요구되는 IoT 워크로드 및 실시간 분석 시스템에 매우 적합한 접근법이다 [1].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **내구성을 갖춘 연속적 이벤트 로그**: 이벤트 스트리밍 환경에서 이벤트는 파티션 내에 엄격하게 정렬되며 내구성이 있는 로그(durable log) 형태로 기록된다 [3]. 큐(Queue)를 기반으로 한 방식에서는 이벤트가 소비된 후 삭제되는 경우가 많지만, 스트림에서는 이벤트가 영구적으로 저장되어 전체 이력이 유지된다 [4-6].
|
||||
- **클라이언트 주도적 소비 및 재실행(Replay) 능력**: 클라이언트는 시스템이 제공하는 스트림을 단순히 구독(Subscribe)만 하는 것이 아니라, 스트림의 어느 위치에서든 데이터를 읽을 수 있으며 스스로 읽기 위치(offset)를 진행시킨다 [3]. 이 메커니즘을 통해 클라이언트는 언제든지 스트림에 합류할 수 있고, 과거의 이벤트를 재실행(Replay)할 수 있다 [3].
|
||||
- **독립적이고 유연한 비동기 다중 처리**: 스트리밍 플랫폼(예: Azure IoT Hub, Event Hubs, Apache Kafka 등)은 파이프라인 역할을 하여 다수의 하위 스트림 프로세서로 이벤트를 분배한다 [1]. 이벤트가 스트림에 보존되기 때문에, 각 이벤트 핸들러(소비자)는 다른 핸들러에 구애받지 않고 즉시 처리하거나 주기적으로 처리하는 등 각자의 속도와 목적에 맞춰 이벤트를 비동기적으로 처리할 수 있다 [5, 6].
|
||||
- **대규모 실시간 데이터 워크로드 대응**: 주문 결제, RFID 전송, 센서 데이터 등 방대하게 발생하는 일상적 이벤트들을 실시간으로 필터링 및 변환하여 의미 있는 정보로 만들어낸다 [1, 2]. 특히 상태 변화가 잦은 IoT 환경이나 막대한 이벤트 핸들러가 연결되는 복잡한 네트워크에서 효율적인 데이터 처리를 지원한다 [6].
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **시스템 복원성 및 감사 용이성(장점)**: 이벤트를 재실행(Replay)할 수 있는 특성 덕분에 시스템 장애 후의 복구, 늦게 참여한 소비자의 데이터 동기화, 버그 수정 후의 과거 데이터 재처리가 매우 용이하다 [3]. 또한 과거의 이벤트를 분석하여 사용자 행동 패턴을 파악하거나, 이벤트 소싱(Event Sourcing)을 통해 과거의 시스템 상태를 완벽히 재구성할 수 있다 [6].
|
||||
- **최종 일관성(Eventual Consistency) 감수**: 이벤트 생산자와 소비자가 비동기 채널을 통해 완전히 분리되어 작동하기 때문에, 이벤트가 게시된 직후 모든 서비스의 데이터가 즉시 일치하지 않는 데이터 지연(Time lag)이 발생한다 [7]. 시스템의 특정 부분들이 현재 상태에 대해 일시적으로 동의하지 않는 창(window)을 견딜 수 있어야 한다 [7].
|
||||
- **오류 처리 및 순서 보장의 복잡성**: 복수의 소비자 인스턴스가 동시에 실행될 때, 이벤트 처리 순서를 보장하거나 정확히 한 번(exactly-once) 처리되도록 만드는 것은 매우 까다로우며 멱등성(Idempotent)을 고려한 설계가 필수적이다 [7]. 또한 비동기 통신 중 오류가 발생하여 이벤트를 재전송(Resubmit)할 경우 이벤트가 순서를 벗어나 처리될 위험이 있다 [7].
|
||||
- **스토리지 및 디버깅 오버헤드**: 모든 이벤트를 지속적으로 저장하는 설계는 시스템 모니터링에는 유리하지만, 시간이 지남에 따라 데이터 스토리지 요구량과 비용이 기하급수적으로 증가할 수 있다 [6]. 또한 여러 비동기 구성 요소에 걸쳐 흐르는 단일 비즈니스 트랜잭션을 디버깅하고 추적하려면 Correlation ID와 같은 정교한 관측성(Observability) 도구가 도입되어야 한다 [8].
|
||||
### 매 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.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
### 매 핵심 개념
|
||||
- **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.
|
||||
|
||||
#### [아키텍처/기반 기술]
|
||||
- `[[Event-Driven Architecture]]`
|
||||
- 연결 이유: 이벤트 스트림 처리는 컴포넌트 간 비동기적으로 이벤트를 생산하고 소비하는 이벤트 기반 아키텍처의 핵심 실행 모델 중 하나이다 [2, 3].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 이벤트 브로커와 메디에이터 토폴로지의 차이, 생성자와 소비자의 느슨한 결합 원리 [9].
|
||||
- `[[Complex event processing]]`
|
||||
- 연결 이유: 이벤트 스트림 처리를 통해 유입되는 단순 이벤트나 일상적 이벤트들을 시간적, 인과적 패턴으로 평가하여 복합적인 비즈니스 의미나 이상 징후를 도출할 때 사용된다 [10].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 단순한 스트림을 넘어, 다수의 이벤트를 상관 분석(Correlation)하고 패턴을 매칭하는 정교한 데이터 해석 기법 [10].
|
||||
- `[[Event Sourcing]]`
|
||||
- 연결 이유: 스트림에 이벤트를 영구 저장하는 특성은, 애플리케이션의 상태 변경을 일련의 이벤트로만 기록하여 영속성을 확보하는 이벤트 소싱 패턴 구현의 기반이 된다 [6].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 감사 추적(Audit trails) 시스템 및 데이터의 과거 상태 재구성 원리 [6, 11].
|
||||
### 매 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.
|
||||
|
||||
#### [구현/활용 도구]
|
||||
- `[[Apache Kafka]]`
|
||||
- 연결 이유: 이벤트 스트림 처리 환경에서 높은 처리량의 데이터 수집 파이프라인 역할을 수행하며 다수의 스트림 프로세서에 이벤트를 전달하는 대표적인 플랫폼이다 [1].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 파티션, 로그 보존, 그리고 클라이언트가 오프셋을 직접 관리하는 스트림 처리의 실제 물리적 구현 구조 [1, 3].
|
||||
- `[[Azure IoT Hub]]`
|
||||
- 연결 이유: 센서 등 하드웨어 기기(IoT)에서 발생하는 대규모 스트림을 수집하고 이벤트를 전달하는 파이프라인으로 사용되는 클라우드 인프라이다 [1].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 대규모 데이터와 속도를 요구하는 IoT 워크로드에서의 이벤트 처리 방법 [1, 12].
|
||||
### 매 응용
|
||||
1. Real-time fraud detection.
|
||||
2. IoT telemetry aggregation.
|
||||
3. Live dashboards (clickstream).
|
||||
4. CDC → search index sync.
|
||||
5. AI feature stores (real-time).
|
||||
|
||||
### Deeper Research Questions
|
||||
## 💻 패턴
|
||||
|
||||
- 복수의 스트림 프로세서가 개별적인 속도로 이벤트를 읽어갈 때, 데이터 로그의 크기와 스토리지 비용을 효율적으로 제어하기 위한 보존(Retention) 정책은 어떻게 설계해야 하는가?
|
||||
- 비동기 스트림 처리 환경에서 트랜잭션 도중 오류가 발생했을 때, 데이터 일관성을 회복하기 위한 보상 트랜잭션(Compensating Transaction)은 어떻게 구현되는가?
|
||||
- 큐(Queue) 기반의 처리(정확히 한 번 처리)와 스트림(Stream) 기반의 처리(다수 소비자의 다중 페이스 처리)를 단일 시스템 내에서 결합할 때의 설계 기준은 무엇인가?
|
||||
- 고도로 분산된 스트림 환경에서 스키마 버전이 변경되었을 때, 기존 이벤트를 처리하는 레거시 소비자와 신규 소비자가 충돌 없이 동작하기 위한 이벤트 진화(Event Evolution) 전략은 무엇인가?
|
||||
- 복합 이벤트 처리(CEP)와 이벤트 스트림 처리(ESP)를 결합하여 실시간 금융 사기 탐지와 같은 예측 시스템을 구축할 때의 지연 시간(Latency) 최소화 기법은 무엇인가?
|
||||
### 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 });
|
||||
|
||||
### Practical Application Contexts
|
||||
|
||||
- **Implementation:** Apache Kafka, Azure Event Hubs와 같은 데이터 스트리밍 플랫폼을 사용하여 수백만 개의 IoT 센서 데이터를 수집하는 파이프라인을 구축하고, 다양한 스트림 프로세서로 전달한다 [1].
|
||||
- **System Design:** 소비자가 이벤트를 수신하더라도 큐에서 삭제하지 않는 '내구성 있는 로그(durable log)' 시스템을 설계하여, 특정 컴포넌트 장애 시 로그를 다시 읽어 시스템 상태를 안전하게 복구할 수 있도록 구성한다 [3].
|
||||
- **Operation / Maintenance:** 버그가 배포된 후 발견되었을 때, 수정된 코드를 배포한 다음 스트림의 읽기 포인터를 과거로 되돌려(Replay) 영향을 받은 이벤트들을 재처리하는 방식으로 운영 사고에 대처한다 [3].
|
||||
- **Learning Path:** 분산 시스템의 기본 개념 이해 -> 비동기 메시징 및 Event-Driven Architecture 통신 패턴 학습 -> Queue 모델과 Stream 모델 비교 -> Event Sourcing 및 스트림 분석(CEP) 심화 적용 [2, 6, 10, 13].
|
||||
- **My Project Relevance:** 고용량의 실시간 클릭스트림 데이터를 수집해야 하는 e-커머스 플랫폼, 또는 지속적으로 위치 및 상태 정보를 쏟아내는 운송 시스템(예: 차량 호출 앱)의 백엔드 실시간 분석 파이프라인 구축에 적용 가능하다 [1].
|
||||
|
||||
### Adjacent Topics
|
||||
|
||||
- `[[Microservices Architecture]]`
|
||||
- 확장 방향: 마이크로서비스 간 느슨한 결합을 구현하고 데이터 일관성을 맞추기 위해 이벤트 스트리밍 및 비동기 메시지 패싱(Async Message Passing)을 사용하는 전략으로의 확장 [7, 14].
|
||||
- `[[CQRS (Command Query Responsibility Segregation)]]`
|
||||
- 확장 방향: 이벤트 스트림(이벤트 소싱)을 커맨드 모델로 저장한 뒤, 여러 개의 뷰(Read Model)로 투영하기 위해 상태를 동기화하는 구조적 패턴 연구 [15, 16].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
await producer.connect();
|
||||
await producer.send({
|
||||
topic: "orders",
|
||||
messages: [{
|
||||
key: order.id,
|
||||
value: JSON.stringify(order),
|
||||
headers: { "event-time": Date.now().toString() },
|
||||
}],
|
||||
});
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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");
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
orders
|
||||
.keyBy(o -> o.userId)
|
||||
.window(TumblingEventTimeWindows.of(Time.minutes(1)))
|
||||
.aggregate(new OrderCountAgg())
|
||||
.sinkTo(new MetricsSink());
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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");
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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;
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
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;
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]]
|
||||
- 변형: [[Batch Processing]] · [[Lambda Architecture]] · [[Kappa Architecture]]
|
||||
- 응용: [[Real-time Analytics]] · [[Change Data Capture (CDC)]] · [[Feature Store]]
|
||||
- Adjacent: [[Apache Kafka]] · [[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 |
|
||||
|
||||
@@ -2,173 +2,175 @@
|
||||
id: wiki-2026-0508-event-storming
|
||||
title: Event Storming
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [EventStorming, DDD discovery workshop]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
verification_status: applied
|
||||
tags: [ddd, modeling, workshop, architecture, discovery]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: methodology
|
||||
framework: ddd
|
||||
---
|
||||
|
||||
# [[Event Storming|Event Storming]] (이벤트 폭풍 분석)
|
||||
# Event Storming
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> 비즈니스 워크플로우를 구성하는 '사건(Event)'을 중심으로 시스템의 경계, 행위자, 흐름을 시각적으로 모델링하여, 분산 시스템 및 메시징 기반 아키텍처 설계의 초석을 다지는 기법이다.
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
이벤트 스토밍(Event Storming)은 비즈니스 도메인을 깊이 탐색하기 위해 설계된 협업 워크샵 기법입니다 [1]. 개발팀과 도메인 전문가가 함께 참여하여 소프트웨어 모델의 기반이 되는 도메인 이벤트, 명령(commands), 애그리거트(aggregates)를 신속하게 식별할 수 있도록 돕습니다 [1]. 이 기법은 복잡한 시스템 아키텍처를 비즈니스 구조에 맞게 정렬하는 도메인 주도 설계(DDD)의 핵심 실천 방안 중 하나입니다 [1, 2].
|
||||
### 매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **정의:** 비즈니스 도메인의 활동을 '사건(Event)'이라는 관찰 가능한 사실들의 집합으로 바라보고, 이를 시각적 워크숍 형태로 모델링하는 방법론. 시스템 설계에 필요한 모든 상호작용을 이벤트 중심으로 재구성한다.
|
||||
- **주요 구성 요소 (The Grid):**
|
||||
1. **[[Events|Events]] (사건):** 과거에 *일어난* 사실의 기록 (가장 중요). 예: `OrderPlaced`, `UserRegistered`.
|
||||
2. **Commands (명령):** 시스템에게 *무엇을 해야 하는지* 지시하는 행위. 예: `PlaceOrder`, `RegisterUser`.
|
||||
3. **Aggre[[Gates|Gates]]/Services:** 비즈니스 로직이 묶여서 수행되는 주체.
|
||||
4. **Participants:** 이벤트를 발생시키거나 명령을 내리는 사람 또는 시스템 액터.
|
||||
- **아키텍처적 의의:** 이벤트 스트리밍(Event Streaming) 기반 아키텍처 (EDA) 설계에 최적화되어 있으며, 이는 마이크로서비스 간의 비동기 통신 패턴을 정의하는 데 결정적인 역할을 한다.
|
||||
### 매 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.
|
||||
|
||||
* **도메인 주도 설계(DDD)의 실질적 구현 기법:** 이벤트 스토밍은 복잡한 비즈니스 규칙을 중심에 두는 도메인 주도 설계(Domain-Driven Design)를 실무에 효과적으로 적용하기 위한 도구로 활용됩니다 [1, 2].
|
||||
* **공동의 비즈니스 이해 도모:** 개발자, 아키텍트, 도메인 전문가 등 다양한 프로젝트 이해관계자들이 모여 협업하는 워크샵의 형태로 진행되며, 이를 통해 비즈니스 도메인에 대한 공통된 이해를 구축합니다 [1].
|
||||
* **핵심 아키텍처 요소의 신속한 식별:** 워크샵 과정을 거치며 시스템 아키텍처의 뼈대가 되는 '도메인 이벤트(domain events)', 시스템에 조작을 가하는 '명령(commands)', 그리고 데이터와 로직의 군집 단위인 '애그리거트(aggregates)'를 신속하게 파악할 수 있습니다 [1].
|
||||
* **견고한 모델링의 기반 제공:** 비즈니스 도메인에 대한 탐색 결과는 추후 견고하고 유지보수 가능한 도메인 모델을 구축하는 데 필수적인 기반 지식을 제공합니다 [1].
|
||||
### 매 응용
|
||||
1. Greenfield DDD design — 매 aggregate / bounded context discovery.
|
||||
2. Legacy understanding — 매 domain knowledge 의 surface.
|
||||
3. Microservice decomposition — 매 service boundary 의 inform.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 이벤트 중심 설계(Event-Driven [[Architecture|Architecture]], EDA)가 곧 모든 것을 해결한다는 오해를 경계해야 한다. 이벤트를 중심으로 시스템을 모델링하는 것이지, 실제로 모든 통신이 메시징 큐로 이루어져야 하는 것은 아니다.
|
||||
- **정책 변화:** Event Sourcing 패턴과 결합될 때 가장 강력하며, 시간의 흐름에 따른 상태 변화 기록(Audit Log)을 시스템의 핵심 데이터로 활용할 수 있게 된다.
|
||||
## 💻 패턴
|
||||
|
||||
---
|
||||
### 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[];
|
||||
}
|
||||
|
||||
소스에 관련 정보가 부족합니다. (단, 이벤트 스토밍이 근간으로 삼는 도메인 주도 설계(DDD)의 특성상 도메인 전문가의 필수적인 참여와 깊이 있는 도메인 모델링을 위한 분석 시간 투자가 요구되며, 도입 과정에서 상대적으로 높은 구현 복잡성(Implementation Complexity)을 수반한다는 점이 한계 또는 반대 급부로 작용할 수 있습니다 [2].)
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- Parent: [[Event Storming|Event Storming]]
|
||||
- Related: [[Microservices-Architecture|Microservices-Architecture]] ,[[_system|system]] Dynamics , Saga Pattern
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- [[Domain_Driven_Design]]: 이벤트 스토밍을 통해 구현하고자 하는 설계 철학.
|
||||
- [[DDD_Aggregates]]: 이벤트 스토밍에서 도출된 핵심 데이터 관리 단위.
|
||||
- [[Event_Driven_Architecture]]: 도메인 이벤트를 물리적으로 구현하는 아키텍처 스타일.
|
||||
|
||||
---
|
||||
|
||||
### Related Concepts
|
||||
|
||||
#### [설계 패러다임/아키텍처]
|
||||
- [[Domain-Driven Design (DDD)]]
|
||||
- 연결 이유: 이벤트 스토밍은 복잡한 시스템의 비즈니스 도메인을 파악하고 DDD를 구축하기 위해 직접적으로 사용되는 워크샵 기법이기 때문입니다 [1].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 바운디드 컨텍스트(Bounded Context)와 유비쿼터스 언어(Ubiquitous Language)를 통해 대규모 코드베이스의 비즈니스 논리를 해독하는 방법 [3-6].
|
||||
|
||||
- [[Event-Driven Architecture]]
|
||||
- 연결 이유: 이벤트 스토밍을 통해 도출되는 '도메인 이벤트'는 이벤트 기반 아키텍처(EDA)에서 시스템 컴포넌트 간 비동기적 통신을 트리거하는 기준 요소로 발전할 수 있기 때문입니다 [1, 7, 8].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 컴포넌트 간 결합도를 낮추고 비동기적으로 메시지를 주고받는 시스템의 데이터 흐름 [7, 8].
|
||||
|
||||
#### [설계 요소/모델링 단위]
|
||||
- [[Aggregates (애그리거트)]]
|
||||
- 연결 이유: 이벤트 스토밍 과정에서 도메인 이벤트, 명령과 함께 필수적으로 도출되어야 하는 핵심 도메인 객체의 논리적 그룹이기 때문입니다 [1, 4].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 복잡한 코드베이스 내에서 일관성을 유지해야 하는 데이터와 비즈니스 로직의 트랜잭션 경계 설정 방식 [4].
|
||||
|
||||
### Deeper Research Questions
|
||||
- 이벤트 스토밍 워크샵 내에서 식별된 '도메인 이벤트(Domain Events)'와 '명령(Commands)'은 어떤 과정을 거쳐 실제 코드베이스의 구조로 매핑되는가?
|
||||
- 대규모 코드베이스(모놀리식 아키텍처 등)를 분석하고 마이크로서비스로 분리할 때, 이벤트 스토밍은 구체적으로 어떤 시각적·논리적 기준을 제공하는가?
|
||||
- 소스에 관련 정보가 부족하지만, 이벤트 스토밍을 진행할 때 기술적 배경이 없는 도메인 전문가와 개발자 간의 원활한 소통을 이끄는 퍼실리테이션(Facilitation) 전략은 무엇인가?
|
||||
- 코드베이스를 역분석(상향식 접근)하여 기존 시스템의 이벤트와 애그리거트를 추출하는 '리버스 이벤트 스토밍' 기법이 존재하는가?
|
||||
- 도메인 주도 설계(DDD)가 적용되지 않은 기존 레거시 시스템을 이해하는 데에도 이벤트 스토밍의 개념적 도구를 적용할 수 있는가?
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 소스에 관련 정보가 부족합니다.
|
||||
- **System Design:** 소프트웨어 설계 초기 단계에 비즈니스 도메인을 탐구하고, 이를 기반으로 데이터 모델 및 시스템 아키텍처의 탄탄한 토대를 마련하기 위한 공동 워크샵 형태로 활용됩니다 [1].
|
||||
- **Operation / Maintenance:** 소스에 관련 정보가 부족합니다.
|
||||
- **Learning Path:** 낯선 대규모 코드베이스를 읽기 전, 비즈니스 용어와 워크플로우를 빠르게 습득하기 위한 도메인 지식 획득 과정으로 유용하게 활용할 수 있습니다 [1, 3].
|
||||
- **My Project Relevance:** 소스에 관련 정보가 부족합니다.
|
||||
|
||||
### Adjacent Topics
|
||||
- [[Ubiquitous Language (유비쿼터스 언어)]]
|
||||
- 확장 방향: 도메인 전문가와 개발자 사이의 소통 격차를 줄이고, 대화에 사용되는 용어를 코드베이스(변수, 클래스 명 등)에 그대로 반영하여 코드 가독성을 극대화하는 방법 [1, 3, 9].
|
||||
- [[Bounded Context (바운디드 컨텍스트)]]
|
||||
- 확장 방향: 방대한 도메인을 논리적 단위로 쪼개어 개별적인 모델과 언어를 갖도록 시스템 경계를 명확히 분리함으로써 코드베이스의 복잡도를 낮추는 기법 [4-6].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
|
||||
## 1. 개요
|
||||
이벤트 스토밍(Event Storming)은 비즈니스 도메인을 깊이 탐색하고 복잡한 시스템의 구조를 식별하기 위한 협업 워크샵 기법이다. 개발자, 아키텍트, 도메인 전문가가 함께 참여하여 서비스의 흐름을 시각화하고, 도메인 이벤트(Domain Events), 명령(Commands), 애그리거트(Aggregates) 등 핵심 설계 요소를 신속하게 도출하는 데 최적화되어 있다.
|
||||
|
||||
## 2. 워크샵 구성 요소
|
||||
- **도메인 이벤트 (Orange Card)**: 비즈니스에서 발생한 과거 시점의 중요한 사건. 시스템의 상태 변화를 나타냄.
|
||||
- **명령 (Blue Card)**: 사용자의 의도나 시스템에 의해 발생하는 동작. 이벤트를 트리거함.
|
||||
- **애그리거트 (Yellow Card)**: 명령을 받아 이벤트를 생성하는 데이터와 로직의 군집(트랜잭션의 단위).
|
||||
- **액터/사용자 (Small Yellow)**: 명령을 수행하는 주체.
|
||||
- **정책 (Lilac Card)**: 이벤트가 발생했을 때 자동으로 실행되는 반응 로직.
|
||||
|
||||
## 3. 실전 적용 가치
|
||||
- **비즈니스-기술 싱크로**: 도메인 전문가의 지식을 개발자가 즉각적으로 이해하고 모델링에 반영 가능.
|
||||
- **병목 지점 식별**: 전체 프로세스를 시각화하는 과정에서 비즈니스상의 비효율이나 병목 지점을 자연스럽게 발견.
|
||||
- **아키텍처 설계의 뼈대**: 도출된 이벤트와 애그리거트는 바운디드 컨텍스트를 정의하고 마이크로서비스 경계를 나누는 결정적 근거가 됨.
|
||||
|
||||
## 4. 트레이드오프 및 주의사항
|
||||
- **장점**: 짧은 시간 내에 복잡한 도메인에 대한 공통 멘탈 모델 형성.
|
||||
- **단점**: 도메인 전문가의 적극적인 참여 없이는 반쪽짜리 결과가 나올 수 있으며, 대규모 인원이 참여할 경우 퍼실리테이션 역량이 중요함.
|
||||
- **주의**: 시각화된 결과물에만 집중하지 말고, 그 과정에서 오가는 '대화'와 '보편적 언어'의 확립을 최우선으로 할 것.
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
- **정보 상태**: 검증 완료 (Verified)
|
||||
- **출처 신뢰도**: A
|
||||
- **검토 이유**: 도메인 모델링과 시스템 설계를 위한 실천적인 협업 프레임워크 표준 정립.
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
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"] },
|
||||
];
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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 };
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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);
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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.
|
||||
}
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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:[] }.
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
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
|
||||
- 부모: [[Domain-Driven Design (DDD)]] · [[Software Modeling]]
|
||||
- 변형: [[Example Mapping]] · [[Domain Storytelling]]
|
||||
- 응용: [[Bounded Context]] · [[Aggregate Design]] · [[CQRS]]
|
||||
- Adjacent: [[Event Sourcing]] · [[User Story Mapping]] · [[C4 Model]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -2,127 +2,186 @@
|
||||
id: wiki-2026-0508-eventual-consistency
|
||||
title: Eventual Consistency
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-60B39197]
|
||||
aliases: [Eventual Consistency, BASE, AP System]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [eventual-consistency, microservices-architecture, event-driven-architecture, saga-pattern, cqrs, architecture-principles]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [distributed-systems, database, consistency, cap]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-02
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: sql
|
||||
framework: cassandra
|
||||
---
|
||||
|
||||
# [[Eventual Consistency]]
|
||||
# Eventual Consistency
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
Eventual Consistency(최종 일관성)는 분산 시스템 내 여러 서비스나 데이터 저장소에 걸쳐 데이터가 즉각적으로 일치하지 않더라도, 일정 시간(지연 시간)이 지나면 결국 모든 데이터가 동일한 상태에 도달하게 되는 모델입니다 [1, 2]. 주로 이벤트 기반 아키텍처(EDA)나 마이크로서비스 아키텍처(MSA)에서 각 서비스의 독립성과 비동기 통신을 지원하기 위해 사용됩니다 [1, 3]. 이는 가용성(Availability)과 파티션 허용성(Partition Tolerance)을 확보하기 위해 강력한 일관성을 의도적으로 양보하는 아키텍처적 트레이드오프(Trade-off) 전략입니다 [1, 4].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **비동기 처리와 상태 지연**: 생산자(Producer)와 소비자(Consumer)가 비동기 이벤트 채널을 통해 분리되어 있기 때문에, 생산자가 상태 변경을 방출한 시점과 소비자가 그 변경을 반영하는 시점 사이에 측정 가능한 지연(Delay)이 발생합니다 [1]. 예를 들어, 전자상거래 시스템에서는 이 지연으로 인해 주문 상태가 일시적으로 '대기 중(pending)'으로 표시될 수 있습니다 [5].
|
||||
- **의도적인 설계적 타협 (가용성 우선)**: 시스템의 서로 다른 부분들이 특정 순간에 데이터 상태에 대해 상이한 관점(view)을 가질 수 있지만, 이는 오류가 아니라 의도적인 설계의 결과입니다 [1]. 아키텍트들은 시스템 전체의 가용성과 성능을 높이기 위해 특정 워크플로우에 최종 일관성을 채택하며, 데이터 소비자와 하위 시스템이 이러한 지연되거나 부분적으로 업데이트된 데이터를 허용(tolerate)할 수 있도록 설계해야 합니다 [1].
|
||||
- **분산 환경 구현 패턴의 기반**: 마이크로서비스 환경에서 느슨한 결합을 유지하려면 각 서비스가 고유한 데이터베이스를 가져야 하므로, 기존의 단일 데이터베이스 기반 ACID 트랜잭션을 적용하기 어렵습니다 [2, 3]. 대신 이벤트 소싱(Event Sourcing), CQRS, Saga 패턴과 같은 분산 트랜잭션 관리 기법을 활용하여 시스템 전반의 최종 일관성을 구현합니다 [2, 3, 6].
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **구현 및 테스트의 높은 복잡성**: 기존 동기식(CRUD/ACID) 사고방식에서 벗어나 여러 데이터 저장소 간의 트랜잭션과 비동기 이벤트를 조정해야 하므로 시스템 구현, 디버깅, 테스트의 난이도가 크게 상승합니다 [2, 7, 8].
|
||||
- **데이터 불일치 윈도우 발생**: 데이터가 동기화되기 전까지 밀리초 단위의 지연이나 일시적인 데이터 불일치가 필연적으로 발생합니다 [1, 9]. 따라서 잔액이 즉각적이고 정확하게 반영되어야 하는 은행의 금융 트랜잭션처럼 강력한 일관성(Strong Consistency)이 요구되는 시스템에는 이 모델의 사용을 피해야 합니다 [10, 11].
|
||||
- **상태 관리 및 오류 처리의 한계**: 비동기 통신 중 구성 요소 간 이벤트 전달이 실패하거나 순서가 뒤바뀔 수 있으며, 이를 처리하기 위해 오류 핸들러나 재시도(Retry) 메커니즘, 데드 레터 큐(DLQ) 등의 추가적인 설계가 필요하여 인프라 및 운영 오버헤드가 발생합니다 [1].
|
||||
### 매 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
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
### 매 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
|
||||
|
||||
#### [아키텍처 패턴 / 스타일]
|
||||
- [[Microservices Architecture]]
|
||||
- 연결 이유: MSA는 각 서비스가 독립된 데이터베이스를 소유하는 원칙을 따르기 때문에, 서비스 간 데이터 동기화를 위해 최종 일관성 도입이 필수적입니다 [2, 3].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 최종 일관성이 왜 현대의 분산된 서비스 환경에서 불가피한 선택이 되었는지 구조적 원인을 제공합니다.
|
||||
- [[Event-Driven Architecture]]
|
||||
- 연결 이유: 컴포넌트 간에 비동기적으로 이벤트를 생산하고 소비하는 구조적 특성상 데이터의 상태 변경이 순차적으로 퍼져나가며 최종 일관성을 형성합니다 [1].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 최종 일관성이 비동기 메시징 및 통신 채널을 통해 어떻게 물리적으로 구현되고 지연(Latency)을 유발하는지 파악할 수 있습니다.
|
||||
### 매 응용
|
||||
1. DNS (TTL-based eventual).
|
||||
2. CDN cache invalidation.
|
||||
3. Social media feed (read-your-writes는 보장).
|
||||
4. Shopping cart (Amazon Dynamo paper).
|
||||
|
||||
#### [구현 및 설계 패턴]
|
||||
- [[Saga Pattern]]
|
||||
- 연결 이유: 분산된 마이크로서비스 환경에서 최종 일관성을 달성하기 위해 ACID 트랜잭션 대신 연속된 로컬 트랜잭션과 보상(Compensation) 작업으로 비즈니스 로직을 처리하는 패턴입니다 [2, 12].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 최종 일관성 환경에서 트랜잭션 실패 시 시스템이 어떻게 오류를 복구하고 데이터 일관성을 회복하는지 구체적인 메커니즘을 배울 수 있습니다.
|
||||
- [[CQRS]]
|
||||
- 연결 이유: 데이터의 읽기(Query) 모델과 쓰기(Command) 모델을 분리하여 각각 최적화할 때, 쓰기 내용이 읽기 모델로 동기화되는 과정에서 필연적으로 최종 일관성이 발생합니다 [6, 13].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 읽기와 쓰기의 성능을 비대칭적으로 확장하는 과정에서 데이터 지연(Lag)이 어떻게 아키텍처 내에서 처리되는지 이해할 수 있습니다.
|
||||
- [[ACID Transactions]]
|
||||
- 연결 이유: 전통적인 관계형 데이터베이스에서 보장하는 강력한 일관성 속성으로, 최종 일관성 모델과 대비되는 핵심 개념입니다 [2, 3].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 시스템 설계 시 강력한 일관성과 최종 일관성 중 어느 것을 선택해야 하는지에 대한 트레이드오프 기준을 제공합니다.
|
||||
## 💻 패턴
|
||||
|
||||
### Deeper Research Questions
|
||||
- 마이크로서비스 환경에서 최종 일관성을 수용할 때, Saga 패턴은 실패한 트랜잭션을 롤백(Rollback)하기 위해 보상(Compensating) 트랜잭션을 어떻게 조율하는가?
|
||||
- 실시간으로 강력한 일관성이 필수적인 금융 시스템에서 마이크로서비스와 최종 일관성 개념을 혼합(Hybrid)하여 안전성을 확보하는 아키텍처적 전략은 무엇인가?
|
||||
- CQRS 패턴 적용 시, 쓰기 데이터베이스에서 읽기 데이터베이스로 상태가 동기화되는 지연 시간 동안 사용자 경험(UX) 저하를 방지하기 위해 프론트엔드와 백엔드는 어떻게 협력해야 하는가?
|
||||
- 비동기 환경의 최종 일관성 모델 하에서 메시지 순서가 뒤섞이거나 중복 수신될 경우, 멱등성(Idempotence)을 보장하기 위해 소비자를 어떻게 설계해야 하는가?
|
||||
- 분산 시스템 전반에 걸친 비동기 데이터 불일치 및 통신 장애를 추적하기 위해 상관 ID(Correlation ID) 및 분산 트레이싱을 어떻게 효과적으로 구현할 수 있는가?
|
||||
### Cassandra tunable consistency
|
||||
```python
|
||||
from cassandra.cluster import Cluster
|
||||
from cassandra import ConsistencyLevel
|
||||
from cassandra.query import SimpleStatement
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 각각 다른 데이터베이스를 사용하는 여러 마이크로서비스가 비동기 메시징(예: Kafka, RabbitMQ)을 통해 이벤트를 주고받으며 각자의 데이터를 점진적으로 업데이트하도록 코드를 구현할 때 적용됩니다 [8, 14].
|
||||
- **System Design:** 아키텍트는 결제 승인과 같이 즉각적이고 강력한 일관성이 필요한 워크플로우와, 이메일 알림 전송과 같이 파티션 허용성과 가용성을 위해 최종 일관성을 허용할 수 있는 워크플로우를 분리하여 시스템을 설계해야 합니다 [1].
|
||||
- **Operation / Maintenance:** 비동기 이벤트 환경에서는 오류가 발생해도 시스템이 즉각 정지하지 않으므로, 데드 레터 큐(DLQ) 모니터링 및 로깅 시스템(상관 ID 사용)을 통한 분산 트레이싱으로 이벤트 지연 및 불일치 지점을 상시 추적해야 합니다 [1, 15].
|
||||
- **Learning Path:** 전통적인 RDBMS 및 ACID 트랜잭션의 이해 -> 모놀리식에서 분산 시스템(MSA)으로의 전환 이유 학습 -> 이벤트 기반 아키텍처(EDA) 설계 -> 최종 일관성, CQRS, Event Sourcing 등 심화 패턴 습득 순으로 학습합니다.
|
||||
- **My Project Relevance:** 글로벌 전자상거래 플랫폼, 소셜 미디어 피드 갱신, IoT 데이터 수집 등 실시간 100% 동기화보다 끊김 없는 서비스 가용성과 대규모 트래픽 처리가 더 중요한 대규모 분산 프로젝트 기획 시 핵심 근간이 됩니다.
|
||||
cluster = Cluster(['node1', 'node2', 'node3'])
|
||||
session = cluster.connect('myapp')
|
||||
|
||||
### Adjacent Topics
|
||||
- [[Distributed Tracing]]
|
||||
- 확장 방향: 최종 일관성을 갖는 여러 비동기 서비스에 걸친 하나의 논리적 트랜잭션 흐름을 상관 ID(Correlation ID) 등으로 추적하고 디버깅하는 운영 기술 관점으로 확장 [15].
|
||||
- [[Event Sourcing]]
|
||||
- 확장 방향: 데이터의 최종 상태를 저장하는 대신 모든 상태 변경 이벤트를 순차적으로 로깅하여 영속성을 부여함으로써, 과거 상태로의 복원 및 최종 일관성 구현을 돕는 데이터 관리 패턴 관점으로 확장 [16, 17].
|
||||
# 매 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))
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
# 매 R + W > N → strong consistency
|
||||
# 매 R=1, W=1, N=3 → eventual
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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)
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Read-your-writes (sticky session)
|
||||
```nginx
|
||||
upstream backend {
|
||||
ip_hash; # 매 same client → same backend → reads see own writes
|
||||
server backend1;
|
||||
server backend2;
|
||||
server backend3;
|
||||
}
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### Hinted Handoff (Cassandra)
|
||||
```yaml
|
||||
# cassandra.yaml
|
||||
hinted_handoff_enabled: true
|
||||
max_hint_window_in_ms: 10800000 # 매 3 hours
|
||||
# 매 down node 회복 시 hint replay → eventual consistency 보장
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]]
|
||||
- 변형: [[Strong Consistency]] · [[Causal Consistency]] · [[Read-Your-Writes]]
|
||||
- 응용: [[DynamoDB]] · [[Cassandra]] · [[CRDT]] · [[Riak]]
|
||||
- Adjacent: [[Vector Clock]] · [[Quorum]] · [[Anti-Entropy]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -2,109 +2,32 @@
|
||||
id: wiki-2026-0508-evolutionary-computation
|
||||
title: Evolutionary Computation
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
canonical_id: self
|
||||
status: duplicate
|
||||
canonical_id: evolutionary-biology
|
||||
duplicate_of: "[[Evolutionary Biology]]"
|
||||
aliases: []
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, evolutionary-algorithms]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
---
|
||||
|
||||
# [[Evolutionary Computation|Evolutionary Computation]] (진화 연산)
|
||||
# Evolutionary Computation
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> "생물 진화의 원리를 빌려와 가장 효율적인 해답을 찾아내는 디지털 적자생존." 자연의 진화 과정(선택, 교차, 변이)을 모방하여 복잡한 최적화 문제를 해결하는 휴리스틱 기반 인공지능 기법이다.
|
||||
> **이 문서는 [[Evolutionary Biology]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
---
|
||||
## 핵심 요약 (specialization aspects)
|
||||
- Evolutionary Computation 매 computational application 의 evolutionary principles — GA, GP, ES, NEAT.
|
||||
- Evolutionary Biology 매 biological substrate.
|
||||
- 매 wiki 매 Evolutionary Biology canonical 의 use, 매 computational variant 의 sub-section 의 cover.
|
||||
|
||||
> "생존에 유리한 코드를 남기고 진화시켜 전역 최적해를 향한 지름길을 찾아라" — 다윈의 진화론에서 영감을 얻어, 후보 해들의 집단(Population)을 생성하고 교배와 돌연변이를 거쳐 세대를 거듭하며 해의 품질을 높여가는 확률적 최적화 알고리즘.
|
||||
## 🔗 Graph
|
||||
- 부모: [[Evolutionary Biology]] (canonical)
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **Genetic Algorithm (GA)**: 염색체 연산을 통해 최적 해를 탐색하는 가장 대중적인 방식.
|
||||
- **Evolutionary Strategies (ES)**: 실수 값 벡터 최적화에 특화된 접근.
|
||||
- **Fitness Function**: 개체가 얼마나 문제 해결에 적합한지를 평가하는 척도.
|
||||
- **Mutation & Crossover**: 지역 최적점(Local Minima)에 빠지지 않게 하고 새로운 탐색 영역을 넓히는 핵심 메커니즘.
|
||||
|
||||
---
|
||||
|
||||
- **추출된 패턴:** 목표 지점에 도달하기 위해 수학적 경사(Gradient)를 따라가는 대신, 무작위성을 가미한 탐색과 적자생존의 원칙을 결합하여 지역 최적해(Local Minima)를 돌파하는 진화적 탐색 패턴.
|
||||
- **주요 구성 요소:**
|
||||
- **Selection:** 적합도(Fitness)가 높은 우수한 해를 다음 세대의 부모로 선택.
|
||||
- **Crossover (Recombination):** 부모 해들의 특징을 결합하여 새로운 자손 생성.
|
||||
- **Mutation:** 무작위 변화를 주어 집단의 다양성을 유지하고 탐색 공간 확장.
|
||||
- **Fitness Landscape:** 해의 품질이 분포된 지형을 탐험하며 정상을 찾는 과정.
|
||||
- **의의:** 미분 불가능한 비선형 문제, 다목적 최적화, 신경망 구조 탐색(NAS) 등 광범위한 분야에서 활용.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- 딥러닝의 역전파([[Backpropagation|Backpropagation]]) 방식은 미분 가능한 함수에서만 작동하지만, 진화 연산은 '미분 불가능하거나 블랙박스 형태'의 최적화 문제에서도 강력한 위력을 발휘한다. 최근에는 신경망의 구조 자체를 진화시키는 '[[Neuroevolution|Neuroevolution]]'과 강화학습의 대안으로 대두되며 다시 주목받고 있다.
|
||||
|
||||
---
|
||||
|
||||
- **과거 데이터와의 충돌:** 초기에는 연산량이 많아 비효율적인 방식으로 여겨졌으나, 병렬 컴퓨팅의 발달과 신경망과의 결합([[Neuroevolution|Neuroevolution]])을 통해 다시 주목받음.
|
||||
- **정책 변화:** Antigravity 프로젝트는 에이전트의 전략 수립 모델 최적화 시, 강화학습과 진화 연산을 결합하여 안정성과 탐색 능력의 균형을 맞춤.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- Related: [[Optimization-Algorithms|Optimization-Algorithms]] , [[Genetic-Algorithms|Genetic-Algorithms]]
|
||||
- AI Context: [[Reinforcement-Learning|Reinforcement-Learning]]-vs-[[Evolutionary-Computation|Evolutionary-Computation]]
|
||||
|
||||
---
|
||||
|
||||
- [[Genetic-Algorithms|Genetic-Algorithms]], [[Black-Box-Optimization|Black-Box-Optimization]], Neural-Architecture-Search-NAS, [[Neural-Darwinism|Neural-Darwinism]]
|
||||
- **Raw Source:** 10_Wiki/Topics/AI/Evolutionary-Computation.md
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
|
||||
@@ -2,206 +2,157 @@
|
||||
id: wiki-2026-0508-excess-property-checking
|
||||
title: Excess Property Checking
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [TypeScript Excess Property, Strict Object Literal]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [typescript, type-system, structural-typing]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: none
|
||||
---
|
||||
|
||||
# [[Excess Property Checking|Excess Property Checking]]
|
||||
# Excess Property Checking
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> TypeScript의 Excess Property Checking(과잉 속성 체크)은 객체 리터럴이 다른 변수에 할당되거나 함수의 인수로 전달될 때 예상치 못한 초과 속성을 감지하고 타입 에러를 표출하는 기능이다 [1-3]. 이는 TypeScript의 기본 동작인 구조적 타이핑([[Structural Typing|Structural Typing]]) 규칙을 더 엄격하게 적용하는 예외적인 사례로 볼 수 있다 [1]. 개발자가 속성 이름에 오타를 내는 등의 실수로 인해 발생할 수 있는 의도치 않은 런타임 오류를 방지하기 위해 존재한다 [4-6].
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
> "너 정체가 뭐야? 시키지 않은 건 하지 마." 객체 리터럴을 변수에 할당하거나 함수 인자로 전달할 때, 정의되지 않은 추가 속성이 포함되어 있으면 타입 에러를 발생시켜 오타나 실수(Mistyping)를 방지하는 TypeScript의 안전장치다.
|
||||
### 매 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.
|
||||
|
||||
> TypeScript의 과잉 속성 체크(Excess Property Checking, EPC)는 객체 리터럴이 다른 변수에 직접 할당되거나 함수의 인자로 전달될 때, 대상 타입에 정의되지 않은 속성이 포함되어 있는지를 엄격하게 검사하는 기능이다[1-4]. 이는 구조적 타이핑([[Structural Typing|Structural Typing]])의 유연함으로 인해 속성 이름의 오타나 잘못된 데이터가 유입되어 발생하는 런타임 오류를 컴파일 시점에 방지하는TypeScript의 핵심 방어 기제로 작동한다[5-7].
|
||||
### 매 응용
|
||||
1. React props typo detection.
|
||||
2. Config object validation.
|
||||
3. API request body shape enforcement.
|
||||
4. Discriminated union narrowing aid.
|
||||
|
||||
---
|
||||
## 💻 패턴
|
||||
|
||||
> 과잉 속성 체크(Excess Property Checking)는 TypeScript에서 객체 리터럴을 다른 변수에 직접 할당하거나 함수의 인자로 전달할 때, 예상치 못한(정의되지 않은) 잉여 속성이 포함되어 있는지 엄격하게 검사하여 에러를 발생시키는 기능입니다 [1-4]. 구조적 타이핑의 유연성 속에서 발생할 수 있는 오타나 잘못된 속성 전달 실수를 컴파일 시점에 포착하여 런타임 오류를 방지하는 첫 번째 방어선 역할을 합니다 [5-7].
|
||||
|
||||
---
|
||||
|
||||
> 초과 속성 검사(Excess Property Checking)는 TypeScript에서 객체 리터럴을 다른 변수에 직접 할당하거나 함수의 인수로 전달할 때, 예상치 못한(정의되지 않은) 속성이 객체에 포함되어 있는지 감지하여 에러를 발생시키는 기능입니다 [1-5]. 이는 개발자가 속성 이름에 오타를 내거나 잘못된 속성을 전달하는 실수를 방지하여 의도치 않은 런타임 동작을 막기 위해 존재합니다 [6-8]. 하지만 객체를 중간 변수에 먼저 할당한 후 전달하면 구조적 타이핑의 원칙에 따라 이 검사를 우회하게 되는 특징이 있습니다 [6, 9, 10].
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **동작 원리와 목적**
|
||||
TypeScript의 타입 시스템은 기본적으로 객체가 요구되는 최소한의 속성만 가지고 있다면 호환성을 허용하는 구조적 타이핑(Structural Typing, 일명 덕 타이핑)을 따른다 [7-9]. 그러나 대상 타입에 직접 객체 리터럴을 할당하거나 함수의 인자로 객체 리터럴을 넘길 때는 특별히 Excess Property Checking이 발동하여 선언되지 않은 잉여 속성이 있는지 엄격하게 검사한다 [1, 3, 6, 10-12]. 이는 개발자가 초과 속성을 전달하려는 의도가 없을 것이라고 가정하여 오타(예: `color` 대신 `colour`) 등의 실수를 컴파일 시점에 포착하기 위함이다 [4-6, 9].
|
||||
|
||||
* **한계점 및 우회 문제**
|
||||
Excess Property Checking은 객체 리터럴을 중간 변수(intermediate variable)에 먼저 할당한 뒤 다른 변수나 인수로 전달할 경우에는 작동하지 않는다는 맹점이 있다 [1, 3, 4, 12, 13]. 중간 변수를 사용할 때 대상 타입과 최소 하나의 속성이라도 일치한다면, TypeScript는 초과 속성이 있더라도 에러를 발생시키지 않는다 [14]. (만약 공통 속성이 하나도 없다면 '약한 타입 검사(Weak Type Detection)' 규칙에 의해 에러가 발생한다 [3, 15]). 또한 명시적인 반환 타입 어노테이션이 없는 문맥적인 할당에서도 에러를 제대로 잡아내지 못하는 한계가 보고된 바 있다 [16].
|
||||
|
||||
* **보완 전략 (`satisfies` 및 커스텀 타입)**
|
||||
객체 리터럴을 중간 변수를 통해 전달하면서 발생하는 우회 문제를 극복하기 위해 TypeScript 4.9에서 도입된 `satisfies` 연산자를 활용할 수 있다 [17, 18]. `satisfies` 연산자는 객체의 구체적인 값 형태를 유지하면서도 대상 타입에 정의되지 않은 초과 속성을 엄격히 걸러내어 타입 안전성을 보장한다 [18-21]. 또한, 제네릭과 `never` 타입을 결합하여 대상 인터페이스와 실제 입력을 비교하고 잉여 속성을 잡아내는 재귀적 유틸리티 타입을 만들어 수동으로 초과 속성을 찾아낼 수도 있지만, 이는 타입 검사 성능에 부정적인 영향을 미칠 수 있어 주의해서 사용해야 한다 [22-24].
|
||||
|
||||
---
|
||||
|
||||
- **Object Literal Restriction**: 변수에 미리 담지 않고 직접 `{...}` 형태로 넘길 때만 발동함.
|
||||
- **[[Structural Typing|Structural Typing]] Exception**: TypeScript는 기본적으로 구조적 타이핑을 따르지만, 리터럴 할당 시에는 '엄격한 타입 일치'를 요구하여 버그를 줄임.
|
||||
- **Bypassing Methods**:
|
||||
- 변수에 할당 후 전달.
|
||||
- 타입 단언(`as AnyType`) 사용.
|
||||
- 인덱스 시그니처(`[key: string]: any`) 추가.
|
||||
|
||||
---
|
||||
|
||||
- **도입 배경 및 목적**: TypeScript는 기본적으로 객체의 형태(구조)가 일치하면 타입의 호환성을 인정하는 구조적 타이핑(덕 타이핑) 원칙을 따른다[7-9]. 그러나 대상 타입의 속성을 충족하더라도 오타(예: `color` 대신 `colour`를 입력)와 같은 실수로 잉여 속성이 포함되면 의도치 않은 런타임 동작이 발생할 수 있다[5, 6]. 이러한 한계를 보완하기 위해 TypeScript는 객체 리터럴에 대해 예외적으로 더 엄격한 잣대를 들이대는 '과잉 속성 체크'를 수행한다[1, 5].
|
||||
- **동작 방식과 한계 (우회 현상)**: 과잉 속성 체크는 객체 리터럴이 변수에 직접 할당되거나 인자로 전달되는 특수한 경우에만 작동한다[3, 5]. 만약 변수를 먼저 선언한 후 이를 다른 타입에 간접적으로 할당하거나 제네릭 타입 매개변수를 사용하는 경우, 두 객체 사이에 최소 하나의 공통 속성만 존재한다면 과잉 속성 체크가 작동하지 않는다[10-12]. 이는 시스템이 "최소 요건 충족"이라는 구조적 타이핑의 기본 원칙으로 되돌아가기 때문이다[12]. (단, 선택적 속성만 가진 '약한 타입(Weak Type)'의 경우에는 공통 속성이 아예 없으면 에러를 발생시키는 약한 타입 탐지가 작동한다[13, 14].)
|
||||
- **우회로 인한 부작용**: 간접 할당 등을 통해 과잉 속성 체크가 우회되면, 예상치 못한 잉여 데이터가 객체 내부에 숨어들 수 있다[12]. 이는 React 컴포넌트 등에서 유효하지 않은 속성이 DOM으로 넘어가 경고를 발생시키거나, 불필요한 리렌더링을 유발하고 런타임 시 보안 유출의 원인이 되기도 한다[12, 15].
|
||||
- **`satisfies` 연산자를 통한 방비**: `as` 키워드를 이용한 타입 캐스팅([[Type Casting|Type Casting]])은 과잉 속성 체크를 수행하지 않아 잠재적인 에러를 유발할 수 있다[16]. 이 같은 취약점을 보완하기 위해 TypeScript 4.9에 도입된 `satisfies` 연산자는 객체가 특정 인터페이스나 타입을 만족하는지 엄격히 검사하여 과잉 속성의 유입을 컴파일 단계에서 차단한다[17, 18]. 더불어 객체의 구체적인 값(리터럴 타입 등)을 유지해 정밀한 타입 추론과 타입 좁히기(Narrowing)를 돕는 혁신적인 수비 전략으로 활용된다[18-20].
|
||||
|
||||
---
|
||||
|
||||
- **구조적 타이핑의 보완 장치**: TypeScript는 기본적으로 객체가 요구되는 최소한의 속성을 가지고 있다면 타입 호환성을 인정하는 구조적 타이핑([[Structural Typing|Structural Typing]], 일명 덕 타이핑)을 사용합니다 [7, 8]. 그러나 이 유연성으로 인해 `color`를 `colour`로 잘못 입력하는 등의 오타가 발생해도 호환되는 것으로 판단될 위험이 있습니다 [6]. TypeScript는 객체 리터럴을 직접 다루는 상황에서는 개발자가 잉여 속성을 전달할 의도가 없었을 것이라 간주하여 더 엄격한 과잉 속성 체크를 적용해 실수를 방지합니다 [5-7].
|
||||
- **발동 조건 및 한계 (우회로)**: 과잉 속성 체크는 "객체 리터럴"이 대상 타입에 직접 할당되거나 인수로 전달될 때만 특별하게 동작합니다 [3-5]. 만약 객체 리터럴을 먼저 중간 변수에 선언 및 할당한 뒤, 해당 변수를 대상 타입에 간접적으로 할당하면 이 기능은 작동하지 않습니다 [3, 5, 9, 10]. 변수를 거치게 되면 구조적 타이핑의 기본 원칙인 "최소 요건 충족"으로 돌아가기 때문에, 대상 타입과 최소 하나의 속성만 겹치면 초과 속성이 존재하더라도 에러를 발생시키지 않게 됩니다 [10, 11].
|
||||
- **잠재적 위험과 `satisfies`를 통한 해결**: 간접 할당을 통해 과잉 속성 체크를 우회하게 될 경우, React 컴포넌트에 유효하지 않은 속성이 전달되거나 불필요한 리렌더링이 발생하는 등 런타임 버그의 원인이 될 수 있습니다 [10, 12, 13]. 이를 해결하기 위해 TypeScript 4.9에 도입된 `satisfies` 연산자를 활용할 수 있습니다 [14]. `satisfies`는 객체의 구체적인 타입(리터럴 타입 등)을 잃지 않고 유지하면서도, 대상 인터페이스의 요구사항을 엄격하게 검사하여 간접 할당 시에도 과잉 속성을 효과적으로 차단합니다 [14, 15].
|
||||
|
||||
---
|
||||
|
||||
* **발동 조건 및 목적**
|
||||
TypeScript는 기본적으로 속성의 구조만 맞으면 타입이 호환된다고 보는 구조적 타이핑([[Structural Typing|Structural Typing]]) 시스템을 따릅니다 [11]. 그러나 객체 리터럴이 변수에 직접 할당되거나 인수로 전달되는 특수한 상황에서는 TypeScript가 더 엄격하게 동작하여 초과 속성 검사를 실행합니다 [1, 4, 6]. 이 기능은 `color`를 `colour`로 입력하는 것과 같은 오타를 잡아내며, 해당 상황에서 개발자가 초과 속성을 의도적으로 전달할 확률이 극히 낮다고 가정하여 런타임 에러를 사전에 차단합니다 [6-8].
|
||||
|
||||
* **검사의 한계 (우회 메커니즘)**
|
||||
객체 리터럴을 중간 변수에 먼저 할당한 뒤 이를 다른 변수나 함수에 전달하면, 초과 속성 검사가 작동하지 않습니다 [6, 9]. 두 객체가 최소 하나 이상의 공통 속성만 가지고 있다면 "최소 요건 충족"이라는 구조적 타이핑 원칙이 적용되기 때문입니다 [6, 9, 10]. 이러한 방식은 [[JavaScript|JavaScript]]의 유연한 패턴을 지원하지만, 동시에 불필요하거나 잘못된 속성이 런타임에 유입되어 부작용(예: React 컴포넌트의 의도치 않은 리렌더링, 잘못된 DOM 속성 전달)을 일으키는 원인이 될 수 있습니다 [10, 12].
|
||||
|
||||
* **완화 및 방어 전략**
|
||||
* **`satisfies` 연산자의 활용:** TypeScript 4.9에서 도입된 `satisfies` 연산자를 사용하면 간접 할당 과정에서도 엄격한 속성 검사를 수행할 수 있습니다. 이를 통해 구체적인 값(리터럴 타입 등)을 유지하면서 대상 타입에 정의되지 않은 초과 속성이 들어오는 것을 원천 차단합니다 [13, 14].
|
||||
* **커스텀 제네릭 타입 활용:** 더 엄격한 수동 검사가 필요한 경우, 제네릭 매개변수(`T`)와 예상 타입(`Shape`)을 비교하여 예상 타입에 없는 속성을 `never` 타입으로 강제 할당하는 방식을 사용할 수 있습니다 [15, 16]. 중첩된 깊은 객체 구조에 대해서는 재귀적 타입을 활용해 초과 속성을 감지해냅니다 [17, 18].
|
||||
|
||||
* **관련 린트(Lint) 규칙 제안**
|
||||
변수 할당 시에도 초과 속성 검사가 누락되는 것을 막기 위해 `[[ESLint|ESLint]]-plugin`에 `no-excess-properties`라는 규칙이 제안된 바 있습니다 [19]. 그러나 TypeScript에서는 모든 객체가 본질적으로 "부정확성(inexact)"을 허용하는 구조적 타이핑에 의존하며, 과잉 속성이 실제 버그로 이어지는 경우가 드물다는 점, 그리고 커뮤니티의 수요가 부족하다는 점 때문에 해당 제안은 채택되지 않고 닫혔습니다 [20-22].
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
|
||||
---
|
||||
|
||||
- 이 기능은 때때로 "덕 타이핑(Duck Typing)이라며 왜 안 돼?"라며 초보자들을 당황하게 만든다. 하지만 이는 리터럴 객체 생성 시 발생할 수 있는 오타(예: `colour` vs `color`)를 런타임 이전 단계에서 원천 봉쇄하기 위한 의도적인 설계다.
|
||||
|
||||
---
|
||||
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
|
||||
---
|
||||
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
|
||||
---
|
||||
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** [[Structural Typing|Structural Typing]], satisfies Operator, Weak Type Detection
|
||||
- **Projects/Contexts:** TypeScript TypeSystem, [[ESLint|ESLint]] Rule Proposals (no-excess-properties)
|
||||
- **Contradictions/Notes:** 소스 [25]에 따르면, Facebook의 Flow처럼 초과 속성을 허용하지 않는 정확한 객체 타입(`Exact<T>`) 구문을 TypeScript에도 도입하자는 오랜 제안이 있었으나, TypeScript 팀은 Excess Property Checking 자체를 더 똑똑하게 개선하는 방향을 선호한다. 한편, ESLint의 린트 룰을 통해 초과 속성 검사를 강제하려는 시도에 대해서는, TypeScript의 모든 객체가 본질적으로 구조적 타이핑에 의해 "inexact"한 특성을 갖기 때문에 린트 룰 적용 시 노이즈(False Positive)가 과도하게 발생할 수 있다는 반론이 제기된다 [26, 27].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-18*
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- Related: Structural-Typing-vs-Nominal-Typing , TypeScript-Best-Practices
|
||||
- Concept: Type-Guard
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** 구조적 타이핑 (Structural Typing), [[satisfies 연산자|satisfies 연산자]], 타입 캐스팅 (Type Casting), [[약한 타입 탐지 (Weak Type Detection)|약한 타입 탐지 (Weak Type Detection]]
|
||||
- **Projects/Contexts:** 철벽 수비대" - TypeScript 타입 시스템 (인터페이스 설계), [[React 컴포넌트 Props 검증|React 컴포넌트 Props 검증]]
|
||||
- **Contradictions/Notes:** 객체 리터럴을 직접 할당할 때는 과잉 속성 체크가 발동되어 에러를 반환하지만, 중간 변수를 통해 간접 할당될 때는 구조적 타이핑 원칙이 적용되어 과잉 속성이 존재해도 에러가 발생하지 않는 모순적 동작을 보인다[1, 3, 5, 12]. 또한 `as` 연산자는 과잉 속성을 무시하고 할당을 허용하지만, `satisfies` 연산자는 초과된 속성에 대해 엄격한 검증을 강제한다[16, 21].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-18*
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** [[구조적 타이핑(Structural Typing)|구조적 타이핑(Structural Typing]], satisfies 연산자, [[약한 타입 검사(Weak Type Detection)|약한 타입 검사(Weak Type Detection]]
|
||||
- **Projects/Contexts:** [[TypeScript의 인터페이스 및 객체 타입 설계|TypeScript의 인터페이스 및 객체 타입 설계]], [[React 컴포넌트 Props 전달 및 상태 관리|React 컴포넌트 Props 전달 및 상태 관리]]
|
||||
- **Contradictions/Notes:** TypeScript는 구조적 타이핑을 핵심 철학으로 삼지만, "객체 리터럴"에 대해서만 과잉 속성 체크라는 예외적으로 엄격한 잣대를 적용합니다. 이로 인해 값을 직접 전달할 때와 중간 변수를 거쳐 전달할 때의 타입 검사 결과가 달라지는 동작 방식의 차이가 존재합니다 [3, 5, 11].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-18*
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** 구조적 타이핑 (Structural Typing), [[satisfies 연산자|satisfies 연산자]]
|
||||
- **Projects/Contexts:** typescript-eslint
|
||||
- **Contradictions/Notes:** TypeScript는 근본적으로 속성 집합의 포함 관계만 확인하는 '구조적 타이핑' 원칙을 따르지만, 객체 리터럴을 직접 다루는 맥락에서는 이러한 유연성을 예외적으로 차단하고 '초과 속성 검사'라는 더 엄격한 잣대를 적용한다는 점에서 뚜렷한 동작의 대비를 보입니다 [1, 6, 11].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-18*
|
||||
|
||||
---
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### React props 의 typo guard
|
||||
```typescript
|
||||
type ButtonProps = { label: string; onClick: () => void };
|
||||
function Button(props: ButtonProps) { /* ... */ }
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
<Button label="Save" onCick={save} />
|
||||
// ^^^^^ Property 'onCick' does not exist
|
||||
// Excess property check catches typo at JSX call site
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### Discriminated union with strict checks
|
||||
```typescript
|
||||
type Shape =
|
||||
| { kind: 'circle'; radius: number }
|
||||
| { kind: 'square'; side: number };
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
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]] · [[Type-System]]
|
||||
- 변형: [[Structural-Typing]] · [[Satisfies-Operator]] · [[Exact-Types]]
|
||||
- 응용: [[React-Props]] · [[API-Contracts]]
|
||||
- Adjacent: [[Discriminated-Unions]] · [[Brand-Types]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -2,183 +2,222 @@
|
||||
id: wiki-2026-0508-executable-documentation
|
||||
title: Executable Documentation
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [Living Documentation, Runnable Docs, Doc Tests]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
verification_status: applied
|
||||
tags: [documentation, bdd, doctest, testing, ai]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: polyglot
|
||||
framework: docs-as-code
|
||||
---
|
||||
|
||||
# Executable Documentation
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
Executable Documentation(실행 가능한 문서)은 시스템의 기대 동작을 명시함과 동시에 실제 코드로 실행되어 검증될 수 있는 형태의 문서를 의미합니다 [1]. 소스 코드 생태계에서는 주로 '테스트 코드(Test Code)'가 가장 신뢰할 수 있는 실행 가능한 문서의 역할을 수행합니다 [1]. 이 외에도 기계가 읽을 수 있는 API 명세 기반의 대화형(Interactive) 문서나 코드로 작성되어 버전 관리가 가능한 다이어그램(Diagrams as Code) 등 코드의 변경과 실시간으로 동기화되는 문서 체계도 이에 해당합니다 [2, 3].
|
||||
## 매 한 줄
|
||||
> **"매 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, 2]. 새로운 코드베이스를 탐색할 때 테스트 코드는 코드가 시스템에서 어떻게 사용되어야 하는지를 보여주는 훌륭한 무료 사용 설명서 역할을 합니다 [3]. 개발자는 이러한 테스트 코드를 통해 개별 컴포넌트의 논리부터 시스템 전반의 상호작용 흐름까지 파악할 수 있습니다 [2].
|
||||
### 매 종류
|
||||
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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **테스트 코드를 통한 실행 가능한 문서화:** 대규모 코드베이스에서 테스트 코드는 시스템의 설계 철학과 기대 동작을 명시하는 가장 신뢰할 수 있는 실행 가능한 문서입니다 [1]. 개발자는 단위 테스트(Unit Test)를 통해 개별 컴포넌트의 국소적 논리를 이해하고, 통합 테스트(Integration Test)를 통해 시스템 전반의 상호작용 흐름을 파악할 수 있습니다 [4].
|
||||
* **동적 동작 관찰과 기술적 통찰:** 새로운 시스템에 온보딩하거나 코드를 분석할 때, 정적인 독해만으로는 시스템의 전체를 파악하기 어렵습니다 [4, 5]. 테스트 코드에서 특정 값을 임의로 변경해 보고 시스템의 반응을 관찰하는 실험적 접근은, 문서 읽기만으로는 얻을 수 없는 깊은 기술적 통찰을 제공합니다 [4].
|
||||
* **API 명세 기반의 문서 자동화:** API-First 아키텍처 환경에서는 OpenAPI나 AsyncAPI와 같은 명세(Specification)를 통해 서버 스텁, 클라이언트 SDK 및 대화형 문서를 사양 파일에서 직접 자동 생성할 수 있습니다 [2, 6]. 이 과정은 수동 작업의 노력을 줄이고 시스템 변경 시 문서가 낙후되는 것을 방지합니다 [2].
|
||||
* **다이어그램의 코드화 (Diagrams as Code):** 시스템 아키텍처를 시각적으로 이해하기 위해 Structurizr(C4 모델 기반), Mermaid, PlantUML과 같은 텍스트 및 마크다운 기반 구문을 사용하여 다이어그램을 생성할 수 있습니다 [3, 7]. 이는 버전 관리 시스템을 통해 코드와 함께 관리되므로 항상 최신 상태를 유지하는 문서의 역할을 합니다 [3].
|
||||
### 매 왜 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).
|
||||
|
||||
* **코드의 사용법을 보여주는 진입점:** 새로운 코드베이스의 복잡성에 직면했을 때, HTTP 컨트롤러나 CLI 명령어와 같은 메인 진입점과 함께 가장 먼저 찾아야 할 것이 바로 테스트 코드입니다 [3]. 테스트는 시스템 로직이 어떻게 사용되도록 의도되었는지 보여주는 명확한 가이드 역할을 합니다 [3].
|
||||
* **단위 및 통합 테스트를 통한 흐름 파악:** 단위 테스트를 분석하면 개별 컴포넌트의 논리를 이해할 수 있으며, 통합 테스트를 살펴보면 시스템 전반에 걸친 상호작용의 흐름을 파악하는 데 큰 도움이 됩니다 [2].
|
||||
* **실험적 접근을 통한 동적 통찰:** 정적인 독해만으로는 코드베이스를 깊이 있게 파악하기 어렵습니다 [2]. 테스트 코드 내에서 특정 값을 인위적으로 변경해 보고 시스템의 반응을 관찰하는 실험적인 접근 방식은 시스템 동작에 대한 깊은 기술적 통찰을 제공합니다 [2].
|
||||
* **온보딩과 학습의 도구:** 복잡한 시스템에 새롭게 합류했을 때, 단순히 코드를 눈으로 읽는 것을 넘어 일부 테스트를 추가하거나 변경해 보는 행위는 코드가 실제로 어떻게 작동하는지를 체득하는 데 매우 효과적인 방법입니다 [4].
|
||||
## 💻 패턴
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
소스에 "Executable Documentation" 자체에 대한 직접적이고 포괄적인 제약 사항 정보가 부족합니다. 다만, 소스에서 다루는 실행 가능한 문서의 구체적 구현체(테스트 코드, 도구화된 문서 등)와 관련된 부작용 및 제약 사항은 다음과 같습니다:
|
||||
### Pattern 1: Python doctest
|
||||
```python
|
||||
def fibonacci(n: int) -> int:
|
||||
"""Return the n-th Fibonacci number.
|
||||
|
||||
* **테스트 스위트의 복잡성 및 유지보수 부담:** 테스트 코드를 논리적 구조로 그룹화(Test Suites)하여 실행 가능한 문서로 사용할 때, 과도하게 조직화하면 각각이 하위 테스트 집합을 포함하게 되어 유지보수가 매우 어려워질 수 있습니다 [8].
|
||||
* **잘못된 경계 설정의 위험성:** 모호하게 코딩되어 경계가 명확하지 않은 테스트 스위트는 테스트를 제대로 격리하지 못하여 실행 가능한 문서로서의 정확성과 신뢰도를 떨어뜨립니다 [8].
|
||||
* **상호 의존성 문제:** 시스템이 커지면서 상호 의존성을 가진 테스트 스위트가 늘어나면 복잡성이 증가하며, 올바른 순서로 시퀀싱하지 않을 경우 누락이 발생하거나 실패할 수 있습니다 [9].
|
||||
* **초기 설정 및 지속적 관리 요구:** 도구를 활용해 문서와 코드를 동기화하고 API 목(Mock) 서버를 구성하는 등 실행 가능한 상태를 유지하기 위해서는 팀의 규율과 지속적인 유지보수 작업이 요구됩니다 [2, 8].
|
||||
>>> 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
|
||||
|
||||
---
|
||||
|
||||
테스트 코드를 시스템을 이해하기 위한 실행 가능한 문서로 활용할 때, 테스트 파일과 스위트(Test Suites)의 구성 방식에 따라 오히려 이해를 방해하는 제약이 생길 수 있습니다 [5].
|
||||
* 테스트 스위트가 모호하게 코딩되어 있거나 경계가 불명확할 경우, 개별 테스트를 적절히 격리(isolate)하지 못하여 시스템의 정확한 동작을 파악하기 어렵게 만듭니다 [5].
|
||||
* 프로젝트가 커짐에 따라 테스트 파일들을 모듈 타입에 맞춰 너무 파편화하여 분리해두면, 모듈 간의 상호작용을 테스트하는 통합 테스트 과정이 매우 복잡해져 전체 맥락을 잃기 쉽습니다 [6].
|
||||
* 과도하게 얽힌 불필요한 테스트 스위트들의 묶음은 유지보수를 매우 어렵게 만들고, 테스트 실행의 논리적 시퀀스를 맞추는 데 불필요한 복잡성을 더할 수 있습니다 [5, 7].
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
|
||||
#### [테스트 및 검증 기반 기술]
|
||||
- [[단위 테스트 (Unit Testing)]]
|
||||
- 연결 이유: 개별 컴포넌트의 논리와 예상되는 입출력 데이터를 실행 가능한 형태로 문서화하는 가장 기초적인 수단입니다 [4].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 격리된 모듈의 책임(Responsibility)과 정확한 동작 원리.
|
||||
- [[통합 테스트 (Integration Testing)]]
|
||||
- 연결 이유: 모듈 간의 결합과 통신 흐름을 검증하여, 분산된 시스템 전반의 상호작용을 파악하는 실행 가능한 문서 역할을 합니다 [4].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 아키텍처 내 컴포넌트 간의 인터페이스 및 전체 기능 작동 메커니즘.
|
||||
|
||||
#### [설계 및 명세 자동화 도구]
|
||||
- [[OpenAPI / AsyncAPI]]
|
||||
- 연결 이유: API-First 설계에서 사용하는 기계 해독 가능(Machine-readable) 명세로, 대화형 문서와 코드를 자동 생성하는 기반입니다 [2].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 시스템 외부 및 클라이언트와의 계약(Contract) 기반 통신과 병렬 개발 파이프라인.
|
||||
- [[Diagrams as Code]]
|
||||
- 연결 이유: Mermaid나 PlantUML을 사용하여 시스템 구조를 텍스트 구문으로 정의하고, 소스 코드와 함께 버전 컨트롤로 관리하는 시각적 문서 체계입니다 [3, 7].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 소스 코드의 변경 사항과 아키텍처 다이어그램 간의 동기화 및 형상 관리 기법.
|
||||
|
||||
### Deeper Research Questions
|
||||
- 실행 가능한 문서(테스트 코드)가 실제 운영 코드의 변경 사항과 동기화되지 않고 방치될 때, 코드베이스 이해도와 기술적 부채에 어떠한 악영향을 미치는가?
|
||||
- OpenAPI와 같은 명세를 통한 자동 생성 문서가 사람이 직접 작성하는 전통적인 기술 문서에 비해 가지는 인지적, 맥락적 한계점은 무엇인가?
|
||||
- Diagrams as Code를 적용하여 아키텍처 문서를 버전 관리할 때, 거대한 마이크로서비스 아키텍처에서 발생하는 시각적 복잡성을 어떻게 제어하고 추상화할 수 있는가?
|
||||
- 낯선 레거시 코드베이스를 탐색할 때, 단위 테스트와 통합 테스트 중 시스템의 초기 멘탈 모델을 형성하는 데 더 효율적인 '실행 가능한 문서'는 무엇이며 그 이유는 무엇인가?
|
||||
- 강하게 결합되어 테스트가 불가능한 레거시 코드를 실행 가능한 문서(테스트 스위트)가 존재하는 안정적인 구조로 리팩토링하기 위한 가장 안전한 접근법은 무엇인가?
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 백엔드 API 개발 시 OpenAPI 명세를 먼저 작성하고 이를 바탕으로 대화형 문서와 Mock 서버를 자동 생성하여, 프론트엔드 팀이 백엔드 구현 완료를 기다리지 않고 병렬로 개발을 진행할 수 있습니다 [2, 6].
|
||||
- **System Design:** 소프트웨어 아키텍처를 그릴 때 정적인 이미지 도구가 아닌 Mermaid나 Structurizr를 사용하여 설계하고 Git 저장소에 커밋함으로써, 코드 리뷰 시 설계 변경 사항을 함께 검토하고 문서를 최신 상태로 유지합니다 [3].
|
||||
- **Operation / Maintenance:** 방대한 시스템을 유지보수할 때 테스트 스위트를 기능과 모듈에 따라 논리적으로 그룹화하여 관리함으로써, 운영 중인 시스템에 변경을 가할 때 발생할 수 있는 부수 효과(Side effect)를 즉시 파악하는 안전망이자 가이드 문서로 활용합니다 [8, 10].
|
||||
- **Learning Path:** 새로운 코드베이스나 팀에 합류(Onboarding)할 때, 방치된 문서 파일을 읽는 대신 잘 작성된 테스트 코드를 직접 찾아 값을 변경해 보고 디버거로 실행하며 시스템의 런타임 반응을 관찰하는 방식으로 시스템 구조를 학습합니다 [1, 4, 5].
|
||||
- **My Project Relevance:** 복잡한 시스템이나 레거시 코드의 비즈니스 로직을 파악해야 할 때, 코드를 하향식 혹은 상향식으로 탐색하는 것과 병행하여 해당 도메인을 다루는 테스트 코드(실행 가능한 문서)를 확인하여 코드 작성자의 원래 의도를 가장 신뢰성 있게 도출할 수 있습니다 [1, 4].
|
||||
|
||||
### Adjacent Topics
|
||||
- [[API-First Architecture]]
|
||||
- 확장 방향: 제품 구현 전 API 명세(실행 가능한 계약)를 우선적으로 설계하여 프론트엔드와 백엔드 간의 결합도를 낮추고 문서화를 자동화하는 접근법으로 이해를 확장합니다 [2, 6, 11].
|
||||
- [[Version Control Systems (Git)]]
|
||||
- 확장 방향: 소스 코드 및 Diagrams as Code의 변경 이력을 추적하고, 과거의 PR 설명과 커밋 메시지라는 맥락 데이터를 통해 현재 코드의 의도를 유추하는 방법론으로 학습을 확장합니다 [12, 13].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
---
|
||||
|
||||
### Related Concepts
|
||||
|
||||
#### [코드 탐색 및 분석 전략]
|
||||
- [[하향식 및 상향식 접근법 (Top-Down and Bottom-Up Approaches)]]
|
||||
- 연결 이유: 대규모 코드베이스의 정보 흐름을 파악하는 가장 근본적인 두 가지 탐색 방향입니다 [8].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 테스트 코드를 분석의 시작점(진입점)으로 삼아, 하향식으로 비즈니스 의도를 파악하거나 상향식으로 기술적 한계 및 동작을 역추적하는 전략을 세울 수 있습니다 [8, 9].
|
||||
|
||||
#### [프로젝트 구조화 도구]
|
||||
- [[테스트 파일 조직화 (Test File Organization)]]
|
||||
- 연결 이유: 실행 가능한 문서로서의 테스트 코드가 저장소 내에 어떻게 배치되고 분류되는지(예: 테스트 타입별, 모듈별, 애플리케이션 계층별)를 의미합니다 [10-12].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 방대한 테스트 코드들이 어떤 논리(단위, E2E, UI 등)로 그룹화되어 있는지 파악함으로써, 특정 비즈니스 로직이나 모듈의 문서를 어디에서 찾아야 할지 빠르게 매핑할 수 있습니다 [10, 11, 13].
|
||||
|
||||
### Deeper Research Questions
|
||||
|
||||
- 테스트 코드(실행 가능한 문서)가 부족하거나 거의 없는 레거시 시스템 환경에서, 어떤 전략을 통해 점진적으로 시스템을 탐색하고 실행 가능한 문서를 보강할 수 있는가?
|
||||
- 경계가 불명확하고 모호하게 작성되어 격리(isolation)에 실패한 테스트 스위트를 어떻게 리팩토링하여 명확한 실행 가능한 문서로 탈바꿈시킬 수 있는가? [5]
|
||||
- 테스트 코드에서 특정 값을 임의로 변경하며 시스템의 반응을 살피는 '실험적 접근법'을 디버깅 과정의 중단점(Breakpoints) 설정 등 동적 분석 기법과 어떻게 효과적으로 결합할 수 있는가? [2, 14]
|
||||
- Qodo(CodiumAI)와 같이 테스트 생성에 특화된 AI 도구를 활용하여, 방대한 코드베이스의 실행 가능한 문서(테스트 코드)를 자동 생성할 때 발생하는 환각(Hallucination) 위험을 어떻게 통제할 것인가? [15, 16]
|
||||
|
||||
### Practical Application Contexts
|
||||
|
||||
- **Implementation:** 새로운 기능을 개발하거나 수정하기 전, 해당 모듈에 작성된 단위/통합 테스트 코드를 먼저 읽고 시스템의 의도된 입력과 출력을 파악합니다 [2, 3].
|
||||
- **System Design:** 소프트웨어 설계 단계에서부터 테스트 코드가 미래의 유지보수 담당자를 위한 살아있는 설명서가 될 수 있도록, 테스트 스위트의 범위를 명확히 격리하고 직관적인 명명 규칙(Naming conventions)을 적용합니다 [5, 7].
|
||||
- **Operation / Maintenance:** 기존 기능의 버그를 추적하거나 로직을 수정할 때, 테스트 코드의 특정 값을 변경해 보면서 시스템 동적 반응의 부수 효과를 사전에 실험합니다 [2].
|
||||
- **Learning Path:** 낯선 대규모 코드베이스를 처음 배정받았을 때 코드 전체를 완벽히 이해하려 하기보다는, 가장 먼저 단위 테스트가 위치한 디렉토리를 찾아 시스템의 동작 방식을 파악하는 훈련을 합니다 [3, 4].
|
||||
- **My Project Relevance:** 문서화가 빈약한 오픈소스나 내부 레거시 프로젝트를 분석할 때, 별도의 외부 문서에 의존하기보다 소스 코드와 함께 제공된 테스트 코드를 신뢰할 수 있는 단일 진실 공급원(Single Source of Truth)으로 삼아 구조를 해독합니다 [1, 3].
|
||||
|
||||
### Adjacent Topics
|
||||
|
||||
- [[버전 관리 이력 (Version Control History)]]
|
||||
- 확장 방향: 테스트 코드가 시스템이 '어떻게(How)' 동작하는지 보여주는 문서라면, 버전 관리 시스템(Git)의 커밋 메시지나 PR 기록은 코드가 '왜(Why)' 그렇게 설계되었는지를 알려줍니다. 이 두 가지를 결합하여 코드베이스의 역사적 맥락과 현재 동작의 상호 관계를 종합적으로 이해하는 방향으로 학습을 확장할 수 있습니다 [17, 18].
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
# pytest --doctest-modules
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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 }
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
// cargo test --doc
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
```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);
|
||||
});
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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).
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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
|
||||
- 부모: [[Documentation]] · [[Testing]] · [[Docs as Code]]
|
||||
- 변형: [[Literate Programming]] · [[Behavior-Driven Development (BDD)]]
|
||||
- 응용: [[OpenAPI]] · [[Cucumber]] · [[doctest]] · [[Marimo]] · [[Quarto]]
|
||||
- Adjacent: [[Property-Based Testing]] · [[Contract Testing]] · [[Specification by Example]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -2,121 +2,216 @@
|
||||
id: wiki-2026-0508-exergaming
|
||||
title: Exergaming
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [Exergaming, Exergame, Fitness Gaming, Active Gaming]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [game-design, fitness, vr, ar, health]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: design
|
||||
framework: vr-fitness
|
||||
---
|
||||
|
||||
# [[Exergaming|Exergaming]]
|
||||
# Exergaming
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> 엑서게이밍(Exergaming)은 운동(exercise)과 게임 플레이(gameplay)를 결합하여 사용자의 신체 활동을 촉진하는 방식입니다 [1]. 어린이, 청소년, 성인의 앉아 있는 습관(sedentary [[Behavior|Behavior]]s)을 개선하는 데 유효한 방법으로 인정받고 있으며, 달리기나 에어로빅 댄스 등과 유사한 수준의 생리학적 건강 이점을 제공합니다 [1]. 최근에는 가상현실(VR)과 결합하여 사용자가 운동의 육체적 피로를 잊고 게임에 더 깊이 몰입하게 하여 지속적인 신체 활동을 유도하는 'VR 엑서게이밍'이 각광받고 있습니다 [2].
|
||||
## 매 한 줄
|
||||
> **"매 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 결합.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
> 엑서게임(Exergaming)은 **운동(Exercise)과 게임 플레이(Gameplay)를 가상 환경에 결합하여 사용자의 신체 활동을 촉진하는 게임**이다 [1]. 이는 아동, 청소년, 성인 모두의 좌식 생활 습관(sedentary [[Behavior|Behavior]])을 개선하기 위해 활용되며 달리기나 에어로빅과 비견되는 건강상의 이점을 제공한다 [1]. 특히 게임에 대한 몰입감을 통해 **사용자가 육체적 피로를 잊게 만들고 지속적인 운동 동기를 부여**하는 것이 가장 큰 특징이다 [2].
|
||||
### 매 Why it works
|
||||
- **Intrinsic motivation**: 매 fun → exercise (vs treadmill 의 외재 동기)
|
||||
- **Flow**: 매 difficulty/skill match — 매 exercise 인지 인식 안 됨
|
||||
- **Social**: 매 multiplayer 가 적정한 peer pressure
|
||||
- **Telemetry feedback**: 매 calorie, heart rate 즉시 가시화
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
* **신체적 및 심리적 이점:** 엑서게이밍은 전통적인 신체 운동 형태보다 사용자에게 더 큰 즐거움과 긍정적인 감정을 제공합니다 [1]. 사용자는 게임의 목표와 도전 과제에 쉽게 빠져드는 '몰입(flow)' 상태를 경험하게 되며, 이는 운동에 대한 즐거움과 지속적인 참여(adherence)를 높이는 데 기여합니다 [1].
|
||||
* **VR 엑서게이밍의 부상:** 가상현실(VR) 기술은 엑서게이밍의 효과를 더욱 극대화합니다 [2]. 3D 환경, 360도 공간 및 신체 트래킹 기능을 통해 사용자는 육체적 피로감을 잊고 가상 세계의 몰입감(presence)을 강하게 느끼며 게임에 집중할 수 있습니다 [2]. 인기 있는 VR 엑서게임인 '비트 세이버([[Beat Saber|Beat Saber]])'의 경우, 게임을 플레이하며 소비되는 에너지가 실제 테니스를 치는 것과 맞먹는 수준으로 평가됩니다 [3].
|
||||
* **잠재적 부작용 및 한계:** VR 엑서게이밍의 가장 큰 장애물 중 하나는 두부 장착형 디스플레이(HMD) 사용으로 인해 발생하는 VR 멀미([[VR Sickness|VR Sickness]])입니다 [4]. 사용자는 메스꺼움, 안구 운동 장애, 방향 감각 상실 등의 증상을 겪을 수 있으며, 이는 게임 내 성과와 즐거움을 저해하는 요인이 됩니다 [4, 5].
|
||||
* **안전 권고사항:** VR 엑서게이밍이 신체와 인지에 미치는 후유증을 조사한 연구에 따르면, 짧거나 긴 시간 동안 HMD를 착용하고 엑서게임을 즐긴 후에는 사용자의 웰빙을 위해 대기 시간이 필요합니다 [6]. 사용자가 가상현실에서 벗어난 뒤, 후유증이 완전히 사라질 때까지(예: 약 40분) 운전과 같이 부상 위험이 있는 활동을 피하는 것이 권장됩니다 [6].
|
||||
### 매 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).
|
||||
|
||||
* **신체적·심리적 이점 및 몰입(Flow)**:
|
||||
엑서게임은 전통적인 신체 운동보다 더 큰 즐거움과 긍정적인 감정을 유발한다 [1]. 사용자는 게임의 목표와 도전에 깊이 빠져드는 **몰입([[Flow State|Flow State]])을 경험하며, 이는 육체적 피로를 분산시키고 운동에 대한 높은 순응도를 이끌어낸다** [1, 2]. 대표적으로 상업적 성공을 거둔 가상현실(VR) 엑서게임인 '비트 세이버([[Beat Saber|Beat Saber]])'를 플레이할 때 소모되는 에너지는 실제 환경에서 테니스를 치는 것과 맞먹는 것으로 평가된다 [3].
|
||||
* **가상현실(VR) 엑서게임과 부작용(VR Aftereffects)**:
|
||||
HMD(Head-Mounted Display)를 활용한 VR 엑서게임은 사용자의 몰입도(immersion)와 실재감(presence)을 극대화하여 엑서게임의 효과를 높인다 [2, 4]. 하지만 시각적 자극과 신체 움직임이 많은 엑서게임의 특성상 **가상현실 멀미([[VR Sickness|VR Sickness]]/Motion Sickness)를 유발**할 수 있으며, 이는 게임의 성과와 즐거움을 크게 저해하는 부정적 요인이 된다 [4-6].
|
||||
* **안전한 이용 가이드라인**:
|
||||
연구에 따르면 엑서게임으로 인한 신체적/인지적 후유증을 최소화하기 위해 사용자는 장시간 노출 전 짧은 시간 동안 미리 테스트를 해보는 것이 권장된다 [7]. 또한 10분이나 50분 등 플레이 시간에 상관없이 VR 엑서게임을 종료한 후에는, 멀미 증상과 시력 및 인지적 후유증이 완전히 사라질 때까지 **운전 등 부상 위험이 있는 활동을 피하고 약 40분의 대기/휴식 시간**을 가져야 한다 [7, 8].
|
||||
## 💻 패턴
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
### 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)
|
||||
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
cap = cv2.VideoCapture(0)
|
||||
squat_count = 0
|
||||
in_squat = False
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** Virtual Reality (VR), Flow, [[VR Sickness|VR Sickness]]
|
||||
- **Projects/Contexts:** [[Beat Saber|Beat Saber]]
|
||||
- **Contradictions/Notes:** VR 기술은 사용자의 몰입도(presence)를 극대화하여 엑서게임의 동기를 부여하고 신체적 피로를 잊게 하는 긍정적인 역할을 하지만, 동시에 VR 멀미(motion sickness)를 유발하여 오히려 사용자의 게임 플레이 성과와 체감하는 즐거움을 떨어뜨릴 수 있는 양면성을 지니고 있습니다 [2, 4].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-19*
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** [[Flow State|Flow State]], Virtual Reality (VR) Sickness, Sedentary Behavior
|
||||
- **Projects/Contexts:** 비트 세이버(Beat Saber) 시각 및 인지 후유증 연구
|
||||
- **Contradictions/Notes:** 소스에 따르면, HMD를 사용하는 VR 엑서게임은 대형 스크린 기반의 엑서게임보다 몰입도가 높지만, 동시에 더 높은 수준의 멀미(VR Sickness)를 유발할 위험이 있다는 양면성(trade-off)을 지니고 있습니다 [4].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-19*
|
||||
|
||||
---
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
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}")
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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)
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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; }
|
||||
}
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Heart rate zone (Apple Watch / WatchOS)
|
||||
```swift
|
||||
import HealthKit
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
let store = HKHealthStore()
|
||||
let hrType = HKQuantityType.quantityType(forIdentifier: .heartRate)!
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
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)
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
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]] · [[Health Tech]]
|
||||
- 변형: [[VR Fitness]] · [[AR Gaming]] · [[Active Gaming]]
|
||||
- 응용: [[Beat Saber]] · [[Pokemon Go]] · [[Ring Fit Adventure]] · [[Zwift]]
|
||||
- Adjacent: [[Gamification]] · [[Wearable Tech]] · [[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 |
|
||||
|
||||
@@ -2,91 +2,210 @@
|
||||
id: wiki-2026-0508-experience-sampling-method
|
||||
title: Experience Sampling Method
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-Reinforce-AUTO-EXSM-001]
|
||||
aliases: [ESM, EMA, Ecological Momentary Assessment, Diary Studies]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.93
|
||||
tags: [auto-reinforced, esm, experience-sampling, user-Research, ecoLogical-validity, emotion-tracking, Psychology]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [research-methodology, psychology, ux-research, mobile]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-04-20
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: react-native
|
||||
---
|
||||
|
||||
# [[Experience-Sampling-Method|Experience-Sampling-Method]]
|
||||
# Experience Sampling Method
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> "감정의 인스턴트 촬영: 사용자가 하루 동안 느끼는 감정과 생각을 나중에 기억(회상)에 의존해 물어보는 것이 아니라, 특정 시간마다 스마트폰으로 신호를 보내 '지금 이 순간'의 상태를 즉시 기록하게 하여 데이터의 왜곡을 없애는 리얼타임 리서치."
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
경험 샘플링 기법(Experience-Sampling-Method, ESM)은 연구 참여자에게 일상 생활 중에 임의 또는 예정된 시점에 신호를 보내 현재의 활동, 생각, 감정을 보고하게 하는 조사 방법입니다.
|
||||
## 매 핵심
|
||||
|
||||
1. **3대 강점**:
|
||||
* **Reduced Recall Bias**: 나중에 기억을 떠올릴 때 생기는 왜곡(회상 편향) 방지.
|
||||
* **Ecological Validity**: 실험실이 아닌 실제 생활 맥락(Natural setting)에서의 현상 포착. ([[Ethnographic-Research|Ethnographic-Research]]와 연결)
|
||||
* **Temporal Micro-patterns**: 하루 중 어떤 시간에 어떤 자극에 의해 감정이 변하는지 미세 패턴 분석.
|
||||
2. **왜 중요한가?**:
|
||||
* 웰빙, 스트레스, 제품에 대한 실제 만족도 등 '시간에 따라 변하는(Dynamic)' 주관적 경험 정책을 포착하는 가장 정밀한 도구이기 때문임. ([[Eudaimonia-and-Well-being|Eudaimonia-and-Well-being]]와 연결)
|
||||
### 매 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.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌**: 과거에는 종이 수첩 정책이나 삐삐 정책을 써서 응답률 정책이 낮았으나, 현대 정책은 모바일 앱 정책과 웨어러블 기기 정책(Heart rate 등)을 결합하여 자동으로 상황 정책을 인지하고 질문을 던지는 '지능형 샘플링 정책'으로 고도화됨(RL Update).
|
||||
- **정책 변화(RL Update)**: 이제는 단순 질문 정책을 넘어, AI 가 사용자의 음성 톤 정책이나 표정 정책을 분석하여 '부정적 감정 정책'이 감지될 때만 샘플링을 수행(Triggered sampling)하는 등 사용자 부하 정책을 줄이는 방향으로 진화 중임. (Social-Psychology와 연결)
|
||||
### 매 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.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- [[Ethnographic-Research|Ethnographic-Research]], [[Eudaimonia-and-Well-being|Eudaimonia-and-Well-being]], Social-Psychology, [[Research|Re[[Search]]-Methodology]], Personalization, [[Continuous-Discovery|Continuous-Discovery]]
|
||||
- **Key Metric**: Affective [[State|State]] variability.
|
||||
---
|
||||
### 매 응용
|
||||
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.
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
## 💻 패턴
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
### Mobile prompt scheduler (React Native)
|
||||
```typescript
|
||||
import * as Notifications from 'expo-notifications';
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
interface ESMConfig {
|
||||
startHour: number; endHour: number;
|
||||
promptsPerDay: number;
|
||||
minIntervalMinutes: number;
|
||||
}
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
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 },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
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;
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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;
|
||||
}
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Multilevel analysis (within vs between)
|
||||
```python
|
||||
import statsmodels.formula.api as smf
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
# 매 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
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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);
|
||||
}
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]] · [[Psychometrics]]
|
||||
- 변형: [[Ecological-Momentary-Assessment]] · [[Diary-Study]] · [[Day-Reconstruction]]
|
||||
- 응용: [[Mood-Tracking-Apps]] · [[UX-Research]] · [[Flow-State]]
|
||||
- Adjacent: [[Csikszentmihalyi]] · [[Multilevel-Modeling]] · [[Mobile-Sensing]]
|
||||
|
||||
## 🤖 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 |
|
||||
|
||||
@@ -2,116 +2,200 @@
|
||||
id: wiki-2026-0508-exploration-vs-exploitation
|
||||
title: Exploration vs Exploitation
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [Explore-Exploit, Multi-Armed Bandit Tradeoff, RL Tradeoff]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [reinforcement-learning, bandits, decision-theory, optimization]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: python
|
||||
framework: numpy
|
||||
---
|
||||
|
||||
# [[Exploration vs Exploitation|Exploration vs Exploitation]]
|
||||
# Exploration vs Exploitation
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> "모험과 안주의 저울질: 이미 알고 있는 최선을 선택하여 확실한 이득을 챙길 것인가(Exploitation), 아니면 더 큰 보상이 있을지 모르는 새로운 영역을 탐험할 것인가(Exploration) 사이의 영원한 전략적 딜레마."
|
||||
## 매 한 줄
|
||||
> **"매 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.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
> "안전한 현재의 수익과 불확실한 미래의 가능성 사이에서 최적의 배팅 지점을 찾아라" — 강화학습의 핵심 딜레마로, 이미 알고 있는 최선의 행동을 반복하여 보상을 얻는 것(Exploitation)과 더 나은 행동을 찾기 위해 새로운 시도를 하는 것(Exploration) 사이의 트레이드오프.
|
||||
### 매 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.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
탐사 대 이용(Exploration vs Exploitation)은 강화학습과 의사결정 이론의 핵심적인 트레이드오프 문제입니다.
|
||||
### 매 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. **두 개념**:
|
||||
* **Exploitation (이용)**: 과거 경험상 보상이 가장 컸던 행동을 반복. 단기 수익 최적화.
|
||||
* **Exploration (탐사)**: 정보가 부족한 새로운 행동을 시도. 장기적인 '더 나은 최적해' 발견 가능성.
|
||||
2. **해결 전략**:
|
||||
* **Epsilon-Greedy**: 대부분($1-\epsilon$)은 이용하되, 무작위($\epsilon$)로 탐사.
|
||||
* **UCB (Upper Confidence Bound)**: 불확실성(가보지 않은 곳)에 가중치를 두어 탐사 유도.
|
||||
* **Thompson Sampling**: 확률 분포를 기반으로 유연하게 선택.
|
||||
### 매 응용
|
||||
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.
|
||||
|
||||
---
|
||||
## 💻 패턴
|
||||
|
||||
- **추출된 패턴:** 제한된 자원(시간, 에너지) 내에서 누적 보상을 극대화하기 위해 초기에는 광범위하게 탐색하고, 정보가 쌓일수록 최선의 선택에 집중하는 적응형 의사결정 패턴.
|
||||
- **주요 전략:**
|
||||
- **$\epsilon$-greedy:** 아주 작은 확률($\epsilon$)로 무작위 행동을 하고, 나머지 확률로 최선의 행동 수행.
|
||||
- **Softmax:** 보상 가치에 비례한 확률로 행동 선택.
|
||||
- **Upper Confidence Bound (UCB):** 불확실성이 큰 행동에 가산점을 주어 우선적으로 탐색.
|
||||
- **Thompson Sampling:** 확률 분포를 모델링하여 샘플링 기반으로 탐색 결정.
|
||||
- **의의:** 너무 빨리 활용에만 집중하면 지역 최적해(Local Optima)에 갇히고, 너무 탐색만 하면 보상을 충분히 얻지 못함.
|
||||
### ε-greedy bandit
|
||||
```python
|
||||
import numpy as np
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌**: 과거에는 최대한 빠르게 '안주 정책'으로 들어가는 것이 효율적이라 보았으나, 현대 정책은 복잡한 환경일수록 시스템에 '호기심(Curiosity) 정책'을 주입하여 끝까지 탐사하게 하는 것이 궁극의 지능을 만든다고 믿음(RL Update). (Reinforcement Learning과 연결)
|
||||
- **정책 변화(RL Update)**: 비즈니스 전략 정책에서, 기존 수익 모델에 안주하는 것(Exploitation)과 신사업을 발굴하는 것(Exploration) 사이의 '양손잡이 경영 정책'의 이론적 토대가 됨. ([[Strategic-Planning|Strategic-Planning]]과 연결)
|
||||
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))
|
||||
|
||||
- **과거 데이터와의 충돌:** 단순히 '운'에 맡기던 무작위 탐색에서, 수학적 근거(UCB 등)를 바탕으로 '똑똑하게' 탐색하는 방식으로 진화.
|
||||
- **정책 변화:** Antigravity 프로젝트의 지식 검색 에이전트는 사용자의 질문에 대해 가장 관련성 높은 문서만 보여주는 것(Exploitation)을 넘어, 가끔은 의외의 연결 고리를 가진 문서를 제안(Exploration)하여 창의적 통찰을 돕도록 설계됨.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- [[Reinforcement Learning (RL)|Reinforcement Learning (RL)]], Multi-Armed Bandit (MAB), [[Decision Theory|Decision Theory]], [[Strategic-Planning|Strategic-Planning]], [[Optimization|Optimization]]
|
||||
- **Modern Tech/Tools**: Recommender[[_system|system]]s (Exploration balance), A/B [[Testing|Testing]] algorithms.
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- [[Reinforcement-Learning|Reinforcement-Learning]], Q-Learning-Foundations, Multi-Armed-Bandit-MAB, Decision-Making
|
||||
- **Raw Source:** 10_Wiki/Topics/AI/Exploration-vs-Exploitation.md
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
def update(self, a, r):
|
||||
self.N[a] += 1
|
||||
self.Q[a] += (r - self.Q[a]) / self.N[a]
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### UCB1
|
||||
```python
|
||||
class UCB1:
|
||||
def __init__(self, k):
|
||||
self.k, self.t = k, 0
|
||||
self.Q = np.zeros(k)
|
||||
self.N = np.zeros(k)
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
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))
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
def update(self, a, r):
|
||||
self.N[a] += 1
|
||||
self.Q[a] += (r - self.Q[a]) / self.N[a]
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### Thompson Sampling (Bernoulli)
|
||||
```python
|
||||
class ThompsonBernoulli:
|
||||
def __init__(self, k):
|
||||
self.alpha = np.ones(k) # successes + 1
|
||||
self.beta = np.ones(k) # failures + 1
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
def select(self):
|
||||
samples = np.random.beta(self.alpha, self.beta)
|
||||
return int(np.argmax(samples))
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
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]] · [[UCB]] · [[Thompson-Sampling]] · [[Epsilon-Greedy]]
|
||||
- 응용: [[A-B-Testing]] · [[Recommender-Systems]] · [[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 |
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user