docs(10_Wiki): Topic_Business/General/Graphic/Programming을 Topics/ 하위로 이동
최상위 10_Wiki/Topic_*였던 4개 카테고리 폴더를 10_Wiki/Topics/Topic_* 로 재배치. 콘텐츠 변경 없음(순수 폴더 이동) — Topics/ 하위 나머지 폴더는 이미 지난 커밋에서 전부 정리된 상태(잔존 항목은 에이전트 운영 상태 및 사용자가 보존을 요청한 업데이트0615/무제 3.canvas 뿐).
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
---
|
||||
id: wiki-2026-0508-api-응답-및-에러-핸들링-아키텍처
|
||||
title: API 응답 및 에러 핸들링 아키텍처
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: api-error-handling
|
||||
duplicate_of: "[[API Error Handling]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, api, error-handling]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# API 응답 및 에러 핸들링 아키텍처
|
||||
|
||||
> **이 문서는 [[API Error Handling]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 핵심 요약 (specialization aspects)
|
||||
- 매 Result<T, E> 타입 + Discriminated Union 의 typed error.
|
||||
- 매 Response Envelope: `{ success, data, error }` 구조.
|
||||
- 매 HTTP status code + domain error code 의 separation.
|
||||
|
||||
## 🔗 Graph
|
||||
- Adjacent: [[Result Type]] · [[Discriminated_Unions|Discriminated Unions]] · [[Zod 런타임 유효성 검사 통합]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
@@ -0,0 +1,139 @@
|
||||
---
|
||||
id: wiki-2026-0508-aspnet-core
|
||||
title: ASP.NET Core
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [ASP.NET Core, .NET Web, Kestrel, Minimal API]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [dotnet, csharp, web, backend]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: csharp
|
||||
framework: ASP.NET Core 9 / .NET 9
|
||||
---
|
||||
|
||||
# ASP.NET Core
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 cross-platform high-performance 의 .NET 의 web framework"**. 매 Microsoft 의 2016 release 후 의 modular middleware pipeline + Kestrel server + DI built-in 의 design — 매 2026 의 .NET 9 의 native AOT, Minimal API, Blazor United, gRPC 의 first-class support 로 매 enterprise + cloud-native workload 의 dominant choice.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 Architecture
|
||||
- **Kestrel**: 매 cross-platform HTTP server (libuv → managed sockets).
|
||||
- **Middleware pipeline**: 매 request 의 ordered chain — auth, logging, routing, endpoint.
|
||||
- **DI container** (built-in): scoped/singleton/transient.
|
||||
- **Configuration**: appsettings.json + env + secrets + Azure KeyVault 의 layered.
|
||||
- **Hosting model**: Generic Host (`IHostBuilder`) → minimal `WebApplication`.
|
||||
|
||||
### 매 API styles
|
||||
1. **Minimal API** (.NET 6+): top-level, lambda-based — small services 의 default.
|
||||
2. **MVC controllers**: 매 conventional REST.
|
||||
3. **Blazor Server / WASM / United** (.NET 8+): full-stack C# UI.
|
||||
4. **gRPC**: HTTP/2, Protobuf — service-to-service.
|
||||
5. **SignalR**: WebSocket / long-poll.
|
||||
|
||||
### 매 응용
|
||||
1. REST API (Stripe, Shopify-style backends).
|
||||
2. gRPC microservice mesh (.NET 9 의 native AOT 의 cold-start fast).
|
||||
3. Blazor 의 internal admin panel.
|
||||
4. Azure Functions / AWS Lambda (isolated worker).
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Minimal API
|
||||
```csharp
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
builder.Services.AddDbContext<AppDb>(o => o.UseNpgsql(builder.Configuration.GetConnectionString("Db")));
|
||||
builder.Services.AddAuthentication().AddJwtBearer();
|
||||
|
||||
var app = builder.Build();
|
||||
app.MapGet("/users/{id:int}", async (int id, AppDb db) =>
|
||||
await db.Users.FindAsync(id) is { } u ? Results.Ok(u) : Results.NotFound());
|
||||
app.MapPost("/users", async (User u, AppDb db) => {
|
||||
db.Users.Add(u); await db.SaveChangesAsync();
|
||||
return Results.Created($"/users/{u.Id}", u);
|
||||
});
|
||||
app.Run();
|
||||
```
|
||||
|
||||
### Middleware
|
||||
```csharp
|
||||
app.Use(async (ctx, next) => {
|
||||
var sw = Stopwatch.StartNew();
|
||||
await next();
|
||||
Console.WriteLine($"{ctx.Request.Path} {sw.ElapsedMilliseconds}ms");
|
||||
});
|
||||
```
|
||||
|
||||
### DI + scoped service
|
||||
```csharp
|
||||
builder.Services.AddScoped<IRepo, EfRepo>();
|
||||
app.MapGet("/x", (IRepo r) => r.GetAll());
|
||||
```
|
||||
|
||||
### Native AOT (.NET 9)
|
||||
```xml
|
||||
<PropertyGroup>
|
||||
<PublishAot>true</PublishAot>
|
||||
<InvariantGlobalization>true</InvariantGlobalization>
|
||||
</PropertyGroup>
|
||||
```
|
||||
- 매 single-file binary, 매 cold-start <10ms, 매 reflection 의 limit.
|
||||
|
||||
### Authentication (JWT)
|
||||
```csharp
|
||||
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||
.AddJwtBearer(o => {
|
||||
o.TokenValidationParameters = new() {
|
||||
ValidIssuer = "https://issuer",
|
||||
ValidAudience = "api",
|
||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret))
|
||||
};
|
||||
});
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.MapGet("/me", (ClaimsPrincipal u) => u.Identity?.Name).RequireAuthorization();
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Small service / prototype | Minimal API |
|
||||
| Complex routing / filters | MVC Controllers |
|
||||
| Service-to-service (internal) | gRPC |
|
||||
| Real-time (chat, dashboard) | SignalR |
|
||||
| Cold-start sensitive (lambda) | Native AOT + Minimal API |
|
||||
| Full-stack C# | Blazor United |
|
||||
|
||||
**기본값**: 매 Minimal API + EF Core + JWT — 매 modern .NET 의 standard stack.
|
||||
|
||||
## 🔗 Graph
|
||||
- 응용: [[Microservices]]
|
||||
- Adjacent: [[Kestrel]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: Minimal API endpoint 의 생성, EF Core query 의 LINQ, middleware 의 boilerplate.
|
||||
**언제 X**: 매 native AOT 의 reflection-heavy 의 third-party library 의 compatibility — 매 manual 의 verify.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Sync-over-async** (`.Result`, `.Wait()`): 매 thread pool 의 deadlock — 매 `await` 의 사용.
|
||||
- **DbContext singleton**: 매 EF Core 의 not thread-safe — 매 scoped.
|
||||
- **Middleware order 의 random**: 매 auth 의 routing 의 후 — 매 401 의 not enforced.
|
||||
- **Returning IQueryable from controller**: 매 N+1, 매 connection 의 leak.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (learn.microsoft.com/aspnet/core, .NET 9 release notes).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — Minimal API + AOT + JWT patterns |
|
||||
@@ -0,0 +1,142 @@
|
||||
---
|
||||
id: wiki-20260508-ast-abstract-syntax-tree--redir
|
||||
title: AST (Abstract Syntax Tree)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [AST, Abstract Syntax Tree, 추상 구문 트리]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
verification_status: applied
|
||||
tags: [compiler, parser, ast, language]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: typescript
|
||||
framework: babel-parser, ts-morph, tree-sitter
|
||||
---
|
||||
|
||||
# AST (Abstract Syntax Tree)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 source code 의 tree-shaped semantic skeleton"**. 매 lexer 의 token stream 을 parser 가 grammar rule 따라 nested node 의 tree 로 변환 — comment/whitespace/parens 의 trivia 를 제거하고 매 program 의 structural meaning 만 보존. 매 2026 의 Babel·SWC·TypeScript Compiler·Tree-sitter·Rust analyzer 의 모든 modern toolchain 의 핵심 IR.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 AST vs CST
|
||||
- **CST** (Concrete Syntax Tree): 매 source 의 every char 보존 — formatter, linter용.
|
||||
- **AST**: 매 semantic structure 만 — compiler, transpiler, type checker용.
|
||||
- 매 trade-off: lossless ↔ analysis-friendly.
|
||||
|
||||
### 매 Node 의 구조
|
||||
- 매 `type` field (e.g. `BinaryExpression`, `Identifier`).
|
||||
- 매 children (positional or named).
|
||||
- 매 `loc`/`range` (source position).
|
||||
- 매 ESTree spec — JS 의 standard AST shape.
|
||||
|
||||
### 매 응용
|
||||
1. **Compiler**: AST → IR → bytecode/machine code.
|
||||
2. **Transpiler** (Babel, SWC): AST → transformed AST → code.
|
||||
3. **Linter** (ESLint): AST traversal + rule matching.
|
||||
4. **Formatter** (Prettier): AST → printer.
|
||||
5. **IDE**: hover, refactor, go-to-def 의 AST query.
|
||||
6. **Codemod** (jscodeshift, ts-morph): bulk refactor.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Babel parse
|
||||
```typescript
|
||||
import { parse } from "@babel/parser";
|
||||
|
||||
const code = `const x = 1 + 2;`;
|
||||
const ast = parse(code, { sourceType: "module" });
|
||||
console.log(ast.program.body[0]);
|
||||
// VariableDeclaration { kind: "const", declarations: [...] }
|
||||
```
|
||||
|
||||
### Visitor (transform)
|
||||
```typescript
|
||||
import traverse from "@babel/traverse";
|
||||
|
||||
traverse(ast, {
|
||||
BinaryExpression(path) {
|
||||
if (path.node.operator === "+") {
|
||||
// 매 constant folding
|
||||
const { left, right } = path.node;
|
||||
if (left.type === "NumericLiteral" && right.type === "NumericLiteral") {
|
||||
path.replaceWith({ type: "NumericLiteral", value: left.value + right.value });
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### TypeScript Compiler API
|
||||
```typescript
|
||||
import * as ts from "typescript";
|
||||
|
||||
const source = ts.createSourceFile("x.ts", "const x: number = 1;", ts.ScriptTarget.Latest);
|
||||
function visit(node: ts.Node) {
|
||||
if (ts.isVariableDeclaration(node)) {
|
||||
console.log(node.name.getText(source));
|
||||
}
|
||||
ts.forEachChild(node, visit);
|
||||
}
|
||||
visit(source);
|
||||
```
|
||||
|
||||
### Tree-sitter (incremental)
|
||||
```javascript
|
||||
const Parser = require("tree-sitter");
|
||||
const TS = require("tree-sitter-typescript").typescript;
|
||||
const parser = new Parser();
|
||||
parser.setLanguage(TS);
|
||||
const tree = parser.parse("const x = 1;");
|
||||
// 매 incremental: tree.edit(...) 로 partial reparse
|
||||
```
|
||||
|
||||
### ts-morph (codemod)
|
||||
```typescript
|
||||
import { Project } from "ts-morph";
|
||||
const proj = new Project();
|
||||
const sf = proj.addSourceFileAtPath("src/foo.ts");
|
||||
sf.getFunctions().forEach((fn) => fn.setIsAsync(true));
|
||||
sf.saveSync();
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Compile / transpile JS/TS | Babel (@babel/parser) or SWC |
|
||||
| IDE / editor highlighting | Tree-sitter (incremental, fast) |
|
||||
| TypeScript-specific 의 type-aware refactor | TypeScript Compiler API or ts-morph |
|
||||
| Linting | ESLint (espree/typescript-eslint) |
|
||||
| 1-off codemod | jscodeshift or ts-morph |
|
||||
| Native speed (Rust/Go) | SWC, Rome, Biome |
|
||||
|
||||
**기본값**: 매 TS 의 type-aware 작업 → ts-morph. 매 perf-critical 의 transpile → SWC. 매 editor → Tree-sitter.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Parser]]
|
||||
- 응용: [[ESLint]] · [[Prettier]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 codemod 의 generation, AST node type 의 explanation, visitor pattern 의 boilerplate.
|
||||
**언제 X**: 매 large-scale 의 type-aware refactor — ts-morph 의 deterministic 가 더 안전.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Regex 의 code 의 transform**: 매 nested syntax 의 break — AST 의 use.
|
||||
- **Mutate AST 의 children array 의 직접**: 매 visitor 의 path API 의 use.
|
||||
- **Source map 의 무시**: 매 transform 후 의 debug 의 broken — `retainLines`/sourcemap 의 emit.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Babel docs, TS Compiler API, ESTree spec).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — full AST treatment with Babel/TS/Tree-sitter patterns |
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
id: wiki-2026-0508-ci-cd-파이프라인-자동화
|
||||
title: CI/CD 파이프라인 자동화
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: ci-cd-pipeline
|
||||
duplicate_of: "[[CI_CD_Pipeline|CI/CD Pipeline]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
verification_status: redirected
|
||||
tags: [duplicate, cicd, automation]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# CI/CD 파이프라인 자동화
|
||||
|
||||
> **이 문서는 [[CI_CD_Pipeline|CI/CD Pipeline]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 핵심 요약 (specialization aspects)
|
||||
- 매 한국어 alias 의 lookup 용.
|
||||
- 매 build → test → deploy 의 자동화 — 매 GitHub Actions / GitLab CI / Jenkins 의 modern stack.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[CI_CD_Pipeline|CI/CD Pipeline]] (canonical)
|
||||
- Adjacent: [[Continuous Integration (CI)]] · [[TeamCity]] · [[데브섹옵스 (DevSecOps) 환경에서의 지속적인 보안 검사]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
id: wiki-2026-0508-ci-cd-파이프라인
|
||||
title: CI/CD 파이프라인
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: ci-cd-pipeline
|
||||
duplicate_of: "[[CI_CD_Pipeline|CI/CD Pipeline]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
verification_status: redirected
|
||||
tags: [duplicate, cicd]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# CI/CD 파이프라인
|
||||
|
||||
> **이 문서는 [[CI_CD_Pipeline|CI/CD Pipeline]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 핵심 요약 (specialization aspects)
|
||||
- 매 한국어 alias.
|
||||
- 매 commit → build → test → deploy 의 자동화.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[CI_CD_Pipeline|CI/CD Pipeline]] (canonical)
|
||||
- Adjacent: [[Continuous Integration (CI)]] · [[CI_CD 파이프라인 자동화]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
id: wiki-2026-0508-cst-구체-구문-트리
|
||||
title: CST (구체 구문 트리)
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: cst
|
||||
duplicate_of: "[[CST (Concrete Syntax Tree)]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, parser, compiler]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# CST (구체 구문 트리)
|
||||
|
||||
> **이 문서는 [[CST (Concrete Syntax Tree)]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 핵심 요약 (specialization aspects)
|
||||
- 매 한국어 alias 의 lookup 용.
|
||||
- 매 every char (whitespace, comment) 의 lossless 보존 — formatter, linter, IDE refactor 의 source.
|
||||
- 매 vs AST: AST 는 semantic 만, CST 는 surface 의 모든 token.
|
||||
|
||||
## 🔗 Graph
|
||||
- Adjacent: [[AST (Abstract Syntax Tree)]] · [[Parser]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
@@ -0,0 +1,121 @@
|
||||
---
|
||||
id: wiki-2026-0508-chromium
|
||||
title: Chromium
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Chromium, Blink, V8 Browser]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [browser, engine, blink, v8]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: cpp
|
||||
framework: Blink, V8, Skia
|
||||
---
|
||||
|
||||
# Chromium
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 Google 의 open-source browser engine codebase"**. 매 Blink (rendering, fork of WebKit, 2013) + V8 (JS) + Skia (graphics) + Mojo (IPC) 의 결합 — 매 2026 의 Chrome / Edge / Brave / Opera / Arc / Vivaldi / Electron / Tauri (WebView2) 의 base. 매 multi-process security architecture (sandbox, site isolation) 의 reference.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 Architecture
|
||||
- **Browser process**: 매 UI, network, disk — privileged.
|
||||
- **Renderer process** (per site): 매 Blink + V8 — sandboxed.
|
||||
- **GPU process**: Skia 의 hardware-accel.
|
||||
- **Utility processes**: audio, network service.
|
||||
- **Mojo IPC**: typed message passing.
|
||||
|
||||
### 매 Components
|
||||
- **Blink**: HTML parse, CSS, layout, paint, compositor.
|
||||
- **V8**: JS + WebAssembly (Sparkplug, Maglev, TurboFan, Liftoff).
|
||||
- **Skia**: 2D graphics.
|
||||
- **WebRTC, WebGPU, WebCodecs**: media.
|
||||
- **Site Isolation**: 매 origin 의 process-level isolation — Spectre 의 mitigate.
|
||||
|
||||
### 매 응용
|
||||
1. Chrome browser (1B+ users).
|
||||
2. Embed: Electron, Tauri (WebView2 on Win), CEF.
|
||||
3. Headless: Puppeteer, Playwright (chromium build).
|
||||
4. Forks: Edge (2020+), Brave, Vivaldi, Arc, Opera.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Build chromium (sketch)
|
||||
```bash
|
||||
git clone https://chromium.googlesource.com/chromium/src.git
|
||||
cd src
|
||||
gclient sync
|
||||
gn gen out/Release --args='is_debug=false'
|
||||
autoninja -C out/Release chrome
|
||||
```
|
||||
|
||||
### Headless via Puppeteer
|
||||
```javascript
|
||||
import puppeteer from "puppeteer";
|
||||
const browser = await puppeteer.launch({ headless: "new", args: ["--no-sandbox"] });
|
||||
const page = await browser.newPage();
|
||||
await page.goto("https://example.com");
|
||||
await page.screenshot({ path: "x.png" });
|
||||
await browser.close();
|
||||
```
|
||||
|
||||
### CDP (Chrome DevTools Protocol) raw
|
||||
```javascript
|
||||
const client = await page.target().createCDPSession();
|
||||
await client.send("Performance.enable");
|
||||
const metrics = await client.send("Performance.getMetrics");
|
||||
```
|
||||
|
||||
### Site Isolation flag
|
||||
```bash
|
||||
chrome --site-per-process # default since 2018
|
||||
chrome --disable-site-isolation-trials # debug only — never prod
|
||||
```
|
||||
|
||||
### V8 inspect
|
||||
```bash
|
||||
node --inspect-brk app.js
|
||||
# DevTools 의 chrome://inspect 의 attach
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Build cross-platform desktop app | Tauri (smaller) > Electron (mature) |
|
||||
| Web automation | Playwright > Puppeteer (multi-engine) |
|
||||
| Custom browser | fork Chromium (Brave-style) — 매 maintenance cost 큼 |
|
||||
| Embed web view | WebView2 (Win) / WKWebView (Mac) — 매 native > Electron |
|
||||
|
||||
**기본값**: 매 web app 의 Electron / Tauri 의 ship — 매 user-facing 의 자체 fork X.
|
||||
|
||||
## 🔗 Graph
|
||||
- 변형: [[Chrome]] · [[Electron]]
|
||||
- 응용: [[Playwright]]
|
||||
- Adjacent: [[Blink]] · [[V8]] · [[WebKit]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: CDP 사용법, Puppeteer/Playwright script, Chromium component 의 explanation.
|
||||
**언제 X**: 매 Chromium 의 internal C++ refactor — 매 LLM 의 outdated 가능.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **--no-sandbox in production**: 매 sandboxing 의 disable — RCE 의 risk.
|
||||
- **--disable-web-security**: 매 dev 만 — prod 의 catastrophic.
|
||||
- **Pinning to old Chromium**: 매 CVE 의 backlog — 매 latest stable.
|
||||
- **Electron + remote module**: 매 deprecated, 매 contextIsolation: true.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (chromium.org, source.chromium.org, V8 blog).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — multi-process arch + Puppeteer/CDP patterns |
|
||||
@@ -0,0 +1,161 @@
|
||||
---
|
||||
id: wiki-2026-0508-code-minification
|
||||
title: Code Minification
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Minification, JS Minify, CSS Minify, Bundle Minification]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [build, performance, javascript, web]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: javascript
|
||||
framework: esbuild/swc/terser
|
||||
---
|
||||
|
||||
# Code Minification
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 source code 의 semantic 보존 + size 의 minimize"**. 매 whitespace/comment 제거 + identifier rename + dead code elimination + constant folding. 2026 의 esbuild/SWC/OXC 의 native-speed mainstream, Terser 의 max compression fallback.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 변환 단계
|
||||
- **Strip**: whitespace, comments, semicolon redundancy.
|
||||
- **Mangle**: local identifier → 매 short (a, b, c).
|
||||
- **Compress**: constant fold, DCE, inline single-use, sequence expression.
|
||||
- **Property mangle** (optional): `obj.privateField` → `obj.a` (매 risky).
|
||||
|
||||
### 매 Tree shaking
|
||||
- ES module static imports 의 분석 → 매 unused exports 의 제거.
|
||||
- `sideEffects: false` in package.json 의 강력한 hint.
|
||||
|
||||
### 매 Source maps
|
||||
- Mangled output 의 production debugging 의 essential.
|
||||
- `//# sourceMappingURL=app.js.map` + Sentry/DataDog upload.
|
||||
|
||||
### 매 응용
|
||||
1. JS bundle 의 70-80% 크기 reduction (gzip 후 추가).
|
||||
2. CSS 의 50% reduction (whitespace + selector merging).
|
||||
3. HTML 의 inline asset minification (Astro, Next).
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### esbuild (fastest, default for new)
|
||||
```javascript
|
||||
// build.mjs
|
||||
import { build } from 'esbuild';
|
||||
await build({
|
||||
entryPoints: ['src/app.ts'],
|
||||
bundle: true,
|
||||
minify: true, // whitespace + identifier + syntax
|
||||
sourcemap: true,
|
||||
target: ['es2022'],
|
||||
treeShaking: true,
|
||||
outfile: 'dist/app.js',
|
||||
});
|
||||
```
|
||||
|
||||
### SWC (Rust, used by Next/Parcel)
|
||||
```javascript
|
||||
// .swcrc
|
||||
{
|
||||
"jsc": { "target": "es2022", "minify": { "compress": true, "mangle": true } },
|
||||
"minify": true,
|
||||
"sourceMaps": true
|
||||
}
|
||||
```
|
||||
|
||||
### Terser (max compression, slower)
|
||||
```javascript
|
||||
import { minify } from 'terser';
|
||||
const out = await minify(src, {
|
||||
compress: { passes: 3, pure_getters: true, unsafe_arrows: true },
|
||||
mangle: { properties: { regex: /^_/ } }, // 매 only _-prefixed
|
||||
format: { comments: false },
|
||||
sourceMap: { url: 'app.js.map' },
|
||||
});
|
||||
```
|
||||
|
||||
### Vite production
|
||||
```javascript
|
||||
// vite.config.ts
|
||||
export default {
|
||||
build: {
|
||||
minify: 'esbuild', // or 'terser' for max
|
||||
sourcemap: true,
|
||||
rollupOptions: {
|
||||
output: { manualChunks: { vendor: ['react', 'react-dom'] } },
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### CSS — Lightning CSS
|
||||
```javascript
|
||||
import { transform } from 'lightningcss';
|
||||
const { code } = transform({
|
||||
filename: 'style.css',
|
||||
code: Buffer.from(src),
|
||||
minify: true,
|
||||
targets: { chrome: 100 << 16, safari: 16 << 16 },
|
||||
});
|
||||
```
|
||||
|
||||
### Sentry source map upload
|
||||
```bash
|
||||
sentry-cli sourcemaps inject ./dist
|
||||
sentry-cli sourcemaps upload --release "$VERSION" ./dist
|
||||
# 매 production 에 .map 의 ship 의 X — Sentry 의 server-side 보관
|
||||
```
|
||||
|
||||
### DCE / pure annotation
|
||||
```javascript
|
||||
// 매 tree shaker 에 hint
|
||||
const heavyConst = /*#__PURE__*/ buildHeavy();
|
||||
// 매 unused → bundle 에서 제거
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Tool |
|
||||
|---|---|
|
||||
| Default new project | esbuild / SWC |
|
||||
| Maximum compression | Terser (passes: 3) |
|
||||
| CSS | Lightning CSS |
|
||||
| HTML | html-minifier-terser |
|
||||
| Library publish | Rollup + esbuild minify |
|
||||
| Browser extension | esbuild (size budget) |
|
||||
|
||||
**기본값**: esbuild minify + tree shake + source maps + Sentry upload.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Web_Performance]]
|
||||
- 변형: [[Code Splitting]] · [[Compression]]
|
||||
- 응용: [[Bundle_Analysis]] · [[Source_Maps]]
|
||||
- Adjacent: [[esbuild]] · [[Vite]] · [[Rollup]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: build config 작성, minifier option tuning, bundle analysis.
|
||||
**언제 X**: 매 generated bundle 의 manual edit — 매 source 의 수정 후 rebuild.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **No source map in prod**: 매 stack trace 의 obfuscated — debug 불가.
|
||||
- **Property mangle without test**: 매 `obj["field"]` access 의 break.
|
||||
- **Minify before bundling**: 매 cross-module DCE 의 손실.
|
||||
- **Comments preserved**: license 의 `/*! */` 만 keep, rest strip.
|
||||
- **One huge bundle**: code split 의 X — initial load 의 huge.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (esbuild docs, Terser README, Vite docs, Lightning CSS docs).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — esbuild/SWC/Terser/Lightning CSS patterns + DCE |
|
||||
@@ -0,0 +1,175 @@
|
||||
---
|
||||
id: wiki-2026-0508-dom-요소-조작-및-타입-좁히기
|
||||
title: DOM 요소 조작 및 타입 좁히기
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [DOM Manipulation, Type Narrowing, querySelector Typing]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [typescript, dom, web, type-narrowing]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: typescript
|
||||
framework: dom
|
||||
---
|
||||
|
||||
# DOM 요소 조작 및 타입 좁히기
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 DOM API 의 untyped boundary 의 TypeScript narrowing 의 적용"**. 매 `querySelector` 의 default `Element | null` 위 의 generic + instanceof + assertion. 2026 의 strict null checks + satisfies + lib.dom.d.ts 의 mainstream type ergonomics.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 Type narrowing tools
|
||||
- **Generic param**: `querySelector<HTMLInputElement>(...)` — runtime check 의 X, 매 assertion 만.
|
||||
- **`instanceof`**: 매 runtime check + narrow.
|
||||
- **Type guard function**: `function isInput(el): el is HTMLInputElement`.
|
||||
- **Discriminated property**: `el.tagName === 'INPUT'` (의 narrow X — manual cast 필요).
|
||||
|
||||
### 매 Null safety
|
||||
- `querySelector` 의 `null` 의 always 가능 — 매 explicit check.
|
||||
- `getElementById` 의 same — `HTMLElement | null`.
|
||||
- `as!` non-null assertion 의 last resort — 매 prefer guard.
|
||||
|
||||
### 매 응용
|
||||
1. Form value 추출 + validation.
|
||||
2. Dynamic widget hydration (서버 HTML 위 의 JS enhance).
|
||||
3. Custom element / Web Component 의 typed access.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### querySelector with generic
|
||||
```typescript
|
||||
// 매 generic 의 assertion 만 — 매 null 의 still 가능
|
||||
const input = document.querySelector<HTMLInputElement>('#email');
|
||||
if (!input) throw new Error('email input missing');
|
||||
input.value; // 매 narrowed to HTMLInputElement
|
||||
```
|
||||
|
||||
### instanceof guard
|
||||
```typescript
|
||||
const el = document.getElementById('email');
|
||||
if (el instanceof HTMLInputElement) {
|
||||
el.value = 'test@example.com'; // 매 narrowed
|
||||
} else {
|
||||
throw new Error('not an input');
|
||||
}
|
||||
```
|
||||
|
||||
### Custom type guard
|
||||
```typescript
|
||||
function isInput(el: Element | null): el is HTMLInputElement {
|
||||
return el instanceof HTMLInputElement;
|
||||
}
|
||||
function getValue(selector: string): string {
|
||||
const el = document.querySelector(selector);
|
||||
if (!isInput(el)) throw new Error(`${selector} is not input`);
|
||||
return el.value;
|
||||
}
|
||||
```
|
||||
|
||||
### Helper: assertElement
|
||||
```typescript
|
||||
function $<T extends HTMLElement>(
|
||||
selector: string,
|
||||
ctor: new () => T = HTMLElement as new () => T,
|
||||
root: ParentNode = document,
|
||||
): T {
|
||||
const el = root.querySelector(selector);
|
||||
if (!el) throw new Error(`Missing: ${selector}`);
|
||||
if (!(el instanceof ctor)) throw new Error(`Wrong type: ${selector}`);
|
||||
return el as T;
|
||||
}
|
||||
const form = $('#login', HTMLFormElement);
|
||||
const email = $('input[name=email]', HTMLInputElement, form);
|
||||
```
|
||||
|
||||
### Form data — typed
|
||||
```typescript
|
||||
function getFormData<T extends Record<string, string>>(form: HTMLFormElement): T {
|
||||
const fd = new FormData(form);
|
||||
return Object.fromEntries(fd.entries()) as T;
|
||||
}
|
||||
type LoginForm = { email: string; password: string };
|
||||
const data = getFormData<LoginForm>(form);
|
||||
```
|
||||
|
||||
### Event delegation with narrowing
|
||||
```typescript
|
||||
document.addEventListener('click', (e) => {
|
||||
const target = e.target;
|
||||
if (!(target instanceof HTMLElement)) return;
|
||||
const btn = target.closest<HTMLButtonElement>('button[data-action]');
|
||||
if (!btn) return;
|
||||
switch (btn.dataset.action) {
|
||||
case 'save': return save();
|
||||
case 'delete': return remove(btn.dataset.id!);
|
||||
default: throw new Error(`Unknown action: ${btn.dataset.action}`);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Custom element typing
|
||||
```typescript
|
||||
class MyToggle extends HTMLElement {
|
||||
toggle() { this.toggleAttribute('open'); }
|
||||
}
|
||||
customElements.define('my-toggle', MyToggle);
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap { 'my-toggle': MyToggle; }
|
||||
}
|
||||
const t = document.querySelector('my-toggle'); // 매 typed as MyToggle | null
|
||||
t?.toggle();
|
||||
```
|
||||
|
||||
### satisfies for config (2026 idiom)
|
||||
```typescript
|
||||
const handlers = {
|
||||
'#save': (el: HTMLButtonElement) => el.addEventListener('click', save),
|
||||
'#email': (el: HTMLInputElement) => el.addEventListener('blur', validate),
|
||||
} satisfies Record<string, (el: HTMLElement) => void>;
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Pattern |
|
||||
|---|---|
|
||||
| Single fetch + null OK | `querySelector<T>` + null check |
|
||||
| Strict invariant | `$()` helper with ctor |
|
||||
| Multiple element types | instanceof in switch |
|
||||
| Reusable check | Custom type guard |
|
||||
| Event handler | `target instanceof HTMLElement` |
|
||||
| Custom element | HTMLElementTagNameMap augment |
|
||||
|
||||
**기본값**: assertElement helper + instanceof + custom guards. `as` casts 의 last resort 만.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[TypeScript]] · [[DOM]]
|
||||
- 변형: [[Discriminated_Unions]]
|
||||
- 응용: [[DOM 요소 조작]] · [[Web_Components]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: helper 작성, type guard 추출, refactor untyped jQuery → typed TS.
|
||||
**언제 X**: 매 framework (React/Vue/Svelte) 안 — 매 framework type 의 사용.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **`as HTMLInputElement` everywhere**: runtime mismatch 의 silent.
|
||||
- **`!` non-null assertion 남발**: 매 null check 의 미루기 — runtime crash.
|
||||
- **`any` for events**: 매 `Event` subclass 의 사용.
|
||||
- **`getElementById` raw return 사용**: null check skip.
|
||||
- **innerHTML with user input**: 매 XSS — `textContent` / DOMPurify 의 사용.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (TypeScript handbook, lib.dom.d.ts, MDN DOM docs).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — generic/instanceof/guard/helper patterns for typed DOM |
|
||||
@@ -0,0 +1,194 @@
|
||||
---
|
||||
id: wiki-2026-0508-dom-요소-조작
|
||||
title: DOM 요소 조작
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [DOM Manipulation, Vanilla JS DOM, Document API]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [dom, javascript, web, browser]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: javascript
|
||||
framework: dom
|
||||
---
|
||||
|
||||
# DOM 요소 조작
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 Document 의 tree 의 query + mutation 의 web 기본 API"**. 매 jQuery 의 era 종료, 2026 의 modern DOM (querySelector, classList, dataset, MutationObserver) 의 충분 + framework (React/Solid/Svelte) 의 abstraction 위. 매 vanilla 의 fast path + 매 small widget 의 right tool.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 Query
|
||||
- `getElementById(id)` — 매 fastest single lookup.
|
||||
- `querySelector(sel)` / `querySelectorAll(sel)` — CSS selector general.
|
||||
- `closest(sel)` — 매 ancestor traversal.
|
||||
- `matches(sel)` — boolean check.
|
||||
|
||||
### 매 Mutate
|
||||
- **Create**: `createElement`, `cloneNode(true)`, `<template>` + `content.cloneNode`.
|
||||
- **Insert**: `append`, `prepend`, `before`, `after`, `replaceWith`.
|
||||
- **Remove**: `el.remove()`.
|
||||
- **Attribute**: `setAttribute`, `dataset.x`, `classList.add/toggle/remove`.
|
||||
- **Content**: `textContent` (safe) vs `innerHTML` (XSS risk).
|
||||
|
||||
### 매 Observe
|
||||
- `MutationObserver` — 매 subtree change.
|
||||
- `IntersectionObserver` — viewport visibility.
|
||||
- `ResizeObserver` — element size.
|
||||
|
||||
### 매 응용
|
||||
1. Lightweight widget (no framework) — banner, modal, tooltip.
|
||||
2. Server-rendered HTML enhancement (Hotwire, Astro islands).
|
||||
3. Browser extension content script.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Element creation (template)
|
||||
```html
|
||||
<template id="card-tpl">
|
||||
<article class="card">
|
||||
<h3 class="title"></h3>
|
||||
<p class="body"></p>
|
||||
</article>
|
||||
</template>
|
||||
```
|
||||
```javascript
|
||||
function renderCard({ title, body }) {
|
||||
const tpl = document.getElementById('card-tpl');
|
||||
const node = tpl.content.cloneNode(true);
|
||||
node.querySelector('.title').textContent = title;
|
||||
node.querySelector('.body').textContent = body;
|
||||
return node;
|
||||
}
|
||||
document.querySelector('#list').append(renderCard({ title: 'Hi', body: 'World' }));
|
||||
```
|
||||
|
||||
### classList + dataset
|
||||
```javascript
|
||||
const btn = document.querySelector('#toggle');
|
||||
btn.classList.toggle('active');
|
||||
btn.dataset.count = (Number(btn.dataset.count ?? 0) + 1).toString();
|
||||
// HTML: <button id="toggle" data-count="3">
|
||||
```
|
||||
|
||||
### Event delegation
|
||||
```javascript
|
||||
document.addEventListener('click', (e) => {
|
||||
const action = e.target.closest('[data-action]');
|
||||
if (!action) return;
|
||||
switch (action.dataset.action) {
|
||||
case 'open': openModal(action.dataset.id); break;
|
||||
case 'delete': remove(action.dataset.id); break;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Safe insertion (avoid innerHTML)
|
||||
```javascript
|
||||
// 매 X — XSS
|
||||
container.innerHTML = `<p>${userInput}</p>`;
|
||||
|
||||
// 매 O — textContent
|
||||
const p = document.createElement('p');
|
||||
p.textContent = userInput;
|
||||
container.append(p);
|
||||
|
||||
// 매 trusted HTML 만 — Sanitizer API (2026 baseline)
|
||||
container.setHTML(trustedString); // 의 native sanitize
|
||||
```
|
||||
|
||||
### IntersectionObserver — lazy load
|
||||
```javascript
|
||||
const io = new IntersectionObserver((entries) => {
|
||||
for (const e of entries) {
|
||||
if (!e.isIntersecting) continue;
|
||||
const img = e.target;
|
||||
img.src = img.dataset.src;
|
||||
io.unobserve(img);
|
||||
}
|
||||
});
|
||||
document.querySelectorAll('img[data-src]').forEach((img) => io.observe(img));
|
||||
```
|
||||
|
||||
### MutationObserver — react to subtree
|
||||
```javascript
|
||||
const mo = new MutationObserver((muts) => {
|
||||
for (const m of muts) {
|
||||
for (const n of m.addedNodes) {
|
||||
if (n instanceof HTMLAnchorElement) enhanceLink(n);
|
||||
}
|
||||
}
|
||||
});
|
||||
mo.observe(document.body, { childList: true, subtree: true });
|
||||
```
|
||||
|
||||
### Form serialization
|
||||
```javascript
|
||||
const form = document.querySelector('#login');
|
||||
form.addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
const data = Object.fromEntries(new FormData(form));
|
||||
fetch('/login', { method: 'POST', body: JSON.stringify(data), headers: { 'Content-Type': 'application/json' } });
|
||||
});
|
||||
```
|
||||
|
||||
### Animation — Web Animations API
|
||||
```javascript
|
||||
el.animate(
|
||||
[{ opacity: 0, transform: 'translateY(10px)' }, { opacity: 1, transform: 'none' }],
|
||||
{ duration: 200, easing: 'ease-out', fill: 'forwards' },
|
||||
);
|
||||
```
|
||||
|
||||
### Batched DOM updates
|
||||
```javascript
|
||||
const frag = document.createDocumentFragment();
|
||||
for (const item of items) frag.append(renderRow(item));
|
||||
list.append(frag); // 매 single reflow
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Static + small interaction | Vanilla DOM |
|
||||
| 100s of components | React / Solid / Svelte |
|
||||
| Server HTML + enhancement | Hotwire / Astro |
|
||||
| Lazy load images | IntersectionObserver |
|
||||
| External widget injection | MutationObserver |
|
||||
| Animation | Web Animations API |
|
||||
|
||||
**기본값**: querySelector + classList + textContent + delegation + Observer APIs.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[DOM]]
|
||||
- 변형: [[DOM 요소 조작 및 타입 좁히기]] · [[Shadow_DOM]]
|
||||
- 응용: [[Web_Components]] · [[Hotwire]]
|
||||
- Adjacent: [[IntersectionObserver]] · [[MutationObserver]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: vanilla widget scaffold, Observer setup, jQuery → modern migration.
|
||||
**언제 X**: 매 framework app — 매 framework primitive 의 사용.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **`innerHTML` with user input**: 매 XSS — `textContent` 또는 Sanitizer.
|
||||
- **Loop append in DOM**: 매 N reflows — DocumentFragment 의 사용.
|
||||
- **No event delegation**: 1000 listener 의 memory + perf 비용.
|
||||
- **document.write**: deprecated — 매 stream block.
|
||||
- **Manual style mutation everywhere**: classList toggle + CSS 의 사용.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (MDN DOM, Web Animations, Observers, Sanitizer API spec).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — query/mutate/observe patterns + Sanitizer + delegation |
|
||||
@@ -0,0 +1,140 @@
|
||||
---
|
||||
id: wiki-2026-0508-edge-bleeding
|
||||
title: Edge Bleeding
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Texture Bleeding, Atlas Bleeding]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [graphics, texture, rendering]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: GLSL/HLSL
|
||||
framework: WebGL/Three.js/Unity/Unreal
|
||||
---
|
||||
|
||||
# Edge Bleeding
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 texture sampling 의 인접 texel이 unintended 하게 leak — atlas seam의 colored line으로 manifest."**. 매 mipmap downsample / bilinear interpolation 매 texel boundary를 cross 하면서 발생. 매 sprite atlas, texture array, lightmap에서 매 visible artifact.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 원인
|
||||
- **Bilinear filter**: 매 sample point 매 texel center 사이 → 인접 texel weighted.
|
||||
- **Mipmap downsample**: 매 box filter 매 atlas neighbor를 average.
|
||||
- **UV precision**: float precision 매 정확한 boundary 매 hit 못 함.
|
||||
- **Anisotropic filtering**: 매 large footprint → 매 더 많은 neighbor sampling.
|
||||
|
||||
### 매 manifestation
|
||||
- Sprite atlas: 매 sprite edge 매 인접 sprite color line.
|
||||
- Tilemap: 매 tile seam 매 dark/bright line.
|
||||
- Skybox cubemap: 매 face boundary 매 visible seam.
|
||||
- Lightmap: 매 chart boundary 매 dark crack.
|
||||
|
||||
### 매 응용 (해결책)
|
||||
1. **Padding (gutter)**: 매 sprite 사이 1-2px transparent / replicated edge.
|
||||
2. **Half-texel UV inset**: UV 매 `(0.5/W, 0.5/H)` ~ `(1 - 0.5/W, 1 - 0.5/H)` 의 clamp.
|
||||
3. **CLAMP_TO_EDGE**: wrap mode 매 repeat → clamp.
|
||||
4. **Conservative UV**: 매 mesh UV 매 atlas region 의 inside 의 inset.
|
||||
5. **Mipmap-aware padding**: 매 mip level 별 padding (1px → 2px → 4px).
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Half-texel inset (GLSL)
|
||||
```glsl
|
||||
uniform vec2 atlasSize; // e.g. (2048, 2048)
|
||||
uniform vec4 spriteRect; // x, y, w, h in pixels
|
||||
|
||||
vec2 sampleUV(vec2 localUV) {
|
||||
vec2 halfTexel = 0.5 / atlasSize;
|
||||
vec2 minUV = spriteRect.xy / atlasSize + halfTexel;
|
||||
vec2 maxUV = (spriteRect.xy + spriteRect.zw) / atlasSize - halfTexel;
|
||||
return mix(minUV, maxUV, localUV);
|
||||
}
|
||||
```
|
||||
|
||||
### Atlas packer with padding (TS)
|
||||
```typescript
|
||||
function packSprite(sprite: ImageData, padding = 2): PackedSprite {
|
||||
const w = sprite.width + padding * 2;
|
||||
const h = sprite.height + padding * 2;
|
||||
const padded = new ImageData(w, h);
|
||||
// edge replicate (not transparent) for bilinear safety
|
||||
for (let y = 0; y < h; y++) {
|
||||
for (let x = 0; x < w; x++) {
|
||||
const sx = clamp(x - padding, 0, sprite.width - 1);
|
||||
const sy = clamp(y - padding, 0, sprite.height - 1);
|
||||
copyPixel(sprite, sx, sy, padded, x, y);
|
||||
}
|
||||
}
|
||||
return { data: padded, padding };
|
||||
}
|
||||
```
|
||||
|
||||
### Three.js NearestFilter (no bleed, no smooth)
|
||||
```javascript
|
||||
texture.minFilter = THREE.NearestFilter;
|
||||
texture.magFilter = THREE.NearestFilter;
|
||||
texture.generateMipmaps = false;
|
||||
texture.wrapS = texture.wrapT = THREE.ClampToEdgeWrapping;
|
||||
```
|
||||
|
||||
### Mipmap-aware padding count
|
||||
```typescript
|
||||
function paddingForMipLevels(levels: number): number {
|
||||
return Math.pow(2, levels - 1); // 4 levels → 8px padding
|
||||
}
|
||||
```
|
||||
|
||||
### Conservative cubemap seam fix (HLSL)
|
||||
```hlsl
|
||||
float3 SampleCubeSeamless(TextureCube tex, SamplerState s, float3 dir, float roughness) {
|
||||
float mip = roughness * 8.0;
|
||||
float texSize = 512.0 / pow(2, mip);
|
||||
float scale = 1.0 - 1.0 / texSize;
|
||||
return tex.SampleLevel(s, dir * scale, mip).rgb;
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Pixel art sprite | NearestFilter + padding 1px |
|
||||
| 3D texture atlas (smooth) | Half-texel inset + padding (2 * mip levels) |
|
||||
| Tilemap | Padding + clamp + per-tile texture array (best) |
|
||||
| Cubemap | GL_TEXTURE_CUBE_MAP_SEAMLESS (GL 3.2+) |
|
||||
| Lightmap | Chart padding 4px + dilation |
|
||||
|
||||
**기본값**: 매 padding 2px + half-texel inset, 매 mipmap 매 사용 시 2 * (mip levels) px.
|
||||
|
||||
## 🔗 Graph
|
||||
- 변형: [[Atlas Bleeding]]
|
||||
- 응용: [[Texture Array]]
|
||||
- Adjacent: [[Mipmap]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: sprite atlas / tilemap / lightmap 매 visible seam, 매 mipmap 매 사용한 atlas, 매 cubemap face 경계 artifact.
|
||||
**언제 X**: single texture (no atlas), 매 NEAREST filter 매 사용 + no mipmap, fully procedural texture.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Transparent padding alone**: 매 bilinear가 transparent와 mix → 매 dark fringe.
|
||||
- **Padding 너무 small**: mip level 3+ 매 도달 시 여전히 leak.
|
||||
- **Repeat wrap on atlas**: 매 opposite edge 매 sample → 완전한 wrong color.
|
||||
- **UV exactly at texel boundary**: 매 float precision 의해 random side 매 sample.
|
||||
- **Generate mipmap on packed atlas**: 매 mip downsample 매 인접 sprite를 average → mid-mip levels artifact.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Real-Time Rendering 4ed, Unity / Unreal docs, OpenGL spec).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — Edge bleeding 원인 / padding 전략 / mip-aware solution |
|
||||
@@ -0,0 +1,170 @@
|
||||
---
|
||||
id: wiki-2026-0508-effect-ts
|
||||
title: Effect TS
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Effect, Effect-TS, effect.ts]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [typescript, functional-programming, effect, error-handling]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: TypeScript
|
||||
framework: Effect
|
||||
---
|
||||
|
||||
# Effect TS
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 TypeScript 의 functional effect system — error · concurrency · resource 매 type-level encoding"**. 매 ZIO (Scala) inspired library 의 TS port. 2026 시점 v3.x stable, Discord · Vercel · Stripe internal services 가 production 채택.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 Effect<A, E, R>
|
||||
- `A`: success value type
|
||||
- `E`: error type (typed errors, no exceptions)
|
||||
- `R`: required services (DI context)
|
||||
- 매 lazy description — execution은 `Effect.runPromise` 시점.
|
||||
|
||||
### 매 핵심 primitives
|
||||
- `Effect.succeed` / `Effect.fail` / `Effect.sync` / `Effect.tryPromise`
|
||||
- `Effect.gen` (generator-based do-notation)
|
||||
- `Effect.all` (parallel), `Effect.forEach` (concurrency control)
|
||||
- `Layer` (DI composition), `Context.Tag` (service identity)
|
||||
|
||||
### 매 응용
|
||||
1. API gateway error contracts (`HttpClient` typed errors).
|
||||
2. Database transactional pipelines (`Effect.scoped` + `Layer`).
|
||||
3. Streaming ETL (`Stream` module).
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Effect.gen do-notation
|
||||
```ts
|
||||
import { Effect } from "effect"
|
||||
|
||||
const getUser = (id: string) =>
|
||||
Effect.gen(function* () {
|
||||
const db = yield* DatabaseService
|
||||
const user = yield* db.findUser(id)
|
||||
if (!user) return yield* Effect.fail(new UserNotFound({ id }))
|
||||
return user
|
||||
})
|
||||
```
|
||||
|
||||
### Typed errors (Data.TaggedError)
|
||||
```ts
|
||||
import { Data } from "effect"
|
||||
|
||||
class UserNotFound extends Data.TaggedError("UserNotFound")<{
|
||||
id: string
|
||||
}> {}
|
||||
|
||||
class DbConnectionError extends Data.TaggedError("DbConnectionError")<{
|
||||
cause: unknown
|
||||
}> {}
|
||||
```
|
||||
|
||||
### Layer composition
|
||||
```ts
|
||||
import { Effect, Layer, Context } from "effect"
|
||||
|
||||
class DatabaseService extends Context.Tag("DatabaseService")<
|
||||
DatabaseService,
|
||||
{ findUser: (id: string) => Effect.Effect<User | null, DbConnectionError> }
|
||||
>() {}
|
||||
|
||||
const DatabaseLive = Layer.succeed(DatabaseService, {
|
||||
findUser: (id) =>
|
||||
Effect.tryPromise({
|
||||
try: () => pgClient.query("SELECT * FROM users WHERE id=$1", [id]),
|
||||
catch: (cause) => new DbConnectionError({ cause }),
|
||||
}),
|
||||
})
|
||||
```
|
||||
|
||||
### Concurrent execution
|
||||
```ts
|
||||
const fetchAll = Effect.forEach(
|
||||
["a", "b", "c"],
|
||||
(id) => getUser(id),
|
||||
{ concurrency: 5 }
|
||||
)
|
||||
```
|
||||
|
||||
### Retry + timeout
|
||||
```ts
|
||||
import { Schedule, Duration } from "effect"
|
||||
|
||||
const robust = getUser("123").pipe(
|
||||
Effect.retry(Schedule.exponential(Duration.millis(100)).pipe(
|
||||
Schedule.compose(Schedule.recurs(3))
|
||||
)),
|
||||
Effect.timeout(Duration.seconds(5))
|
||||
)
|
||||
```
|
||||
|
||||
### Resource scoping
|
||||
```ts
|
||||
const program = Effect.scoped(
|
||||
Effect.gen(function* () {
|
||||
const file = yield* Effect.acquireRelease(
|
||||
openFile("data.txt"),
|
||||
(f) => closeFile(f)
|
||||
)
|
||||
return yield* readContent(file)
|
||||
})
|
||||
)
|
||||
```
|
||||
|
||||
### Schema validation
|
||||
```ts
|
||||
import { Schema } from "effect"
|
||||
|
||||
const User = Schema.Struct({
|
||||
id: Schema.String,
|
||||
age: Schema.Number.pipe(Schema.int(), Schema.nonNegative()),
|
||||
})
|
||||
|
||||
const parse = Schema.decodeUnknown(User)
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 단순 CRUD app | plain async/await + zod |
|
||||
| 복잡한 error taxonomy | Effect (typed errors) |
|
||||
| Concurrency-heavy pipeline | Effect (Schedule + Stream) |
|
||||
| Team unfamiliar with FP | neverthrow / fp-ts 시작 |
|
||||
|
||||
**기본값**: greenfield TS backend with complex error contracts → Effect 채택. 매 learning curve 높음 — team buy-in 매 우선.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Functional Programming]] · [[TypeScript 타입 시스템 및 인터페이스 설계]]
|
||||
- 변형: [[Result Type]]
|
||||
- 응용: [[견고한 도메인 모델 및 API 계약 설계]] · [[API 응답 및 에러 핸들링 아키텍처]]
|
||||
- Adjacent: [[Zod 런타임 유효성 검사 통합]] · [[ts-brand]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: TS backend with strict error typing, dependency injection at type level, retry/circuit-breaker policies.
|
||||
**언제 X**: 매 simple script · prototype · React component logic — overhead 매 큼.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Effect.runSync everywhere**: 매 sync execution 강제 — async benefit 상실.
|
||||
- **Fail with strings**: typed `TaggedError` 의 사용해야 매 discriminated handling 가능.
|
||||
- **Layer.merge spaghetti**: 매 dependency graph 의 명시적 organize.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (effect.website official docs · Effect 3.x release notes 2025).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — Effect 3.x patterns, Layer/Schema/typed errors |
|
||||
@@ -0,0 +1,179 @@
|
||||
---
|
||||
id: wiki-2026-0508-electron
|
||||
title: Electron
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Electron Framework, Atom Shell]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [desktop, javascript, chromium, nodejs]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: TypeScript/JavaScript
|
||||
framework: Electron 33+
|
||||
---
|
||||
|
||||
# Electron
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 Chromium + Node.js를 묶어 web tech 으로 desktop app 을 build"**. GitHub 이 Atom editor 용으로 만든 framework 가 VS Code, Slack, Discord, Figma desktop, 1Password 의 backbone 이 되었음. 2026 현재 Electron 33+ 가 process model 강화 (utility process), V8 sandbox, ASAR integrity 검사 의 기본화.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 process model
|
||||
- **Main process**: Node.js runtime, app lifecycle, native API (file, dialog, tray) 의 owner. 매 1 개 instance.
|
||||
- **Renderer process**: Chromium tab 마다 1 개. BrowserWindow content. Sandbox 기본 ON (Electron 20+).
|
||||
- **Preload script**: Renderer 의 isolated world 에서 실행, `contextBridge` 로 main 과 안전 bridge.
|
||||
- **Utility process**: 매 v22+ 추가. Heavy CPU/IO offload (image decode, ffmpeg).
|
||||
|
||||
### 매 IPC 패턴
|
||||
- `ipcRenderer.invoke` ↔ `ipcMain.handle` (Promise-based, 권장).
|
||||
- `ipcRenderer.send` ↔ `ipcMain.on` (fire-and-forget).
|
||||
- `webContents.send` ↔ `ipcRenderer.on` (main → renderer push).
|
||||
- 매 `contextIsolation: true` + `nodeIntegration: false` 의 mandatory.
|
||||
|
||||
### 매 응용
|
||||
1. **Editor**: VS Code, Atom, Obsidian.
|
||||
2. **Communication**: Slack, Discord, Microsoft Teams.
|
||||
3. **Design**: Figma desktop, Notion.
|
||||
4. **Crypto/Wallet**: 1Password, Exodus.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Secure preload bridge
|
||||
```typescript
|
||||
// preload.ts
|
||||
import { contextBridge, ipcRenderer } from 'electron'
|
||||
|
||||
contextBridge.exposeInMainWorld('api', {
|
||||
readFile: (path: string) => ipcRenderer.invoke('fs:read', path),
|
||||
onUpdate: (cb: (v: string) => void) => {
|
||||
const listener = (_: unknown, v: string) => cb(v)
|
||||
ipcRenderer.on('app:update', listener)
|
||||
return () => ipcRenderer.removeListener('app:update', listener)
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
### Main IPC handler with validation
|
||||
```typescript
|
||||
// main.ts
|
||||
import { ipcMain, app } from 'electron'
|
||||
import { promises as fs } from 'node:fs'
|
||||
import path from 'node:path'
|
||||
|
||||
ipcMain.handle('fs:read', async (_event, requested: string) => {
|
||||
const userData = app.getPath('userData')
|
||||
const resolved = path.resolve(userData, requested)
|
||||
if (!resolved.startsWith(userData)) throw new Error('path traversal')
|
||||
return await fs.readFile(resolved, 'utf-8')
|
||||
})
|
||||
```
|
||||
|
||||
### BrowserWindow secure defaults
|
||||
```typescript
|
||||
import { BrowserWindow } from 'electron'
|
||||
import path from 'node:path'
|
||||
|
||||
const win = new BrowserWindow({
|
||||
width: 1200,
|
||||
height: 800,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js'),
|
||||
contextIsolation: true,
|
||||
nodeIntegration: false,
|
||||
sandbox: true,
|
||||
webSecurity: true,
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
### Auto-updater (electron-updater)
|
||||
```typescript
|
||||
import { autoUpdater } from 'electron-updater'
|
||||
|
||||
autoUpdater.checkForUpdatesAndNotify()
|
||||
autoUpdater.on('update-downloaded', () => autoUpdater.quitAndInstall())
|
||||
```
|
||||
|
||||
### Utility process offload
|
||||
```typescript
|
||||
import { utilityProcess, MessageChannelMain } from 'electron'
|
||||
|
||||
const { port1, port2 } = new MessageChannelMain()
|
||||
const child = utilityProcess.fork(path.join(__dirname, 'worker.js'))
|
||||
child.postMessage({ task: 'transcode' }, [port2])
|
||||
port1.on('message', (msg) => console.log('result', msg))
|
||||
```
|
||||
|
||||
### Code signing build (electron-builder)
|
||||
```json
|
||||
{
|
||||
"build": {
|
||||
"appId": "com.example.app",
|
||||
"mac": { "hardenedRuntime": true, "gatekeeperAssess": false, "notarize": true },
|
||||
"win": { "signingHashAlgorithms": ["sha256"] },
|
||||
"asar": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Cross-platform desktop, web team | Electron |
|
||||
| Bundle size critical (<50MB) | Tauri (Rust) 고려 |
|
||||
| Native feel mandatory | Native (Swift/Kotlin) |
|
||||
| Existing web app → wrap | Electron |
|
||||
| Mobile target 도 필요 | React Native / Flutter |
|
||||
|
||||
**기본값**: 매 Electron 33+ + contextIsolation + electron-builder + auto-updater.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Chromium]] · [[Nodejs_and_Backend_Optimization|Nodejs]]
|
||||
- 변형: [[Tauri]]
|
||||
- Adjacent: [[Chrome DevTools(크롬 개발자 도구)]] · [[V8 엔진 힙 아키텍처]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: web stack 재사용, 빠른 cross-platform delivery, rich web-based UI 필요.
|
||||
**언제 X**: 매 100MB+ binary 가 unacceptable, 매 deep OS integration (kernel ext, system tray 만 의 limit), battery-critical mobile.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **nodeIntegration: true with remote content**: 매 RCE risk. 매 contextIsolation 강제.
|
||||
- **`require('electron').remote`**: deprecated, removed v14+. `@electron/remote` 도 안티 — IPC handle 로 교체.
|
||||
- **불특정 origin loadURL**: 매 untrusted web 을 BrowserWindow 에 load 하면 sandbox escape 위험.
|
||||
- **ASAR 만 의 protection**: ASAR 는 압축 일 뿐. Source 보호 의 X — 매 native module / 서버 side 로 logic 이동.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (electronjs.org docs, Electron 33 release notes 2026).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — Electron 33 process model + secure IPC patterns |
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
|
||||
<!-- CODE-GROUNDING:START -->
|
||||
### 🔎 코드베이스 근거 (자동 추출 — E:\Wiki 레포)
|
||||
**실제 구현/사용 위치:**
|
||||
- `photoai/electron.vite.config.ts:2` — import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
|
||||
- `photoai/src/shared/types.ts:485` — /** 드롭된 File의 로컬 절대경로 반환(Electron webUtils). 경로가 없으면 빈 문자열. */
|
||||
- `photoai/src/preload/inference.ts:1` — import { contextBridge, ipcRenderer } from 'electron'
|
||||
- `photoai/src/preload/index.ts:1` — import { contextBridge, ipcRenderer, webUtils } from 'electron'
|
||||
- `photoai/src/main/fsExplorer.ts:4` — import { shell } from 'electron'
|
||||
- `photoai/src/main/embedder.ts:1` — import { BrowserWindow } from 'electron'
|
||||
|
||||
**관련 커밋:**
|
||||
- `photoai 3e73967 darktable-inspired reskin + metadata/collections, map, easy mode, select/export`
|
||||
- `photoai 8a8c102 Initial commit: AI Photo Organizer (Electron + face-api)`
|
||||
|
||||
_자동 생성: code_grounding.mjs · 재실행 시 갱신됨_
|
||||
<!-- CODE-GROUNDING:END -->
|
||||
@@ -0,0 +1,204 @@
|
||||
---
|
||||
id: wiki-2026-0508-escape-hatch-탈출구
|
||||
title: Escape Hatch (탈출구)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [React escape hatch, useRef escape hatch, useEffect escape hatch]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [react, hooks, useref, useeffect, framework-design]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: TypeScript
|
||||
framework: React
|
||||
---
|
||||
|
||||
# Escape Hatch (탈출구)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 framework 가 model 외의 reality 의 reach 매 escape hatch"**. React 의 escape hatch — useRef, useEffect, flushSync, ref callback 의 declarative model 외의 imperative DOM/non-React system 의 bridge. 매 2026 React 19 (Activity API, useOptimistic) 의 도입 매 escape hatch 의 사용 빈도 의 감소 but 매 여전히 essential.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 왜 필요
|
||||
- React model: declarative — UI = f(state).
|
||||
- 매 reality 매 imperative — DOM focus, video play, third-party (D3, Chart.js, Three.js), browser API (IntersectionObserver).
|
||||
- 매 escape hatch 의 controlled bridge 의 제공.
|
||||
|
||||
### 매 React 의 4 hatch
|
||||
- **useRef**: 매 mutable container 매 re-render trigger 없음.
|
||||
- **useEffect**: 매 commit 후 의 side-effect — 매 subscription, manual DOM, external system.
|
||||
- **flushSync**: 매 sync update 의 force — 매 layout measurement before paint.
|
||||
- **ref callback**: 매 mount/unmount lifecycle 의 ref level access.
|
||||
|
||||
### 매 응용
|
||||
1. Third-party library integration (D3, Three.js).
|
||||
2. Imperative DOM (focus, scroll, select).
|
||||
3. Subscription (WebSocket, EventSource).
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### useRef Mutable Value
|
||||
```tsx
|
||||
function Stopwatch() {
|
||||
const intervalRef = useRef<number | null>(null)
|
||||
const [time, setTime] = useState(0)
|
||||
|
||||
const start = () => {
|
||||
if (intervalRef.current) return
|
||||
intervalRef.current = window.setInterval(() => setTime((t) => t + 1), 1000)
|
||||
}
|
||||
const stop = () => {
|
||||
if (intervalRef.current) clearInterval(intervalRef.current)
|
||||
intervalRef.current = null
|
||||
}
|
||||
return <button onClick={start}>{time}</button>
|
||||
}
|
||||
```
|
||||
|
||||
### useRef DOM Reference
|
||||
```tsx
|
||||
function AutoFocus() {
|
||||
const inputRef = useRef<HTMLInputElement>(null)
|
||||
useEffect(() => {
|
||||
inputRef.current?.focus()
|
||||
}, [])
|
||||
return <input ref={inputRef} />
|
||||
}
|
||||
```
|
||||
|
||||
### useEffect External System
|
||||
```tsx
|
||||
function ChatRoom({ roomId }: { roomId: string }) {
|
||||
useEffect(() => {
|
||||
const conn = createConnection(roomId)
|
||||
conn.connect()
|
||||
return () => conn.disconnect() // 매 cleanup essential
|
||||
}, [roomId])
|
||||
return <h1>Welcome to {roomId}</h1>
|
||||
}
|
||||
```
|
||||
|
||||
### Third-party Integration (Three.js)
|
||||
```tsx
|
||||
function ThreeScene() {
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
useEffect(() => {
|
||||
const scene = new THREE.Scene()
|
||||
const camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000)
|
||||
const renderer = new THREE.WebGLRenderer()
|
||||
renderer.setSize(800, 600)
|
||||
containerRef.current?.appendChild(renderer.domElement)
|
||||
|
||||
let raf: number
|
||||
const animate = () => {
|
||||
raf = requestAnimationFrame(animate)
|
||||
renderer.render(scene, camera)
|
||||
}
|
||||
animate()
|
||||
|
||||
return () => {
|
||||
cancelAnimationFrame(raf)
|
||||
renderer.dispose()
|
||||
containerRef.current?.removeChild(renderer.domElement)
|
||||
}
|
||||
}, [])
|
||||
return <div ref={containerRef} />
|
||||
}
|
||||
```
|
||||
|
||||
### flushSync (force sync)
|
||||
```tsx
|
||||
import { flushSync } from "react-dom"
|
||||
|
||||
function ScrollToBottom() {
|
||||
const [items, setItems] = useState<string[]>([])
|
||||
const listRef = useRef<HTMLUListElement>(null)
|
||||
|
||||
const addItem = (text: string) => {
|
||||
flushSync(() => {
|
||||
setItems((prev) => [...prev, text])
|
||||
})
|
||||
// 매 flushSync 후 매 DOM 매 updated 의 guaranteed
|
||||
listRef.current?.scrollTo(0, listRef.current.scrollHeight)
|
||||
}
|
||||
return (/* ... */)
|
||||
}
|
||||
```
|
||||
|
||||
### Ref Callback (mount/unmount)
|
||||
```tsx
|
||||
function ObservedItem({ onVisible }: { onVisible: () => void }) {
|
||||
const refCallback = useCallback((node: HTMLDivElement | null) => {
|
||||
if (!node) return
|
||||
const obs = new IntersectionObserver(([entry]) => {
|
||||
if (entry.isIntersecting) onVisible()
|
||||
})
|
||||
obs.observe(node)
|
||||
return () => obs.disconnect() // React 19+ cleanup
|
||||
}, [onVisible])
|
||||
return <div ref={refCallback}>Observed</div>
|
||||
}
|
||||
```
|
||||
|
||||
### useImperativeHandle (parent 의 controlled API)
|
||||
```tsx
|
||||
type ModalHandle = { open: () => void; close: () => void }
|
||||
|
||||
const Modal = forwardRef<ModalHandle>((_, ref) => {
|
||||
const [open, setOpen] = useState(false)
|
||||
useImperativeHandle(ref, () => ({
|
||||
open: () => setOpen(true),
|
||||
close: () => setOpen(false),
|
||||
}), [])
|
||||
return open ? <div>Modal</div> : null
|
||||
})
|
||||
|
||||
function App() {
|
||||
const modalRef = useRef<ModalHandle>(null)
|
||||
return <button onClick={() => modalRef.current?.open()}>Open</button>
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Hatch |
|
||||
|---|---|
|
||||
| Mutable value 매 no re-render | useRef |
|
||||
| DOM focus/scroll | useRef + useEffect |
|
||||
| External lib (D3/Three.js) | useEffect |
|
||||
| Sync DOM measurement | flushSync |
|
||||
| Mount/unmount lifecycle | ref callback |
|
||||
| Parent imperative API | useImperativeHandle |
|
||||
|
||||
**기본값**: 매 declarative 매 first — 매 hatch 매 last resort.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[React]]
|
||||
- 변형: [[Vue Composition API]] · [[Solid Signals]]
|
||||
- 응용: [[IntersectionObserver]]
|
||||
- Adjacent: [[useEffect]] · [[useRef]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 third-party imperative library 의 React 의 integration, DOM 의 manual control.
|
||||
**언제 X**: 매 pure UI state — 매 useState/useReducer 의 사용.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **useRef 매 derived state**: 매 useState 또는 useMemo 매 사용.
|
||||
- **useEffect 매 data fetch (cascading)**: 매 React Query / RSC 매 사용.
|
||||
- **Stale ref read in render**: 매 ref.current 의 render 의 read 매 X.
|
||||
- **Cleanup 의 omit**: 매 memory leak — 매 return 매 always.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (React 공식 docs "Escape Hatches" chapter, React 19 — 2026).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — React 19 escape hatch 4종 + 패턴 작성 |
|
||||
@@ -0,0 +1,121 @@
|
||||
---
|
||||
id: wiki-2026-0508-flame-chart
|
||||
title: Flame Chart
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Flame Graph, 플레임 차트]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [profiling, performance, devtools, visualization]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: JavaScript
|
||||
framework: Chrome DevTools
|
||||
---
|
||||
|
||||
# Flame Chart
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 시간축 stack frame 의 visual profile — width=duration, depth=call stack"**. Brendan Gregg (2013) 의 flame graph 매 origin. 2026 시점 Chrome DevTools Performance panel · Node `--prof` · Linux `perf` · Speedscope 매 standard tooling.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 Flame Chart vs Flame Graph
|
||||
- **Flame Chart**: x축 = 매 wall-clock time (left→right chronological). DevTools default.
|
||||
- **Flame Graph**: x축 = 매 aggregated time (alphabetical), 매 hot path 발견.
|
||||
|
||||
### 매 reading rules
|
||||
- 매 wide bar = 매 long-running function.
|
||||
- 매 tall stack = 매 deep call chain (recursion · over-abstraction signal).
|
||||
- 매 plateau = 매 single function dominate.
|
||||
|
||||
### 매 응용
|
||||
1. JS main-thread bottleneck 식별.
|
||||
2. React render 의 expensive component 추적.
|
||||
3. Backend RPC handler latency 분해.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Chrome DevTools 캡처
|
||||
```js
|
||||
// 1. DevTools → Performance → Record
|
||||
// 2. Reproduce slow interaction
|
||||
// 3. Stop → bottom-up / call tree / flame chart 탭
|
||||
|
||||
// Programmatic mark
|
||||
performance.mark("render-start")
|
||||
expensiveRender()
|
||||
performance.mark("render-end")
|
||||
performance.measure("render", "render-start", "render-end")
|
||||
```
|
||||
|
||||
### Node.js CPU profile
|
||||
```bash
|
||||
node --cpu-prof --cpu-prof-dir=./profiles app.js
|
||||
# .cpuprofile 의 Chrome DevTools "Performance" 탭에 drag-drop
|
||||
```
|
||||
|
||||
### 0x flame graph 생성
|
||||
```bash
|
||||
npx 0x -o server.js
|
||||
# HTML 매 자동 open — interactive flame graph
|
||||
```
|
||||
|
||||
### React Profiler API
|
||||
```tsx
|
||||
import { Profiler } from "react"
|
||||
|
||||
function onRender(id, phase, actualDuration) {
|
||||
if (actualDuration > 16) console.warn(`slow ${id}: ${actualDuration}ms`)
|
||||
}
|
||||
|
||||
<Profiler id="UserList" onRender={onRender}>
|
||||
<UserList />
|
||||
</Profiler>
|
||||
```
|
||||
|
||||
### Speedscope (universal viewer)
|
||||
```bash
|
||||
# Node, Chrome, py-spy, perf 매 모두 import
|
||||
npx speedscope profile.cpuprofile
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Browser frontend lag | Chrome DevTools Performance |
|
||||
| Node server CPU spike | `--cpu-prof` + DevTools |
|
||||
| Production hot-path discovery | Flame **graph** (aggregated) |
|
||||
| Specific user interaction | Flame **chart** (chronological) |
|
||||
|
||||
**기본값**: Chrome DevTools Performance panel — 매 60% case cover.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Performance_Profiling_and_Memory|Performance Profiling]] · [[Chrome DevTools(크롬 개발자 도구)]]
|
||||
- 변형: [[할당 타임라인(Allocation Timeline)]]
|
||||
- 응용: [[Nodejs 성능 디버깅]] · [[SPA 라우트 전환 성능 최적화]]
|
||||
- Adjacent: [[Core Web Vitals Optimization (INP, LCP, CLS)|Cumulative Layout Shift (CLS)]] · [[Google Lighthouse]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 latency / jank / unknown bottleneck 발견 → flame chart 의 first tool.
|
||||
**언제 X**: 매 memory leak (heap snapshot 사용) · 매 network waterfall (Network panel).
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Optimize the wide-but-shallow bar**: 매 actually unimportant 일 수 있음 — call tree로 cross-check.
|
||||
- **Sampling rate 신뢰**: 매 short bursts (<1ms) 의 missed — `performance.mark` precise.
|
||||
- **Production 에서 always-on profiling**: 매 overhead — sampling profiler (e.g. `pprof`) 만 OK.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Brendan Gregg flame graph paper · Chrome DevTools docs 2026).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — DevTools/0x/Speedscope tooling 매 설명 |
|
||||
@@ -0,0 +1,154 @@
|
||||
---
|
||||
id: wiki-2026-0508-fuzzing
|
||||
title: Fuzzing
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Fuzz Testing, Coverage-Guided Fuzzing]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [security, testing, dast]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: C/Rust/Go
|
||||
framework: AFL++/libFuzzer/cargo-fuzz
|
||||
---
|
||||
|
||||
# Fuzzing
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 random/mutated input 으로 crash, hang, UB 의 hunt"**. 매 1988 Miller (Wisconsin) 의 random input shell experiment 가 origin. 2026 현재 매 coverage-guided (AFL++, libFuzzer, Honggfuzz), structure-aware (libprotobuf-mutator), grammar-based (Nautilus), LLM-augmented (OSS-Fuzz Gen) 가 mainstream. Google OSS-Fuzz 가 100K+ bug 발견, Chrome/Linux kernel/OpenSSL 의 routine workflow.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 fuzzing categories
|
||||
- **Black-box (dumb)**: random input, no instrumentation. 매 zzuf, radamsa.
|
||||
- **Coverage-guided (grey-box)**: input 의 mutation + branch coverage feedback. 매 AFL++, libFuzzer, Honggfuzz.
|
||||
- **White-box (concolic)**: symbolic execution + solver. 매 KLEE, SAGE.
|
||||
- **Structure-aware**: protobuf, JSON 의 grammar 의 valid input. 매 libprotobuf-mutator, FuzzGrammar.
|
||||
- **Differential**: 매 동일 input 을 두 implementation 에 → divergence 의 bug.
|
||||
|
||||
### 매 sanitizers
|
||||
- ASan (heap/stack OOB, UAF), UBSan (UB), MSan (uninit read), TSan (data race), LSan (leak).
|
||||
- 매 fuzzing 의 corpus 는 sanitizer 와 함께 build 의 mandatory.
|
||||
|
||||
### 매 응용
|
||||
1. Memory-safety bug discovery (C/C++ codebases).
|
||||
2. Parser hardening (image, video, network protocols).
|
||||
3. Browser engine (V8 fuzzilli, JSC fuzzer).
|
||||
4. Crypto library (OpenSSL, BoringSSL via OSS-Fuzz).
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### libFuzzer (C++)
|
||||
```cpp
|
||||
// fuzz_target.cc — clang -fsanitize=fuzzer,address fuzz_target.cc parser.cc
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "parser.h"
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
if (size < 4) return 0;
|
||||
Parser p;
|
||||
p.Parse(reinterpret_cast<const char*>(data), size); // ASan catches OOB/UAF
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### cargo-fuzz (Rust)
|
||||
```rust
|
||||
// fuzz/fuzz_targets/parse.rs
|
||||
#![no_main]
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
if let Ok(s) = std::str::from_utf8(data) {
|
||||
let _ = mycrate::parse(s); // panics 는 fuzz crash 로 catch
|
||||
}
|
||||
});
|
||||
```
|
||||
```bash
|
||||
cargo fuzz run parse -- -max_total_time=600
|
||||
```
|
||||
|
||||
### Go native fuzzing (1.18+)
|
||||
```go
|
||||
func FuzzParseURL(f *testing.F) {
|
||||
f.Add("http://example.com")
|
||||
f.Fuzz(func(t *testing.T, s string) {
|
||||
u, err := url.Parse(s)
|
||||
if err == nil && u.String() != s && url.QueryEscape(u.String()) == "" {
|
||||
t.Errorf("roundtrip mismatch: %q", s)
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
```bash
|
||||
go test -fuzz=FuzzParseURL -fuzztime=10m
|
||||
```
|
||||
|
||||
### AFL++ (compile-time instrumentation)
|
||||
```bash
|
||||
CC=afl-clang-fast CXX=afl-clang-fast++ ./configure
|
||||
make -j8
|
||||
mkdir in; echo "seed" > in/0
|
||||
afl-fuzz -i in -o out -- ./target @@
|
||||
```
|
||||
|
||||
### Structure-aware (libprotobuf-mutator)
|
||||
```cpp
|
||||
DEFINE_PROTO_FUZZER(const my::Message& msg) {
|
||||
HandleMessage(msg); // valid proto guaranteed → deeper coverage
|
||||
}
|
||||
```
|
||||
|
||||
### OSS-Fuzz integration
|
||||
```dockerfile
|
||||
FROM gcr.io/oss-fuzz-base/base-builder
|
||||
RUN apt-get install -y libssl-dev
|
||||
COPY . $SRC/myproject
|
||||
COPY build.sh $SRC/
|
||||
WORKDIR $SRC/myproject
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| C/C++ memory bug hunt | libFuzzer + ASan/UBSan |
|
||||
| Rust panic / logic bug | cargo-fuzz |
|
||||
| Network protocol parser | AFL++ + structure-aware mutator |
|
||||
| Two implementations comparison | Differential fuzzing |
|
||||
| Continuous (open-source) | OSS-Fuzz |
|
||||
| Grammar-rich (JS, SQL) | Grammar-based (Nautilus, fuzzilli) |
|
||||
|
||||
**기본값**: 매 coverage-guided (libFuzzer/AFL++) + ASan + corpus minimization + CI 에 5min smoke.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[DAST (동적 애플리케이션 보안 테스트)]]
|
||||
- 변형: [[SCA (소프트웨어 구성 분석)]]
|
||||
- 응용: [[OSS-Fuzz]] · [[V8 엔진 힙 아키텍처]]
|
||||
- Adjacent: [[Property-Based Testing]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 untrusted input 의 parser, codec, deserializer 가 있는 경우. 매 security-critical library 의 release 전 mandatory.
|
||||
**언제 X**: pure functional code 의 deterministic 한 input space (property-based testing 이 더 적절). 매 GUI / network state-heavy code.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Sanitizer 없이 fuzz**: 매 silent corruption 을 miss. 매 ASan 의 mandatory.
|
||||
- **Seed corpus 없음**: 매 coverage 의 plateau 가 빠름. 매 valid sample 10-100 개 의 seed.
|
||||
- **CI 에 30s 만 fuzz**: 매 너무 짧음. 매 minimum 10min, ideal continuous (OSS-Fuzz pattern).
|
||||
- **Crash 만 의 focus**: 매 hang, OOM, slow input 도 bug. 매 timeout / rss_limit 설정.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Miller 1990 "Empirical Study of Reliability of UNIX Utilities"; AFL++ docs; OSS-Fuzz reports).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — coverage-guided + sanitizers + OSS-Fuzz |
|
||||
@@ -0,0 +1,172 @@
|
||||
---
|
||||
id: wiki-2026-0508-gc-root
|
||||
title: GC Root
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Garbage Collection Root, GC 루트, Root Set]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [gc, jvm, memory, runtime]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: Java/Kotlin
|
||||
framework: JVM/HotSpot/ZGC
|
||||
---
|
||||
|
||||
# GC Root
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 도달 가능성(reachability) 의 출발점"**. GC Root 는 garbage collector 가 live object 를 판별하기 위해 traversal 을 시작하는 reference set. 매 root 에서 도달 불가능한 object 는 collectible 로 marking 된다. JVM, .NET CLR, V8, Go runtime 모두 같은 개념을 공유한다.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 GC Root 종류 (HotSpot 기준)
|
||||
- **Stack reference**: 매 thread 의 local variable / parameter / operand stack.
|
||||
- **Static field**: 매 loaded class 의 static reference.
|
||||
- **JNI local/global**: 매 native code 가 hold 한 reference.
|
||||
- **Active thread**: 매 살아있는 `Thread` object 자체.
|
||||
- **Class metadata**: 매 ClassLoader, Class object (Metaspace).
|
||||
- **Synchronization monitor**: 매 `synchronized` 로 lock 된 object.
|
||||
- **Weak/Soft/Phantom 제외**: 매 reachability 약한 reference 는 root 가 아님.
|
||||
|
||||
### 매 Reachability tier
|
||||
1. **Strongly reachable**: root 에서 strong ref 만으로 도달 → never collected.
|
||||
2. **Softly reachable**: SoftReference 로만 도달 → 매 memory pressure 시 collect.
|
||||
3. **Weakly reachable**: WeakReference 만 → 매 next GC cycle 에 collect.
|
||||
4. **Phantom reachable**: PhantomReference → enqueue 후 cleaning.
|
||||
5. **Unreachable**: → collectible.
|
||||
|
||||
### 매 응용
|
||||
1. **Memory leak 진단** (heap dump → root path 추적).
|
||||
2. **Escape analysis** (root 도달 안 되는 local → stack alloc).
|
||||
3. **Concurrent GC 의 root scanning** (ZGC, Shenandoah, G1 의 phase 1).
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### 1. Heap dump 에서 root path 찾기 (Eclipse MAT / jhat)
|
||||
```bash
|
||||
# JVM heap dump 생성
|
||||
jcmd <pid> GC.heap_dump /tmp/heap.hprof
|
||||
|
||||
# Eclipse MAT CLI 로 leak suspects 분석
|
||||
./MemoryAnalyzer -consoleLog -application org.eclipse.mat.api.parse \
|
||||
/tmp/heap.hprof org.eclipse.mat.api:suspects
|
||||
```
|
||||
|
||||
### 2. JFR 로 GC root 통계 수집 (JDK 21+)
|
||||
```bash
|
||||
java -XX:StartFlightRecording=duration=60s,filename=app.jfr,settings=profile \
|
||||
-XX:+UseZGC -Xmx4g -jar app.jar
|
||||
|
||||
jfr print --events GarbageCollection,GCReferenceStatistics app.jfr
|
||||
```
|
||||
|
||||
### 3. WeakReference 로 root 진입 회피
|
||||
```java
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
// Cache 가 GC root 가 되어 leak 발생하는 anti-pattern 회피
|
||||
public class Cache<K, V> {
|
||||
private final WeakHashMap<K, V> map = new WeakHashMap<>();
|
||||
|
||||
public void put(K key, V value) { map.put(key, value); }
|
||||
public V get(K key) { return map.get(key); }
|
||||
// key 가 외부에서 strong ref 사라지면 entry 자동 제거
|
||||
}
|
||||
```
|
||||
|
||||
### 4. ThreadLocal leak 회피 (매 typical root leak)
|
||||
```java
|
||||
public class RequestContext {
|
||||
private static final ThreadLocal<UserSession> CTX = new ThreadLocal<>();
|
||||
|
||||
public static void set(UserSession s) { CTX.set(s); }
|
||||
public static UserSession get() { return CTX.get(); }
|
||||
|
||||
// 매 critical: thread pool 환경에서 반드시 remove() 호출
|
||||
public static void clear() { CTX.remove(); }
|
||||
}
|
||||
|
||||
// Servlet filter 에서:
|
||||
try {
|
||||
RequestContext.set(session);
|
||||
chain.doFilter(req, res);
|
||||
} finally {
|
||||
RequestContext.clear(); // 매 root reference 끊기
|
||||
}
|
||||
```
|
||||
|
||||
### 5. JNI global ref 정리 (native code 가 GC root)
|
||||
```c
|
||||
// JNI: global ref 는 명시적으로 free 해야 함
|
||||
jobject globalRef = (*env)->NewGlobalRef(env, localObj);
|
||||
// ... 사용 ...
|
||||
(*env)->DeleteGlobalRef(env, globalRef); // 매 빠뜨리면 영구 leak
|
||||
```
|
||||
|
||||
### 6. Static field 로 의도된 long-lived root
|
||||
```kotlin
|
||||
object AppMetrics { // 매 Kotlin object → static singleton → GC root
|
||||
private val counter = AtomicLong(0)
|
||||
fun increment() = counter.incrementAndGet()
|
||||
fun snapshot() = counter.get()
|
||||
}
|
||||
```
|
||||
|
||||
### 7. ZGC / Shenandoah concurrent root scanning 활성화
|
||||
```bash
|
||||
# JDK 21+: ZGC generational
|
||||
java -XX:+UseZGC -XX:+ZGenerational \
|
||||
-XX:SoftMaxHeapSize=8g -Xmx16g -jar app.jar
|
||||
|
||||
# Shenandoah
|
||||
java -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational -jar app.jar
|
||||
```
|
||||
|
||||
### 8. Async profiler 로 allocation root 찾기
|
||||
```bash
|
||||
./profiler.sh -e alloc -d 60 -f alloc.html <pid>
|
||||
# 매 flamegraph 에서 root → leaking site path 시각화
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Long-lived cache | `WeakHashMap` / Caffeine `weakKeys()` |
|
||||
| Per-request state in pool | `ThreadLocal` + `try/finally remove()` |
|
||||
| Native handle wrapping | `Cleaner` (java.lang.ref.Cleaner, JDK 9+) |
|
||||
| Listener registration | `WeakReference` 로 listener wrap |
|
||||
| 매 short-lived burst alloc | 매 그냥 strong ref + young gen 의존 |
|
||||
|
||||
**기본값**: 매 strong ref + escape analysis 신뢰. WeakReference 는 매 진짜 leak 패턴 (cache, listener, ThreadLocal in pool) 에만.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Garbage Collection]]
|
||||
- 응용: [[Memory Leak Detection]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: heap dump 의 leak suspect 해석, root path 의 의미 설명, ThreadLocal/static leak pattern detection.
|
||||
**언제 X**: 매 production 의 실제 GC tuning (real profiling 데이터 없이 추측 X).
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Static collection 무한 grow**: `static List` 에 매 add 만 하고 remove 안 함 → 영구 root.
|
||||
- **ThreadLocal in pool no remove**: 매 thread 재사용 시 이전 request data 가 root 로 남음.
|
||||
- **JNI GlobalRef leak**: native 에서 `DeleteGlobalRef` 누락.
|
||||
- **Anonymous inner class capture**: `new Runnable() {}` 가 outer `this` 를 capture → outer 가 root 에 매달림.
|
||||
- **Listener 등록 후 unregister 안 함**: 매 EventBus, Observer 패턴의 classic leak.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (OpenJDK HotSpot source, JEP 376/439, Eclipse MAT docs).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — GC root taxonomy + leak 진단 패턴 |
|
||||
@@ -0,0 +1,160 @@
|
||||
---
|
||||
id: wiki-2026-0508-google-lighthouse
|
||||
title: Google Lighthouse
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Lighthouse, Web Vitals Audit]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [performance, web-vitals, audit, ci]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: JavaScript
|
||||
framework: Lighthouse 12+ / lighthouse-ci
|
||||
---
|
||||
|
||||
# Google Lighthouse
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 web page 의 performance, accessibility, best-practices, SEO, PWA 를 자동 audit"**. Chrome DevTools 내장, CLI, Node API, lighthouse-ci 의 form. 2026 현재 v12+ 가 INP (Interaction to Next Paint) 의 primary metric, LCP/CLS/INP 의 Core Web Vitals 와 align. 매 PR 마다 budget 검증 의 standard practice.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 5 categories
|
||||
- **Performance**: LCP, INP, CLS, TBT, FCP, Speed Index → 0-100 score.
|
||||
- **Accessibility**: axe-core 기반 a11y 검사.
|
||||
- **Best Practices**: HTTPS, secure headers, deprecated API.
|
||||
- **SEO**: meta tags, mobile viewport, structured data.
|
||||
- **PWA** (deprecated 2024 후 separate plugin).
|
||||
|
||||
### 매 Performance 의 weight (v12)
|
||||
- LCP 25%, TBT 30%, CLS 25%, FCP 10%, SI 10%.
|
||||
- INP 의 field metric 만 — lab 에서 measure X (Total Blocking Time 으로 proxy).
|
||||
|
||||
### 매 응용
|
||||
1. Local audit (DevTools).
|
||||
2. CI gate (lighthouse-ci, budgets.json).
|
||||
3. Field monitoring 보조 (CrUX + RUM 와 결합).
|
||||
4. PageSpeed Insights backend.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### CLI run
|
||||
```bash
|
||||
npm i -g lighthouse
|
||||
lighthouse https://example.com --output=html --output=json \
|
||||
--output-path=./report --chrome-flags="--headless"
|
||||
```
|
||||
|
||||
### Node programmatic
|
||||
```javascript
|
||||
import lighthouse from 'lighthouse'
|
||||
import * as chromeLauncher from 'chrome-launcher'
|
||||
|
||||
const chrome = await chromeLauncher.launch({ chromeFlags: ['--headless'] })
|
||||
const result = await lighthouse('https://example.com', {
|
||||
port: chrome.port,
|
||||
output: 'json',
|
||||
onlyCategories: ['performance'],
|
||||
})
|
||||
console.log(result.lhr.categories.performance.score)
|
||||
await chrome.kill()
|
||||
```
|
||||
|
||||
### Lighthouse CI in GitHub Actions
|
||||
```yaml
|
||||
# .github/workflows/lhci.yml
|
||||
name: lhci
|
||||
on: [pull_request]
|
||||
jobs:
|
||||
lhci:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with: { node-version: 20 }
|
||||
- run: npm ci && npm run build
|
||||
- run: npm i -g @lhci/cli@0.14.x
|
||||
- run: lhci autorun
|
||||
env:
|
||||
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
|
||||
```
|
||||
|
||||
### lighthouserc.js with budgets
|
||||
```javascript
|
||||
module.exports = {
|
||||
ci: {
|
||||
collect: {
|
||||
url: ['http://localhost:3000/', 'http://localhost:3000/about'],
|
||||
numberOfRuns: 3,
|
||||
startServerCommand: 'npm start',
|
||||
},
|
||||
assert: {
|
||||
assertions: {
|
||||
'categories:performance': ['error', { minScore: 0.9 }],
|
||||
'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
|
||||
'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
|
||||
'total-blocking-time': ['warn', { maxNumericValue: 200 }],
|
||||
},
|
||||
},
|
||||
upload: { target: 'temporary-public-storage' },
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### User flow (multi-step)
|
||||
```javascript
|
||||
import { startFlow } from 'lighthouse'
|
||||
import puppeteer from 'puppeteer'
|
||||
|
||||
const browser = await puppeteer.launch()
|
||||
const page = await browser.newPage()
|
||||
const flow = await startFlow(page, { name: 'Checkout flow' })
|
||||
await flow.navigate('https://shop.example.com')
|
||||
await flow.startTimespan({ name: 'Add to cart' })
|
||||
await page.click('#add')
|
||||
await flow.endTimespan()
|
||||
await flow.snapshot({ name: 'Cart loaded' })
|
||||
const report = await flow.generateReport()
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Local optimization | DevTools Lighthouse panel |
|
||||
| PR budget gate | lighthouse-ci + assertions |
|
||||
| Multi-page audit | lhci with multiple URLs |
|
||||
| SPA route transitions | User flows API |
|
||||
| Real-user metrics | CrUX / web-vitals JS (Lighthouse 의 X) |
|
||||
|
||||
**기본값**: 매 lhci + budgets.json + GitHub Action + 3 runs median.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Performance_Profiling_and_Memory|Performance Profiling]]
|
||||
- 응용: [[CI_CD_Pipeline|CI_CD Pipeline]] · [[Continuous Integration (CI)]]
|
||||
- Adjacent: [[Core Web Vitals Optimization (INP, LCP, CLS)|Cumulative Layout Shift (CLS)]] · [[SPA 라우트 전환 성능 최적화]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: pre-deploy quality gate, regression catch, web vitals tracking.
|
||||
**언제 X**: 매 real-user perf 측정 (lab condition 일 뿐 — RUM 사용). Native app, server-only API.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **단일 run score 의 의존**: variance 가 큼 — 매 median of 3-5 runs.
|
||||
- **Lab score = field score 의 가정**: throttling profile 이 user 와 다름. 매 CrUX 와 cross-check.
|
||||
- **High score 만 의 chase**: 100 score ≠ good UX. 매 INP/LCP 의 actual budget 의 focus.
|
||||
- **CI 에 emulated mobile 만 의 test**: desktop user 도 audit.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (web.dev/lighthouse, lighthouse-ci docs, Lighthouse 12 release notes 2025).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — Lighthouse 12 + CI integration patterns |
|
||||
@@ -0,0 +1,168 @@
|
||||
---
|
||||
id: wiki-2026-0508-index-masking
|
||||
title: Index Masking
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Bitmask Index, Power-of-Two Masking]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [optimization, low-level, ring-buffer, hash]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: C/C++/Rust/JavaScript
|
||||
framework: General
|
||||
---
|
||||
|
||||
# Index Masking
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 capacity 가 power-of-two 일 때 `% N` 의 `& (N-1)` replacement"**. 매 modulo 의 expensive (CPU cycle 10-30) 의 single-cycle `AND` 로 대체. Ring buffer, hash table bucket, fixed-size LRU, lock-free queue 의 hot path 의 universal trick. CPU branch predictor 와 cache line 의 friendly.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 정확성 조건
|
||||
- N 이 power-of-two: `2^k`.
|
||||
- `index % N == index & (N - 1)` (unsigned 또는 non-negative).
|
||||
- `N - 1` 이 모든 lower bit 의 1 의 mask.
|
||||
|
||||
### 매 대표 사용 처
|
||||
- Ring buffer / circular queue.
|
||||
- Open-addressing hash table bucket index.
|
||||
- Game loop frame index modulo history size.
|
||||
- Hardware register address calc.
|
||||
- Lock-free SPSC/MPMC queue (Disruptor pattern).
|
||||
|
||||
### 매 응용
|
||||
1. LMAX Disruptor (Java) — sequence & ringMask.
|
||||
2. Linux kernel ringbuffer.
|
||||
3. Redis hash table — sizemask.
|
||||
4. V8 hidden class transitions table.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Basic ring buffer (C)
|
||||
```c
|
||||
#define RB_CAP 1024 // must be power of two
|
||||
typedef struct {
|
||||
int data[RB_CAP];
|
||||
uint32_t head, tail; // free-running counters
|
||||
} RingBuf;
|
||||
|
||||
static inline void rb_push(RingBuf *r, int v) {
|
||||
r->data[r->head & (RB_CAP - 1)] = v;
|
||||
r->head++;
|
||||
}
|
||||
static inline int rb_pop(RingBuf *r) {
|
||||
int v = r->data[r->tail & (RB_CAP - 1)];
|
||||
r->tail++;
|
||||
return v;
|
||||
}
|
||||
```
|
||||
|
||||
### TypeScript fixed-size circular log
|
||||
```typescript
|
||||
class CircularLog<T> {
|
||||
private buf: (T | undefined)[]
|
||||
private mask: number
|
||||
private head = 0
|
||||
constructor(capacityPow2: number) {
|
||||
if ((capacityPow2 & (capacityPow2 - 1)) !== 0)
|
||||
throw new Error('capacity must be power of two')
|
||||
this.buf = new Array(capacityPow2)
|
||||
this.mask = capacityPow2 - 1
|
||||
}
|
||||
push(v: T) {
|
||||
this.buf[this.head & this.mask] = v
|
||||
this.head++
|
||||
}
|
||||
recent(n: number): T[] {
|
||||
const out: T[] = []
|
||||
for (let i = 0; i < n; i++) {
|
||||
const v = this.buf[(this.head - 1 - i) & this.mask]
|
||||
if (v !== undefined) out.push(v)
|
||||
}
|
||||
return out
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Round-up to next power of two
|
||||
```c
|
||||
uint32_t next_pow2(uint32_t v) {
|
||||
v--;
|
||||
v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16;
|
||||
return v + 1;
|
||||
}
|
||||
```
|
||||
|
||||
### Hash table bucket
|
||||
```rust
|
||||
struct Map<K, V> {
|
||||
buckets: Vec<Option<(K, V)>>,
|
||||
mask: usize,
|
||||
}
|
||||
impl<K: Hash + Eq, V> Map<K, V> {
|
||||
fn bucket(&self, k: &K) -> usize {
|
||||
let mut h = DefaultHasher::new();
|
||||
k.hash(&mut h);
|
||||
(h.finish() as usize) & self.mask // mask = capacity - 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### SPSC lock-free (Disruptor-style)
|
||||
```c
|
||||
// producer
|
||||
void produce(RingBuf *r, int v) {
|
||||
uint32_t h = atomic_load(&r->head);
|
||||
while (h - atomic_load(&r->tail) >= RB_CAP) cpu_relax(); // full
|
||||
r->data[h & (RB_CAP - 1)] = v;
|
||||
atomic_store(&r->head, h + 1);
|
||||
}
|
||||
```
|
||||
|
||||
### Branch-free wrap (negative-safe)
|
||||
```c
|
||||
// for signed wrap, use bit-and after cast
|
||||
int idx = ((int)(counter) & ((int)CAP - 1)); // counter must be non-negative
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Hot path, capacity 가 control 가능 | Power-of-2 + masking |
|
||||
| Capacity 가 user-input arbitrary | `%` (or round up to pow2) |
|
||||
| Capacity 가 dynamic resize | resize 시 `mask` recompute |
|
||||
| Signed counter | unsigned cast 또는 modulo |
|
||||
| Hardware-aligned (cache line) | pow2 + alignment 조합 |
|
||||
|
||||
**기본값**: 매 ring/hash table 는 power-of-two + bitmask. 매 capacity 의 dynamic 이면 round-up.
|
||||
|
||||
## 🔗 Graph
|
||||
- 응용: [[Object Pooling (오브젝트 풀링)]]
|
||||
- Adjacent: [[SharedArrayBuffer로 스레드 간 메모리 공유 효율 높이기]] · [[Pointer Compression]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 high-throughput data structure, lock-free queue, HFT, game engine frame loop.
|
||||
**언제 X**: capacity 의 control 안 되거나 readability priority 인 일반 application code.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Non-pow2 size 에 mask 적용**: 매 silent index out-of-range, data corruption.
|
||||
- **Signed negative index 의 masking**: `-1 & (N-1)` 의 N-1 이 됨 → 매 unsigned cast 또는 `((i % N) + N) % N` pattern.
|
||||
- **Capacity 1 의 mask 0**: 매 always index 0, degenerate.
|
||||
- **Premature application**: 매 측정 없이 micro-optimization. 매 hot path 만 의 적용.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Hacker's Delight Ch.3, LMAX Disruptor paper, Linux kfifo source, Redis dict.c).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — power-of-2 masking patterns + ring/hash applications |
|
||||
@@ -0,0 +1,256 @@
|
||||
---
|
||||
id: wiki-2026-0508-instancedmesh-동적-버퍼-확장
|
||||
title: InstancedMesh 동적 버퍼 확장
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Dynamic InstancedMesh, Resize InstancedMesh, InstancedMesh Growth]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [threejs, webgl, webgpu, performance, buffer]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: TypeScript
|
||||
framework: Three.js r172
|
||||
---
|
||||
|
||||
# InstancedMesh 동적 버퍼 확장
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 InstancedMesh 의 capacity 부족 시 GPU buffer 를 reallocate"**. Three.js InstancedMesh 의 `count` 는 fixed allocation. 매 instance 추가가 capacity 초과하면 새 buffer 를 만들고 기존 data 를 copy. 매 amortized O(1) 을 위한 geometric growth 가 정석.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 기본 한계
|
||||
- 매 `new InstancedMesh(geo, mat, count)` 는 매 `count` 만큼 GPU buffer alloc.
|
||||
- 매 `mesh.count` 변경은 draw 만 줄이지 buffer 는 그대로.
|
||||
- 매 capacity 초과 → 매 새 mesh / 새 InstancedBufferAttribute 가 필요.
|
||||
|
||||
### 매 Strategy
|
||||
- **Geometric growth**: 매 capacity 부족 시 ×1.5 또는 ×2 로 resize.
|
||||
- **Pool & free list**: 매 deletion 후 빈 slot 재사용 (compact 회피).
|
||||
- **Chunked**: 매 fixed-size chunk N 개로 운영 (한 chunk 가득 차면 새 chunk).
|
||||
|
||||
### 매 응용
|
||||
1. **Realtime particle spawn / despawn**.
|
||||
2. **User-placed object editor** (매 추가 무한).
|
||||
3. **Streaming voxel chunk** (매 LOD 별 instance 수 가변).
|
||||
4. **NPC spawn system**.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### 1. Geometric resize utility
|
||||
```typescript
|
||||
class DynamicInstancedMesh {
|
||||
private mesh: THREE.InstancedMesh;
|
||||
private capacity: number;
|
||||
private size = 0;
|
||||
private freeList: number[] = [];
|
||||
|
||||
constructor(
|
||||
private geo: THREE.BufferGeometry,
|
||||
private mat: THREE.Material,
|
||||
initialCapacity = 64,
|
||||
private maxCapacity = 1_000_000,
|
||||
) {
|
||||
this.capacity = initialCapacity;
|
||||
this.mesh = this.makeMesh(initialCapacity);
|
||||
}
|
||||
|
||||
private makeMesh(cap: number): THREE.InstancedMesh {
|
||||
const m = new THREE.InstancedMesh(this.geo, this.mat, cap);
|
||||
m.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
|
||||
m.count = this.size;
|
||||
return m;
|
||||
}
|
||||
|
||||
add(matrix: THREE.Matrix4): number {
|
||||
let idx: number;
|
||||
if (this.freeList.length > 0) {
|
||||
idx = this.freeList.pop()!;
|
||||
} else {
|
||||
if (this.size >= this.capacity) this.grow();
|
||||
idx = this.size++;
|
||||
}
|
||||
this.mesh.setMatrixAt(idx, matrix);
|
||||
this.mesh.instanceMatrix.needsUpdate = true;
|
||||
this.mesh.count = this.size;
|
||||
return idx;
|
||||
}
|
||||
|
||||
remove(idx: number) {
|
||||
// 매 zero-scale matrix 로 hide → free list 등록
|
||||
const zero = new THREE.Matrix4().scale(new THREE.Vector3(0, 0, 0));
|
||||
this.mesh.setMatrixAt(idx, zero);
|
||||
this.mesh.instanceMatrix.needsUpdate = true;
|
||||
this.freeList.push(idx);
|
||||
}
|
||||
|
||||
private grow() {
|
||||
const newCap = Math.min(this.capacity * 2, this.maxCapacity);
|
||||
if (newCap <= this.capacity) throw new Error('Max capacity hit');
|
||||
const newMesh = this.makeMesh(newCap);
|
||||
|
||||
// 매 기존 matrix 복사
|
||||
const m = new THREE.Matrix4();
|
||||
for (let i = 0; i < this.size; i++) {
|
||||
this.mesh.getMatrixAt(i, m);
|
||||
newMesh.setMatrixAt(i, m);
|
||||
}
|
||||
// 매 color 도 있으면 copy
|
||||
if (this.mesh.instanceColor) {
|
||||
const oldColor = this.mesh.instanceColor.array as Float32Array;
|
||||
const newColor = new Float32Array(newCap * 3);
|
||||
newColor.set(oldColor);
|
||||
newMesh.instanceColor = new THREE.InstancedBufferAttribute(newColor, 3);
|
||||
}
|
||||
|
||||
// 매 swap
|
||||
const parent = this.mesh.parent;
|
||||
if (parent) {
|
||||
parent.remove(this.mesh);
|
||||
parent.add(newMesh);
|
||||
}
|
||||
this.mesh.dispose(); // 매 매 critical: GPU buffer free
|
||||
this.mesh = newMesh;
|
||||
this.capacity = newCap;
|
||||
console.log(`[DynamicInstancedMesh] grew → ${newCap}`);
|
||||
}
|
||||
|
||||
get object(): THREE.InstancedMesh { return this.mesh; }
|
||||
get instanceCount(): number { return this.size - this.freeList.length; }
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Chunked strategy (매 large N 친화적)
|
||||
```typescript
|
||||
class ChunkedInstancedMesh {
|
||||
private chunks: THREE.InstancedMesh[] = [];
|
||||
private group = new THREE.Group();
|
||||
private CHUNK_SIZE = 4096;
|
||||
private currentChunkSize = 0;
|
||||
|
||||
constructor(private geo: THREE.BufferGeometry, private mat: THREE.Material) {
|
||||
this.addChunk();
|
||||
}
|
||||
|
||||
private addChunk() {
|
||||
const m = new THREE.InstancedMesh(this.geo, this.mat, this.CHUNK_SIZE);
|
||||
m.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
|
||||
m.count = 0;
|
||||
this.chunks.push(m);
|
||||
this.group.add(m);
|
||||
this.currentChunkSize = 0;
|
||||
}
|
||||
|
||||
add(matrix: THREE.Matrix4): { chunk: number; idx: number } {
|
||||
if (this.currentChunkSize >= this.CHUNK_SIZE) this.addChunk();
|
||||
const chunkIdx = this.chunks.length - 1;
|
||||
const chunk = this.chunks[chunkIdx];
|
||||
const idx = this.currentChunkSize++;
|
||||
chunk.setMatrixAt(idx, matrix);
|
||||
chunk.count = idx + 1;
|
||||
chunk.instanceMatrix.needsUpdate = true;
|
||||
return { chunk: chunkIdx, idx };
|
||||
}
|
||||
|
||||
get object(): THREE.Group { return this.group; }
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Partial buffer update (updateRange)
|
||||
```typescript
|
||||
// 매 매 frame 일부만 변경 시 매 전체 upload 회피
|
||||
function updateInstanceRange(
|
||||
mesh: THREE.InstancedMesh, startIdx: number, count: number
|
||||
) {
|
||||
mesh.instanceMatrix.updateRange.offset = startIdx * 16; // mat4 = 16 floats
|
||||
mesh.instanceMatrix.updateRange.count = count * 16;
|
||||
mesh.instanceMatrix.needsUpdate = true;
|
||||
}
|
||||
```
|
||||
|
||||
### 4. WebGPU StorageBuffer 동적 grow
|
||||
```typescript
|
||||
import { storage, instanceIndex } from 'three/tsl';
|
||||
|
||||
class GPUDynamicInstances {
|
||||
private buffer: THREE.StorageBufferAttribute;
|
||||
private capacity: number;
|
||||
|
||||
constructor(initial = 1024) {
|
||||
this.capacity = initial;
|
||||
this.buffer = new THREE.StorageBufferAttribute(initial, 16);
|
||||
}
|
||||
|
||||
grow(needed: number) {
|
||||
const newCap = Math.max(this.capacity * 2, needed);
|
||||
const newBuf = new THREE.StorageBufferAttribute(newCap, 16);
|
||||
// 매 GPU-side copy: compute pass 로 old → new
|
||||
// 매 또는 CPU readback 후 재upload (매 비싸지만 단순)
|
||||
newBuf.array.set(this.buffer.array);
|
||||
this.buffer = newBuf;
|
||||
this.capacity = newCap;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Defragment (free list 가 너무 커지면)
|
||||
```typescript
|
||||
defragment(dim: DynamicInstancedMesh) {
|
||||
// 매 freeList sort 후 살아있는 instance 를 앞으로 compact
|
||||
// 매 user-facing index 가 바뀌므로 index map 도 업데이트해야 함
|
||||
// ... (구현은 use case 별 — id↔index 매핑 유지가 매 critical)
|
||||
}
|
||||
```
|
||||
|
||||
### 6. dispose 와 GPU memory 관리
|
||||
```typescript
|
||||
function disposeInstanced(mesh: THREE.InstancedMesh) {
|
||||
mesh.geometry.dispose();
|
||||
if (Array.isArray(mesh.material)) mesh.material.forEach(m => m.dispose());
|
||||
else mesh.material.dispose();
|
||||
mesh.dispose(); // 매 InstancedMesh 자체 buffer
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 매 instance 수가 천천히 변동 | Geometric grow ×2 |
|
||||
| 매 instance 수 매 frame 격변 | Pre-alloc max + count 조절 |
|
||||
| 매 매우 큰 N + streaming | Chunked (CHUNK_SIZE 4-16k) |
|
||||
| 매 frequent delete | Free list + zero-scale hide |
|
||||
| 매 free list ≥ 30% | Defragment 한 번 |
|
||||
| 매 GPU-driven spawn | WebGPU StorageBuffer + compute |
|
||||
|
||||
**기본값**: 매 generic dynamic case → DynamicInstancedMesh (×2 grow + free list + zero-scale remove).
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[InstancedMesh 최적화]] · [[Three.js]]
|
||||
- 변형: [[BatchedMesh]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: dynamic spawn/despawn 시스템 설계, free list vs chunked 의 trade-off 설명.
|
||||
**언제 X**: 매 specific WebGL driver memory bug.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **매 add 마다 new InstancedMesh**: 매 GPU alloc storm — 반드시 amortize.
|
||||
- **dispose() 빠뜨림**: 매 grow 후 옛 mesh GPU buffer 의 leak.
|
||||
- **Linear grow (+1, +1)**: O(N²) total copy. 매 geometric (×1.5 or ×2) 만 사용.
|
||||
- **remove 후 splice**: 매 모든 후속 idx shift → 비싸다. 매 zero-scale + free list.
|
||||
- **매 free list 만 쓰고 defrag 없음**: 매 hide 된 instance 도 vertex shader 실행 (zero-scale 은 깎임).
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Three.js r172 source `src/objects/InstancedMesh.js`).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — dynamic grow + free list + chunked |
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
---
|
||||
id: wiki-2026-0508-instancedmesh-사용-시-드로우-콜-최적화의-한계
|
||||
title: InstancedMesh 사용 시 드로우 콜 최적화의 한계점 사례 연구
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [InstancedMesh Limits, Instancing Limits]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [graphics, three-js, performance, instancing]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: JavaScript/GLSL
|
||||
framework: Three.js r170+/WebGL2/WebGPU
|
||||
---
|
||||
|
||||
# InstancedMesh 사용 시 드로우 콜 최적화의 한계점 사례 연구
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 InstancedMesh 매 1 draw call로 N copies — but 매 frustum culling, material variation, animation, picking 의 cost가 instance 수에 따라 explode."**. 매 naive 사용 시 draw call 매 줄어들어도 GPU vertex/fragment 매 burden, CPU matrix update 매 bottleneck. 매 production 매 LOD + spatial partition + GPU culling 매 결합.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 한계 list
|
||||
- **No per-instance frustum culling**: 매 single bounding sphere → 매 모든 instance가 frustum 안에 있다고 GPU가 가정.
|
||||
- **No per-instance material**: 매 same material → color/texture variation 매 instanceColor / instance attribute 의 manual.
|
||||
- **Animation cost**: 매 instance마다 matrix update → CPU bound at 10k+.
|
||||
- **Picking 어려움**: raycaster 매 instance index 매 별도 처리.
|
||||
- **Memory**: 16 floats × N instances = 매 1M instances → 64MB matrix buffer.
|
||||
- **Shadow map**: 매 light 마다 또 한 번 instanced draw — culling 없으면 shadow waste.
|
||||
|
||||
### 매 case: 100k cubes
|
||||
- Naive InstancedMesh: 매 1 draw call, GPU 60fps but matrix update 60ms/frame on CPU.
|
||||
- Static (`setMatrixAt` once): 매 GPU bound, fillrate 매 issue → LOD 필요.
|
||||
- Dynamic: 매 매 frame matrix update → useDynamicDrawUsage + partial updates.
|
||||
|
||||
### 매 응용 (해결 전략)
|
||||
1. **GPU instancing + GPU culling**: compute shader 매 frustum check, 매 indirect draw.
|
||||
2. **Spatial partitioning**: octree / BVH로 매 chunk 단위 InstancedMesh.
|
||||
3. **LOD groups**: distance 별 다른 InstancedMesh (high/med/low/billboard).
|
||||
4. **BatchedMesh (Three.js r170+)**: 매 different geometries를 single draw call.
|
||||
5. **Hierarchical LOD + impostor**: 매 far away는 single quad billboard.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Frustum culling 수동 (Three.js)
|
||||
```javascript
|
||||
const frustum = new THREE.Frustum();
|
||||
const m = new THREE.Matrix4();
|
||||
m.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
|
||||
frustum.setFromProjectionMatrix(m);
|
||||
|
||||
const dummy = new THREE.Object3D();
|
||||
const sphere = new THREE.Sphere(new THREE.Vector3(), boundingRadius);
|
||||
let visibleCount = 0;
|
||||
for (let i = 0; i < totalInstances; i++) {
|
||||
sphere.center.copy(positions[i]);
|
||||
if (frustum.intersectsSphere(sphere)) {
|
||||
dummy.position.copy(positions[i]);
|
||||
dummy.updateMatrix();
|
||||
instancedMesh.setMatrixAt(visibleCount++, dummy.matrix);
|
||||
}
|
||||
}
|
||||
instancedMesh.count = visibleCount;
|
||||
instancedMesh.instanceMatrix.needsUpdate = true;
|
||||
```
|
||||
|
||||
### Per-instance color
|
||||
```javascript
|
||||
const mesh = new THREE.InstancedMesh(geo, mat, N);
|
||||
const color = new THREE.Color();
|
||||
for (let i = 0; i < N; i++) {
|
||||
color.setHSL(i / N, 0.7, 0.5);
|
||||
mesh.setColorAt(i, color);
|
||||
}
|
||||
mesh.instanceColor.needsUpdate = true;
|
||||
// shader auto: gl_InstanceID → vInstanceColor
|
||||
```
|
||||
|
||||
### Dynamic draw usage (partial updates)
|
||||
```javascript
|
||||
mesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
|
||||
// only update changed instances
|
||||
mesh.setMatrixAt(idx, newMatrix);
|
||||
mesh.instanceMatrix.updateRange = { offset: idx * 16, count: 16 };
|
||||
mesh.instanceMatrix.needsUpdate = true;
|
||||
```
|
||||
|
||||
### Chunked InstancedMesh (spatial bucket)
|
||||
```javascript
|
||||
class ChunkedInstances {
|
||||
constructor(geo, mat, chunkSize = 64) {
|
||||
this.chunks = new Map(); // "x,y,z" → InstancedMesh
|
||||
this.chunkSize = chunkSize;
|
||||
}
|
||||
add(pos) {
|
||||
const key = this.chunkKey(pos);
|
||||
if (!this.chunks.has(key)) {
|
||||
this.chunks.set(key, new THREE.InstancedMesh(geo, mat, 1024));
|
||||
}
|
||||
// ...
|
||||
}
|
||||
cullChunks(frustum) {
|
||||
for (const [key, mesh] of this.chunks) {
|
||||
mesh.visible = frustum.intersectsBox(this.chunkBox(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### BatchedMesh (Three.js r170+)
|
||||
```javascript
|
||||
const batched = new THREE.BatchedMesh(maxGeoms, maxVerts, maxIdx);
|
||||
const geoIdA = batched.addGeometry(geoA);
|
||||
const geoIdB = batched.addGeometry(geoB);
|
||||
const instA = batched.addInstance(geoIdA);
|
||||
batched.setMatrixAt(instA, matrixA);
|
||||
// 매 different geometries 매 single draw call
|
||||
```
|
||||
|
||||
### GPU compute culling (WebGPU)
|
||||
```javascript
|
||||
// compute shader: input matrices + frustum planes → atomic counter + visible matrix buffer
|
||||
const cullPipeline = device.createComputePipeline({...});
|
||||
pass.setPipeline(cullPipeline);
|
||||
pass.dispatchWorkgroups(Math.ceil(N / 64));
|
||||
// then drawIndexedIndirect from visible buffer
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| < 1k static instances | Plain InstancedMesh |
|
||||
| 1k–100k mostly static | InstancedMesh + manual frustum culling |
|
||||
| 100k+ static | Chunked InstancedMesh (spatial) + LOD |
|
||||
| Dynamic per-frame (particles) | Points / GPU particle system |
|
||||
| Different geometries | BatchedMesh (r170+) |
|
||||
| Massive (1M+) | WebGPU compute culling + indirect draw |
|
||||
| Picking 필요 | InstancedMesh + raycaster.firstHitOnly = true |
|
||||
|
||||
**기본값**: < 10k는 plain InstancedMesh, 그 이상 매 chunked + LOD.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[GPU Instancing]] · [[Three.js]]
|
||||
- 변형: [[BatchedMesh]]
|
||||
- Adjacent: [[Frustum Culling]] · [[LOD]] · [[Indirect Draw]] · [[WebGPU]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 같은 geometry+material의 N copies, 매 N > 50, 매 draw call 매 hot path bottleneck.
|
||||
**언제 X**: 매 highly varying geometry (use BatchedMesh), 매 < 50 copies (overhead > benefit), 매 fully dynamic mesh (skinning per instance은 expensive).
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **No bounding 갱신**: 매 instance 매 spread out 매 single boundingSphere가 too large → frustum culling 작동 안 함.
|
||||
- **매 frame full matrix rebuild**: 매 instance 매 100% update assumption 매 wrong → updateRange 활용.
|
||||
- **Different materials → multiple InstancedMesh**: 매 점 defeats the purpose. Use texture atlas + instance attribute.
|
||||
- **Skip LOD**: 매 far instance 매 close instance와 same vertex count → fillrate explosion.
|
||||
- **InstancedMesh on top of skinned mesh**: 매 shader 매 manual instancing 필요 — Three.js native skinning 매 instance와 conflict.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Three.js docs r170+, mrdoob InstancedMesh PR, WebGPU spec).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — InstancedMesh 한계 / 해결 패턴 / BatchedMesh + WebGPU compute culling |
|
||||
@@ -0,0 +1,225 @@
|
||||
---
|
||||
id: wiki-2026-0508-instancedmesh-최적화
|
||||
title: InstancedMesh 최적화
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [InstancedMesh, GPU Instancing, Three.js Instancing]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [threejs, webgl, webgpu, rendering, performance]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: TypeScript
|
||||
framework: Three.js r172 / WebGPU
|
||||
---
|
||||
|
||||
# InstancedMesh 최적화
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 동일 geometry 의 N 개를 1 draw call 로"**. InstancedMesh 는 매 같은 mesh 를 instance attribute (matrix, color) 만 바꿔 GPU 에 한 번에 제출. 매 forest, particle, crowd 같은 thousands-of-objects scene 에서 50-1000x throughput.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 작동 원리
|
||||
- 매 vertex shader 는 `gl_InstanceID` (WebGL2) / `instance_index` (WebGPU) 로 per-instance 데이터 lookup.
|
||||
- 매 instanceMatrix (mat4) 는 default attribute. 매 추가로 instanceColor, custom attribute 가능.
|
||||
- 매 draw call: `gl.drawElementsInstanced(mode, count, type, offset, instanceCount)`.
|
||||
|
||||
### 매 비용 분석
|
||||
- **CPU 절감**: 매 N draw call → 1. 매 binding state 변경 N → 1.
|
||||
- **GPU 비용**: 매 동일 (vertex 처리 N×). 매 절감은 driver overhead 에서.
|
||||
- **Break-even**: 매 보통 ~50-100 instance 부터 이득. 매 이하면 batched geometry 가 더 빠를 수도.
|
||||
|
||||
### 매 응용
|
||||
1. **Forest / vegetation** (10k trees).
|
||||
2. **Particle system** (smoke, sparks).
|
||||
3. **Crowd / NPC swarm**.
|
||||
4. **Voxel chunk rendering**.
|
||||
5. **UI marker overlay** (map pins).
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### 1. 기본 InstancedMesh 셋업 (Three.js r172)
|
||||
```typescript
|
||||
import * as THREE from 'three';
|
||||
|
||||
const geo = new THREE.BoxGeometry(1, 1, 1);
|
||||
const mat = new THREE.MeshStandardMaterial({ color: 0x88aaff });
|
||||
const COUNT = 10_000;
|
||||
const mesh = new THREE.InstancedMesh(geo, mat, COUNT);
|
||||
mesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage); // 매 자주 업데이트면
|
||||
|
||||
const m = new THREE.Matrix4();
|
||||
const q = new THREE.Quaternion();
|
||||
const s = new THREE.Vector3(1, 1, 1);
|
||||
const p = new THREE.Vector3();
|
||||
|
||||
for (let i = 0; i < COUNT; i++) {
|
||||
p.set((Math.random() - 0.5) * 200, 0, (Math.random() - 0.5) * 200);
|
||||
q.setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.random() * Math.PI * 2);
|
||||
m.compose(p, q, s);
|
||||
mesh.setMatrixAt(i, m);
|
||||
}
|
||||
mesh.instanceMatrix.needsUpdate = true;
|
||||
scene.add(mesh);
|
||||
```
|
||||
|
||||
### 2. Per-instance color (vertex color attribute)
|
||||
```typescript
|
||||
const colors = new Float32Array(COUNT * 3);
|
||||
for (let i = 0; i < COUNT; i++) {
|
||||
colors[i*3] = Math.random();
|
||||
colors[i*3+1] = Math.random();
|
||||
colors[i*3+2] = Math.random();
|
||||
}
|
||||
mesh.instanceColor = new THREE.InstancedBufferAttribute(colors, 3);
|
||||
```
|
||||
|
||||
### 3. Frustum culling per-instance (BVH-based)
|
||||
```typescript
|
||||
import { computeBoundsTree, MeshBVH } from 'three-mesh-bvh';
|
||||
|
||||
// 매 default InstancedMesh 는 whole-mesh frustum culling 만 함.
|
||||
// 매 instance-level 은 manual: BVH 로 visible instance 만 update.
|
||||
const bvh = new MeshBVH(geo);
|
||||
const visibleMatrices: THREE.Matrix4[] = [];
|
||||
const frustum = new THREE.Frustum().setFromProjectionMatrix(
|
||||
new THREE.Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse)
|
||||
);
|
||||
|
||||
let visibleCount = 0;
|
||||
for (let i = 0; i < COUNT; i++) {
|
||||
mesh.getMatrixAt(i, m);
|
||||
p.setFromMatrixPosition(m);
|
||||
if (frustum.containsPoint(p)) {
|
||||
mesh.setMatrixAt(visibleCount++, m);
|
||||
}
|
||||
}
|
||||
mesh.count = visibleCount; // 매 핵심: count 만 줄여 draw 절감
|
||||
mesh.instanceMatrix.needsUpdate = true;
|
||||
```
|
||||
|
||||
### 4. WebGPU instancing (Three.js r172 WebGPURenderer)
|
||||
```typescript
|
||||
import { WebGPURenderer, MeshBasicNodeMaterial } from 'three/webgpu';
|
||||
import { instanceIndex, vec3, color } from 'three/tsl';
|
||||
|
||||
const mat = new MeshBasicNodeMaterial();
|
||||
// 매 TSL 로 per-instance color 계산
|
||||
mat.colorNode = color(vec3(
|
||||
instanceIndex.toFloat().div(COUNT).fract(),
|
||||
0.5,
|
||||
0.8
|
||||
));
|
||||
const mesh = new THREE.InstancedMesh(geo, mat, COUNT);
|
||||
```
|
||||
|
||||
### 5. LOD + InstancedMesh 결합
|
||||
```typescript
|
||||
class InstancedLOD {
|
||||
constructor(private high: THREE.InstancedMesh,
|
||||
private mid: THREE.InstancedMesh,
|
||||
private low: THREE.InstancedMesh) {}
|
||||
|
||||
update(camera: THREE.Camera, positions: THREE.Vector3[]) {
|
||||
let h = 0, m = 0, l = 0;
|
||||
const matrix = new THREE.Matrix4();
|
||||
for (const p of positions) {
|
||||
const d = p.distanceTo(camera.position);
|
||||
const target = d < 30 ? this.high : d < 100 ? this.mid : this.low;
|
||||
const idx = d < 30 ? h++ : d < 100 ? m++ : l++;
|
||||
matrix.setPosition(p);
|
||||
target.setMatrixAt(idx, matrix);
|
||||
}
|
||||
this.high.count = h; this.mid.count = m; this.low.count = l;
|
||||
[this.high, this.mid, this.low].forEach(x => x.instanceMatrix.needsUpdate = true);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6. GPU compute 로 instance 위치 (WebGPU)
|
||||
```typescript
|
||||
import { Fn, instanceIndex, storage, vec3, time } from 'three/tsl';
|
||||
import { compute } from 'three/tsl';
|
||||
|
||||
const positionBuffer = storage(new THREE.StorageBufferAttribute(COUNT, 3), 'vec3');
|
||||
|
||||
const updateFn = Fn(() => {
|
||||
const i = instanceIndex.toFloat();
|
||||
const t = time;
|
||||
positionBuffer.element(instanceIndex).assign(
|
||||
vec3(i.mul(0.1).sin().mul(50), t.add(i).sin().mul(5), i.mul(0.1).cos().mul(50))
|
||||
);
|
||||
});
|
||||
|
||||
const computePass = updateFn().compute(COUNT);
|
||||
renderer.computeAsync(computePass); // 매 frame 마다
|
||||
```
|
||||
|
||||
### 7. Memory layout 최적화 (matrix → quat+pos+scale)
|
||||
```typescript
|
||||
// 매 mat4 (16 floats × 4B = 64B) 대신 quat (4) + pos (3) + scale (1) = 32B
|
||||
const compactBuffer = new Float32Array(COUNT * 8);
|
||||
mesh.geometry.setAttribute('iQuat',
|
||||
new THREE.InstancedBufferAttribute(compactBuffer, 4, false, 1).setUsage(THREE.DynamicDrawUsage));
|
||||
// shader 에서 quat → matrix reconstruct
|
||||
```
|
||||
|
||||
### 8. Sort by depth (transparency)
|
||||
```typescript
|
||||
const indices = Array.from({length: COUNT}, (_, i) => i);
|
||||
indices.sort((a, b) => {
|
||||
mesh.getMatrixAt(a, m); const da = p.setFromMatrixPosition(m).distanceTo(camera.position);
|
||||
mesh.getMatrixAt(b, m); const db = p.setFromMatrixPosition(m).distanceTo(camera.position);
|
||||
return db - da; // 매 back-to-front
|
||||
});
|
||||
const sorted = new Float32Array(COUNT * 16);
|
||||
for (let i = 0; i < COUNT; i++) {
|
||||
mesh.getMatrixAt(indices[i], m);
|
||||
m.toArray(sorted, i * 16);
|
||||
}
|
||||
mesh.instanceMatrix.array.set(sorted);
|
||||
mesh.instanceMatrix.needsUpdate = true;
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Static, identical mesh × thousands | `InstancedMesh` |
|
||||
| Static, varied meshes | `BatchedMesh` (Three.js r158+) |
|
||||
| 매 < 50 instance | 매 그냥 separate Mesh, 차이 없음 |
|
||||
| 매 frequent matrix update | `setUsage(DynamicDrawUsage)` + partial `updateRange` |
|
||||
| Per-instance custom data | `InstancedBufferAttribute` |
|
||||
| GPU-driven motion | TSL compute + storage buffer |
|
||||
|
||||
**기본값**: 매 ≥100 identical instance → InstancedMesh + DynamicDrawUsage + frustum culling.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Three.js]] · [[GPU Instancing]] · [[WebGL/WebGPU]]
|
||||
- 변형: [[BatchedMesh]]
|
||||
- Adjacent: [[InstancedMesh 동적 버퍼 확장]] · [[Frustum Culling]] · [[LOD]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: instance 수에 따른 기법 선택, draw call 분석 해석, TSL compute shader 작성.
|
||||
**언제 X**: 매 specific GPU/driver bug 진단 (실측 profile 없이).
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **매 frame 마다 setMatrixAt 전체 N**: 매 변하지 않는 instance 까지 update → CPU bound. 매 dirty flag 사용.
|
||||
- **DynamicDrawUsage 빠뜨림**: 매 default StaticDrawUsage 면 매 update 시 driver hint mismatch.
|
||||
- **count 줄이지 않고 culling**: 매 invisible 도 vertex shader 실행됨.
|
||||
- **너무 작은 N (< 50)**: 매 instancing overhead 가 이득보다 큼.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Three.js r172 docs, WebGPU spec, Khronos WebGL2 spec).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — InstancedMesh 패턴 + WebGPU TSL compute |
|
||||
@@ -0,0 +1,150 @@
|
||||
---
|
||||
id: wiki-2026-0508-interop-2025
|
||||
title: Interop 2025
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Web Interop 2025]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [web-platform, browser, standards]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: HTML/CSS/JavaScript
|
||||
framework: Web Platform
|
||||
---
|
||||
|
||||
# Interop 2025
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 browser vendor 들이 매년 합의하여 fix 하는 web platform inconsistency list"**. Apple, Google, Microsoft, Mozilla, Bocoup, Igalia 가 공동으로 select 한 focus area 를 1년간 implement, web-platform-tests pass rate 의 dashboard 로 progress 의 track. 2025 cycle 의 anchor positioning, scrollbar styling, navigation API, View Transitions cross-document, storage access API 가 highlight.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 origin & process
|
||||
- 2021 Compat 2021 시작, 2022 부터 "Interop" 명칭.
|
||||
- 매년 vendor 공동 선정 + community proposal.
|
||||
- WPT (web-platform-tests) score 로 measure — wpt.fyi dashboard.
|
||||
|
||||
### 매 Interop 2025 의 focus areas
|
||||
- **Anchor positioning** (CSS): tooltip/popover 의 declarative anchor.
|
||||
- **View Transitions cross-document**: MPA 도 SPA 같은 transition.
|
||||
- **Scrollbar gutter / colors**: scrollbar styling cross-browser.
|
||||
- **Navigation API**: history API replacement.
|
||||
- **Storage Access API**: cross-site cookie consent flow.
|
||||
- **Container queries** (residual gaps).
|
||||
- **Custom highlights API**: native highlight rendering.
|
||||
|
||||
### 매 응용
|
||||
1. Web feature 의 production-safe baseline 결정 (Baseline initiative 와 align).
|
||||
2. Polyfill / progressive enhancement strategy 의 기준.
|
||||
3. Browser team 의 quarterly priority.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Anchor positioning (CSS)
|
||||
```css
|
||||
/* Trigger */
|
||||
.btn { anchor-name: --my-anchor; }
|
||||
|
||||
/* Popover positioned relative to anchor */
|
||||
.tooltip {
|
||||
position: absolute;
|
||||
position-anchor: --my-anchor;
|
||||
top: anchor(bottom);
|
||||
left: anchor(center);
|
||||
translate: -50% 8px;
|
||||
}
|
||||
```
|
||||
|
||||
### View Transitions cross-document
|
||||
```html
|
||||
<!-- both pages opt in -->
|
||||
<meta name="view-transition" content="same-origin">
|
||||
<style>
|
||||
@view-transition { navigation: auto; }
|
||||
.hero { view-transition-name: hero; }
|
||||
</style>
|
||||
```
|
||||
|
||||
### Navigation API
|
||||
```javascript
|
||||
navigation.addEventListener('navigate', (e) => {
|
||||
if (!e.canIntercept || e.hashChange) return
|
||||
e.intercept({
|
||||
handler: async () => {
|
||||
const data = await fetch(e.destination.url).then(r => r.json())
|
||||
render(data)
|
||||
},
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
### Storage Access API
|
||||
```javascript
|
||||
// inside iframe — request 1P-like cookie access
|
||||
if (await document.hasStorageAccess() === false) {
|
||||
try {
|
||||
await document.requestStorageAccess()
|
||||
} catch (e) { /* user denied */ }
|
||||
}
|
||||
```
|
||||
|
||||
### Scrollbar styling (modern)
|
||||
```css
|
||||
.list {
|
||||
scrollbar-gutter: stable both-edges;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--thumb) transparent;
|
||||
}
|
||||
```
|
||||
|
||||
### Feature detect via Baseline / `@supports`
|
||||
```css
|
||||
@supports (anchor-name: --x) {
|
||||
.tooltip { position-anchor: --my-anchor; }
|
||||
}
|
||||
@supports not (anchor-name: --x) {
|
||||
.tooltip { /* fallback positioning JS */ }
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| New feature production use | Interop 2025 list + Baseline check |
|
||||
| 필요한 feature 가 still red | polyfill or feature flag |
|
||||
| Cross-browser bug found | wpt.fyi 에 issue file |
|
||||
| Greenfield SPA | Navigation API 채택 검토 |
|
||||
| Tooltip / popover | Anchor positioning + popover API |
|
||||
|
||||
**기본값**: 매 Baseline Newly Available + Interop 2025 통과 feature 만 의 default 사용.
|
||||
|
||||
## 🔗 Graph
|
||||
- 변형: [[Interop 2026]]
|
||||
- 응용: [[View Transitions API]] · [[Navigation API]]
|
||||
- Adjacent: [[Chromium]] · [[Baseline]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 web platform feature 의 cross-browser readiness 의 query, polyfill strategy, modern CSS/JS adoption 결정.
|
||||
**언제 X**: server-side, native, non-browser runtime.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Single-vendor preview 의 production**: Chrome canary 만 의 working ≠ ship-ready.
|
||||
- **WPT pass = bug-free 의 가정**: real-world edge case 는 WPT 가 다 cover X.
|
||||
- **Polyfill 의 무지성 적용**: native 가 ship 된 후에도 polyfill 유지 = bundle bloat.
|
||||
- **Interop list 의 구속**: list 외 의 feature 도 needed 면 채택 가능 — list 는 priority 일 뿐.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (web.dev/interop-2025, wpt.fyi/interop-2025, vendor blog posts 2025).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — Interop 2025 focus areas + adoption patterns |
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
---
|
||||
id: wiki-2026-0508-inventory-management-example
|
||||
title: Inventory Management Example
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Inventory Domain Model, 재고 관리 예제]
|
||||
duplicate_of: none
|
||||
source_trust_level: B
|
||||
confidence_score: 0.85
|
||||
verification_status: applied
|
||||
tags: [example, domain-modeling, typescript, ddd]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: TypeScript
|
||||
framework: Zod
|
||||
---
|
||||
|
||||
# Inventory Management Example
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 SKU · stock · reservation 의 type-safe domain model 의 walking example"**. 매 branded types · discriminated unions · runtime validation 매 결합 — 2026 modern TS pattern 의 canonical illustration.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 도메인 entities
|
||||
- `SKU` (branded string)
|
||||
- `Stock` (positive int)
|
||||
- `Reservation` (id, sku, qty, expiresAt)
|
||||
- `InventoryEvent` (Tagged: Received | Reserved | Shipped | Cancelled)
|
||||
|
||||
### 매 invariants
|
||||
- 매 stock ≥ 0 항상.
|
||||
- 매 reservation 의 release 후 stock 회복.
|
||||
- 매 ship 의 reservation 의 존재 시.
|
||||
|
||||
### 매 응용
|
||||
1. E-commerce checkout flow (재고 차감 · 복구).
|
||||
2. Warehouse management (multi-location).
|
||||
3. Event-sourced inventory ledger.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Branded SKU
|
||||
```ts
|
||||
type SKU = string & { readonly __brand: "SKU" }
|
||||
|
||||
const SkuSchema = z.string().regex(/^[A-Z]{3}-\d{6}$/).brand("SKU")
|
||||
const sku = SkuSchema.parse("ABC-123456") // SKU
|
||||
```
|
||||
|
||||
### Stock value object
|
||||
```ts
|
||||
class Stock {
|
||||
private constructor(public readonly value: number) {}
|
||||
static of(n: number): Stock {
|
||||
if (!Number.isInteger(n) || n < 0) throw new Error("invalid stock")
|
||||
return new Stock(n)
|
||||
}
|
||||
reserve(qty: number): Stock { return Stock.of(this.value - qty) }
|
||||
release(qty: number): Stock { return Stock.of(this.value + qty) }
|
||||
}
|
||||
```
|
||||
|
||||
### Discriminated event union
|
||||
```ts
|
||||
type InventoryEvent =
|
||||
| { type: "Received"; sku: SKU; qty: number; at: Date }
|
||||
| { type: "Reserved"; sku: SKU; qty: number; reservationId: string }
|
||||
| { type: "Shipped"; reservationId: string }
|
||||
| { type: "Cancelled"; reservationId: string }
|
||||
|
||||
function reduce(state: Map<SKU, Stock>, e: InventoryEvent): Map<SKU, Stock> {
|
||||
switch (e.type) {
|
||||
case "Received":
|
||||
return new Map(state).set(e.sku, (state.get(e.sku) ?? Stock.of(0)).release(e.qty))
|
||||
case "Reserved":
|
||||
return new Map(state).set(e.sku, state.get(e.sku)!.reserve(e.qty))
|
||||
case "Shipped":
|
||||
case "Cancelled":
|
||||
return state
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Reservation lifecycle (Result type)
|
||||
```ts
|
||||
type Result<T, E> = { ok: true; value: T } | { ok: false; error: E }
|
||||
|
||||
function reserve(stock: Stock, qty: number): Result<Stock, "INSUFFICIENT"> {
|
||||
if (stock.value < qty) return { ok: false, error: "INSUFFICIENT" }
|
||||
return { ok: true, value: stock.reserve(qty) }
|
||||
}
|
||||
```
|
||||
|
||||
### Zod runtime parse (API boundary)
|
||||
```ts
|
||||
const ReserveCmd = z.object({
|
||||
sku: SkuSchema,
|
||||
qty: z.number().int().positive(),
|
||||
customerId: z.string().uuid(),
|
||||
})
|
||||
|
||||
app.post("/reserve", (req, res) => {
|
||||
const cmd = ReserveCmd.safeParse(req.body)
|
||||
if (!cmd.success) return res.status(400).json(cmd.error.flatten())
|
||||
// ... cmd.data is fully typed
|
||||
})
|
||||
```
|
||||
|
||||
### Exhaustive switch guard
|
||||
```ts
|
||||
function never(x: never): never { throw new Error(`unhandled: ${x}`) }
|
||||
// switch default → never(e) 매 새 event 추가 시 compile error
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Single-location inventory | In-memory `Map<SKU, Stock>` |
|
||||
| Multi-location | Add `LocationId` brand · partition state |
|
||||
| Audit-required | Event sourcing (full event log) |
|
||||
| High-concurrency | Optimistic concurrency token + retry |
|
||||
|
||||
**기본값**: event-sourced reduce 매 audit + replay benefit. 매 단순 case도 future-proof.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Domain-Driven Design]] · [[견고한 도메인 모델 및 API 계약 설계]]
|
||||
- 변형: [[Result Type]] · [[Discriminated_Unions|Discriminated Unions]]
|
||||
- 응용: [[Zod 파싱과 브랜디드 타입을 결합한 런타임 데이터 검증]]
|
||||
- Adjacent: [[브랜디드 타입 (Branded Types)]] · [[ts-brand]] · [[완전성 검사(Exhaustiveness Checking)]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 type-safe domain modeling 의 teaching example 으로 reuse.
|
||||
**언제 X**: 매 production app 의 직접 copy — 매 oversimplified.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Plain `number` for stock**: 매 invariant 의 enforce 의 X — class · brand 의 사용.
|
||||
- **Stringly-typed events**: 매 discriminated union 의 사용.
|
||||
- **Skipping runtime parse at boundary**: 매 type erasure 후 — Zod / Effect Schema 의 필수.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (DDD blue book · Effect/Zod docs · TypeScript handbook 2026).
|
||||
- 신뢰도 B (illustrative example, not canonical implementation).
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — full domain example with brands · DU · event sourcing |
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
id: wiki-20260508-netflix--redir
|
||||
title: Netflix 마이크로서비스 전환
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: netflix-cosmos-platform
|
||||
duplicate_of: "[[Netflix 마이크로서비스 및 코스모스 플랫폼 전환]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, netflix, microservices, architecture]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# Netflix 마이크로서비스 전환
|
||||
|
||||
> **이 문서는 [[넷플릭스(Netflix)의 마이크로서비스 및 코스모스 플랫폼 전환]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 핵심 요약
|
||||
- 매 Netflix 의 monolith → microservices 전환 (2008-2016).
|
||||
- 매 Cosmos 플랫폼: 매 next-gen media processing — workflow + service 의 통합.
|
||||
- 매 OSS 산출물: Eureka, Hystrix, Zuul, Chaos Monkey.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[넷플릭스(Netflix)의 마이크로서비스 및 코스모스 플랫폼 전환]] (canonical)
|
||||
- Adjacent: [[Cosmos 플랫폼 (Netflix)]] · [[넷플릭스 코스모스 플랫폼 (Netflix Cosmos)]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
@@ -0,0 +1,180 @@
|
||||
---
|
||||
id: wiki-2026-0508-nodejs-성능-최적화-및-디버깅
|
||||
title: Nodejs 성능 최적화 및 디버깅
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Nodejs 메모리 최적화, Nodejs 메모리 튜닝, Nodejs 성능 디버깅, Nodejs 프로세스 모니터링]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [nodejs, performance, debugging, memory, v8]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: javascript
|
||||
framework: nodejs
|
||||
---
|
||||
|
||||
# Nodejs 성능 최적화 및 디버깅
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 production Node 의 성능 의 V8 heap + event loop + async I/O 의 3-축 의 governing"**. 매 2026 의 Node 22 LTS 의 default — 매 V8 12.x 의 Maglev/Turbofan tier 의 활용 + native diagnostic_channel + clinic.js 4.x 의 standard toolchain.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 3-축 model
|
||||
- **Heap**: 매 V8 의 Old/New Space 의 GC pressure.
|
||||
- **Event Loop**: 매 microtask + macrotask + nextTick 의 priority.
|
||||
- **Async I/O**: 매 libuv thread pool (`UV_THREADPOOL_SIZE` default 4).
|
||||
|
||||
### 매 진단 toolkit (2026)
|
||||
- `node --inspect` + Chrome DevTools.
|
||||
- `clinic.js doctor / flame / bubbleprof / heapprofiler`.
|
||||
- `0x` (flamegraph generator).
|
||||
- `node --prof` + `--prof-process`.
|
||||
- `diagnostic_channel` (Node 16+) — 매 production-safe instrumentation.
|
||||
|
||||
### 매 응용
|
||||
1. Memory leak 의 추적 — heap snapshot diff.
|
||||
2. CPU bottleneck 의 식별 — flame graph.
|
||||
3. Event loop lag 의 monitoring — `perf_hooks.monitorEventLoopDelay`.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Heap snapshot 비교
|
||||
```javascript
|
||||
const v8 = require('v8');
|
||||
const fs = require('fs');
|
||||
|
||||
function snapshot(label) {
|
||||
const file = `/tmp/heap-${label}-${Date.now()}.heapsnapshot`;
|
||||
const stream = v8.getHeapSnapshot();
|
||||
stream.pipe(fs.createWriteStream(file));
|
||||
return file;
|
||||
}
|
||||
|
||||
// usage
|
||||
const before = snapshot('before');
|
||||
runWorkload();
|
||||
global.gc?.(); // --expose-gc
|
||||
const after = snapshot('after');
|
||||
// → load both into Chrome DevTools, compare retainers
|
||||
```
|
||||
|
||||
### Event loop delay monitoring
|
||||
```javascript
|
||||
import { monitorEventLoopDelay } from 'node:perf_hooks';
|
||||
|
||||
const h = monitorEventLoopDelay({ resolution: 20 });
|
||||
h.enable();
|
||||
|
||||
setInterval(() => {
|
||||
const p99 = h.percentile(99) / 1e6; // ms
|
||||
if (p99 > 100) console.warn(`event loop p99 lag: ${p99.toFixed(1)}ms`);
|
||||
h.reset();
|
||||
}, 5000);
|
||||
```
|
||||
|
||||
### CPU profile (production-safe)
|
||||
```javascript
|
||||
import { Session } from 'node:inspector/promises';
|
||||
|
||||
const session = new Session();
|
||||
session.connect();
|
||||
await session.post('Profiler.enable');
|
||||
await session.post('Profiler.start');
|
||||
// ... run workload
|
||||
const { profile } = await session.post('Profiler.stop');
|
||||
fs.writeFileSync('cpu.cpuprofile', JSON.stringify(profile));
|
||||
```
|
||||
|
||||
### Heap limit 설정
|
||||
```bash
|
||||
# 8GB heap
|
||||
node --max-old-space-size=8192 server.js
|
||||
|
||||
# container-aware
|
||||
node --max-old-space-size=$(echo "$(cat /sys/fs/cgroup/memory.max) * 0.75 / 1024 / 1024" | bc) server.js
|
||||
```
|
||||
|
||||
### diagnostic_channel instrumentation
|
||||
```javascript
|
||||
import diagnostics_channel from 'node:diagnostics_channel';
|
||||
|
||||
const ch = diagnostics_channel.channel('app:slow-query');
|
||||
ch.subscribe((msg) => {
|
||||
metrics.histogram('db.query.slow', msg.duration);
|
||||
});
|
||||
|
||||
// publisher
|
||||
ch.publish({ query, duration });
|
||||
```
|
||||
|
||||
### Async resource tracking
|
||||
```javascript
|
||||
import { AsyncLocalStorage } from 'node:async_hooks';
|
||||
|
||||
const als = new AsyncLocalStorage();
|
||||
|
||||
app.use((req, res, next) => {
|
||||
als.run({ requestId: req.id }, next);
|
||||
});
|
||||
|
||||
logger.info = (msg) => {
|
||||
const ctx = als.getStore();
|
||||
console.log(JSON.stringify({ msg, requestId: ctx?.requestId }));
|
||||
};
|
||||
```
|
||||
|
||||
### Worker thread offload
|
||||
```javascript
|
||||
import { Worker } from 'node:worker_threads';
|
||||
|
||||
function cpuHeavyTask(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const w = new Worker('./worker.js', { workerData: data });
|
||||
w.on('message', resolve);
|
||||
w.on('error', reject);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Memory leak 의심 | heap snapshot diff (3개 시점) |
|
||||
| CPU spike | clinic flame / 0x flamegraph |
|
||||
| Latency p99 ↑ | event loop delay monitor |
|
||||
| OOM kill (container) | `--max-old-space-size` 의 container limit 의 75% |
|
||||
| Async chain debugging | AsyncLocalStorage + diagnostic_channel |
|
||||
|
||||
**기본값**: clinic doctor 로 시작 → 매 specific tool (flame/bubbleprof) 의 narrowing.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[V8 엔진 힙 아키텍처]] · [[Garbage Collection]]
|
||||
- 변형: [[Nodejs 메모리 최적화]] · [[Nodejs 메모리 튜닝]] · [[Nodejs 성능 디버깅]]
|
||||
- 응용: [[Nodejs 프로세스 모니터링 및 메모리 분석]] · [[브라우저 및 Nodejs 메모리 튜닝]]
|
||||
- Adjacent: [[Chrome DevTools(크롬 개발자 도구)]] · [[Flame Chart]] · [[할당 타임라인(Allocation Timeline)]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: production Node 의 성능 회귀 의 진단, heap leak 의 root cause analysis.
|
||||
**언제 X**: synthetic benchmark — 매 real workload profile 만 의 trustworthy.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Premature optimization**: 매 profile 의 X — guess 의 X.
|
||||
- **`global.gc()` 의 production 호출**: 매 stop-the-world — latency spike.
|
||||
- **`UV_THREADPOOL_SIZE` 의 무분별 증가**: 매 context switch 의 overhead.
|
||||
- **heap snapshot 의 production load 의 down**: 매 GB-scale 의 dump — disk + pause.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Node.js 22 docs, V8 blog, Matteo Collina's perf talks).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — Node 22 / clinic 4.x / diagnostic_channel 반영 |
|
||||
@@ -0,0 +1,230 @@
|
||||
---
|
||||
id: wiki-2026-0508-object-pooling-오브젝트-풀링
|
||||
title: Object Pooling (오브젝트 풀링)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [오브젝트 풀링, Object Pool Pattern]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [pattern, performance, memory, gc, gamedev]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: typescript
|
||||
framework: agnostic
|
||||
---
|
||||
|
||||
# Object Pooling (오브젝트 풀링)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 expensive object 의 reuse 로 GC pressure + allocation cost 의 회피"**. 매 game loop / hot path / high-frequency event handler 의 standard 의 패턴 — 매 2026 의 game engine (Three.js, Bevy, Unity DOTS), DB connection pool, HTTP keep-alive, worker pool 의 universal 의 pattern.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 3-component
|
||||
- **Pool**: 매 object 의 collection (free list).
|
||||
- **Acquire**: 매 free object 의 dequeue (또는 신규 생성).
|
||||
- **Release**: 매 object 의 reset + enqueue.
|
||||
|
||||
### 매 언제 적용
|
||||
- 매 allocation rate > 10K/sec.
|
||||
- 매 object lifetime 의 짧음 (< 1 frame).
|
||||
- 매 GC pause 의 user-visible (game, real-time).
|
||||
- 매 expensive constructor (DB connect, file open, GPU buffer alloc).
|
||||
|
||||
### 매 응용
|
||||
1. Game particle system — bullet, explosion, enemy.
|
||||
2. DB connection pool — `pg-pool`, HikariCP.
|
||||
3. HTTP agent — `http.Agent({ keepAlive: true })`.
|
||||
4. Web Worker pool — `piscina`.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Generic pool (TypeScript)
|
||||
```typescript
|
||||
class ObjectPool<T> {
|
||||
private free: T[] = [];
|
||||
constructor(
|
||||
private factory: () => T,
|
||||
private reset: (obj: T) => void,
|
||||
initialSize = 0
|
||||
) {
|
||||
for (let i = 0; i < initialSize; i++) this.free.push(factory());
|
||||
}
|
||||
|
||||
acquire(): T {
|
||||
return this.free.pop() ?? this.factory();
|
||||
}
|
||||
|
||||
release(obj: T): void {
|
||||
this.reset(obj);
|
||||
this.free.push(obj);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Three.js Vector3 pool (game loop)
|
||||
```typescript
|
||||
import { Vector3 } from 'three';
|
||||
|
||||
const vec3Pool = new ObjectPool<Vector3>(
|
||||
() => new Vector3(),
|
||||
(v) => v.set(0, 0, 0),
|
||||
256
|
||||
);
|
||||
|
||||
function updateBullet(b: Bullet, dt: number) {
|
||||
const tmp = vec3Pool.acquire();
|
||||
tmp.copy(b.velocity).multiplyScalar(dt);
|
||||
b.position.add(tmp);
|
||||
vec3Pool.release(tmp);
|
||||
}
|
||||
```
|
||||
|
||||
### Particle system pool
|
||||
```typescript
|
||||
class Particle {
|
||||
position = new Vector3();
|
||||
velocity = new Vector3();
|
||||
life = 0;
|
||||
active = false;
|
||||
}
|
||||
|
||||
class ParticleSystem {
|
||||
private pool: Particle[];
|
||||
private active: Particle[] = [];
|
||||
|
||||
constructor(maxParticles: number) {
|
||||
this.pool = Array.from({ length: maxParticles }, () => new Particle());
|
||||
}
|
||||
|
||||
spawn(pos: Vector3, vel: Vector3, life: number) {
|
||||
const p = this.pool.pop();
|
||||
if (!p) return; // pool exhausted
|
||||
p.position.copy(pos);
|
||||
p.velocity.copy(vel);
|
||||
p.life = life;
|
||||
p.active = true;
|
||||
this.active.push(p);
|
||||
}
|
||||
|
||||
update(dt: number) {
|
||||
for (let i = this.active.length - 1; i >= 0; i--) {
|
||||
const p = this.active[i];
|
||||
p.life -= dt;
|
||||
if (p.life <= 0) {
|
||||
p.active = false;
|
||||
this.active.splice(i, 1);
|
||||
this.pool.push(p); // return to pool
|
||||
} else {
|
||||
p.position.addScaledVector(p.velocity, dt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### DB connection pool (pg)
|
||||
```typescript
|
||||
import { Pool } from 'pg';
|
||||
|
||||
const pool = new Pool({
|
||||
max: 20,
|
||||
idleTimeoutMillis: 30_000,
|
||||
connectionTimeoutMillis: 2000,
|
||||
});
|
||||
|
||||
async function query(sql: string, params: unknown[]) {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
return await client.query(sql, params);
|
||||
} finally {
|
||||
client.release(); // ← back to pool
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Worker thread pool (piscina)
|
||||
```typescript
|
||||
import Piscina from 'piscina';
|
||||
|
||||
const piscina = new Piscina({
|
||||
filename: new URL('./worker.js', import.meta.url).href,
|
||||
minThreads: 2,
|
||||
maxThreads: 8,
|
||||
});
|
||||
|
||||
const result = await piscina.run({ payload: data });
|
||||
```
|
||||
|
||||
### Bounded pool with backpressure
|
||||
```typescript
|
||||
class BoundedPool<T> {
|
||||
private free: T[] = [];
|
||||
private waiters: ((obj: T) => void)[] = [];
|
||||
private created = 0;
|
||||
|
||||
constructor(
|
||||
private factory: () => T,
|
||||
private reset: (obj: T) => void,
|
||||
private max: number
|
||||
) {}
|
||||
|
||||
async acquire(): Promise<T> {
|
||||
if (this.free.length) return this.free.pop()!;
|
||||
if (this.created < this.max) {
|
||||
this.created++;
|
||||
return this.factory();
|
||||
}
|
||||
return new Promise((resolve) => this.waiters.push(resolve));
|
||||
}
|
||||
|
||||
release(obj: T): void {
|
||||
this.reset(obj);
|
||||
const w = this.waiters.shift();
|
||||
if (w) w(obj);
|
||||
else this.free.push(obj);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Hot path allocation (game loop) | object pool (generic) |
|
||||
| DB / network connection | bounded pool with backpressure |
|
||||
| Heavy CPU task | worker thread pool (piscina) |
|
||||
| Short-lived simple obj (< 1KB) | 매 V8 의 young-gen GC 의 충분 — pool 의 X |
|
||||
| Object 의 reset cost > construct cost | pool 의 X |
|
||||
|
||||
**기본값**: 매 profile 후 의 적용 — premature pooling 의 X.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Garbage Collection]] · [[V8 엔진 힙 아키텍처]]
|
||||
- 변형: [[bitECS와 SharedArrayBuffer를 결합한 멀티스레드 고성능 아키텍처]]
|
||||
- 응용: [[InstancedMesh 최적화]] · [[가변적 LOD(Level of Detail) 시스템]]
|
||||
- Adjacent: [[Old_Space|Old Space]] · [[세대 가설(Generational Hypothesis)]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: game loop / real-time pipeline 의 GC pause 회피, expensive resource (DB conn, GPU buffer) 의 reuse.
|
||||
**언제 X**: simple short-lived object — 매 modern GC 의 충분.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Reset 의 누락**: 매 stale state 의 leak — 매 security risk (sensitive data).
|
||||
- **Unbounded pool**: 매 memory leak — 매 max size 의 강제.
|
||||
- **Pool 의 lock contention**: 매 multi-thread 의 sync overhead — thread-local pool 의 고려.
|
||||
- **Object 의 over-aliasing**: 매 release 후 의 reference 유지 — use-after-free 의 bug.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Game Programming Patterns / R. Nystrom, V8 blog, piscina docs).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — TS generic pool, Three.js, piscina 패턴 추가 |
|
||||
@@ -0,0 +1,135 @@
|
||||
---
|
||||
id: wiki-2026-0508-orinoco-프로젝트
|
||||
title: Orinoco 프로젝트
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Orinoco, V8 Orinoco]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [v8, gc, performance]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: C++
|
||||
framework: V8 12+
|
||||
---
|
||||
|
||||
# Orinoco 프로젝트
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 V8 의 GC 의 mostly-parallel, mostly-concurrent 의 evolution"**. 2016 발표된 Orinoco initiative 가 V8 의 stop-the-world phase 를 minimize — incremental marking, parallel scavenge, concurrent sweeping, compaction 의 background offload. 2026 현재 V8 12+ 의 default. Main thread pause time 이 100ms+ → sub-10ms 로 reduce.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 design pillars
|
||||
- **Parallelism**: 동시 main thread 를 멈추고 worker thread 다수 사용 (parallel scavenge, parallel compaction).
|
||||
- **Concurrency**: main thread 는 mutator 의 user code 실행, GC thread 가 background marking/sweeping.
|
||||
- **Incremental**: long pause 를 작은 step 으로 split, frame 사이 의 짤끔.
|
||||
- **Idle-time GC**: main thread idle window (rAF gap) 의 활용.
|
||||
|
||||
### 매 collector phases
|
||||
- **Young (Scavenger)**: parallel copying, 보통 <1ms.
|
||||
- **Old marking**: incremental + concurrent (mutator 동시 실행).
|
||||
- **Old sweeping**: concurrent free-list rebuild.
|
||||
- **Old compaction**: parallel evacuation, 매 page-level.
|
||||
- **Write barrier**: 매 mutator 가 mark 와 race 의 prevent.
|
||||
|
||||
### 매 응용
|
||||
1. Chrome / Edge / Brave (V8 host).
|
||||
2. Node.js / Deno / Bun (runtime GC 의 같은 Orinoco 기반, Bun 은 JSC 라 다름).
|
||||
3. Electron, VS Code (V8 backend).
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Orinoco trace 보기
|
||||
```bash
|
||||
node --trace-gc --trace-gc-verbose app.js
|
||||
# [Mark-Compact (incremental) ...]
|
||||
# [Scavenge (parallel) ...]
|
||||
```
|
||||
|
||||
### Heap stats with v8 module
|
||||
```javascript
|
||||
const v8 = require('v8')
|
||||
const stats = v8.getHeapStatistics()
|
||||
console.log({
|
||||
used: stats.used_heap_size,
|
||||
total: stats.total_heap_size,
|
||||
limit: stats.heap_size_limit,
|
||||
})
|
||||
const spaces = v8.getHeapSpaceStatistics()
|
||||
spaces.forEach(s => console.log(s.space_name, s.space_used_size))
|
||||
```
|
||||
|
||||
### Triggering Orinoco-friendly allocation
|
||||
```javascript
|
||||
// O — short-lived 의 young space 에 머무름
|
||||
function processBatch(items) {
|
||||
return items.map(i => ({ id: i.id, val: i.val * 2 })) // returns die fast
|
||||
}
|
||||
|
||||
// X — large pre-allocated buffer 의 old promotion 강제
|
||||
const giant = new Array(1e7).fill(0) // bypasses young entirely
|
||||
```
|
||||
|
||||
### --max-old-space-size tuning
|
||||
```bash
|
||||
node --max-old-space-size=4096 app.js # 4GB old space ceiling
|
||||
```
|
||||
|
||||
### Idle-time GC hint
|
||||
```javascript
|
||||
// Chrome internal — webpages cannot directly trigger,
|
||||
// but rAF-aligned work 의 GC 가 idle gap 을 활용
|
||||
requestIdleCallback((deadline) => {
|
||||
while (deadline.timeRemaining() > 0 && tasks.length) doWork(tasks.pop())
|
||||
})
|
||||
```
|
||||
|
||||
### Heap snapshot diff
|
||||
```javascript
|
||||
const v8 = require('v8'); const fs = require('fs')
|
||||
v8.writeHeapSnapshot('before.heapsnapshot')
|
||||
runWorkload()
|
||||
v8.writeHeapSnapshot('after.heapsnapshot')
|
||||
// Chrome DevTools → Memory → Comparison
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Browser frame budget (16.6ms) | Orinoco 의 default 충분 |
|
||||
| Large heap (4GB+) | --max-old-space-size + monitoring |
|
||||
| Latency-critical (game, RT) | Object pool + young-friendly allocation |
|
||||
| Server long-running | --gc-interval + heap dump 주기 |
|
||||
|
||||
**기본값**: 매 V8 default Orinoco + workload 의 short-lived bias.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[V8 엔진 힙 아키텍처]]
|
||||
- 변형: [[Orinoco 가비지 컬렉터]]
|
||||
- 응용: [[Incremental_Marking|Incremental Marking]] · [[Mark-Sweep-Compact 알고리즘]]
|
||||
- Adjacent: [[Garbage Collection|Generational Hypothesis]] · [[Old_Space|Old Space]] · [[Write Barrier]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: V8 GC 의 internals 설명, Node.js / Chrome heap tuning, `--trace-gc` 분석.
|
||||
**언제 X**: 다른 engine (JSC, SpiderMonkey, Hermes) 의 GC.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **`global.gc()` 강제**: 매 production 의 X. Orinoco 가 의 better job 의 함.
|
||||
- **--expose-gc 의 production**: 매 attack surface 와 perf degradation.
|
||||
- **Heavy sync work**: incremental marking 의 main thread 가 idle 해야 진행 → tight loop 의 GC 의 starve.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (V8 blog "Orinoco" 2016, "Concurrent marking" 2017, V8 12.x release notes).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — Orinoco design pillars + tracing patterns |
|
||||
@@ -0,0 +1,181 @@
|
||||
---
|
||||
id: wiki-2026-0508-result-type
|
||||
title: Result Type
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Result, Either, Outcome]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [error-handling, types, functional]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: TypeScript/Rust
|
||||
framework: neverthrow/Effect TS/std::result
|
||||
---
|
||||
|
||||
# Result Type
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 error 를 value 로 만들어 type system 이 강제 handle 하게 함"**. Rust 의 `Result<T, E>`, Haskell `Either e a`, OCaml `result`, Swift `Result` 가 origin. TypeScript ecosystem 에서 매 neverthrow, Effect TS, ts-results 가 mainstream. 매 throw/catch 의 invisible control flow 와 unsafe error 의 alternative.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 motivation
|
||||
- Exception 은 type signature 에 안 보임 → 매 caller 가 forget 가능.
|
||||
- `Result<T, E>` 는 매 return type 에 explicit → handle X 면 type error.
|
||||
- 매 functional composition 에 friendly (map, andThen, mapErr).
|
||||
|
||||
### 매 ADT shape
|
||||
- `Ok(T)` | `Err(E)` — 매 두 variant 의 sum type.
|
||||
- `unwrap`, `unwrap_or`, `map`, `andThen` (flatMap), `match`.
|
||||
|
||||
### 매 응용
|
||||
1. Validation pipeline (parse → transform → save).
|
||||
2. Network call wrapping (fetch, DB query).
|
||||
3. Domain error modeling (NotFound, Unauthorized, Conflict).
|
||||
4. Recoverable failure (vs panic / unrecoverable).
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### TypeScript discriminated union
|
||||
```typescript
|
||||
type Result<T, E = Error> =
|
||||
| { ok: true; value: T }
|
||||
| { ok: false; error: E }
|
||||
|
||||
const ok = <T,>(value: T): Result<T, never> => ({ ok: true, value })
|
||||
const err = <E,>(error: E): Result<never, E> => ({ ok: false, error })
|
||||
|
||||
function parseAge(s: string): Result<number, 'NaN' | 'Negative'> {
|
||||
const n = Number(s)
|
||||
if (Number.isNaN(n)) return err('NaN')
|
||||
if (n < 0) return err('Negative')
|
||||
return ok(n)
|
||||
}
|
||||
|
||||
const r = parseAge('42')
|
||||
if (r.ok) console.log(r.value)
|
||||
else console.error(r.error)
|
||||
```
|
||||
|
||||
### neverthrow library
|
||||
```typescript
|
||||
import { Result, ok, err, ResultAsync } from 'neverthrow'
|
||||
|
||||
const fetchUser = (id: string): ResultAsync<User, 'NotFound' | 'Network'> =>
|
||||
ResultAsync.fromPromise(
|
||||
fetch(`/api/users/${id}`).then(r => r.ok ? r.json() : Promise.reject('NotFound')),
|
||||
(e): 'NotFound' | 'Network' => e === 'NotFound' ? 'NotFound' : 'Network',
|
||||
)
|
||||
|
||||
await fetchUser('u1')
|
||||
.map(u => u.email)
|
||||
.mapErr(e => `failed: ${e}`)
|
||||
.match(
|
||||
email => console.log(email),
|
||||
err => console.error(err),
|
||||
)
|
||||
```
|
||||
|
||||
### Effect TS (richer)
|
||||
```typescript
|
||||
import { Effect, pipe } from 'effect'
|
||||
|
||||
const parseJSON = (s: string) =>
|
||||
Effect.try({
|
||||
try: () => JSON.parse(s),
|
||||
catch: () => new Error('InvalidJSON'),
|
||||
})
|
||||
|
||||
const program = pipe(
|
||||
parseJSON('{"x":1}'),
|
||||
Effect.map((o: { x: number }) => o.x * 2),
|
||||
Effect.catchAll(e => Effect.succeed(0)),
|
||||
)
|
||||
Effect.runPromise(program).then(console.log) // 2
|
||||
```
|
||||
|
||||
### Rust (canonical)
|
||||
```rust
|
||||
fn divide(a: i32, b: i32) -> Result<i32, &'static str> {
|
||||
if b == 0 { Err("division by zero") } else { Ok(a / b) }
|
||||
}
|
||||
|
||||
fn pipeline() -> Result<i32, &'static str> {
|
||||
let x = divide(10, 2)?; // ? propagates Err
|
||||
let y = divide(x, 0)?;
|
||||
Ok(y)
|
||||
}
|
||||
```
|
||||
|
||||
### Validation accumulation (multiple errors)
|
||||
```typescript
|
||||
type Validated<T, E> = { ok: true; value: T } | { ok: false; errors: E[] }
|
||||
|
||||
const combine = <T, E>(rs: Result<T, E>[]): Validated<T[], E> => {
|
||||
const errs: E[] = []
|
||||
const vals: T[] = []
|
||||
for (const r of rs) r.ok ? vals.push(r.value) : errs.push(r.error)
|
||||
return errs.length ? { ok: false, errors: errs } : { ok: true, value: vals }
|
||||
}
|
||||
```
|
||||
|
||||
### Match helper
|
||||
```typescript
|
||||
function match<T, E, R>(r: Result<T, E>, on: { ok: (v: T) => R; err: (e: E) => R }): R {
|
||||
return r.ok ? on.ok(r.value) : on.err(r.error)
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Recoverable error, type-safety 중요 | Result type |
|
||||
| Truly unrecoverable (bug, OOM) | throw / panic |
|
||||
| Multiple errors 누적 | Validated / Either with NonEmptyArray |
|
||||
| Async + retry + interrupt | Effect TS |
|
||||
| Simple library, no dep | hand-rolled discriminated union |
|
||||
| Existing throw-based API | wrap with try/catch → Result |
|
||||
|
||||
**기본값**: 매 domain layer 는 Result, infrastructure boundary 에서 unwrap → throw 변환.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Error Handling]] · [[Discriminated_Unions|Discriminated Unions]]
|
||||
- 변형: [[Effect TS]]
|
||||
- 응용: [[Zod 런타임 유효성 검사 통합]] · [[API 응답 및 에러 핸들링 아키텍처]]
|
||||
- Adjacent: [[Type Theory]] · [[Functional Programming]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 explicit error path, validation pipeline, FP-style composition, "this can fail" type-level documentation.
|
||||
**언제 X**: 매 trivial script, throw 가 더 idiomatic 한 case (e.g. assertion, programmer error).
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **`unwrap()` 의 production**: 매 `Result` 의 의도 의 부정. 매 explicit `match` / `mapErr`.
|
||||
- **`Result<T, Error>` 의 generic**: 매 specific tagged union (`'NotFound' | 'Conflict'`) 가 useful.
|
||||
- **Mixed throw + Result**: layer 의 inconsistent → caller 의 confusing. 매 boundary 의 명확.
|
||||
- **Async 에 raw Promise<Result>**: rejection 도 발생 → 매 ResultAsync / Effect 가 안전.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Rust std::result docs, neverthrow README, Effect TS docs 3.x, "Domain Modeling Made Functional" Wlaschin).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — Result patterns (TS, neverthrow, Effect, Rust) |
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
|
||||
<!-- CODE-GROUNDING:START -->
|
||||
### 🔎 코드베이스 근거 (자동 추출 — E:\Wiki 레포)
|
||||
**실제 구현/사용 위치:**
|
||||
- `connectai/src/core/dataProcessor.ts:2` — * Aggregate result type definition
|
||||
|
||||
_자동 생성: code_grounding.mjs · 재실행 시 갱신됨_
|
||||
<!-- CODE-GROUNDING:END -->
|
||||
@@ -0,0 +1,125 @@
|
||||
---
|
||||
id: wiki-2026-0508-scheduler-api
|
||||
title: Scheduler API
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [scheduler.postTask, Prioritized Task Scheduling]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [web, performance, scheduling, browser-api]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: JavaScript
|
||||
framework: Web Platform
|
||||
---
|
||||
|
||||
# Scheduler API
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 priority-aware task scheduling for the main thread"**. Scheduler API (`scheduler.postTask`, `scheduler.yield`) 는 long task breakup + priority hint (user-blocking / user-visible / background) 로 INP/responsiveness 최적화. 2026 Chromium + Firefox stable.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 Priorities
|
||||
- `user-blocking`: 매 immediate UI response (input handler post-work).
|
||||
- `user-visible`: 매 default — visible 하지만 non-blocking.
|
||||
- `background`: 매 lazy work (analytics, prefetch).
|
||||
|
||||
### 매 vs setTimeout(0) / requestIdleCallback
|
||||
- 매 setTimeout(0): no priority, no abort.
|
||||
- 매 rIC: idle only, deadline-based.
|
||||
- 매 postTask: explicit priority + AbortSignal + delay.
|
||||
|
||||
### 매 응용
|
||||
1. 매 long list rendering 분할.
|
||||
2. 매 input handler 후 heavy work 양보.
|
||||
3. 매 background data prefetch.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### postTask 기본
|
||||
```js
|
||||
scheduler.postTask(() => doWork(), { priority: 'background' });
|
||||
```
|
||||
|
||||
### scheduler.yield (long task breakup)
|
||||
```js
|
||||
async function processItems(items) {
|
||||
for (const item of items) {
|
||||
process(item);
|
||||
if (navigator.scheduling?.isInputPending?.() || items.indexOf(item) % 50 === 0) {
|
||||
await scheduler.yield();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### TaskController로 abort
|
||||
```js
|
||||
const controller = new TaskController({ priority: 'user-visible' });
|
||||
scheduler.postTask(longJob, { signal: controller.signal });
|
||||
// 매 cancel
|
||||
controller.abort();
|
||||
// 매 priority 동적 변경
|
||||
controller.setPriority('background');
|
||||
```
|
||||
|
||||
### Delay
|
||||
```js
|
||||
scheduler.postTask(refresh, { priority: 'background', delay: 5000 });
|
||||
```
|
||||
|
||||
### Polyfill fallback
|
||||
```js
|
||||
const yield_ = () =>
|
||||
globalThis.scheduler?.yield?.() ??
|
||||
new Promise(r => setTimeout(r, 0));
|
||||
```
|
||||
|
||||
### React + Scheduler API
|
||||
```js
|
||||
// React 19+ 의 useTransition + scheduler integration
|
||||
startTransition(() => {
|
||||
scheduler.postTask(() => setState(heavy), { priority: 'background' });
|
||||
});
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Heavy work after input | `scheduler.yield()` mid-loop |
|
||||
| Lazy prefetch | `postTask({priority:'background'})` |
|
||||
| Cancel-able task | `TaskController` |
|
||||
| Idle-only callback | `requestIdleCallback` |
|
||||
| 매 simple deferral | `queueMicrotask` |
|
||||
|
||||
**기본값**: 매 long loops 의 `scheduler.yield()` + 매 background work `postTask({priority:'background'})`.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Core Web Vitals Optimization (INP, LCP, CLS)|Core_Web_Vitals]]
|
||||
- 응용: [[INP_Optimization]]
|
||||
- Adjacent: [[AbortController]] · [[React_useTransition]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 INP regression 발견 + 매 long task (>50ms) breakup 필요 시. 매 prioritized background work.
|
||||
**언제 X**: 매 worker offload 가 더 적합한 CPU-heavy work, 또는 매 framework scheduler (React) 가 이미 처리.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **postTask 안 yield**: 매 single long callback 은 여전히 long task. 매 internally yield 필요.
|
||||
- **user-blocking 남용**: 매 priority inversion 의. 매 진짜 input-critical 만.
|
||||
- **Polyfill 없는 production deploy**: 매 Safari 일부 버전 미지원.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (W3C Prioritized Task Scheduling, web.dev/optimize-inp).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — postTask + yield patterns |
|
||||
@@ -0,0 +1,180 @@
|
||||
---
|
||||
id: wiki-2026-0508-server-architecture
|
||||
title: Server Architecture
|
||||
category: 10_Wiki/Topics
|
||||
aliases: [서버 아키텍처, Backend Architecture]
|
||||
status: verified
|
||||
canonical_id: self
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [architecture, backend, distributed-systems, scalability]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: polyglot
|
||||
framework: cloud-native
|
||||
---
|
||||
|
||||
# Server Architecture
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 architecture 는 trade-off 의 명시화"**. Monolith → Modular monolith → Service-oriented → Microservices → Cells/Serverless 의 spectrum 에서 팀 규모, 도메인 복잡도, scale 요구에 맞춰 선택. 2026 현재 majority 는 modular monolith + targeted services.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 layer
|
||||
- **Edge**: CDN (Cloudflare, Fastly), DDoS, TLS termination.
|
||||
- **Gateway**: API gateway, authn, rate limit (Kong, Envoy, AWS API GW).
|
||||
- **Application**: stateless service tier (horizontal scale).
|
||||
- **Data**: OLTP DB, cache, search, object store, queue.
|
||||
- **Async**: message broker (Kafka, NATS, SQS), workers.
|
||||
- **Observability**: traces (OTel), metrics (Prom), logs.
|
||||
|
||||
### 매 archetype
|
||||
- **Monolith**: 단일 deploy unit — 작은 팀, 빠른 iteration.
|
||||
- **Modular monolith**: bounded context 명확, 단일 배포 — 2026 default.
|
||||
- **Microservices**: 팀당 service, 독립 배포 — Conway's law 정렬 시.
|
||||
- **Cells**: bulkhead 별 독립 stack — high-availability.
|
||||
- **Serverless**: Lambda/CF Workers — bursty, low-traffic OK.
|
||||
|
||||
### 매 응용
|
||||
1. SaaS multi-tenant.
|
||||
2. E-commerce platform.
|
||||
3. Real-time messaging.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### 1. Stateless service + sticky data
|
||||
```yaml
|
||||
# k8s deployment
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
spec:
|
||||
replicas: 6
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: api
|
||||
image: app:v1.42
|
||||
readinessProbe:
|
||||
httpGet: { path: /ready, port: 8080 }
|
||||
resources:
|
||||
requests: { cpu: 250m, memory: 512Mi }
|
||||
limits: { cpu: 1, memory: 1Gi }
|
||||
```
|
||||
|
||||
### 2. CQRS read replica fan-out
|
||||
```typescript
|
||||
class OrderService {
|
||||
constructor(private writeDb: Pool, private readDb: Pool) {}
|
||||
|
||||
async create(o: Order) {
|
||||
return this.writeDb.tx(async (tx) => {
|
||||
await tx.insert("orders", o);
|
||||
await tx.publish("order.created", o);
|
||||
});
|
||||
}
|
||||
|
||||
async query(userId: string) {
|
||||
return this.readDb.query("SELECT * FROM orders_view WHERE user_id=$1", [userId]);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Circuit breaker
|
||||
```typescript
|
||||
import CircuitBreaker from "opossum";
|
||||
|
||||
const breaker = new CircuitBreaker(callPaymentApi, {
|
||||
timeout: 3000,
|
||||
errorThresholdPercentage: 50,
|
||||
resetTimeout: 30_000,
|
||||
});
|
||||
breaker.fallback(() => ({ status: "queued" }));
|
||||
```
|
||||
|
||||
### 4. Outbox pattern
|
||||
```sql
|
||||
BEGIN;
|
||||
INSERT INTO orders (...) VALUES (...);
|
||||
INSERT INTO outbox (topic, payload) VALUES ('order.created', $1);
|
||||
COMMIT;
|
||||
-- separate poller publishes outbox → kafka, then deletes
|
||||
```
|
||||
|
||||
### 5. Backpressure with bounded queue
|
||||
```go
|
||||
sem := make(chan struct{}, 100) // max 100 in-flight
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
select {
|
||||
case sem <- struct{}{}:
|
||||
defer func() { <-sem }()
|
||||
handle(w, r)
|
||||
default:
|
||||
http.Error(w, "busy", 503)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### 6. Cell-based isolation
|
||||
```
|
||||
Customer A → Cell-1 (LB, app, DB shard)
|
||||
Customer B → Cell-2 (LB, app, DB shard)
|
||||
Customer C → Cell-1
|
||||
# Cell failure blast radius = 1 cell only
|
||||
```
|
||||
|
||||
### 7. SLO-based deploy gate
|
||||
```yaml
|
||||
# Argo Rollouts
|
||||
strategy:
|
||||
canary:
|
||||
steps:
|
||||
- setWeight: 10
|
||||
- analysis:
|
||||
templates: [{ templateName: error-rate-slo }]
|
||||
- setWeight: 50
|
||||
- pause: { duration: 10m }
|
||||
- setWeight: 100
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 팀 < 20명, 단일 도메인 | Modular monolith |
|
||||
| 팀 > 50명, 다 도메인 | Microservices (bounded context별) |
|
||||
| Bursty traffic, 0 → 1000 RPS | Serverless |
|
||||
| Multi-tenant, blast radius 우려 | Cells |
|
||||
| Strong consistency 핵심 | Single-writer + read replicas |
|
||||
| Eventual OK, throughput 핵심 | Event-driven + CQRS |
|
||||
|
||||
**기본값**: modular monolith + Postgres + Redis + 1-2 async workers. 명확히 필요할 때 split.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Distributed Systems]] · [[Cloud Native]]
|
||||
- 변형: [[Microservices]] · [[Serverless]] · [[Event-Driven Architecture]]
|
||||
- Adjacent: [[Kubernetes]] · [[Service Mesh]] · [[Observability]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 신규 시스템 설계, scale 병목 분석, monolith → service split 시점 판단.
|
||||
**언제 X**: 작은 internal tool (overengineering 위험), prototype (속도 우선).
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Distributed monolith**: 서비스 분리 + 동기 호출 chain — latency, 장애 전파.
|
||||
- **Premature microservices**: 팀 < 10명에 서비스 20개 — ops 폭발.
|
||||
- **Shared DB across services**: coupling, schema migration 지옥.
|
||||
- **No observability**: 분산 시 trace 없으면 디버깅 불가.
|
||||
- **Synchronous everything**: queue/event 활용 안 하면 cascading failure.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (AWS Well-Architected, Google SRE book, Sam Newman "Building Microservices").
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — server architecture archetypes & patterns (2026 cloud-native) |
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
---
|
||||
id: wiki-2026-0508-sharedarraybuffer로-스레드-간-메모리-공유-
|
||||
title: SharedArrayBuffer로 스레드 간 메모리 공유 효율 높이기
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [SAB, SharedArrayBuffer, Shared Memory JS]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [javascript, web-worker, concurrency, performance]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: JavaScript
|
||||
framework: Web Workers
|
||||
---
|
||||
|
||||
# SharedArrayBuffer로 스레드 간 메모리 공유 효율 높이기
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 zero-copy shared memory between JS threads"**. SharedArrayBuffer (SAB) 는 main thread + Web Worker 간 동일 raw bytes 를 공유. postMessage structured clone 의 copy 비용 제거 + Atomics 로 race-free coordination 가능.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 동작 모델
|
||||
- 매 buffer instance 는 multiple threads 에서 동일 backing store 참조.
|
||||
- 매 TypedArray view (Int32Array, Float64Array) 로 typed access.
|
||||
- 매 Atomics.load/store/add 로 atomic ops.
|
||||
- 매 Atomics.wait/notify 로 futex-like blocking sync.
|
||||
|
||||
### 매 vs ArrayBuffer
|
||||
- 매 ArrayBuffer: postMessage 시 structured clone (copy) 또는 transfer (ownership move).
|
||||
- 매 SharedArrayBuffer: postMessage 시 reference 전달, 양쪽 동시 access.
|
||||
|
||||
### 매 응용
|
||||
1. WASM linear memory 공유 (multi-threaded WASM).
|
||||
2. 매 large image/audio buffer worker 처리 (zero-copy).
|
||||
3. Lock-free queue / ring buffer 구현.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Worker 에 SAB 전달
|
||||
```js
|
||||
// main.js
|
||||
const sab = new SharedArrayBuffer(1024);
|
||||
const view = new Int32Array(sab);
|
||||
const worker = new Worker('worker.js');
|
||||
worker.postMessage({ sab });
|
||||
|
||||
// worker.js
|
||||
self.onmessage = ({ data }) => {
|
||||
const view = new Int32Array(data.sab);
|
||||
Atomics.store(view, 0, 42);
|
||||
Atomics.notify(view, 0, 1);
|
||||
};
|
||||
```
|
||||
|
||||
### Atomic counter
|
||||
```js
|
||||
const sab = new SharedArrayBuffer(4);
|
||||
const counter = new Int32Array(sab);
|
||||
Atomics.add(counter, 0, 1); // race-free increment
|
||||
const value = Atomics.load(counter, 0);
|
||||
```
|
||||
|
||||
### Producer / Consumer wait+notify
|
||||
```js
|
||||
// consumer
|
||||
Atomics.wait(view, 0, 0); // sleep until view[0] != 0
|
||||
const data = Atomics.load(view, 0);
|
||||
|
||||
// producer
|
||||
Atomics.store(view, 0, 99);
|
||||
Atomics.notify(view, 0, 1); // wake 1 waiter
|
||||
```
|
||||
|
||||
### Lock (spinlock)
|
||||
```js
|
||||
function lock(view, idx) {
|
||||
while (Atomics.compareExchange(view, idx, 0, 1) !== 0) {
|
||||
Atomics.wait(view, idx, 1);
|
||||
}
|
||||
}
|
||||
function unlock(view, idx) {
|
||||
Atomics.store(view, idx, 0);
|
||||
Atomics.notify(view, idx, 1);
|
||||
}
|
||||
```
|
||||
|
||||
### Ring buffer (lock-free SPSC)
|
||||
```js
|
||||
class RingBuffer {
|
||||
constructor(sab, capacity) {
|
||||
this.head = new Int32Array(sab, 0, 1);
|
||||
this.tail = new Int32Array(sab, 4, 1);
|
||||
this.data = new Int32Array(sab, 8, capacity);
|
||||
this.cap = capacity;
|
||||
}
|
||||
push(v) {
|
||||
const t = Atomics.load(this.tail, 0);
|
||||
const next = (t + 1) % this.cap;
|
||||
if (next === Atomics.load(this.head, 0)) return false; // full
|
||||
this.data[t] = v;
|
||||
Atomics.store(this.tail, 0, next);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### WASM threads memory
|
||||
```js
|
||||
const memory = new WebAssembly.Memory({ initial: 10, maximum: 100, shared: true });
|
||||
// memory.buffer is SharedArrayBuffer
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Small data, infrequent | postMessage (clone) |
|
||||
| Large buffer, hot path | SAB + Atomics |
|
||||
| Transfer ownership once | postMessage with transfer list |
|
||||
| Multi-threaded WASM | shared:true Memory |
|
||||
|
||||
**기본값**: 매 small data postMessage, 매 hot-path large buffer SAB.
|
||||
|
||||
## 🔗 Graph
|
||||
- 변형: [[SharedArrayBuffer_보안_이슈와_Cross-Origin_Isolation]]
|
||||
- 응용: [[OffscreenCanvas]]
|
||||
- Adjacent: [[Structured_Clone]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 large data parallel processing (image/video/ML inference) 의 + 매 worker 간 frequent sync 필요 시.
|
||||
**언제 X**: 매 simple task offload (postMessage 충분) 또는 매 COOP/COEP 헤더 설정 불가능한 환경.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Non-atomic access on shared view**: 매 race condition. 매 always Atomics.* 사용.
|
||||
- **Spin without wait**: 매 CPU burn. 매 Atomics.wait 으로 block.
|
||||
- **Missing COOP/COEP**: 매 modern browser 에서 SAB 비활성화. 매 cross-origin isolation 필수.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (MDN SharedArrayBuffer, ECMAScript Atomics spec).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — SAB + Atomics patterns |
|
||||
@@ -0,0 +1,151 @@
|
||||
---
|
||||
id: wiki-2026-0508-structural-typing
|
||||
title: Structural Typing
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [duck typing, shape typing, structural type system]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.93
|
||||
verification_status: applied
|
||||
tags: [typescript, type-system, fundamentals]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: TypeScript
|
||||
framework: tsc
|
||||
---
|
||||
|
||||
# Structural Typing
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 type 의 compatibility 의 name 이 아닌 shape 으로 결정"**. TypeScript / Go 의 핵심 — 매 nominal typing (Java / C#) 의 반대. 매 2026 TS 5.7 의 동일 원칙 — 매 modern web 의 fundamental.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 Nominal vs Structural
|
||||
- **Nominal** (Java/C#): 매 declared name 의 일치 — 매 같은 shape 라도 다른 type 시 incompatible.
|
||||
- **Structural** (TS/Go): 매 properties / methods 의 shape 의 match 의 compatible — 매 declaration site 의 무관.
|
||||
|
||||
### 매 동작 원리
|
||||
- 매 assignability check: 매 source type 의 모든 required member 의 target type 의 존재 의 확인.
|
||||
- 매 method signature: 매 parameter 의 contravariant, return 의 covariant.
|
||||
- 매 excess property checking: 매 object literal 의 special case — 매 추가 property 의 error.
|
||||
|
||||
### 매 응용
|
||||
1. 매 function parameter 의 minimal interface 의 require — 매 flexibility.
|
||||
2. 매 mock / stub 의 작성 의 자연스러움 — 매 test 의 친화.
|
||||
3. 매 ad-hoc type 의 inline definition.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### 매 Structural 의 기본
|
||||
```typescript
|
||||
interface Point { x: number; y: number; }
|
||||
class Vector { constructor(public x: number, public y: number) {} }
|
||||
|
||||
function dist(p: Point): number {
|
||||
return Math.sqrt(p.x ** 2 + p.y ** 2);
|
||||
}
|
||||
|
||||
dist(new Vector(3, 4)); // OK — 매 Vector 의 Point shape 의 satisfy
|
||||
dist({ x: 3, y: 4 }); // OK — 매 object literal 의 동일
|
||||
```
|
||||
|
||||
### 매 Branded type 의 nominal 의 흉내
|
||||
```typescript
|
||||
// 매 structural 의 약점 — 매 같은 shape 의 다른 의미 의 mix
|
||||
type UserId = string & { __brand: 'UserId' };
|
||||
type OrderId = string & { __brand: 'OrderId' };
|
||||
|
||||
function getUser(id: UserId) { /* ... */ }
|
||||
const oid = 'order-1' as OrderId;
|
||||
// getUser(oid); // 매 ERROR — 매 brand 의 mismatch
|
||||
```
|
||||
|
||||
### 매 Function 의 contravariance
|
||||
```typescript
|
||||
type Logger = (msg: string) => void;
|
||||
const wide: (msg: string | number) => void = (m) => console.log(m);
|
||||
|
||||
const log: Logger = wide; // OK — 매 parameter 의 contravariant
|
||||
// 매 wide 의 string 도 number 도 받으므로 string-only 의 substitute 가능
|
||||
```
|
||||
|
||||
### 매 Excess property checking 의 우회
|
||||
```typescript
|
||||
interface Config { url: string; }
|
||||
|
||||
// declareConfig({ url: '/api', timeout: 5000 }); // ERROR — 매 excess
|
||||
const cfg = { url: '/api', timeout: 5000 };
|
||||
declareConfig(cfg); // OK — 매 variable 의 우회 (매 fresh literal 만 check)
|
||||
|
||||
function declareConfig(c: Config) { /* ... */ }
|
||||
```
|
||||
|
||||
### 매 Subtyping 의 자동
|
||||
```typescript
|
||||
interface Animal { name: string; }
|
||||
interface Dog { name: string; bark(): void; }
|
||||
|
||||
const dogs: Dog[] = [{ name: 'Rex', bark: () => {} }];
|
||||
const animals: Animal[] = dogs; // OK — 매 Dog 의 superset 의 자동 subtype
|
||||
```
|
||||
|
||||
### 매 Class 의 structural 의 trap
|
||||
```typescript
|
||||
class Cat { meow() {} }
|
||||
class Lion { meow() {} }
|
||||
|
||||
const c: Cat = new Lion(); // OK?? — 매 동일 shape 의 compatible
|
||||
// 매 nominal 기대 시 private field 의 brand 의 사용
|
||||
class CatN { #species = 'cat'; meow() {} }
|
||||
class LionN { #species = 'lion'; meow() {} }
|
||||
// 매 #private 의 nominal effect — 매 cross-class 의 incompatible
|
||||
```
|
||||
|
||||
### 매 Generic 의 structural 의 활용
|
||||
```typescript
|
||||
function pluck<T, K extends keyof T>(arr: T[], key: K): T[K][] {
|
||||
return arr.map(x => x[key]);
|
||||
}
|
||||
// 매 T 의 shape 의 자유 — 매 keyof T 의 structural inference
|
||||
const names = pluck([{ name: 'a' }, { name: 'b' }], 'name');
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 일반 type | structural (default) — 매 TS 의 native |
|
||||
| Domain ID 의 mix 방지 | branded type |
|
||||
| Strict nominal 필요 | private field / unique symbol brand |
|
||||
| External library compat | structural — 매 자연스러운 fit |
|
||||
|
||||
**기본값**: structural typing 의 활용. 매 ID confusion 의 risk 시 branded type 의 추가.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[TypeScript]] · [[TypeScript 타입 시스템 (TypeScript Type System)|Type System]]
|
||||
- 변형: [[Nominal-Typing-in-TypeScript|Nominal Typing]] · [[Duck Typing]]
|
||||
- 응용: [[Excess_Property_Checking|Excess Property Checking]] · [[ts-brand]]
|
||||
- Adjacent: [[Discriminated_Unions|Discriminated Unions]] · [[Type Casting]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: TS type error 의 explain, branded type 의 권장, structural vs nominal 의 비교.
|
||||
**언제 X**: Java/C# 같은 nominal 언어 의 답변 의 mix — 매 언어 의 명시.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **ID confusion**: 매 UserId / OrderId 의 같은 string — 매 brand 의 추가.
|
||||
- **Class identity 의 의존**: 매 instanceof 없이 type 만 의 distinguish — 매 trap.
|
||||
- **Excess 의 silence**: 매 변수 거쳐 우회 후 typo 의 미발견.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (TypeScript Handbook, "Type Compatibility").
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — Structural typing FULL 작성 |
|
||||
@@ -0,0 +1,158 @@
|
||||
---
|
||||
id: wiki-2026-0508-teamcity
|
||||
title: TeamCity
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [JetBrains TeamCity, TC]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [ci-cd, jetbrains, build, devops]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: Kotlin DSL
|
||||
framework: TeamCity 2025.x
|
||||
---
|
||||
|
||||
# TeamCity
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 enterprise CI server with first-class build chains + Kotlin DSL config"**. JetBrains TeamCity 는 build configuration 의 strong dependency graph + snapshot/artifact dep + 매 versioned settings (Kotlin DSL) 를 제공하는 self-hosted CI. 2026 의 TeamCity 2025.x 는 cloud agents + GitHub Actions 호환성 + native AI test analytics.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 핵심 개념
|
||||
- **Project / Build Configuration / Build**: 3-tier hierarchy.
|
||||
- **Snapshot dependency**: 매 동일 VCS revision 보장된 build chain.
|
||||
- **Artifact dependency**: 매 upstream artifact pull.
|
||||
- **Build chain**: composite build (status rollup).
|
||||
- **Versioned settings**: 매 Kotlin DSL `.teamcity/settings.kts` git 관리.
|
||||
|
||||
### 매 vs Jenkins / GitHub Actions
|
||||
- 매 Jenkins: plugin sprawl, 매 declarative 선택적.
|
||||
- 매 GitHub Actions: SaaS-first, 매 enterprise 의 self-host 약함.
|
||||
- 매 TeamCity: 매 enterprise self-host + Kotlin DSL + 매 strong test history.
|
||||
|
||||
### 매 응용
|
||||
1. JVM monorepo (Gradle/Maven) build chain.
|
||||
2. .NET / Kotlin Multiplatform CI.
|
||||
3. Hybrid cloud agents (AWS/GCP/K8s) + on-prem.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Kotlin DSL 의 build config
|
||||
```kotlin
|
||||
import jetbrains.buildServer.configs.kotlin.*
|
||||
import jetbrains.buildServer.configs.kotlin.buildSteps.gradle
|
||||
|
||||
object Build : BuildType({
|
||||
name = "Build & Test"
|
||||
vcs { root(DslContext.settingsRoot) }
|
||||
steps {
|
||||
gradle {
|
||||
tasks = "clean build"
|
||||
useGradleWrapper = true
|
||||
}
|
||||
}
|
||||
triggers { vcs {} }
|
||||
features {
|
||||
perfmon {}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Build chain (snapshot dep)
|
||||
```kotlin
|
||||
object Deploy : BuildType({
|
||||
name = "Deploy"
|
||||
dependencies {
|
||||
snapshot(Build) { onDependencyFailure = FailureAction.FAIL_TO_START }
|
||||
artifacts(Build) { artifactRules = "build/libs/*.jar => libs" }
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Parameter + secret
|
||||
```kotlin
|
||||
params {
|
||||
param("env.NODE_ENV", "production")
|
||||
password("env.NPM_TOKEN", "credentialsJSON:...")
|
||||
}
|
||||
```
|
||||
|
||||
### Agent requirements
|
||||
```kotlin
|
||||
requirements {
|
||||
contains("teamcity.agent.jvm.os.name", "Linux")
|
||||
exists("env.DOCKER_HOST")
|
||||
}
|
||||
```
|
||||
|
||||
### Matrix-style (composite build)
|
||||
```kotlin
|
||||
object Matrix : BuildType({ name = "All Platforms"; type = Type.COMPOSITE
|
||||
dependencies {
|
||||
snapshot(BuildLinux) {}
|
||||
snapshot(BuildMac) {}
|
||||
snapshot(BuildWin) {}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### REST API trigger
|
||||
```bash
|
||||
curl -u user:token -X POST \
|
||||
-H "Content-Type: application/xml" \
|
||||
-d '<build><buildType id="Build"/></build>' \
|
||||
https://tc.example.com/app/rest/buildQueue
|
||||
```
|
||||
|
||||
### Cloud agent profile (Kubernetes)
|
||||
```kotlin
|
||||
features {
|
||||
feature {
|
||||
type = "CloudImage"
|
||||
param("cloud-code", "kubernetes")
|
||||
param("image-name", "myorg/tc-agent:2025")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | CI choice |
|
||||
|---|---|
|
||||
| 매 JVM enterprise self-host | TeamCity |
|
||||
| 매 GitHub-centric OSS | GitHub Actions |
|
||||
| 매 plugin-heavy legacy | Jenkins |
|
||||
| 매 GitLab-native | GitLab CI |
|
||||
| 매 monorepo with cache focus | Buildkite / Bazel CI |
|
||||
|
||||
**기본값**: 매 enterprise JVM/.NET 의 TeamCity, 매 OSS GitHub repo 의 Actions.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[CI_CD_Pipeline|CI_CD]]
|
||||
- 변형: [[GitHub_Actions]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 enterprise CI 설계, 매 build chain 의존성 모델링, 매 Kotlin DSL 마이그레이션.
|
||||
**언제 X**: 매 single-repo OSS — 매 GitHub Actions 가 zero-ops.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **UI-only config (no DSL)**: 매 settings drift, 매 review 불가능.
|
||||
- **Snapshot dep 없이 chain**: 매 inconsistent revision.
|
||||
- **Agent 의 secret 평문 저장**: 매 Token credentials 사용 필수.
|
||||
- **Build history retention 무한**: 매 server 디스크 폭발.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (JetBrains TeamCity 2025 docs, Kotlin DSL guide).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — TeamCity 2025 + Kotlin DSL |
|
||||
@@ -0,0 +1,162 @@
|
||||
---
|
||||
id: wiki-2026-0508-type-theory
|
||||
title: Type Theory
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Type System Theory, Lambda Calculus Types, Curry-Howard]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [type-theory, lambda-calculus, formal-methods, curry-howard, dependent-types]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: Haskell / Idris / Lean / Coq
|
||||
framework: theoretical
|
||||
---
|
||||
|
||||
# Type Theory
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 타입은 명제, 매 프로그램은 증명 — Curry-Howard correspondence"**. Type theory 는 1902 Russell paradox 회피용 simple type theory 부터, 1934 Church 의 simply typed lambda calculus, 1972 Martin-Löf dependent type theory, 2026 Lean 4 / Idris 2 / Rocq (formerly Coq) 의 매 mathematical proof + program verification 의 통일 framework. 매 modern type system (Haskell, Rust, TypeScript) 의 매 핵심 개념 (parametric polymorphism, GADTs, refinement types) 의 출처.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 type theory 의 계층
|
||||
- **Simply Typed Lambda Calculus (STLC)**: `τ ::= ι | τ → τ` — function types only.
|
||||
- **System F (parametric polymorphism)**: `∀α. τ` — generics 의 이론적 기반.
|
||||
- **System Fω (type operators)**: `* → *` kinds — Haskell 의 type-level computation.
|
||||
- **Calculus of Constructions (CoC)**: dependent types — Coq, Lean.
|
||||
- **Homotopy Type Theory (HoTT)**: types as spaces, equality as paths.
|
||||
|
||||
### 매 Curry-Howard correspondence
|
||||
- 매 propositions ⟺ types.
|
||||
- 매 proofs ⟺ programs.
|
||||
- 매 implication `A → B` ⟺ function `A → B`.
|
||||
- 매 conjunction `A ∧ B` ⟺ pair `(A, B)`.
|
||||
- 매 disjunction `A ∨ B` ⟺ sum `Either A B`.
|
||||
- 매 universal `∀x. P(x)` ⟺ dependent function `(x: A) → P(x)`.
|
||||
|
||||
### 매 응용
|
||||
1. Theorem proving — Lean 4 (mathlib), Coq/Rocq (CompCert verified C compiler).
|
||||
2. Verified software — seL4 microkernel (Isabelle/HOL).
|
||||
3. Practical type systems — Haskell GADT, Rust lifetime, TypeScript conditional types.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Haskell: parametric polymorphism (System F)
|
||||
```haskell
|
||||
-- 매 ∀α. [α] → Int
|
||||
length :: forall a. [a] -> Int
|
||||
length [] = 0
|
||||
length (_:xs) = 1 + length xs
|
||||
```
|
||||
|
||||
### Haskell: GADT (refined return types)
|
||||
```haskell
|
||||
{-# LANGUAGE GADTs #-}
|
||||
data Expr a where
|
||||
IntLit :: Int -> Expr Int
|
||||
BoolLit :: Bool -> Expr Bool
|
||||
If :: Expr Bool -> Expr a -> Expr a -> Expr a
|
||||
|
||||
eval :: Expr a -> a
|
||||
eval (IntLit n) = n
|
||||
eval (BoolLit b) = b
|
||||
eval (If c t e) = if eval c then eval t else eval e
|
||||
```
|
||||
|
||||
### Idris: dependent type (vector with length)
|
||||
```idris
|
||||
data Vect : Nat -> Type -> Type where
|
||||
Nil : Vect Z a
|
||||
(::) : a -> Vect n a -> Vect (S n) a
|
||||
|
||||
-- 매 length encoded in type — no runtime check needed
|
||||
append : Vect n a -> Vect m a -> Vect (n + m) a
|
||||
append Nil ys = ys
|
||||
append (x :: xs) ys = x :: append xs ys
|
||||
```
|
||||
|
||||
### Lean 4: theorem as type
|
||||
```lean
|
||||
-- 매 proposition: ∀ n : ℕ, n + 0 = n
|
||||
theorem add_zero (n : Nat) : n + 0 = n := by
|
||||
induction n with
|
||||
| zero => rfl
|
||||
| succ k ih => rw [Nat.succ_add, ih]
|
||||
```
|
||||
|
||||
### TypeScript: conditional types (System Fω-ish)
|
||||
```typescript
|
||||
type IsArray<T> = T extends Array<any> ? true : false;
|
||||
type A = IsArray<number[]>; // true
|
||||
type B = IsArray<string>; // false
|
||||
|
||||
// 매 distributive
|
||||
type ToArray<T> = T extends any ? T[] : never;
|
||||
type C = ToArray<string | number>; // string[] | number[]
|
||||
```
|
||||
|
||||
### Rust: phantom type for state encoding
|
||||
```rust
|
||||
use std::marker::PhantomData;
|
||||
struct Connection<State> { _state: PhantomData<State> }
|
||||
struct Open; struct Closed;
|
||||
|
||||
impl Connection<Closed> {
|
||||
fn open(self) -> Connection<Open> { Connection { _state: PhantomData } }
|
||||
}
|
||||
impl Connection<Open> {
|
||||
fn send(&self, data: &[u8]) {}
|
||||
fn close(self) -> Connection<Closed> { Connection { _state: PhantomData } }
|
||||
}
|
||||
// 매 .send() on Closed 는 compile error
|
||||
```
|
||||
|
||||
### Haskell: refinement via Liquid Haskell
|
||||
```haskell
|
||||
{-@ type Pos = {v:Int | v > 0} @-}
|
||||
{-@ divPos :: Int -> Pos -> Int @-}
|
||||
divPos x y = x `div` y -- 매 SMT solver 가 y > 0 검증
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Mathematical proof | Lean 4 / Rocq (Coq) |
|
||||
| Verified compiler / OS | Coq (CompCert) / Isabelle (seL4) |
|
||||
| Industrial typed FP | Haskell + GADT + TypeFamilies |
|
||||
| Practical dependent types | Idris 2 |
|
||||
| TypeScript-level type-level | conditional + mapped + template literal |
|
||||
| Compile-time state machine | Rust phantom types / typestate |
|
||||
|
||||
**기본값**: 매 application 은 Haskell/Rust/TS 의 expressive type system; 매 critical proof 는 Lean 4.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[TypeScript 타입 시스템 (TypeScript Type System)|Type System]] · [[Formal Methods]]
|
||||
- 응용: [[Coq]]
|
||||
- Adjacent: [[Curry-Howard]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 type system design 이해, advanced FP, formal verification, TS type-level wizardry.
|
||||
**언제 X**: 매 일반 application 작성 — overkill.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Type-level "abuse" in TS**: 매 IDE 가 5분 freeze — 단순 runtime check 가 나음.
|
||||
- **Dependent type 없는 곳 흉내**: 매 Haskell phantom type 으로 vector length 흉내 — 진짜 검증 안됨, runtime panic 가능.
|
||||
- **Curry-Howard 의 직접 응용 실수**: 매 Hindley-Milner type inference 는 type-level recursion 에 약함 — 매 explicit annotation 필요.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Pierce "Types and Programming Languages", Martin-Löf "Intuitionistic Type Theory", HoTT Book).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — type theory full content (Curry-Howard, GADT, dependent, Lean) |
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
---
|
||||
id: wiki-2026-0508-typescript-타입-시스템-및-인터페이스-설계
|
||||
title: TypeScript 타입 시스템 및 인터페이스 설계
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: typescript-types
|
||||
duplicate_of: "[[TypeScript Type System]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, typescript, interface]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# TypeScript 타입 시스템 및 인터페이스 설계
|
||||
|
||||
> **이 문서는 [[TypeScript Type System]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 핵심 요약 (specialization aspects)
|
||||
- 매 interface 설계 측면 — `interface` vs `type alias`, declaration merging, `extends` chain.
|
||||
- 매 structural typing 의 핵심: shape match.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[TypeScript Type System]] (canonical)
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
---
|
||||
id: wiki-2026-0508-typescript의-제어-흐름-분석-및-상태-관리-패턴
|
||||
title: TypeScript의 제어 흐름 분석 및 상태 관리 패턴
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: typescript-types
|
||||
duplicate_of: "[[TypeScript Type System]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, typescript, narrowing, discriminated-union]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# TypeScript의 제어 흐름 분석 및 상태 관리 패턴
|
||||
|
||||
> **이 문서는 [[TypeScript Type System]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 핵심 요약 (specialization aspects)
|
||||
- 매 control flow analysis 측면 — type narrowing (`typeof`, `instanceof`, `in`, custom type guards).
|
||||
- 매 discriminated union 의 state machine pattern: `type State = { kind: 'idle' } | { kind: 'loading' } | { kind: 'error', err: Error }`.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[TypeScript Type System]] (canonical)
|
||||
- 변형: [[Discriminated Union]] · [[Type Guard]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
@@ -0,0 +1,200 @@
|
||||
---
|
||||
id: wiki-2026-0508-union-types
|
||||
title: Union Types
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Sum Types, Tagged Union, Discriminated Union, Variant]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [type-system, union, sum-type, discriminated-union, typescript, rust]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: TypeScript / Rust / Haskell
|
||||
framework: language-agnostic
|
||||
---
|
||||
|
||||
# Union Types
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 값이 A 또는 B (또는 C, ...) 의 하나 — 매 sum type 의 set-theoretic 표현"**. Union types 은 1970s ML 의 datatype, 1980s C union (untagged) 부터, 2026 TypeScript discriminated union, Rust enum, Haskell ADT, Python `X | Y` (PEP 604) 까지 매 type-safe variant modeling 의 표준. 매 product type (struct/tuple) 의 dual: AND 가 product, OR 가 sum.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 두 종류
|
||||
- **Untagged union (C-style)**: 매 같은 메모리 영역, runtime 에 active variant 알 수 없음 — unsafe.
|
||||
- **Tagged / discriminated union**: 매 tag field 로 variant 구분 — type-safe (Rust `enum`, TS discriminated, Haskell ADT).
|
||||
|
||||
### 매 set theory 관점
|
||||
- 매 `A | B` ≅ A ∪ B (set union, 중복 제거).
|
||||
- 매 `{a:1} | {b:2}` ≅ `{a:1, b?:undefined} ∪ {a?:undefined, b:2}` (TS structural).
|
||||
- 매 cardinality: `|A | B| = |A| + |B|` (disjoint).
|
||||
|
||||
### 매 응용
|
||||
1. API response — `Success<T> | Error` (Result type).
|
||||
2. State machine — `Idle | Loading | Success | Error`.
|
||||
3. Parser AST — `BinOp | UnaryOp | Literal | Variable`.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### TypeScript: discriminated union
|
||||
```typescript
|
||||
type Shape =
|
||||
| { kind: "circle"; radius: number }
|
||||
| { kind: "square"; side: number }
|
||||
| { kind: "rect"; width: number; height: number };
|
||||
|
||||
function area(s: Shape): number {
|
||||
switch (s.kind) {
|
||||
case "circle": return Math.PI * s.radius ** 2;
|
||||
case "square": return s.side ** 2;
|
||||
case "rect": return s.width * s.height;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### TypeScript: exhaustiveness check
|
||||
```typescript
|
||||
function area(s: Shape): number {
|
||||
switch (s.kind) {
|
||||
case "circle": return Math.PI * s.radius ** 2;
|
||||
case "square": return s.side ** 2;
|
||||
case "rect": return s.width * s.height;
|
||||
default: {
|
||||
const _exhaustive: never = s; // 매 새 variant 추가 시 compile error
|
||||
throw new Error(`unhandled: ${_exhaustive}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### TypeScript: Result type
|
||||
```typescript
|
||||
type Result<T, E = Error> =
|
||||
| { ok: true; value: T }
|
||||
| { ok: false; error: E };
|
||||
|
||||
async function fetchUser(id: string): Promise<Result<User>> {
|
||||
try { return { ok: true, value: await api.get(id) }; }
|
||||
catch (e) { return { ok: false, error: e as Error }; }
|
||||
}
|
||||
|
||||
const r = await fetchUser("1");
|
||||
if (r.ok) console.log(r.value.name);
|
||||
else console.error(r.error.message);
|
||||
```
|
||||
|
||||
### Rust: enum with data
|
||||
```rust
|
||||
enum Message {
|
||||
Quit,
|
||||
Move { x: i32, y: i32 },
|
||||
Write(String),
|
||||
ChangeColor(u8, u8, u8),
|
||||
}
|
||||
|
||||
fn handle(msg: Message) {
|
||||
match msg {
|
||||
Message::Quit => println!("quit"),
|
||||
Message::Move { x, y } => println!("move to {},{}", x, y),
|
||||
Message::Write(s) => println!("write {}", s),
|
||||
Message::ChangeColor(r, g, b) => println!("rgb({},{},{})", r, g, b),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Rust: Option / Result (built-in unions)
|
||||
```rust
|
||||
fn divide(a: f64, b: f64) -> Result<f64, String> {
|
||||
if b == 0.0 { Err("division by zero".into()) }
|
||||
else { Ok(a / b) }
|
||||
}
|
||||
|
||||
match divide(10.0, 2.0) {
|
||||
Ok(v) => println!("{}", v),
|
||||
Err(e) => eprintln!("error: {}", e),
|
||||
}
|
||||
```
|
||||
|
||||
### Haskell: ADT (sum + product)
|
||||
```haskell
|
||||
data Tree a = Leaf | Node (Tree a) a (Tree a)
|
||||
|
||||
depth :: Tree a -> Int
|
||||
depth Leaf = 0
|
||||
depth (Node l _ r) = 1 + max (depth l) (depth r)
|
||||
|
||||
-- 매 Maybe = Nothing | Just a — sum type
|
||||
safeDiv :: Int -> Int -> Maybe Int
|
||||
safeDiv _ 0 = Nothing
|
||||
safeDiv a b = Just (a `div` b)
|
||||
```
|
||||
|
||||
### Python 3.10+: union via `|`
|
||||
```python
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass
|
||||
class Circle: radius: float
|
||||
@dataclass
|
||||
class Square: side: float
|
||||
|
||||
Shape = Circle | Square
|
||||
|
||||
def area(s: Shape) -> float:
|
||||
match s:
|
||||
case Circle(radius=r): return 3.14159 * r * r
|
||||
case Square(side=x): return x * x
|
||||
```
|
||||
|
||||
### TypeScript: narrowing without discriminant
|
||||
```typescript
|
||||
type Pet = { swim: () => void } | { fly: () => void };
|
||||
function move(p: Pet) {
|
||||
if ("swim" in p) p.swim(); // 매 narrowed
|
||||
else p.fly();
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 2-3 variants, simple | TS plain union `A \| B` |
|
||||
| Many variants, type-safe dispatch | discriminated union with `kind` |
|
||||
| Result / Option | TS Result type / Rust built-in / Haskell Maybe |
|
||||
| Cross-language ADT | Rust enum / Haskell data |
|
||||
| Untagged (FFI / memory layout) | C union / Rust `union` (unsafe) |
|
||||
| Exhaustive matching | switch + `never` (TS) / `match` (Rust/Python) |
|
||||
|
||||
**기본값**: 매 discriminated union with literal `kind`/`tag` field — exhaustiveness 보장.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[TypeScript 타입 시스템 (TypeScript Type System)|Type System]] · [[Algebraic Data Types]]
|
||||
- 변형: [[Discriminated Union]] · [[Tagged Union]] · [[Sum Types]] · [[Variant]]
|
||||
- 응용: [[Result Type]] · [[State Machine]] · [[AST]]
|
||||
- Adjacent: [[Pattern Matching]] · [[Type Narrowing]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 모델링 "A or B" 의 alternatives, error handling (Result), state representation.
|
||||
**언제 X**: 매 단순 enum (no associated data) — plain enum 이 나음.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Boolean flags 의 union 흉내**: `{ ok: boolean, value?, error? }` — 매 `value && error` 동시 가능 → bug. Discriminated union 으로.
|
||||
- **Discriminant 없는 큰 union**: 매 narrowing 불가능 — `kind`/`tag` 추가.
|
||||
- **`default` 없는 switch**: 매 새 variant 추가 시 silent miss — `never` exhaustive check.
|
||||
- **Rust untagged `union`**: 매 unsafe 만 사용 — 99% 의 case 는 `enum`.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (TypeScript handbook, Rust book, Haskell report 2010).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — union types full content (4 langs, exhaustive, Result, 8 patterns) |
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
---
|
||||
id: wiki-20260508-vergence-accommodation-conflicts-redir
|
||||
title: Vergence-Accommodation Conflicts
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [VAC, vergence accommodation conflict, focal mismatch]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.91
|
||||
verification_status: applied
|
||||
tags: [vr, perception, optics, ux]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: TypeScript
|
||||
framework: Three.js / WebXR
|
||||
---
|
||||
|
||||
# Vergence-Accommodation Conflicts
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 eye 의 vergence (cross-eye angle) 와 accommodation (lens focus) 의 mismatch 의 eye strain / sickness"**. 매 stereoscopic VR / AR 의 fundamental 한계 — 매 fixed focal plane 의 cause. 2026 의 Vision Pro 의 여전히 mitigation 만 가능 — 매 light field display 의 future.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 원인
|
||||
- **Real world**: 매 vergence (eye 가 object 로 cross) 와 accommodation (lens focus 의 거리) 의 동기.
|
||||
- **VR/AR**: 매 vergence 의 virtual depth 의 따라 변화 — 매 accommodation 의 fixed display focal plane (~2m) 에 lock.
|
||||
- **Conflict**: 매 brain 의 두 cue 의 mismatch 의 fatigue / blur / nausea 의 trigger.
|
||||
|
||||
### 매 mitigation
|
||||
- **Dolly comfort zone**: 매 0.5-2m 의 main interaction — focal mismatch minimum.
|
||||
- **Reduce small text**: 매 close-up text 의 conflict 의 amplify.
|
||||
- **Vary focus only with intent**: 매 sudden depth change 의 avoid.
|
||||
- **Pupil-aware DOF**: 매 eye-tracking 의 dynamic blur (Vision Pro).
|
||||
- **Light field display** (future): 매 multi-focal — true accommodation cue.
|
||||
|
||||
### 매 응용
|
||||
1. UI design — 매 menu 의 1.5m 거리 의 default.
|
||||
2. AR overlay 의 real-world depth match — 매 ARKit / ARCore 의 plane anchor.
|
||||
3. eye-tracked foveated rendering 의 결합.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### 매 Three.js + WebXR 의 comfort zone 의 UI 배치
|
||||
```typescript
|
||||
const COMFORT_DISTANCE = 1.5; // m
|
||||
|
||||
const menu = new THREE.Group();
|
||||
menu.position.set(0, 1.5, -COMFORT_DISTANCE); // 매 1.5m 의 fixed focal
|
||||
camera.parent.add(menu); // 매 head-locked
|
||||
|
||||
// 매 menu 의 readable 의 maintain
|
||||
```
|
||||
|
||||
### 매 거리 별 text size 의 scaling
|
||||
```typescript
|
||||
function readableTextSize(distance: number): number {
|
||||
// 매 angular size = arctan(size / distance) — 매 적정 1-2°
|
||||
return distance * 0.025; // 매 1.5m 의 ~3.75cm height
|
||||
}
|
||||
```
|
||||
|
||||
### 매 Eye-tracking 의 dynamic DOF (Vision Pro / Quest Pro)
|
||||
```typescript
|
||||
const xrSession = renderer.xr.getSession();
|
||||
const gazeRay = await xrSession?.requestReferenceSpace('viewer');
|
||||
|
||||
// 매 gaze 의 depth 의 추정
|
||||
function applyDOF(focusDistance: number) {
|
||||
postProcessing.bokehPass.uniforms.focus.value = focusDistance;
|
||||
postProcessing.bokehPass.uniforms.aperture.value = 0.025;
|
||||
}
|
||||
```
|
||||
|
||||
### 매 Sudden depth change 의 mitigation
|
||||
```typescript
|
||||
// 매 fade transition 의 사용
|
||||
async function transitionScene(newDepth: number) {
|
||||
await fadeToBlack(200);
|
||||
scene.position.z = -newDepth;
|
||||
await fadeFromBlack(200);
|
||||
}
|
||||
```
|
||||
|
||||
### 매 AR plane anchor 의 align
|
||||
```typescript
|
||||
// 매 WebXR hit-test
|
||||
const hitTestSource = await xrSession.requestHitTestSource({ space: viewerSpace });
|
||||
|
||||
xrSession.requestAnimationFrame((time, frame) => {
|
||||
const results = frame.getHitTestResults(hitTestSource);
|
||||
if (results.length > 0) {
|
||||
const pose = results[0].getPose(refSpace);
|
||||
object.position.setFromMatrixPosition(new THREE.Matrix4().fromArray(pose.transform.matrix));
|
||||
// 매 real surface 의 attach — 매 vergence/accommodation 의 align
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### 매 Comfort range 의 enforce
|
||||
```typescript
|
||||
function clampInteractionDistance(target: THREE.Object3D) {
|
||||
const dist = camera.position.distanceTo(target.position);
|
||||
if (dist < 0.3) target.scale.setScalar(0.3 / dist); // 매 too-close 시 shrink
|
||||
if (dist > 3) target.scale.setScalar(dist / 3); // 매 too-far 시 enlarge
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| UI / menu | 1.5-2m fixed (comfort zone) |
|
||||
| Reading | 0.7-1m, large font |
|
||||
| AR overlay | real surface anchor |
|
||||
| Cinematic | distant scene (>3m) |
|
||||
| Sudden depth jump | fade transition |
|
||||
|
||||
**기본값**: 0.5-2m comfort zone 의 default, 매 UI 의 1.5m 의 fixed.
|
||||
|
||||
## 🔗 Graph
|
||||
- 응용: [[VR Sickness]] · [[깊이 지각(Depth perception)]]
|
||||
- Adjacent: [[Edge Bleeding]] · [[가상현실(VR) 자전거 시뮬레이터]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: VR/AR UX 의 comfort design, UI 거리 의 권장, eye strain 의 explain.
|
||||
**언제 X**: 매 specific HMD 의 hardware 의 specific recommendation 의 over-confidence — 매 device 의 명시.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Tiny text 의 close**: 매 0.3m 의 small font — 매 conflict 의 max.
|
||||
- **Sudden zoom**: 매 fade 없는 depth jump — 매 nausea.
|
||||
- **Floating UI 의 무한 거리**: 매 readable 거리 의 무시.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Oculus VR Best Practices, Apple Vision Pro Human Interface Guidelines).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — VAC FULL 작성 |
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
id: wiki-2026-0508-war-yes
|
||||
title: War Yes
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: yes-command
|
||||
duplicate_of: "[[yes (Unix command)]]"
|
||||
aliases: []
|
||||
source_trust_level: B
|
||||
confidence_score: 0.7
|
||||
verification_status: redirected
|
||||
tags: [duplicate, unix, cli, ambiguous-title]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# War Yes
|
||||
|
||||
> **이 문서는 ambiguous title — likely [[yes (Unix command)]] 의 typo / OCR artifact.** Canonical 문서로 redirect.
|
||||
|
||||
## 핵심 요약
|
||||
- "War-Yes" 는 의미 불명 — 매 likely "war yes" / "yes(1)" 명령어 관련 OCR / scrape artifact.
|
||||
- Unix `yes` 명령은 stdout에 무한히 "y" 출력 (interactive prompt 자동 응답용).
|
||||
- 만약 "war"가 의도적이라면 [[Game Theory]] 의 cooperation game / iterated prisoner's dilemma 참조.
|
||||
|
||||
## 🔗 Graph
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복/ambiguous 처리 — canonical (yes 명령) 으로 redirect |
|
||||
@@ -0,0 +1,142 @@
|
||||
---
|
||||
id: wiki-20260508-write-barrier-redir
|
||||
title: Write Barrier
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [쓰기 장벽, GC Write Barrier, Generational Barrier]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [garbage-collection, runtime, v8, jvm, performance]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: cpp
|
||||
framework: v8, jvm
|
||||
---
|
||||
|
||||
# Write Barrier
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 inter-generational pointer 의 tracking 의 cost"**. Write barrier 는 매 generational / incremental GC 가 매 old-gen object 의 reference 가 매 young-gen 의 가리킬 때 매 remembered set 의 update 의 small code snippet. 매 V8 / JVM / .NET 의 모든 modern GC 의 essential primitive — 매 minor GC 가 매 entire old-gen 의 scan 의 회피.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 why
|
||||
- **Generational hypothesis**: 매 most objects die young → young-gen 만 frequent collect.
|
||||
- **Inter-gen pointer 의 problem**: 매 minor GC 의 root 로 매 stack + old→young pointer 의 필요.
|
||||
- **Naive: scan all old-gen** → expensive.
|
||||
- **Solution**: 매 write 마다 (old.field = young) 매 barrier 의 firing → remembered set 의 add.
|
||||
|
||||
### 매 type
|
||||
- **Snapshot-at-the-Beginning (SATB)**: 매 incremental marking 의 use (G1, ZGC, V8 Orinoco). 매 overwritten old reference 의 record.
|
||||
- **Incremental Update**: 매 new reference 의 record (CMS).
|
||||
- **Card marking**: 매 old-gen 의 fixed-size card (e.g., 512B) 의 dirty bit 의 mark — coarse but cheap.
|
||||
|
||||
### 매 cost
|
||||
- 매 store 마다 ~3-5 instruction overhead.
|
||||
- 매 hot-loop 의 store 의 bottleneck 가능 — 매 elision optimization 의 important.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### 1. Card-marking pseudo-implementation
|
||||
```cpp
|
||||
// 매 1MB heap 의 512B card → 2048 cards
|
||||
const size_t CARD_SIZE = 512;
|
||||
uint8_t card_table[HEAP_SIZE / CARD_SIZE];
|
||||
|
||||
inline void write_barrier(Object* obj, Object** field, Object* new_val) {
|
||||
*field = new_val;
|
||||
if (in_old_gen(obj) && in_young_gen(new_val)) {
|
||||
size_t card = ((uintptr_t)field - heap_base) / CARD_SIZE;
|
||||
card_table[card] = 1; // dirty
|
||||
}
|
||||
}
|
||||
|
||||
void minor_gc_scan() {
|
||||
for (size_t i = 0; i < num_cards; i++) {
|
||||
if (card_table[i]) {
|
||||
scan_card_for_young_refs(i);
|
||||
card_table[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. V8-style incremental marking barrier (simplified)
|
||||
```cpp
|
||||
// 매 SATB: overwritten reference 의 mark gray
|
||||
inline void v8_write_barrier(HeapObject* host, Object** slot, Object* value) {
|
||||
Object* old = *slot;
|
||||
*slot = value;
|
||||
if (incremental_marking_active && is_white(old)) {
|
||||
mark_gray(old); // 매 not-yet-marked 의 reference 의 처리 보장
|
||||
}
|
||||
// 매 generational: old→young 의 record
|
||||
if (host->in_old_space() && value->in_young_space()) {
|
||||
remembered_set.insert(slot);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. JIT-emitted barrier elision
|
||||
```cpp
|
||||
// 매 compiler 의 barrier 의 omit 가능 case:
|
||||
// 1. 매 store 의 target 이 fresh allocation (young → ?)
|
||||
// 2. 매 store value 의 primitive (int, double)
|
||||
// 3. 매 immutable field 의 init store
|
||||
function emitStore(host, field, value) {
|
||||
if (isFreshlyAllocated(host)) emitRawStore(host, field, value);
|
||||
else emitBarrieredStore(host, field, value);
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Measure barrier overhead (benchmark)
|
||||
```typescript
|
||||
// Node.js / V8 의 barrier overhead 의 indirect measure
|
||||
const N = 1e7;
|
||||
const arr = new Array(N);
|
||||
const obj = { ref: null };
|
||||
console.time('store-loop');
|
||||
for (let i = 0; i < N; i++) obj.ref = arr; // 매 barrier 의 fire
|
||||
console.timeEnd('store-loop');
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 매 hot inner loop 의 store | primitive 의 use, object reference 의 회피 |
|
||||
| 매 immutable struct | barrier-free design |
|
||||
| 매 large old-gen | card marking 의 prefer |
|
||||
| 매 incremental GC | SATB barrier 의 use |
|
||||
| 매 low-latency (ZGC) | colored pointers + load barrier 의 alternative |
|
||||
|
||||
**기본값**: 매 application code 의 barrier 의 invisible — 매 GC 의 implementation detail.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Garbage Collection]] · [[Memory Management]]
|
||||
- 변형: [[Card Marking]]
|
||||
- 응용: [[Incremental GC]] · [[Orinoco]]
|
||||
- Adjacent: [[Mark Sweep Compact]] · [[Garbage Collection|Generational Hypothesis]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: GC internals 의 understanding, runtime tuning, performance 의 explain.
|
||||
**언제 X**: Rust / non-GC language (no barrier), reference counting (no generational).
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Barrier elision 의 manual attempt 의 application code**: 매 unsafe.
|
||||
- **Excessive store-to-old-gen 의 hot path**: 매 remembered set 의 explosion.
|
||||
- **Ignoring barrier cost 의 high-frequency mutation**: 매 hidden bottleneck.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Jones GC handbook 2011, V8 Orinoco docs, JVM HotSpot source).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — write barrier 의 type, cost, V8 example 의 expand |
|
||||
@@ -0,0 +1,209 @@
|
||||
---
|
||||
id: wiki-2026-0508-zod-런타임-유효성-검사-통합
|
||||
title: Zod 런타임 유효성 검사 통합
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Zod, TypeScript runtime validation, Zod schema]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [typescript, validation, zod, runtime-types, schema]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: TypeScript
|
||||
framework: Zod 3.x
|
||||
---
|
||||
|
||||
# Zod 런타임 유효성 검사 통합
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 type schema = single source of truth"**. Zod는 매 TypeScript type을 런타임 schema 로 정의하고, parse 시점에 매 validation + type narrowing 을 동시 제공한다. API boundary, env vars, form input 매 unsafe input 의 매 첫 검증선.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 동기 (Why Zod over alternatives)
|
||||
- **TypeScript types are erased**: 매 컴파일 후 `interface User`는 매 사라짐 → API response 의 `data as User` 매 lying.
|
||||
- **Zod = schema → type**: `z.infer<typeof Schema>` 로 매 schema 가 source of truth.
|
||||
- **Composability**: 매 `.merge`, `.partial`, `.extend`, `.transform` 으로 매 schema 합성.
|
||||
- **Error-rich**: parse failure 시 매 path, code, message tree 반환.
|
||||
|
||||
### 매 경쟁 라이브러리
|
||||
- **Yup**: 매 older, schema → type 약함, 매 Zod 가 대체.
|
||||
- **io-ts**: 매 더 functional (fp-ts), 매 learning curve 높음.
|
||||
- **Valibot**: 매 tree-shakable, 매 bundle size 우선이면 고려 (~10x smaller).
|
||||
- **ArkType**: 매 string-based syntax, 매 빠르지만 ecosystem 작음.
|
||||
- **Zod**: 매 default choice in 2026 — DX, ecosystem (tRPC, React Hook Form), maturity.
|
||||
|
||||
### 매 응용
|
||||
1. **API boundary**: fetch response 매 parse 후 typed 으로 사용.
|
||||
2. **Form validation**: React Hook Form + zodResolver.
|
||||
3. **env vars**: `process.env` 의 매 schema parse, missing key 시 즉시 fail.
|
||||
4. **DB row → domain**: ORM 결과 매 `Schema.parse(row)`.
|
||||
5. **LLM structured output**: Claude/GPT JSON response 매 schema 로 검증.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Pattern 1: 기본 schema + type inference
|
||||
```typescript
|
||||
import { z } from "zod";
|
||||
|
||||
export const UserSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
email: z.string().email(),
|
||||
age: z.number().int().min(0).max(150),
|
||||
role: z.enum(["admin", "user", "guest"]),
|
||||
createdAt: z.coerce.date(),
|
||||
});
|
||||
|
||||
export type User = z.infer<typeof UserSchema>;
|
||||
|
||||
// usage
|
||||
const raw: unknown = await fetchUser();
|
||||
const user = UserSchema.parse(raw); // throws ZodError if invalid
|
||||
// ^? User
|
||||
```
|
||||
|
||||
### Pattern 2: safeParse for non-throw
|
||||
```typescript
|
||||
const result = UserSchema.safeParse(raw);
|
||||
if (!result.success) {
|
||||
console.error(result.error.flatten());
|
||||
return;
|
||||
}
|
||||
const user = result.data; // typed
|
||||
```
|
||||
|
||||
### Pattern 3: env validation (fail fast at boot)
|
||||
```typescript
|
||||
const EnvSchema = z.object({
|
||||
DATABASE_URL: z.string().url(),
|
||||
PORT: z.coerce.number().int().positive().default(3000),
|
||||
NODE_ENV: z.enum(["development", "production", "test"]),
|
||||
ANTHROPIC_API_KEY: z.string().startsWith("sk-ant-"),
|
||||
});
|
||||
|
||||
export const env = EnvSchema.parse(process.env);
|
||||
// process exits at startup if invalid — better than runtime surprise
|
||||
```
|
||||
|
||||
### Pattern 4: discriminated union
|
||||
```typescript
|
||||
const ResultSchema = z.discriminatedUnion("status", [
|
||||
z.object({ status: z.literal("ok"), data: z.string() }),
|
||||
z.object({ status: z.literal("error"), code: z.number() }),
|
||||
]);
|
||||
|
||||
type Result = z.infer<typeof ResultSchema>;
|
||||
// narrowing on .status works correctly
|
||||
```
|
||||
|
||||
### Pattern 5: transform for parse-not-validate
|
||||
```typescript
|
||||
const DateSchema = z.string().transform((s, ctx) => {
|
||||
const d = new Date(s);
|
||||
if (isNaN(d.getTime())) {
|
||||
ctx.addIssue({ code: "custom", message: "Invalid date" });
|
||||
return z.NEVER;
|
||||
}
|
||||
return d;
|
||||
});
|
||||
|
||||
const out = DateSchema.parse("2026-05-10"); // Date instance
|
||||
```
|
||||
|
||||
### Pattern 6: API client with Zod
|
||||
```typescript
|
||||
async function fetchUser(id: string): Promise<User> {
|
||||
const res = await fetch(`/api/users/${id}`);
|
||||
const json = await res.json();
|
||||
return UserSchema.parse(json); // unknown → User
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 7: tRPC integration
|
||||
```typescript
|
||||
import { router, procedure } from "./trpc";
|
||||
|
||||
export const userRouter = router({
|
||||
create: procedure
|
||||
.input(UserSchema.omit({ id: true, createdAt: true }))
|
||||
.mutation(async ({ input }) => {
|
||||
// input is fully typed + validated
|
||||
return db.user.create({ data: input });
|
||||
}),
|
||||
});
|
||||
```
|
||||
|
||||
### Pattern 8: React Hook Form + Zod
|
||||
```typescript
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
|
||||
const FormSchema = z.object({
|
||||
email: z.string().email(),
|
||||
password: z.string().min(8),
|
||||
});
|
||||
|
||||
const { register, handleSubmit, formState } = useForm({
|
||||
resolver: zodResolver(FormSchema),
|
||||
});
|
||||
```
|
||||
|
||||
### Pattern 9: schema composition
|
||||
```typescript
|
||||
const Base = z.object({ id: z.string(), createdAt: z.date() });
|
||||
const Post = Base.extend({ title: z.string(), body: z.string() });
|
||||
const PostUpdate = Post.partial().required({ id: true });
|
||||
```
|
||||
|
||||
### Pattern 10: refinement (custom rules)
|
||||
```typescript
|
||||
const PasswordSchema = z
|
||||
.object({ password: z.string(), confirm: z.string() })
|
||||
.refine((d) => d.password === d.confirm, {
|
||||
message: "Passwords do not match",
|
||||
path: ["confirm"],
|
||||
});
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| API boundary, untrusted input | Zod parse |
|
||||
| Internal pure-TS code | Type only, no Zod |
|
||||
| Bundle size critical (mobile, edge) | Valibot |
|
||||
| Functional ergonomics | io-ts |
|
||||
| LLM structured output (Claude/GPT) | Zod + tool schema |
|
||||
| Performance hot path (>10k parses/sec) | Compile to TypeBox/AJV |
|
||||
|
||||
**기본값**: Zod 3.x — 매 modern TS app 의 default validation layer.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[TypeScript]] · [[Runtime_Validation|Runtime Type Validation]]
|
||||
- 변형: [[Valibot]] · [[Yup]] · [[ArkType]]
|
||||
- 응용: [[React Hook Form]]
|
||||
- Adjacent: [[JSON Schema]] · [[과잉 속성 체크 (Excess Property Checking)]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: untrusted boundary (API, form, env, LLM output) 매 parse. tool/function calling 의 매 input schema.
|
||||
**언제 X**: internal pure-TS code 매 over-validation 불필요. hot loop 의 매 매 parse 호출.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Anti1: parse everywhere**: 매 internal function 매 Zod parse — 매 overhead 누적, 매 type only 충분.
|
||||
- **Anti2: as cast after parse**: `Schema.parse(x) as MyType` — 매 redundant, parse 가 이미 typed return.
|
||||
- **Anti3: schema duplication**: type + schema 따로 정의 — 매 z.infer 사용.
|
||||
- **Anti4: nested transforms with side effects**: transform 안에서 fetch/IO — 매 pure 하게 유지.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Zod docs colinhacks.com/zod, 2026 ecosystem).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — Zod runtime validation patterns + 2026 ecosystem context |
|
||||
@@ -0,0 +1,191 @@
|
||||
---
|
||||
id: wiki-2026-0508-as-const-assertion
|
||||
title: as const Assertion
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [const assertion, const context, readonly literal]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
verification_status: applied
|
||||
tags: [typescript, type-system, literal-types, immutability]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: TypeScript
|
||||
framework: TypeScript 5.x
|
||||
---
|
||||
|
||||
# as const Assertion
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 widening을 끄는 가장 강력한 단언"**. TypeScript 3.4에 등장한 `as const`는 literal type을 보존하면서 모든 property를 `readonly`로 만든다. 매 modern TS 코드의 type-safety 핵심 도구.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 동작 방식
|
||||
- 매 literal (string, number, boolean, array, object literal) 을 narrow type 으로 고정
|
||||
- 매 type widening 방지 — `"hello"` 는 `string` 이 X, 매 `"hello"` literal type
|
||||
- 매 array → readonly tuple 변환
|
||||
- 매 object → 매 모든 property `readonly` + literal type
|
||||
|
||||
### 매 작동 범위
|
||||
- 매 literal expression 에만 적용 가능
|
||||
- 매 변수 / 함수 호출 결과에 매 X
|
||||
- 매 컴파일 타임 only — 매 runtime 영향 X
|
||||
|
||||
### 매 응용
|
||||
1. Discriminated union 의 tag 정의.
|
||||
2. Const enum 의 modern 대체 (literal object).
|
||||
3. Tuple type 의 명시적 생성 (router params, fixed-length array).
|
||||
4. Configuration object 의 immutable 보장.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### 1. Widening 방지
|
||||
```typescript
|
||||
// 매 widening
|
||||
const x = "foo"; // type: string (let), "foo" (const)
|
||||
let y = "foo"; // type: string (always widened)
|
||||
|
||||
// 매 as const
|
||||
const x2 = "foo" as const; // type: "foo"
|
||||
let y2 = "foo" as const; // type: "foo" — 매 let 도 narrow
|
||||
|
||||
// 매 array
|
||||
const arr1 = [1, 2, 3]; // number[]
|
||||
const arr2 = [1, 2, 3] as const; // readonly [1, 2, 3]
|
||||
```
|
||||
|
||||
### 2. Discriminated Union Tag
|
||||
```typescript
|
||||
const ACTIONS = {
|
||||
INCREMENT: "INCREMENT",
|
||||
DECREMENT: "DECREMENT",
|
||||
RESET: "RESET",
|
||||
} as const;
|
||||
|
||||
type Action =
|
||||
| { type: typeof ACTIONS.INCREMENT; payload: number }
|
||||
| { type: typeof ACTIONS.DECREMENT; payload: number }
|
||||
| { type: typeof ACTIONS.RESET };
|
||||
|
||||
// 매 ACTIONS.INCREMENT 의 type 은 "INCREMENT" — 매 string X
|
||||
```
|
||||
|
||||
### 3. Const Enum 대체
|
||||
```typescript
|
||||
// 매 옛 방식 — const enum (tree-shaking 문제, --isolatedModules 충돌)
|
||||
const enum Color { Red = "red", Blue = "blue" }
|
||||
|
||||
// 매 modern 방식 — as const
|
||||
const Color = {
|
||||
Red: "red",
|
||||
Blue: "blue",
|
||||
} as const;
|
||||
type Color = typeof Color[keyof typeof Color]; // "red" | "blue"
|
||||
```
|
||||
|
||||
### 4. Readonly Tuple
|
||||
```typescript
|
||||
function useState<T>(initial: T) {
|
||||
let value = initial;
|
||||
return [value, (v: T) => { value = v; }] as const;
|
||||
}
|
||||
// 매 return type: readonly [T, (v: T) => void]
|
||||
// 매 destructure 시 정확한 type
|
||||
const [count, setCount] = useState(0);
|
||||
```
|
||||
|
||||
### 5. 매 Object 의 Deep Readonly
|
||||
```typescript
|
||||
const config = {
|
||||
api: {
|
||||
baseUrl: "https://api.example.com",
|
||||
timeout: 5000,
|
||||
retries: 3,
|
||||
},
|
||||
features: ["auth", "billing"],
|
||||
} as const;
|
||||
|
||||
// type:
|
||||
// {
|
||||
// readonly api: {
|
||||
// readonly baseUrl: "https://api.example.com";
|
||||
// readonly timeout: 5000;
|
||||
// readonly retries: 3;
|
||||
// };
|
||||
// readonly features: readonly ["auth", "billing"];
|
||||
// }
|
||||
|
||||
// config.api.timeout = 1000; // ❌ readonly
|
||||
```
|
||||
|
||||
### 6. 매 Type Extraction
|
||||
```typescript
|
||||
const ROLES = ["admin", "user", "guest"] as const;
|
||||
type Role = typeof ROLES[number]; // "admin" | "user" | "guest"
|
||||
|
||||
const HTTP_METHODS = ["GET", "POST", "PUT", "DELETE"] as const;
|
||||
type HttpMethod = typeof HTTP_METHODS[number];
|
||||
|
||||
// 매 사용
|
||||
function fetchData(method: HttpMethod, url: string) { /* ... */ }
|
||||
fetchData("GET", "/api"); // ✅
|
||||
fetchData("PATCH", "/api"); // ❌ Argument of type '"PATCH"' is not assignable
|
||||
```
|
||||
|
||||
### 7. Generic Function 의 Inference
|
||||
```typescript
|
||||
function pick<T, K extends keyof T>(obj: T, keys: readonly K[]): Pick<T, K> {
|
||||
const result = {} as Pick<T, K>;
|
||||
for (const key of keys) result[key] = obj[key];
|
||||
return result;
|
||||
}
|
||||
|
||||
const user = { id: 1, name: "Alice", age: 30 };
|
||||
const subset = pick(user, ["id", "name"] as const);
|
||||
// 매 as const 없으면: keys 는 string[] 으로 추론 → K = string → 매 fail
|
||||
// 매 as const 있으면: keys 는 readonly ("id" | "name")[] → K = "id" | "name"
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Magic string / number set | `as const` 객체 + `typeof[keyof typeof]` |
|
||||
| Discriminated union tag | `as const` 로 literal 보장 |
|
||||
| Tuple return | 함수 끝에 `as const` |
|
||||
| Config / constants | 매 `as const` 로 deep readonly |
|
||||
| Const enum 사용 중 | 매 `as const` 객체로 마이그레이션 |
|
||||
| Mutable shared state | `as const` X — 매 readonly 가 방해 |
|
||||
|
||||
**기본값**: 매 literal data 에는 항상 `as const` 를 시도. 매 widening 이 의도일 때만 제외.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[TypeScript]]
|
||||
- 변형: [[const Assertion]] · [[satisfies Operator]]
|
||||
- 응용: [[Discriminated_Unions|Discriminated Unions]] · [[Literal Types]]
|
||||
- Adjacent: [[Readonly]] · [[Type Narrowing]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 fixed set of values (action types, route names, status codes), tuple return, config object 정의 시 사용.
|
||||
**언제 X**: runtime mutation 필요 시, generic widening 이 의도일 때, 매 single primitive variable (이미 `const` 로 충분).
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Function call 에 적용**: `fetch() as const` — 매 literal 이 X 라 효과 없음.
|
||||
- **Mutable interface 와 충돌**: `as const` 객체를 mutable interface 에 assign — 매 readonly mismatch 에러.
|
||||
- **과도한 nesting**: 매 깊은 readonly 가 매 사용처에서 매 type 좁힘 — 매 trade-off 고려.
|
||||
- **type 와 value 혼동**: `typeof OBJ` vs `OBJ` — 매 type 추출엔 `typeof`.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (TypeScript 3.4+ release notes, TS Handbook 2025 edition).
|
||||
- 신뢰도 A.
|
||||
- 매 [[Const Assertions]] 와 동의어 — 매 같은 기능.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — as const 의 7 패턴 + decision matrix |
|
||||
+227
@@ -0,0 +1,227 @@
|
||||
---
|
||||
id: wiki-2026-0508-bitecs와-sharedarraybuffer를-결합한-멀
|
||||
title: bitECS와 SharedArrayBuffer를 결합한 멀티스레드 고성능 아키텍처
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [bitECS multithreaded, SAB ECS, ECS parallel, bitECS SharedArrayBuffer]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [ecs, bitecs, sharedarraybuffer, parallel, gamedev, browser]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: TypeScript
|
||||
framework: bitECS + Web Worker
|
||||
---
|
||||
|
||||
# bitECS와 SharedArrayBuffer를 결합한 멀티스레드 고성능 아키텍처
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 bitECS Component = TypedArray on SAB"**. bitECS의 매 SoA layout 은 매 SharedArrayBuffer 와 매 자연스럽게 결합 — 매 component data 가 매 worker 에서 매 zero-copy 공유. 매 system 분산 + 매 stripe partition 으로 매 100k+ entity 를 매 60fps 에서 매 simulate 가능.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 bitECS 구조
|
||||
- **Entity**: 32-bit integer ID.
|
||||
- **Component**: 매 TypedArray (Float32Array, Int32Array 등) per field, 매 indexed by entity ID.
|
||||
- **System**: query → process loop.
|
||||
- 매 SoA (Struct of Arrays) → 매 cache-friendly + SIMD-friendly.
|
||||
|
||||
### 매 SAB 통합 핵심
|
||||
- bitECS 의 매 component 매 backing TypedArray 의 매 buffer 를 매 SAB 로 교체.
|
||||
- 매 worker 에서 매 동일 component 에 매 동시 접근 가능.
|
||||
- 매 system 별로 매 worker 분배 — 또는 매 entity range 별 분배.
|
||||
|
||||
### 매 partition strategy
|
||||
1. **System-level**: physics worker, AI worker, render worker 매 별도.
|
||||
2. **Entity-level**: entity ID 매 mod N → worker N 개에 분산.
|
||||
3. **Stripe-level**: contiguous range, cache-friendly.
|
||||
4. **Hybrid**: 매 read-heavy system 매 모든 worker, write 매 owner worker 만.
|
||||
|
||||
### 매 응용
|
||||
1. **Boid/flocking**: 100k boids 매 4 worker 에서 stripe.
|
||||
2. **Particle system**: SAB Float32 의 매 position/velocity, 매 worker 별 batch.
|
||||
3. **Pathfinding**: A* 매 worker pool, 매 result 매 SAB 에 적재.
|
||||
4. **Voxel chunk update**: 매 chunk 별 worker, 매 mesh build 매 OffscreenCanvas worker.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Pattern 1: bitECS component → SAB-backed
|
||||
```typescript
|
||||
// main.ts
|
||||
import { createWorld, defineComponent, Types } from "bitecs";
|
||||
|
||||
const MAX_ENTITIES = 100_000;
|
||||
const sab = new SharedArrayBuffer(MAX_ENTITIES * 3 * 4 * 2); // pos+vel, f32
|
||||
|
||||
// SAB 위에 매 직접 component 정의 (bitECS 0.4+ allows custom buffer)
|
||||
const Position = {
|
||||
x: new Float32Array(sab, 0, MAX_ENTITIES),
|
||||
y: new Float32Array(sab, MAX_ENTITIES * 4, MAX_ENTITIES),
|
||||
};
|
||||
const Velocity = {
|
||||
x: new Float32Array(sab, MAX_ENTITIES * 8, MAX_ENTITIES),
|
||||
y: new Float32Array(sab, MAX_ENTITIES * 12, MAX_ENTITIES),
|
||||
};
|
||||
|
||||
const world = createWorld();
|
||||
// ... addEntity, addComponent (writes go into SAB views)
|
||||
```
|
||||
|
||||
### Pattern 2: worker spawn + SAB share
|
||||
```typescript
|
||||
const N_WORKERS = 4;
|
||||
const workers = Array.from({ length: N_WORKERS }, (_, id) => {
|
||||
const w = new Worker("./physics-worker.ts", { type: "module" });
|
||||
w.postMessage({ sab, workerId: id, n: N_WORKERS, maxEntities: MAX_ENTITIES });
|
||||
return w;
|
||||
});
|
||||
```
|
||||
|
||||
### Pattern 3: physics system in worker
|
||||
```typescript
|
||||
// physics-worker.ts
|
||||
self.onmessage = ({ data: { sab, workerId, n, maxEntities } }) => {
|
||||
const px = new Float32Array(sab, 0, maxEntities);
|
||||
const py = new Float32Array(sab, maxEntities * 4, maxEntities);
|
||||
const vx = new Float32Array(sab, maxEntities * 8, maxEntities);
|
||||
const vy = new Float32Array(sab, maxEntities * 12, maxEntities);
|
||||
|
||||
const stripe = Math.ceil(maxEntities / n);
|
||||
const start = workerId * stripe;
|
||||
const end = Math.min(start + stripe, maxEntities);
|
||||
|
||||
setInterval(() => {
|
||||
const dt = 0.016;
|
||||
for (let i = start; i < end; i++) {
|
||||
px[i] += vx[i] * dt;
|
||||
py[i] += vy[i] * dt;
|
||||
}
|
||||
}, 16);
|
||||
};
|
||||
```
|
||||
|
||||
### Pattern 4: barrier-synchronized frame
|
||||
```typescript
|
||||
// shared int32 frame counter
|
||||
const sync = new Int32Array(sab, syncOffset, 4);
|
||||
// sync[0] = workersReady, sync[1] = generation
|
||||
|
||||
function workerStep() {
|
||||
// do work
|
||||
doStripe();
|
||||
// barrier
|
||||
if (Atomics.add(sync, 0, 1) + 1 === N_WORKERS) {
|
||||
Atomics.store(sync, 0, 0);
|
||||
Atomics.add(sync, 1, 1);
|
||||
Atomics.notify(sync, 1, N_WORKERS - 1);
|
||||
} else {
|
||||
const gen = Atomics.load(sync, 1);
|
||||
Atomics.wait(sync, 1, gen);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 5: read-only system on all workers
|
||||
```typescript
|
||||
// AI system: read pos/vel of others, write own intent → no contention
|
||||
function aiSystem(workerId: number) {
|
||||
for (let i = start; i < end; i++) {
|
||||
let nearestX = 0, nearestY = 0, nearestDist = Infinity;
|
||||
for (let j = 0; j < maxEntities; j++) {
|
||||
if (j === i) continue;
|
||||
const dx = px[j] - px[i], dy = py[j] - py[i];
|
||||
const d = dx * dx + dy * dy;
|
||||
if (d < nearestDist) { nearestDist = d; nearestX = px[j]; nearestY = py[j]; }
|
||||
}
|
||||
// write only own intent slot
|
||||
intent[i] = computeIntent(px[i], py[i], nearestX, nearestY);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 6: render thread on main, worker writes only
|
||||
```typescript
|
||||
// main thread: requestAnimationFrame → read SAB, render
|
||||
function frame() {
|
||||
for (let i = 0; i < activeCount; i++) {
|
||||
ctx.fillRect(px[i], py[i], 2, 2);
|
||||
}
|
||||
requestAnimationFrame(frame);
|
||||
}
|
||||
// 매 race: workers writing while main reads — visual tearing 가능, 대부분 게임에서 허용.
|
||||
// strict 의 매 double buffer (front/back) → flip on barrier.
|
||||
```
|
||||
|
||||
### Pattern 7: double-buffered position
|
||||
```typescript
|
||||
const pxA = new Float32Array(sab, offA, max);
|
||||
const pxB = new Float32Array(sab, offB, max);
|
||||
let frontIdx = 0;
|
||||
|
||||
function workerStep() {
|
||||
const front = frontIdx === 0 ? pxA : pxB;
|
||||
const back = frontIdx === 0 ? pxB : pxA;
|
||||
// read front, write back
|
||||
for (let i = start; i < end; i++) back[i] = front[i] + vx[i] * dt;
|
||||
// barrier → main flips frontIdx
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 8: SoA SIMD (WASM SIMD or manual unroll)
|
||||
```typescript
|
||||
// 매 4-wide unroll — JIT가 종종 SIMD화
|
||||
for (let i = start; i < end; i += 4) {
|
||||
px[i] += vx[i] * dt;
|
||||
px[i + 1] += vx[i + 1] * dt;
|
||||
px[i + 2] += vx[i + 2] * dt;
|
||||
px[i + 3] += vx[i + 3] * dt;
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 9: spawn/kill queue (lock-free SPSC)
|
||||
```typescript
|
||||
// 매 main 만 spawn, worker 만 kill — single-producer queue
|
||||
// 매 ring buffer of entity IDs, Atomics-driven head/tail
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| <1k entities | Single thread, 매 충분 |
|
||||
| 1k–10k, simple physics | bitECS single-thread |
|
||||
| 10k+, heavy AI/physics | bitECS + SAB + worker pool |
|
||||
| Render heavy | OffscreenCanvas worker |
|
||||
| Voxel/chunk world | Per-chunk worker assignment |
|
||||
|
||||
**기본값**: 매 single thread first. 매 measure → SAB 매 4 worker 부터 의미 있을 때만.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[ECS]] · [[bitECS]] · [[Web Worker]] · [[SharedArrayBuffer]]
|
||||
- 응용: [[Particle System]]
|
||||
- Adjacent: [[Web Worker와 SharedArrayBuffer를 이용한 실제 고부하 병렬 처리 구현체 (실패_성공 포함)]] · [[OffscreenCanvas]] · [[가변적 LOD(Level of Detail) 시스템]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 large-scale entity simulation in browser. 매 60fps 매 100k+ entity.
|
||||
**언제 X**: 매 small game, 매 single-thread bitECS 충분 — 매 SAB 의 debug 비용 매 큼.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Anti1: 매 component write 매 worker 동시**: race. 매 ownership 명확히.
|
||||
- **Anti2: 매 frame SAB 재생성**: GC 폭발. startup 1번.
|
||||
- **Anti3: 매 worker 마다 component query**: query overhead 누적. 매 main 에서 ID list 한번 + worker 에 stripe.
|
||||
- **Anti4: false sharing — 매 worker 가 인접 entity write**: 매 stripe 대신 매 mod 분산은 false sharing 위험. stripe 사용.
|
||||
- **Anti5: render race 무시**: visual artifact. 매 double buffer or 매 tolerate.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (bitECS GitHub, 2025–2026 Web Worker SAB ecosystem).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — bitECS+SAB architecture + canonical merge |
|
||||
@@ -0,0 +1,151 @@
|
||||
---
|
||||
id: wiki-2026-0508-ndf-parse-패키지
|
||||
title: ndf-parse 패키지
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [ndf-parse, NDF parser, Eugen NDF]
|
||||
duplicate_of: none
|
||||
source_trust_level: B
|
||||
confidence_score: 0.85
|
||||
verification_status: applied
|
||||
tags: [python, parser, modding, wargame, ndf]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: Python
|
||||
framework: ndf-parse (PyPI)
|
||||
---
|
||||
|
||||
# ndf-parse 패키지
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 Eugen Systems 의 NDF (Niche Definition Files) format 의 Python parser/serializer"**. 매 Wargame: Red Dragon, Steel Division, WARNO 의 mod 작성에 사용. 매 lossless round-trip + AST manipulation 을 제공.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 NDF format 이란
|
||||
- Eugen 의 game data 정의 언어 — 매 unit stats, weapon, sound, UI binding 의 declarative description.
|
||||
- Lua-like syntax + GUID reference + template instantiation. 매 plain text but very large (수만 lines).
|
||||
|
||||
### 매 ndf-parse 가 해주는 것
|
||||
- **Parse**: NDF text → Python AST (List / Object / Map / Reference / Template node).
|
||||
- **Walk**: tree traversal + by-name lookup.
|
||||
- **Mutate**: in-place edit, insert, delete.
|
||||
- **Serialize**: AST → NDF text, 매 formatting 의 보존 (whitespace, comments).
|
||||
|
||||
### 매 응용
|
||||
1. WARNO / Steel Division mod 의 unit balancing.
|
||||
2. Bulk find-replace (e.g. all small-arms 의 damage +10%).
|
||||
3. Mod merge tool — 매 multiple mod 의 conflict-free combination.
|
||||
4. CI validation — 매 NDF schema 의 lint.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Install + 매 first parse
|
||||
```python
|
||||
# pip install ndf-parse
|
||||
import ndf_parse as ndf
|
||||
|
||||
with open("GameData/Generated/Gameplay/Gfx/UniteDescriptor.ndf", "r", encoding="utf-8") as f:
|
||||
source = ndf.load(f) # returns ndf.model.List
|
||||
print(type(source), len(source))
|
||||
```
|
||||
|
||||
### 매 unit lookup by name
|
||||
```python
|
||||
unit = source.by_name("Descriptor_Unit_M1A2_Abrams_US").value
|
||||
# unit is an Object node
|
||||
```
|
||||
|
||||
### 매 module 안의 specific value 변경
|
||||
```python
|
||||
modules = unit.by_name("ModulesDescriptors").value
|
||||
for module in modules:
|
||||
if module.value.type == "TBaseDamageModuleDescriptor":
|
||||
hp_row = module.value.by_name("MaxPhysicalDamages")
|
||||
hp_row.value = "12" # was "10"
|
||||
break
|
||||
```
|
||||
|
||||
### 매 weapon damage 의 bulk +10%
|
||||
```python
|
||||
def bump_damage(node):
|
||||
for member in node:
|
||||
if member.member == "PhysicalDamages":
|
||||
try:
|
||||
old = float(member.value)
|
||||
member.value = f"{old * 1.10:.2f}"
|
||||
except ValueError:
|
||||
pass
|
||||
if hasattr(member.value, "__iter__"):
|
||||
bump_damage(member.value)
|
||||
|
||||
bump_damage(source)
|
||||
```
|
||||
|
||||
### 매 serialize back
|
||||
```python
|
||||
with open("Mod/UniteDescriptor.ndf", "w", encoding="utf-8") as f:
|
||||
ndf.write(source, f)
|
||||
# 매 round-trip: comments / whitespace 의 가능한 한 보존
|
||||
```
|
||||
|
||||
### 매 새 unit 의 clone + rename
|
||||
```python
|
||||
import copy
|
||||
template = source.by_name("Descriptor_Unit_M1A2_Abrams_US")
|
||||
clone = copy.deepcopy(template)
|
||||
clone.name = "Descriptor_Unit_M1A3_Abrams_Custom"
|
||||
source.add(clone)
|
||||
```
|
||||
|
||||
### CLI mod build pipeline
|
||||
```python
|
||||
# build_mod.py
|
||||
from pathlib import Path
|
||||
import ndf_parse as ndf
|
||||
|
||||
for src_path in Path("GameData").rglob("*.ndf"):
|
||||
with src_path.open(encoding="utf-8") as f:
|
||||
tree = ndf.load(f)
|
||||
apply_patches(tree, src_path.name)
|
||||
out = Path("Mod") / src_path.relative_to("GameData")
|
||||
out.parent.mkdir(parents=True, exist_ok=True)
|
||||
with out.open("w", encoding="utf-8") as f:
|
||||
ndf.write(tree, f)
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 매 single field 변경 | by_name + value 직접 assign |
|
||||
| 매 bulk pattern 변경 | recursive walker function |
|
||||
| 매 새 unit 추가 | deepcopy + rename + add |
|
||||
| 매 cross-file reference | 매 파일별 parse + cross-link by GUID |
|
||||
| 매 schema validation | custom walker + assertion |
|
||||
|
||||
**기본값**: 매 ndf-parse + Python script + git for version control. 매 manual NDF text edit 의 X.
|
||||
|
||||
## 🔗 Graph
|
||||
- 응용: [[WARNO Modding]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: NDF mod 작성 + LLM 의 patch generation, schema 추론, balance tweak suggestion.
|
||||
**언제 X**: 매 binary game asset (DDS, BANK) — 매 NDF X.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **매 raw regex 의 NDF edit**: 매 nested template 의 corruption 위험.
|
||||
- **encoding 누락**: NDF 는 UTF-8 (BOM 가능) — 매 default open() 의 fail.
|
||||
- **매 reference name 의 typo**: silent — 매 by_name() 의 None return.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (ndf-parse PyPI docs, Eugen modding wiki 2024).
|
||||
- 신뢰도 B (community-maintained).
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — ndf-parse API + WARNO mod patterns |
|
||||
@@ -0,0 +1,145 @@
|
||||
---
|
||||
id: wiki-2026-0508-ts-brand
|
||||
title: ts-brand
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [ts-brand library, Branded Types library, Nominal Typing TS]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [typescript, branded-types, nominal-typing, library, type-safety]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: typescript
|
||||
framework: ts-brand
|
||||
---
|
||||
|
||||
# ts-brand
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 zero-runtime-cost 의 nominal typing 의 TypeScript"**. ts-brand 는 매 structural typing 의 default 의 TypeScript 에 매 nominal-style brand 의 추가 → 매 UserId 와 매 OrderId 가 매 둘 다 string 이지만 매 swap 의 compile error. 매 2026 의 standard pattern — 매 Effect-TS, Zod, neverthrow 의 모두 의 leverage.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 problem (structural typing 의 limitation)
|
||||
- 매 TypeScript: 매 type UserId = string; type OrderId = string → 매 둘 다 동일 의 interchangeable.
|
||||
- 매 logical bug: 매 fn(userId: UserId) 의 orderId 의 pass 가 의 silent.
|
||||
|
||||
### 매 solution (Brand)
|
||||
- 매 phantom type tag 의 use → 매 compile-time discrimination.
|
||||
- 매 runtime cost = 0 (type-only).
|
||||
|
||||
### 매 ts-brand API
|
||||
- `Brand<Base, Tag>`: 매 branded type 의 create.
|
||||
- `make<T>()`: 매 cast helper.
|
||||
- 매 alternatives: 매 own-rolling, Effect-TS Brand, type-fest Opaque.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### 1. Basic Brand
|
||||
```typescript
|
||||
import { Brand, make } from 'ts-brand';
|
||||
|
||||
type UserId = Brand<string, 'UserId'>;
|
||||
type OrderId = Brand<string, 'OrderId'>;
|
||||
|
||||
const UserId = make<UserId>();
|
||||
const OrderId = make<OrderId>();
|
||||
|
||||
const u: UserId = UserId('u-123');
|
||||
const o: OrderId = OrderId('o-456');
|
||||
|
||||
function fetchUser(id: UserId) { /* ... */ }
|
||||
fetchUser(u); // ✓
|
||||
fetchUser(o); // ✗ Type error
|
||||
fetchUser('raw'); // ✗ Type error
|
||||
```
|
||||
|
||||
### 2. Validated Brand (with runtime check)
|
||||
```typescript
|
||||
type Email = Brand<string, 'Email'>;
|
||||
|
||||
function parseEmail(s: string): Email {
|
||||
if (!/^[^@]+@[^@]+\.[^@]+$/.test(s)) throw new Error(`invalid email: ${s}`);
|
||||
return s as Email;
|
||||
}
|
||||
|
||||
// 매 user 의 input 의 parseEmail 의 통과 만 의 Email 의 acquire.
|
||||
const e = parseEmail(req.body.email);
|
||||
```
|
||||
|
||||
### 3. Brand + Zod (parse 시 brand)
|
||||
```typescript
|
||||
import { z } from 'zod';
|
||||
import type { Brand } from 'ts-brand';
|
||||
|
||||
type UserId = Brand<string, 'UserId'>;
|
||||
const UserIdSchema = z.string().uuid().brand<'UserId'>();
|
||||
// ^? z.ZodBranded<z.ZodString, 'UserId'>
|
||||
|
||||
const id = UserIdSchema.parse('xxx-uuid'); // type: string & z.BRAND<'UserId'>
|
||||
// 매 Zod-native brand 의 ts-brand 와 의 compatible.
|
||||
```
|
||||
|
||||
### 4. Brand removal (rare, escape hatch)
|
||||
```typescript
|
||||
function brandOf<T extends Brand<any, any>>(b: T): UnwrapBrand<T> {
|
||||
return b as any;
|
||||
}
|
||||
type UnwrapBrand<T> = T extends Brand<infer U, any> ? U : never;
|
||||
|
||||
const raw: string = brandOf(u); // 매 e.g., logging
|
||||
```
|
||||
|
||||
### 5. Multi-brand (intersection)
|
||||
```typescript
|
||||
type NonEmpty = Brand<string, 'NonEmpty'>;
|
||||
type Trimmed = Brand<string, 'Trimmed'>;
|
||||
type Clean = NonEmpty & Trimmed;
|
||||
|
||||
function clean(s: string): Clean {
|
||||
const t = s.trim();
|
||||
if (!t) throw new Error('empty');
|
||||
return t as Clean;
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 매 ID type (UserId, OrderId) | brand 의 always |
|
||||
| 매 validated string (Email, URL) | brand + parse function |
|
||||
| 매 unit type (Meters, Seconds) | brand 의 use |
|
||||
| 매 throwaway local | 매 brand 의 skip |
|
||||
| 매 Zod ecosystem | z.brand<T>() 의 native 의 prefer |
|
||||
|
||||
**기본값**: 매 domain 의 distinct identity 의 string/number type → 매 brand 의 use.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[TypeScript]] · [[Nominal-Typing-in-TypeScript|Nominal Typing]]
|
||||
- 변형: [[Branded Types]] · [[Opaque Types (TypeScript)]]
|
||||
- 응용: [[Zod]] · [[Effect TS]] · [[Type Safety]]
|
||||
- Adjacent: [[Structural Typing]] · [[Runtime Validation]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: TypeScript domain modeling, ID type 의 distinguish, validation pipeline.
|
||||
**언제 X**: 매 simple script, runtime-only language (Python, JS).
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Cast 의 brand 의 bypass**: 매 type safety 의 break.
|
||||
- **Brand 의 너무 많음**: 매 cognitive overhead.
|
||||
- **Runtime check 없음 의 external input**: 매 brand 만 의 false security.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (ts-brand npm, Effect-TS Brand docs, Zod 4.x).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — ts-brand 의 API, Zod integration, patterns 의 expand |
|
||||
+210
@@ -0,0 +1,210 @@
|
||||
---
|
||||
id: wiki-2026-0508-가변적-lod-level-of-detail-시스템
|
||||
title: 가변적 LOD(Level of Detail) 시스템
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [LOD, Level of Detail, dynamic LOD, mesh simplification]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [graphics, gamedev, rendering, lod, optimization]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: TypeScript
|
||||
framework: Three.js / Bevy / Unreal Nanite
|
||||
---
|
||||
|
||||
# 가변적 LOD(Level of Detail) 시스템
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 LOD = 매 distance/screen-size 에 따라 매 mesh detail 을 매 동적 교체"**. 매 close 매 high-poly, 매 far 매 low-poly. 매 fixed-bucket LOD (LOD0/1/2/3) 매 classic, 매 continuous/clustered LOD (Unreal Nanite, Bevy meshlet) 매 2026 SOTA — 매 hierarchical cluster + GPU culling 으로 매 sub-pixel triangles 까지 매 streaming.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 motivation
|
||||
- 매 GPU 매 triangle/pixel budget 유한.
|
||||
- 매 멀리 있는 mesh 의 매 millions of triangles 매 1픽셀에 매 수십 — 매 waste + aliasing.
|
||||
- 매 적절한 detail 매 close → 매 가까이 모이는 비용 ↓, 매 visual quality ↑.
|
||||
|
||||
### 매 LOD 종류
|
||||
1. **Discrete LOD**: 매 N개의 pre-built mesh, 매 distance threshold 에서 swap. 매 popping 가능.
|
||||
2. **Continuous LOD (CLOD)**: edge-collapse 매 progressive mesh, 매 smooth transition. 매 CPU heavy.
|
||||
3. **Hierarchical LOD (HLOD)**: 매 region-level 매 single mesh 병합 (먼 city block → 1 mesh).
|
||||
4. **Cluster/Meshlet LOD** (Nanite, Bevy 0.13+): 매 mesh를 매 ~128-tri cluster 로 분해 + 매 BVH, 매 GPU 가 매 cluster 단위로 매 select.
|
||||
5. **Imposter / Billboard**: 매 texture 1장으로 매 멀리서 fake.
|
||||
6. **Tessellation LOD**: 매 GPU tess shader 가 매 dynamic subdivide.
|
||||
|
||||
### 매 selection criteria
|
||||
- **Distance**: euclidean distance 매 가장 단순.
|
||||
- **Screen-space size**: bounding sphere → projected pixel size — 매 정확.
|
||||
- **Velocity / motion**: 매 빠른 object 매 lower LOD 가용.
|
||||
- **Importance**: 매 player focus / center → high LOD.
|
||||
|
||||
### 매 응용
|
||||
1. **Open-world game**: terrain, vegetation, building.
|
||||
2. **Voxel world**: chunk LOD by distance.
|
||||
3. **Crowd rendering**: 매 distant NPC 매 imposter.
|
||||
4. **Vegetation**: tree → bush → billboard.
|
||||
5. **CAD 시각화**: 매 model assembly 매 distant simplify.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Pattern 1: Three.js LOD basic
|
||||
```typescript
|
||||
import * as THREE from "three";
|
||||
|
||||
const lod = new THREE.LOD();
|
||||
lod.addLevel(highMesh, 0); // 0–50
|
||||
lod.addLevel(midMesh, 50); // 50–200
|
||||
lod.addLevel(lowMesh, 200); // 200–500
|
||||
lod.addLevel(billboard, 500); // 500+
|
||||
|
||||
scene.add(lod);
|
||||
// renderer 가 매 frame 마다 camera.position 으로 자동 select
|
||||
```
|
||||
|
||||
### Pattern 2: screen-space size 기반
|
||||
```typescript
|
||||
function selectLOD(obj: THREE.Object3D, camera: THREE.Camera) {
|
||||
const sphere = new THREE.Sphere();
|
||||
obj.traverse((c) => {
|
||||
if (c instanceof THREE.Mesh) c.geometry.computeBoundingSphere();
|
||||
});
|
||||
const dist = camera.position.distanceTo(obj.position);
|
||||
const fov = (camera as THREE.PerspectiveCamera).fov * Math.PI / 180;
|
||||
const screenH = window.innerHeight;
|
||||
const projected = (sphere.radius / dist) / Math.tan(fov / 2) * screenH;
|
||||
|
||||
if (projected > 200) return 0; // high
|
||||
if (projected > 50) return 1; // mid
|
||||
if (projected > 10) return 2; // low
|
||||
return 3; // billboard
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 3: voxel chunk LOD
|
||||
```typescript
|
||||
// each chunk has 4 mesh resolutions
|
||||
type Chunk = { x: number; z: number; meshes: [Mesh, Mesh, Mesh, Mesh] };
|
||||
|
||||
function chunkLOD(c: Chunk, camera: Camera): number {
|
||||
const dx = c.x * CHUNK_SIZE - camera.x;
|
||||
const dz = c.z * CHUNK_SIZE - camera.z;
|
||||
const d = Math.sqrt(dx * dx + dz * dz);
|
||||
if (d < 100) return 0;
|
||||
if (d < 300) return 1;
|
||||
if (d < 700) return 2;
|
||||
return 3;
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 4: hysteresis (popping 완화)
|
||||
```typescript
|
||||
// LOD swap 시 매 threshold 에 매 hysteresis 추가
|
||||
function selectLODHysteresis(dist: number, currentLOD: number): number {
|
||||
const THR = [50, 200, 500];
|
||||
const HYS = 10; // ±10
|
||||
if (currentLOD === 0 && dist > THR[0] + HYS) return 1;
|
||||
if (currentLOD === 1 && dist < THR[0] - HYS) return 0;
|
||||
if (currentLOD === 1 && dist > THR[1] + HYS) return 2;
|
||||
// ...
|
||||
return currentLOD;
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 5: GPU instancing per LOD
|
||||
```typescript
|
||||
// 매 LOD level 별 매 InstancedMesh, 매 entity 매 batch
|
||||
const instancedHigh = new THREE.InstancedMesh(highGeo, mat, MAX);
|
||||
const instancedMid = new THREE.InstancedMesh(midGeo, mat, MAX);
|
||||
// per frame: 매 entity 의 LOD 결정 → 매 해당 instance 행렬 update
|
||||
```
|
||||
|
||||
### Pattern 6: Bevy meshlet (2026)
|
||||
```rust
|
||||
// Bevy 0.13+ — meshlet rendering (cluster LOD)
|
||||
use bevy::pbr::experimental::meshlet::*;
|
||||
|
||||
commands.spawn((
|
||||
MeshletMesh3d(asset_server.load("model.meshlet_mesh")),
|
||||
Transform::default(),
|
||||
));
|
||||
// GPU 가 매 cluster bvh + screen-space error 로 자동 select
|
||||
```
|
||||
|
||||
### Pattern 7: imposter texture (vegetation)
|
||||
```glsl
|
||||
// fragment shader: 매 distance > THRESHOLD → 매 sample atlas billboard
|
||||
uniform float u_distToCam;
|
||||
uniform sampler2D u_imposterAtlas;
|
||||
|
||||
void main() {
|
||||
if (u_distToCam > 200.0) {
|
||||
vec4 imp = texture(u_imposterAtlas, vUV);
|
||||
if (imp.a < 0.5) discard;
|
||||
gl_FragColor = imp;
|
||||
} else {
|
||||
// full mesh shading
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 8: progressive mesh (edge collapse offline)
|
||||
```typescript
|
||||
// build time: 매 mesh → edge collapse sequence
|
||||
type Collapse = { v0: number; v1: number; targetVertex: number };
|
||||
const collapses: Collapse[] = simplify(mesh);
|
||||
|
||||
// runtime: 매 LOD level k → apply collapses[0..k]
|
||||
function applyLOD(mesh: Mesh, level: number) {
|
||||
for (let i = 0; i < level; i++) collapseEdge(mesh, collapses[i]);
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 9: HLOD region merge
|
||||
```typescript
|
||||
// 매 build time: cluster 9 buildings → 1 merged mesh per region
|
||||
// runtime: distance > 1km → region mesh, < 1km → individual buildings
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 게임 props (rocks, trees) | Discrete LOD + imposter |
|
||||
| Open-world terrain | Quadtree HLOD |
|
||||
| Voxel/Minecraft | Chunk LOD by ring |
|
||||
| Crowd (1k+ NPC) | Instancing + LOD + imposter |
|
||||
| Modern AAA / engine 자체 | Nanite / Bevy meshlet |
|
||||
| Scientific visualization | CLOD edge collapse |
|
||||
|
||||
**기본값**: discrete LOD 3-tier + imposter. 매 engine 이 cluster LOD 매 지원하면 우선.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Rendering]] · [[Optimization]]
|
||||
- 변형: [[Nanite]]
|
||||
- Adjacent: [[bitECS와 SharedArrayBuffer를 결합한 멀티스레드 고성능 아키텍처]] · [[Frustum Culling]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 large scene, 매 다양한 distance, 매 GPU/CPU bound. 매 1k+ object scene.
|
||||
**언제 X**: 매 small scene (single character), 매 fixed camera distance — overhead 만 추가.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Anti1: hard popping**: hysteresis/dither 없이 매 instant swap — 매 시각적 jarring.
|
||||
- **Anti2: 매 LOD level 별 mesh 따로 load**: 매 GPU memory 폭발. 매 progressive 또는 매 streaming.
|
||||
- **Anti3: distance only metric**: 매 huge object 매 멀어도 화면 큼 — screen-size 사용.
|
||||
- **Anti4: 매 tick 마다 LOD 재계산 every entity**: 매 batch / spatial hash 로 매 amortize.
|
||||
- **Anti5: imposter 의 매 stale lighting**: 매 shadow / time-of-day 안 맞음 — 매 atlas 재생성 필요.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Unreal Nanite paper SIGGRAPH 2021, Bevy 0.13 meshlet docs, Three.js LOD).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — LOD strategies + 2026 cluster LOD (Nanite/Meshlet) |
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
---
|
||||
id: wiki-2026-0508-가비지-컬렉션-garbage-collection
|
||||
title: 가비지 컬렉션 (Garbage Collection)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [GC, Garbage Collection, 메모리 관리]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [gc, memory, runtime, jvm, v8]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: Java/JS/Go
|
||||
framework: JVM/V8/Go-runtime
|
||||
---
|
||||
|
||||
# 가비지 컬렉션 (Garbage Collection)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 도달 불가능 (unreachable) 한 객체를 자동으로 회수하는 runtime memory manager"**. 1959 LISP의 mark-and-sweep 부터 현대의 ZGC/Shenandoah/G1 까지 — 매 generational + concurrent + region-based 방향으로 진화. 매 sub-millisecond pause 의 실용화 (2024+).
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 GC 의 근본 작업
|
||||
- **Mark**: GC root (stack, globals, registers) 부터 reachable graph traversal.
|
||||
- **Sweep / Compact / Copy**: unreachable 객체의 회수 + 매 fragmentation 의 처리.
|
||||
|
||||
### 매 주요 알고리즘
|
||||
- **Mark-and-Sweep**: 매 simple, 매 fragmentation 발생.
|
||||
- **Mark-Compact**: 매 sweep 후 live object 의 compact — fragmentation X.
|
||||
- **Copying (Cheney)**: 매 from-space → to-space 의 live copy. 매 generational young gen 에 사용.
|
||||
- **Generational**: 매 weak generational hypothesis — 매 young die young. 매 young gen frequent + old gen rare.
|
||||
- **Concurrent / Incremental**: 매 mutator thread 와 동시 실행 — pause 의 최소화.
|
||||
- **Region-based (G1, ZGC, Shenandoah)**: 매 heap 의 region 분할 — 매 partial collection.
|
||||
|
||||
### 매 응용
|
||||
1. JVM (G1 default since Java 9, ZGC production since Java 17, Shenandoah).
|
||||
2. V8 (Orinoco — concurrent + parallel + incremental).
|
||||
3. Go (concurrent tri-color mark-sweep, sub-ms pause).
|
||||
4. .NET CLR (generational + LOH).
|
||||
5. CPython (reference counting + cycle detector).
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Tri-color Marking (concurrent GC 의 기반)
|
||||
```python
|
||||
# Tri-color invariant: White (unmarked), Gray (marked, children pending), Black (done)
|
||||
WHITE, GRAY, BLACK = 0, 1, 2
|
||||
|
||||
def tri_color_mark(roots, heap):
|
||||
for obj in heap:
|
||||
obj.color = WHITE
|
||||
gray_set = set()
|
||||
for r in roots:
|
||||
r.color = GRAY
|
||||
gray_set.add(r)
|
||||
while gray_set:
|
||||
obj = gray_set.pop()
|
||||
for child in obj.refs:
|
||||
if child.color == WHITE:
|
||||
child.color = GRAY
|
||||
gray_set.add(child)
|
||||
obj.color = BLACK
|
||||
# White = unreachable -> sweep
|
||||
return [o for o in heap if o.color == WHITE]
|
||||
```
|
||||
|
||||
### Write Barrier (concurrent GC 의 invariant 유지)
|
||||
```c
|
||||
// Dijkstra-style: black -> white write 발생 시 child를 gray로 승격
|
||||
void write_barrier(Object* parent, Object** field, Object* new_val) {
|
||||
if (parent->color == BLACK && new_val && new_val->color == WHITE) {
|
||||
new_val->color = GRAY;
|
||||
gray_queue_push(new_val);
|
||||
}
|
||||
*field = new_val;
|
||||
}
|
||||
```
|
||||
|
||||
### Generational Allocation (bump allocator)
|
||||
```rust
|
||||
struct YoungGen { start: *mut u8, top: *mut u8, end: *mut u8 }
|
||||
|
||||
impl YoungGen {
|
||||
fn alloc(&mut self, size: usize) -> Option<*mut u8> {
|
||||
unsafe {
|
||||
let new_top = self.top.add(size);
|
||||
if new_top > self.end { return None; } // trigger minor GC
|
||||
let p = self.top;
|
||||
self.top = new_top;
|
||||
Some(p)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Reference Counting + Cycle Detection (CPython)
|
||||
```python
|
||||
class Obj:
|
||||
def __init__(self):
|
||||
self.refcount = 1
|
||||
def incref(self): self.refcount += 1
|
||||
def decref(self):
|
||||
self.refcount -= 1
|
||||
if self.refcount == 0:
|
||||
for child in self.refs: child.decref()
|
||||
free(self)
|
||||
# Cycle: a.refs=[b], b.refs=[a] -> refcount 영원히 >0 -> cycle collector 필요
|
||||
```
|
||||
|
||||
### Finalizer (resource cleanup, careful)
|
||||
```java
|
||||
// Java AutoCloseable + try-with-resources >>> finalize() (deprecated in Java 9+)
|
||||
try (var conn = DriverManager.getConnection(url)) {
|
||||
// use conn
|
||||
} // auto-close, deterministic
|
||||
```
|
||||
|
||||
### Soft / Weak / Phantom Reference
|
||||
```java
|
||||
WeakReference<Cache> ref = new WeakReference<>(cache);
|
||||
// GC가 free하면 ref.get() == null. Cache 구현에 자주 사용
|
||||
```
|
||||
|
||||
### G1 / ZGC tuning (JVM)
|
||||
```bash
|
||||
java -XX:+UseZGC -Xmx16g -XX:+UseLargePages MyApp
|
||||
# ZGC: <1ms pause, multi-TB heap (Java 21+)
|
||||
java -XX:+UseG1GC -XX:MaxGCPauseMillis=200 MyApp
|
||||
# G1: pause-target driven, default since Java 9
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Low-latency service (<10ms p99) | ZGC, Shenandoah, Go GC |
|
||||
| Throughput batch | Parallel GC (JVM), G1 |
|
||||
| Embedded / no-GC | Rust, C++ RAII |
|
||||
| Predictable real-time | No GC + arena allocator |
|
||||
| Reference cycles 빈번 | tracing GC > refcount |
|
||||
|
||||
**기본값**: 매 modern JVM 의 **G1** (or ZGC for >4GB heap), Go 의 **default concurrent collector**.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[메모리 관리]]
|
||||
- 변형: [[Reference Counting]]
|
||||
- 응용: [[V8 Engine]]
|
||||
- Adjacent: [[Memory Leak]] · [[Heap]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: GC tuning, OOM 분석, GC log 해석, allocation pattern 최적화.
|
||||
**언제 X**: 매 hot loop allocation 미세조정 — profiler (async-profiler, pprof) 가 우선.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **System.gc() 호출**: hint 일 뿐, full GC 강제로 pause 유발.
|
||||
- **finalize() 의존**: 매 deprecated. AutoCloseable 사용.
|
||||
- **Large object 의 young gen 할당 가정**: TLAB overflow → tenuring promotion 발생.
|
||||
- **WeakReference cache 의 무한 신뢰**: 매 GC pressure 시 즉시 회수 — cold start.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Jones et al. *The Garbage Collection Handbook* 2nd ed., OpenJDK ZGC docs 2024).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — GC algorithms + tri-color + JVM/Go tuning patterns |
|
||||
@@ -0,0 +1,166 @@
|
||||
---
|
||||
id: wiki-2026-0508-가상현실-멀미-vr-sickness
|
||||
title: 가상현실 멀미 (VR Sickness)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [VR Sickness, Cybersickness, Motion Sickness in VR]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [vr, ux, perception, motion-sickness, hmd]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: C#
|
||||
framework: Unity/Unreal
|
||||
---
|
||||
|
||||
# 가상현실 멀미 (VR Sickness)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 vestibular (전정) 와 visual (시각) input 의 mismatch 로 발생하는 nausea / disorientation"**. 매 motion sickness 의 inverse — 매 눈은 움직임을 보지만 몸은 정지. 매 90+ FPS, low-latency tracking, comfort locomotion 으로 완화. 매 Quest 3 / Vision Pro 시대에도 여전히 핵심 UX 문제.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 원인 (sensory conflict theory)
|
||||
- **Vection**: 매 visual self-motion 의 인지 (정지한 vestibular 와 conflict).
|
||||
- **Latency**: motion-to-photon >20ms — 매 멀미 유발.
|
||||
- **Frame rate dip**: 90Hz → 60Hz drop 의 즉시 swimming sensation.
|
||||
- **Field of view + speed**: 매 wide FOV + fast translation = 매 worst.
|
||||
- **Postural instability**: 매 head tracking error / drift.
|
||||
|
||||
### 매 완화 기법
|
||||
- **High refresh rate**: 90/120Hz 표준 (Quest 3 = 120Hz, Vision Pro = 90/96Hz).
|
||||
- **Low motion-to-photon latency**: <20ms target.
|
||||
- **Vignette / Tunneling**: 매 turn / locomotion 시 peripheral 차단.
|
||||
- **Teleport locomotion**: 매 smooth movement 의 회피.
|
||||
- **Snap turning**: 30/45° discrete rotation.
|
||||
- **Stable horizon / cockpit**: 매 reference frame 의 제공.
|
||||
- **Comfort rating**: Comfortable / Moderate / Intense — 매 store labeling.
|
||||
|
||||
### 매 응용
|
||||
1. VR game design (Half-Life: Alyx, Beat Saber).
|
||||
2. Training sim (medical, military, flight).
|
||||
3. VR therapy 의 조정 (exposure therapy, PTSD).
|
||||
4. Industrial design review.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Unity 의 vignette on locomotion (URP)
|
||||
```csharp
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
|
||||
public class ComfortVignette : MonoBehaviour {
|
||||
[SerializeField] Volume volume;
|
||||
Vignette vignette;
|
||||
public CharacterController player;
|
||||
|
||||
void Start() { volume.profile.TryGet(out vignette); }
|
||||
void Update() {
|
||||
float speed = player.velocity.magnitude;
|
||||
// 매 빠를수록 매 강한 vignette
|
||||
vignette.intensity.value = Mathf.Clamp01(speed / 5f) * 0.6f;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Snap Turn 구현
|
||||
```csharp
|
||||
public class SnapTurn : MonoBehaviour {
|
||||
public float snapAngle = 30f;
|
||||
public Transform xrRig;
|
||||
bool turning;
|
||||
|
||||
void Update() {
|
||||
float x = Input.GetAxis("RightStickX");
|
||||
if (Mathf.Abs(x) > 0.7f && !turning) {
|
||||
xrRig.Rotate(0, Mathf.Sign(x) * snapAngle, 0);
|
||||
turning = true;
|
||||
}
|
||||
if (Mathf.Abs(x) < 0.3f) turning = false;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Teleport locomotion (XR Interaction Toolkit)
|
||||
```csharp
|
||||
// XR Interaction Toolkit 의 TeleportationProvider + TeleportationArea 사용.
|
||||
// 매 thumbstick forward → arc raycast → release → fade-to-black → reposition.
|
||||
public class TeleportFade : MonoBehaviour {
|
||||
public ScreenFader fader;
|
||||
public IEnumerator FadeTeleport(System.Action moveAction) {
|
||||
yield return fader.FadeOut(0.15f);
|
||||
moveAction();
|
||||
yield return fader.FadeIn(0.15f);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Frame rate budget guard (Unity profiler)
|
||||
```csharp
|
||||
void Update() {
|
||||
float dt = Time.unscaledDeltaTime;
|
||||
if (dt > 1f / 80f) { // 12.5ms — 90Hz budget 위반
|
||||
Debug.LogWarning($"Frame {dt*1000:F1}ms — VR comfort risk");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Stable cockpit reference (vehicle VR)
|
||||
```csharp
|
||||
// 매 driver 시점 — 매 cockpit 매 항상 보이도록.
|
||||
// 매 strong reference frame 으로 vection 감소.
|
||||
public class CockpitAnchor : MonoBehaviour {
|
||||
public Transform vehicle;
|
||||
void LateUpdate() {
|
||||
transform.position = vehicle.position;
|
||||
transform.rotation = vehicle.rotation;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Async time warp / reprojection (built-in to Quest, Vision Pro)
|
||||
```csharp
|
||||
// 매 platform 자동 — frame miss 시 last frame 의 reproject.
|
||||
// 매 dev 작업: 매 frame budget 안정 유지로 reproject 발동 X 가 best.
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 매 first-person locomotion | teleport + comfort vignette |
|
||||
| 매 cockpit (car, plane) | smooth motion OK + stable reference frame |
|
||||
| 매 turning | snap turn (default), smooth turn (option) |
|
||||
| 매 wide FOV + fast | vignette + reduced FOV |
|
||||
| 매 cinematic camera | 매 user-controlled — automated camera 의 X |
|
||||
|
||||
**기본값**: 매 90Hz+, teleport locomotion, snap turn 30°, comfort vignette, motion-to-photon <20ms.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Virtual Reality]]
|
||||
- 변형: [[Cybersickness]] · [[Simulator Sickness]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: VR UX review, comfort rating 추정, locomotion design feedback.
|
||||
**언제 X**: 매 individual susceptibility 진단 — 매 user testing 필수.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Cinematic forced camera**: 매 user 통제 X — 즉시 멀미.
|
||||
- **60Hz VR**: 매 사실상 unusable.
|
||||
- **Floating UI head-locked**: 매 head movement 따라 밀착 → vection.
|
||||
- **Acceleration-heavy locomotion**: jerk 의 직접 유발.
|
||||
- **No comfort rating disclosure**: 매 store policy 위반 (Quest, Steam).
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (LaViola *3D User Interfaces* 2nd ed. 2017, Meta VR Design Guidelines 2024, Apple visionOS HIG).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — sensory conflict + comfort techniques + Unity patterns |
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
---
|
||||
id: wiki-2026-0508-객체-지향-프로그래밍-object-oriented-prog
|
||||
title: 객체 지향 프로그래밍 (Object-Oriented Programming)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [OOP, Object-Oriented Programming, 객체지향]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [oop, encapsulation, polymorphism, paradigm]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: Java/TS/Python
|
||||
framework: agnostic
|
||||
---
|
||||
|
||||
# 객체 지향 프로그래밍 (Object-Oriented Programming)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 state + behavior 를 object 로 묶어 message passing 으로 협력시키는 패러다임"**. Smalltalk (1972) → C++/Java → 매 modern composition-over-inheritance + interface-driven 으로 진화. 매 2026 의 OOP 는 functional core + OO shell 의 hybrid 가 dominant.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 4 기둥
|
||||
- **Encapsulation**: state 의 hide + 매 invariant 의 보호.
|
||||
- **Abstraction**: 매 interface 만 노출 — implementation hide.
|
||||
- **Inheritance**: 매 sub-class 의 reuse — 매 fragile base class 위험.
|
||||
- **Polymorphism**: subtype / parametric / ad-hoc — 매 substitutability.
|
||||
|
||||
### 매 modern OOP 의 best practice
|
||||
- **Composition > Inheritance**: 매 has-a >> is-a.
|
||||
- **Program to interface**: 매 concrete type 의 dependency X.
|
||||
- **SOLID**: SRP / OCP / LSP / ISP / DIP.
|
||||
- **Immutable by default**: record / data class / value object.
|
||||
|
||||
### 매 응용
|
||||
1. UI framework (React class — but hooks shifted toward functional).
|
||||
2. Game engine (Unity GameObject / Component).
|
||||
3. ORM entity (JPA / SQLAlchemy / Active Record).
|
||||
4. GUI (Swing, Qt, AppKit).
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Encapsulation + invariant
|
||||
```java
|
||||
public class Account {
|
||||
private long balanceCents; // private = hidden
|
||||
public void deposit(long cents) {
|
||||
if (cents <= 0) throw new IllegalArgumentException();
|
||||
this.balanceCents += cents;
|
||||
}
|
||||
public long getBalanceCents() { return balanceCents; }
|
||||
// 매 setter 없음 — invariant 보호
|
||||
}
|
||||
```
|
||||
|
||||
### Polymorphism (interface)
|
||||
```typescript
|
||||
interface PaymentMethod {
|
||||
charge(amountCents: number): Promise<TxResult>;
|
||||
}
|
||||
class StripeCard implements PaymentMethod {
|
||||
async charge(c: number) { /* stripe sdk */ return { ok: true }; }
|
||||
}
|
||||
class Paypal implements PaymentMethod {
|
||||
async charge(c: number) { /* paypal sdk */ return { ok: true }; }
|
||||
}
|
||||
async function checkout(pm: PaymentMethod, total: number) {
|
||||
return pm.charge(total); // 매 same call, different impl
|
||||
}
|
||||
```
|
||||
|
||||
### Composition over Inheritance
|
||||
```typescript
|
||||
// ❌ Inheritance hell
|
||||
// class FlyingFish extends Fish, Bird {} — multiple inheritance 문제
|
||||
|
||||
// ✅ Composition
|
||||
interface Swim { swim(): void }
|
||||
interface Fly { fly(): void }
|
||||
class Fish implements Swim { swim() { console.log("swim"); } }
|
||||
class Bird implements Fly { fly() { console.log("fly"); } }
|
||||
class FlyingFish implements Swim, Fly {
|
||||
private swimmer = new Fish();
|
||||
private flyer = new Bird();
|
||||
swim() { this.swimmer.swim(); }
|
||||
fly() { this.flyer.fly(); }
|
||||
}
|
||||
```
|
||||
|
||||
### Strategy Pattern
|
||||
```python
|
||||
from typing import Protocol
|
||||
class SortStrategy(Protocol):
|
||||
def sort(self, data: list[int]) -> list[int]: ...
|
||||
|
||||
class QuickSort:
|
||||
def sort(self, data): return sorted(data)
|
||||
class BubbleSort:
|
||||
def sort(self, data):
|
||||
d = data[:]
|
||||
for i in range(len(d)):
|
||||
for j in range(len(d)-i-1):
|
||||
if d[j] > d[j+1]: d[j], d[j+1] = d[j+1], d[j]
|
||||
return d
|
||||
|
||||
class Sorter:
|
||||
def __init__(self, strategy: SortStrategy):
|
||||
self.strategy = strategy
|
||||
def run(self, data):
|
||||
return self.strategy.sort(data)
|
||||
```
|
||||
|
||||
### Dependency Injection
|
||||
```java
|
||||
@Service
|
||||
class OrderService {
|
||||
private final OrderRepo repo;
|
||||
private final PaymentGateway gateway;
|
||||
public OrderService(OrderRepo r, PaymentGateway g) { // constructor inject
|
||||
this.repo = r; this.gateway = g;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Immutable Value Object (Java record)
|
||||
```java
|
||||
public record Money(long cents, String currency) {
|
||||
public Money {
|
||||
if (cents < 0) throw new IllegalArgumentException();
|
||||
}
|
||||
public Money add(Money other) {
|
||||
if (!currency.equals(other.currency)) throw new IllegalArgumentException();
|
||||
return new Money(cents + other.cents, currency);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Sealed Hierarchy (Java 17+, Kotlin, Scala)
|
||||
```java
|
||||
public sealed interface Shape permits Circle, Square, Triangle {}
|
||||
public record Circle(double r) implements Shape {}
|
||||
public record Square(double s) implements Shape {}
|
||||
public record Triangle(double a, double b, double c) implements Shape {}
|
||||
|
||||
double area(Shape s) {
|
||||
return switch (s) { // exhaustive
|
||||
case Circle c -> Math.PI * c.r() * c.r();
|
||||
case Square q -> q.s() * q.s();
|
||||
case Triangle t -> { /* heron */ yield 0; }
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 매 stateful entity (User, Order) | OOP class + invariant |
|
||||
| 매 stateless transformation | functional / pure function |
|
||||
| 매 plugin / extensibility | interface + DI |
|
||||
| 매 data-only | record / dataclass |
|
||||
| 매 algorithm dispatch | strategy / sealed + switch |
|
||||
|
||||
**기본값**: 매 immutable record + composition + interface + constructor DI. 매 deep inheritance 의 X.
|
||||
|
||||
## 🔗 Graph
|
||||
- 변형: [[Functional Programming]]
|
||||
- 응용: [[Design Patterns]] · [[SOLID]]
|
||||
- Adjacent: [[Domain-Driven Design]] · [[TypeScript 타입 시스템 (TypeScript Type System)|Type Systems]] · [[Encapsulation]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: class design review, SOLID 위반 발견, refactor toward composition.
|
||||
**언제 X**: 매 simple data transformation script — function 으로 충분.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **God Object**: 1000+ method 의 single class.
|
||||
- **Yo-yo Inheritance**: 매 6 단 deep — 매 행위 추적 불가.
|
||||
- **Anemic Object**: getter/setter 만, behavior 누락.
|
||||
- **Setter explosion**: 매 invariant 의 무력화.
|
||||
- **Tight coupling to concrete class**: 매 testability X.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Gamma et al. *GoF Design Patterns* 1994, Martin *Clean Architecture* 2017).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — 4 기둥 + composition + sealed hierarchy + DI |
|
||||
@@ -0,0 +1,215 @@
|
||||
---
|
||||
id: wiki-2026-0508-견고한-도메인-모델-및-api-계약-설계
|
||||
title: 견고한 도메인 모델 및 API 계약 설계
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Domain Model Design, API Contract Design, DDD]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [ddd, domain-model, api-design, contract, type-driven]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: TypeScript/Java
|
||||
framework: Zod/Pydantic/OpenAPI
|
||||
---
|
||||
|
||||
# 견고한 도메인 모델 및 API 계약 설계
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 type-driven domain model + 매 versioned API contract 의 결합으로 매 invalid state 를 unrepresentable 로 만든다"**. 매 DDD aggregate + value object + Zod/Pydantic schema + OpenAPI contract — 매 2024 modern stack.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 도메인 모델 의 견고함
|
||||
- **Value Object**: 매 immutable + equality by value (Money, Email, OrderId).
|
||||
- **Entity / Aggregate Root**: 매 identity + lifecycle + invariant 보호.
|
||||
- **Make illegal states unrepresentable**: 매 sum type / discriminated union 사용.
|
||||
- **Smart Constructor**: 매 raw type → validated branded type 의 single entry.
|
||||
|
||||
### 매 API 계약 의 견고함
|
||||
- **Schema-first**: OpenAPI / JSON Schema / GraphQL SDL — 매 source of truth.
|
||||
- **Backward compat**: additive change only, 매 deprecation header, version in URL/header.
|
||||
- **Idempotency key**: 매 mutation 의 retry-safe 화.
|
||||
- **Pagination + filter + sort 표준화**: cursor-based >>> offset-based.
|
||||
|
||||
### 매 응용
|
||||
1. e-commerce checkout (Money, Cart, Order aggregate).
|
||||
2. Banking (Account, Transaction, immutable ledger).
|
||||
3. Multi-tenant SaaS (Tenant 의 invariant 격리).
|
||||
4. Public API (Stripe-style versioned contract).
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### 매 Branded type (TS) — primitive obsession 의 회피
|
||||
```typescript
|
||||
type Brand<T, B> = T & { __brand: B };
|
||||
type Email = Brand<string, "Email">;
|
||||
type UserId = Brand<string, "UserId">;
|
||||
|
||||
const parseEmail = (s: string): Email => {
|
||||
if (!/^[^@]+@[^@]+$/.test(s)) throw new Error("Invalid email");
|
||||
return s as Email;
|
||||
};
|
||||
|
||||
function send(to: Email, msg: string) { /* ... */ }
|
||||
send("not-email" as Email, "x"); // unsafe cast 만 통과 — 매 explicit
|
||||
send(parseEmail("a@b.com"), "x"); // safe path
|
||||
```
|
||||
|
||||
### Value Object (Money)
|
||||
```typescript
|
||||
class Money {
|
||||
private constructor(readonly amount: bigint, readonly currency: string) {}
|
||||
static of(amount: number, currency: string) {
|
||||
if (!Number.isFinite(amount)) throw new Error("non-finite");
|
||||
return new Money(BigInt(Math.round(amount * 100)), currency);
|
||||
}
|
||||
add(other: Money) {
|
||||
if (this.currency !== other.currency) throw new Error("currency mismatch");
|
||||
return new Money(this.amount + other.amount, this.currency);
|
||||
}
|
||||
equals(other: Money) {
|
||||
return this.amount === other.amount && this.currency === other.currency;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 매 illegal state unrepresentable (TS discriminated union)
|
||||
```typescript
|
||||
type OrderState =
|
||||
| { kind: "draft"; cart: CartLine[] }
|
||||
| { kind: "placed"; orderId: OrderId; placedAt: Date }
|
||||
| { kind: "shipped"; orderId: OrderId; tracking: string }
|
||||
| { kind: "cancelled"; reason: string };
|
||||
|
||||
function summary(o: OrderState) {
|
||||
switch (o.kind) {
|
||||
case "draft": return `Draft (${o.cart.length} items)`;
|
||||
case "placed": return `Placed ${o.orderId}`;
|
||||
case "shipped": return `Shipped ${o.tracking}`;
|
||||
case "cancelled": return `Cancelled: ${o.reason}`;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Zod schema (runtime + static type)
|
||||
```typescript
|
||||
import { z } from "zod";
|
||||
|
||||
const CreateOrderSchema = z.object({
|
||||
customerId: z.string().uuid(),
|
||||
items: z.array(z.object({
|
||||
sku: z.string().min(1),
|
||||
qty: z.number().int().positive().max(1000)
|
||||
})).min(1),
|
||||
idempotencyKey: z.string().uuid()
|
||||
});
|
||||
type CreateOrderReq = z.infer<typeof CreateOrderSchema>;
|
||||
|
||||
app.post("/orders", (req, res) => {
|
||||
const parsed = CreateOrderSchema.safeParse(req.body);
|
||||
if (!parsed.success) return res.status(400).json({ errors: parsed.error.issues });
|
||||
// parsed.data is fully typed
|
||||
});
|
||||
```
|
||||
|
||||
### Aggregate Root (invariant protection)
|
||||
```typescript
|
||||
class Order {
|
||||
private constructor(
|
||||
readonly id: OrderId,
|
||||
private state: OrderState,
|
||||
private lines: OrderLine[]
|
||||
) {}
|
||||
|
||||
addLine(line: OrderLine) {
|
||||
if (this.state.kind !== "draft") throw new Error("cannot modify placed order");
|
||||
if (this.lines.length >= 50) throw new Error("max 50 lines");
|
||||
this.lines.push(line);
|
||||
}
|
||||
place(): void {
|
||||
if (this.lines.length === 0) throw new Error("empty cart");
|
||||
this.state = { kind: "placed", orderId: this.id, placedAt: new Date() };
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### OpenAPI 의 versioned contract
|
||||
```yaml
|
||||
# openapi.yaml
|
||||
openapi: 3.1.0
|
||||
info: { title: Orders API, version: "2026-05-01" }
|
||||
paths:
|
||||
/v1/orders:
|
||||
post:
|
||||
parameters:
|
||||
- in: header
|
||||
name: Idempotency-Key
|
||||
required: true
|
||||
schema: { type: string, format: uuid }
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/CreateOrder' }
|
||||
responses:
|
||||
'201': { $ref: '#/components/responses/Order' }
|
||||
'409': { description: Idempotency conflict }
|
||||
```
|
||||
|
||||
### Cursor pagination
|
||||
```typescript
|
||||
type Page<T> = { items: T[]; nextCursor: string | null };
|
||||
async function listOrders(cursor?: string): Promise<Page<OrderDto>> {
|
||||
const rows = await db.query(
|
||||
"SELECT * FROM orders WHERE id > $1 ORDER BY id LIMIT 51",
|
||||
[cursor ?? ""]
|
||||
);
|
||||
const hasMore = rows.length === 51;
|
||||
const items = rows.slice(0, 50);
|
||||
return {
|
||||
items: items.map(toDto),
|
||||
nextCursor: hasMore ? items[items.length - 1].id : null
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 매 simple CRUD | DTO + validator (Zod/Pydantic) — DDD overkill |
|
||||
| 매 complex domain (banking, scheduling) | Aggregate + VO + invariant |
|
||||
| 매 public API | OpenAPI contract-first + version |
|
||||
| 매 internal RPC | gRPC / tRPC + protobuf / TS infer |
|
||||
| 매 event-driven | event schema (Avro/protobuf) + registry |
|
||||
|
||||
**기본값**: 매 schema-first (Zod / OpenAPI) + branded ID + idempotency + cursor pagination.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Domain-Driven Design]] · [[API Design]]
|
||||
- 변형: [[Hexagonal Architecture]] · [[Event Sourcing]] · [[CQRS]]
|
||||
- Adjacent: [[OpenAPI]] · [[gRPC]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: schema generation, contract review, illegal-state 발견, migration 전략.
|
||||
**언제 X**: 매 internal throwaway script — 매 over-engineering.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Primitive Obsession**: string everywhere — UserId 와 OrderId 의 swap silent.
|
||||
- **Anemic Domain**: getter/setter 만, business logic 의 service 누설.
|
||||
- **Shared Mutable Aggregate**: 매 invariant 의 broken.
|
||||
- **Breaking change in v1 endpoint**: 매 client 의 parallel 운영 X.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Evans *DDD* 2003, Vernon *Implementing DDD* 2013, Stripe API design guide 2024).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — branded types + Zod + OpenAPI + aggregate patterns |
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
---
|
||||
id: wiki-2026-0508-계층화-아키텍처-layered-architecture
|
||||
title: 계층화 아키텍처 (Layered Architecture)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Layered Architecture, N-tier, Tiered Architecture]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [architecture, layering, separation-of-concerns, n-tier]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: agnostic
|
||||
framework: Spring/.NET/Django
|
||||
---
|
||||
|
||||
# 계층화 아키텍처 (Layered Architecture)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 application 을 horizontal layer (presentation / business / persistence / data) 의 stack 으로 조직"**. 매 가장 흔한 default architecture — 매 simple, 매 onboarding 쉬움. 매 large-scale 에서 coupling/performance 한계 발생 → microservice/hexagonal 로 진화.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 표준 layer
|
||||
- **Presentation**: UI / REST controller / GraphQL resolver. 매 input 의 validation + serialization.
|
||||
- **Business / Service**: domain logic, transaction boundary, orchestration.
|
||||
- **Persistence / Repository**: ORM, query, cache.
|
||||
- **Data**: DB, file, message broker.
|
||||
|
||||
### 매 strict vs relaxed
|
||||
- **Strict layering**: 매 layer N 은 layer N-1 만 호출 가능. 매 testability 좋음.
|
||||
- **Relaxed**: layer skip 가능 (e.g. controller → repository 직접). 매 anti-pattern 으로 간주.
|
||||
|
||||
### 매 응용
|
||||
1. Spring Boot 의 @Controller / @Service / @Repository.
|
||||
2. Django 의 view / business / model.
|
||||
3. Clean Architecture 의 adapter ring 변형.
|
||||
4. .NET 의 N-tier WebAPI / BLL / DAL.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Spring Boot 의 표준 3-layer
|
||||
```java
|
||||
@RestController
|
||||
@RequestMapping("/orders")
|
||||
public class OrderController {
|
||||
private final OrderService service;
|
||||
public OrderController(OrderService s) { this.service = s; }
|
||||
|
||||
@PostMapping
|
||||
public OrderDto create(@RequestBody @Valid CreateOrderReq req) {
|
||||
return service.create(req);
|
||||
}
|
||||
}
|
||||
|
||||
@Service
|
||||
public class OrderService {
|
||||
private final OrderRepo repo;
|
||||
@Transactional
|
||||
public OrderDto create(CreateOrderReq req) {
|
||||
Order o = Order.from(req);
|
||||
return OrderDto.from(repo.save(o));
|
||||
}
|
||||
}
|
||||
|
||||
@Repository
|
||||
public interface OrderRepo extends JpaRepository<Order, Long> {}
|
||||
```
|
||||
|
||||
### DTO ↔ Domain 매 boundary
|
||||
```java
|
||||
// 매 controller 는 DTO 만, service 는 domain entity 만 다룬다.
|
||||
public record CreateOrderReq(String sku, int qty) {}
|
||||
public record OrderDto(Long id, String sku, int qty, String status) {
|
||||
public static OrderDto from(Order o) {
|
||||
return new OrderDto(o.getId(), o.getSku(), o.getQty(), o.getStatus().name());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Repository abstraction (testability)
|
||||
```java
|
||||
public interface OrderRepo {
|
||||
Order save(Order o);
|
||||
Optional<Order> findById(Long id);
|
||||
}
|
||||
// 매 unit test 의 Stub repository 의 inject:
|
||||
class StubOrderRepo implements OrderRepo { /* in-memory */ }
|
||||
```
|
||||
|
||||
### 매 cross-cutting (logging / tx / auth) 의 AOP
|
||||
```java
|
||||
@Aspect
|
||||
@Component
|
||||
class AuditAspect {
|
||||
@Around("@annotation(Audited)")
|
||||
public Object audit(ProceedingJoinPoint pjp) throws Throwable {
|
||||
long t0 = System.nanoTime();
|
||||
Object result = pjp.proceed();
|
||||
log.info("{} took {}ns", pjp.getSignature(), System.nanoTime() - t0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Layer 의 dependency rule (안티: upward call)
|
||||
```java
|
||||
// ❌ Service 가 Controller 호출 X
|
||||
// ❌ Repository 가 Service 호출 X
|
||||
// ✅ 매 한 방향: presentation → service → persistence
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| CRUD-heavy MVP | 매 layered (default 선택) |
|
||||
| 매 complex domain logic | hexagonal / clean architecture |
|
||||
| 매 high decoupling 필요 | event-driven / CQRS |
|
||||
| 매 large team / bounded context | microservice |
|
||||
| 매 simple script | 매 layer X — single file |
|
||||
|
||||
**기본값**: 매 small/medium app 은 **3-layer (controller / service / repository)** + DI + DTO boundary.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Software Architecture]]
|
||||
- 변형: [[Hexagonal Architecture]] · [[Clean Architecture]] · [[Onion Architecture]]
|
||||
- 응용: [[Spring Boot]] · [[ASP.NET Core]]
|
||||
- Adjacent: [[Separation of Concerns]] · [[Dependency Injection]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: scaffolding generation, layer 위반 review, refactor towards layered.
|
||||
**언제 X**: 매 trivial CRUD — boilerplate overhead.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Anemic Service**: 매 service 가 단순 repo passthrough — domain logic 누락.
|
||||
- **Smart Controller**: business logic 의 controller 누수.
|
||||
- **Layer skip**: controller 가 repo 직접 호출.
|
||||
- **God Service**: 매 service class 가 5000+ lines — bounded context 분할 필요.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Richards *Software Architecture Patterns* 2nd ed. 2022).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — layered patterns + Spring example + anti-patterns |
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
---
|
||||
id: wiki-2026-0508-과잉-속성-체크-excess-property-checkin
|
||||
title: 과잉 속성 체크 (Excess Property Checking)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Excess Property Checking, EPC, TS Excess Property]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [typescript, type-system, structural-typing, epc]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: TypeScript
|
||||
framework: TS 5.x
|
||||
---
|
||||
|
||||
# 과잉 속성 체크 (Excess Property Checking)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 object literal 을 직접 assign / pass 할 때만 발동하는 TS 의 추가 strictness rule"**. 매 structural typing 의 원칙적으론 OK 인 extra property 를 매 fresh object literal 에 한해 error 로 잡아 typo 방지. 매 변수 경유 시 자동 비활성화.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 작동 방식
|
||||
- TS 의 **structural / duck typing** 은 매 extra property OK.
|
||||
- 그러나 매 **object literal 을 fresh 하게 assign 시** TS 는 추가로 surplus key 를 error 로 보고.
|
||||
- 매 변수에 한 번 alias 하면 fresh 신호가 사라져 EPC 우회.
|
||||
|
||||
### 매 발동 조건
|
||||
- 매 object literal 의 직접 assignment / argument / return.
|
||||
- 매 contextual type 이 존재.
|
||||
- 매 변수 경유, type assertion (`as`), spread 시 비활성화.
|
||||
|
||||
### 매 응용
|
||||
1. Component prop typo 방지 (React).
|
||||
2. API request body 의 surplus field 차단.
|
||||
3. Config object 의 misnamed key 발견.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### 매 EPC 발동 (error)
|
||||
```typescript
|
||||
interface User { name: string; age: number }
|
||||
|
||||
const u: User = { name: "Lee", age: 30, emial: "x" };
|
||||
// ^^^^^ 매 EPC: 'emial' does not exist on User
|
||||
```
|
||||
|
||||
### 매 변수 경유 우회 (error 사라짐)
|
||||
```typescript
|
||||
const raw = { name: "Lee", age: 30, emial: "x" };
|
||||
const u: User = raw; // ✅ OK — fresh 아니라 EPC 비활성
|
||||
// 매 structural compatibility 만 본다 (User 의 모든 prop 충족 → OK)
|
||||
```
|
||||
|
||||
### 매 함수 인자 EPC
|
||||
```typescript
|
||||
function greet(u: User) { console.log(u.name); }
|
||||
greet({ name: "A", age: 1, extra: 1 }); // ❌ EPC error
|
||||
const x = { name: "A", age: 1, extra: 1 };
|
||||
greet(x); // ✅ OK
|
||||
```
|
||||
|
||||
### 매 index signature 의 escape hatch
|
||||
```typescript
|
||||
interface Loose {
|
||||
name: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
const l: Loose = { name: "A", whatever: 123, deep: { x: 1 } }; // ✅ OK
|
||||
```
|
||||
|
||||
### 매 union type 의 EPC quirk
|
||||
```typescript
|
||||
type A = { kind: "a"; a: number };
|
||||
type B = { kind: "b"; b: number };
|
||||
|
||||
const x: A | B = { kind: "a", a: 1, b: 2 };
|
||||
// ❌ EPC: 'b' is not in A; not in B 의 fresh form
|
||||
// 매 변수 경유 시 통과 — 의도치 않은 leakage 가능
|
||||
```
|
||||
|
||||
### 매 의도적 우회 (type assertion — 위험)
|
||||
```typescript
|
||||
const u: User = { name: "A", age: 1, emial: "x" } as User;
|
||||
// ⚠ 매 작동하지만 매 typo 의 silent — 매 강력히 X
|
||||
```
|
||||
|
||||
### 매 React component prop typo 방지
|
||||
```typescript
|
||||
type ButtonProps = { label: string; onClick: () => void };
|
||||
const Button = (p: ButtonProps) => <button onClick={p.onClick}>{p.label}</button>;
|
||||
|
||||
<Button labl="Hi" onClick={() => {}} />; // ❌ EPC: 'labl' typo 발견
|
||||
```
|
||||
|
||||
### 매 satisfies operator (TS 4.9+) — 매 EPC 유지 + inference
|
||||
```typescript
|
||||
const config = {
|
||||
port: 8080,
|
||||
host: "localhost",
|
||||
// typoKey: 1 // ❌ EPC error if uncomment
|
||||
} satisfies { port: number; host: string };
|
||||
// 매 config.port: number 의 narrow type 유지 + EPC 활성
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 매 strict typo 검출 | 매 object literal 직접 assign + EPC 활용 |
|
||||
| 매 동적 key 다수 | index signature 추가 |
|
||||
| 매 narrow + EPC 동시 | `satisfies` operator |
|
||||
| 매 변수 경유 필요 | type annotation 변수 + literal 사용 |
|
||||
| 매 EPC 의도적 회피 | 매 보통 X — type 의 재설계 |
|
||||
|
||||
**기본값**: 매 object literal 의 직접 assign + `satisfies` 또는 explicit type — 매 변수 경유 의 무의식적 우회 X.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[TypeScript]] · [[구조적 타이핑(Structural Typing)]]
|
||||
- 변형: [[satisfies operator]]
|
||||
- 응용: [[API Contract]]
|
||||
- Adjacent: [[Type Narrowing]] · [[Discriminated Union]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: TS error 디버깅 ("excess property"), refactor 시 EPC 의도 검증.
|
||||
**언제 X**: 매 runtime validation — 매 EPC 는 컴파일타임만.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **as Type 으로 EPC 회피**: 매 typo 의 silent.
|
||||
- **변수 경유 의 우회**: 매 의도면 OK, 매 실수면 위험.
|
||||
- **EPC 비활성화 의 흔한 오해**: 매 spread `{ ...x, extra: 1 }` 의 fresh — EPC 발동.
|
||||
- **runtime 신뢰**: EPC 는 매 compile-time only — 매 런타임 검증 X.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (TypeScript Handbook — Object Types, TS 5.x source).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — EPC 발동 조건 + 우회 + satisfies |
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
---
|
||||
id: wiki-2026-0508-관심사의-분리-separation-of-concerns
|
||||
title: 관심사의 분리 (Separation of Concerns)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [SoC, Separation of Concerns, 관심사 분리]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [soc, modularity, design-principle, architecture]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: agnostic
|
||||
framework: agnostic
|
||||
---
|
||||
|
||||
# 관심사의 분리 (Separation of Concerns)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 system 을 서로 겹치지 않는 concern 단위로 쪼개 각각이 독립 변경 가능하도록 한다"**. Dijkstra (1974) — 매 modularity 의 근본 원리. 매 layer / module / function / file 모든 scale 에 적용. 매 변경의 locality + 매 testability 를 동시에 얻는다.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 SoC 의 본질
|
||||
- **Concern**: 매 system 이 처리하는 distinct topic (UI, persistence, billing, auth).
|
||||
- **Separation**: 매 concern 별로 코드/모듈/팀/배포 단위 분리.
|
||||
- **Independent change**: concern A 의 변경이 B 의 코드 수정 X.
|
||||
|
||||
### 매 적용 scale
|
||||
- **Function**: 매 single responsibility (SRP).
|
||||
- **Module**: 매 cohesion 높음 + coupling 낮음.
|
||||
- **Layer**: presentation / business / persistence (layered arch).
|
||||
- **Service**: bounded context / microservice.
|
||||
- **Repository**: monorepo path / multirepo.
|
||||
|
||||
### 매 응용
|
||||
1. MVC / MVP / MVVM.
|
||||
2. Clean / Hexagonal Architecture (port-adapter 분리).
|
||||
3. Aspect-Oriented Programming (cross-cutting 분리).
|
||||
4. Microservice (bounded context 분리).
|
||||
5. CSS-in-JS vs separate stylesheet — 매 variant.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Function-level: 매 1 함수 = 1 개념
|
||||
```typescript
|
||||
// ❌ Mixed
|
||||
function processOrder(input: any) {
|
||||
if (!input.email) throw new Error("invalid"); // validation
|
||||
const tax = input.amount * 0.1; // tax calc
|
||||
db.execute("INSERT INTO orders ..."); // persistence
|
||||
smtp.send(input.email, "Confirmed"); // notification
|
||||
}
|
||||
|
||||
// ✅ Separated
|
||||
function validate(input: OrderInput): Order { /* ... */ return order; }
|
||||
function computeTax(order: Order): Money { /* ... */ }
|
||||
async function persist(order: Order, tax: Money): Promise<OrderId> { /* ... */ }
|
||||
async function notify(order: Order): Promise<void> { /* ... */ }
|
||||
async function processOrder(input: OrderInput) {
|
||||
const order = validate(input);
|
||||
const tax = computeTax(order);
|
||||
const id = await persist(order, tax);
|
||||
await notify(order);
|
||||
return id;
|
||||
}
|
||||
```
|
||||
|
||||
### Module: 매 dependency direction
|
||||
```
|
||||
src/
|
||||
├── domain/ ← 매 pure logic (no IO)
|
||||
├── application/ ← 매 use cases (orchestration)
|
||||
├── infrastructure/ ← DB, HTTP, queue
|
||||
└── interface/ ← controller, CLI
|
||||
```
|
||||
|
||||
### MVC (web)
|
||||
```python
|
||||
# model.py
|
||||
class User: ...
|
||||
|
||||
# view.py (template)
|
||||
def render_user(user): ...
|
||||
|
||||
# controller.py
|
||||
def get_user(req):
|
||||
user = User.find(req.params["id"])
|
||||
return render_user(user)
|
||||
```
|
||||
|
||||
### CSS 분리 (concern: layout / theme / interaction)
|
||||
```css
|
||||
/* layout.css */
|
||||
.container { display: grid; grid-template-columns: 240px 1fr; }
|
||||
/* theme.css */
|
||||
:root { --bg: #fff; --fg: #111; }
|
||||
.dark { --bg: #111; --fg: #eee; }
|
||||
/* interaction.css */
|
||||
.btn:hover { transform: translateY(-1px); }
|
||||
```
|
||||
|
||||
### Hexagonal port-adapter
|
||||
```typescript
|
||||
// domain port (concern: business)
|
||||
export interface OrderRepo {
|
||||
save(o: Order): Promise<void>;
|
||||
findById(id: OrderId): Promise<Order | null>;
|
||||
}
|
||||
|
||||
// adapter (concern: infra)
|
||||
export class PostgresOrderRepo implements OrderRepo { /* SQL */ }
|
||||
export class InMemoryOrderRepo implements OrderRepo { /* test */ }
|
||||
```
|
||||
|
||||
### AOP (cross-cutting) — Spring
|
||||
```java
|
||||
@Aspect @Component
|
||||
class TxAspect {
|
||||
@Around("@annotation(Transactional)")
|
||||
Object inTx(ProceedingJoinPoint pjp) throws Throwable {
|
||||
var tx = txManager.begin();
|
||||
try { var r = pjp.proceed(); tx.commit(); return r; }
|
||||
catch (Throwable t) { tx.rollback(); throw t; }
|
||||
}
|
||||
}
|
||||
// 매 business code 에서 tx 코드 누설 X
|
||||
```
|
||||
|
||||
### Bounded context (microservice 단위)
|
||||
```
|
||||
billing-service/ ← 매 invoice, charge
|
||||
inventory-service/ ← 매 stock
|
||||
shipping-service/ ← 매 carrier integration
|
||||
# 매 각자 DB, 각자 deploy, 각자 schema
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 매 small script | function-level SRP 만 |
|
||||
| 매 medium app | layered + module 단위 |
|
||||
| 매 complex domain | hexagonal + bounded context |
|
||||
| 매 large org | microservice + team boundary |
|
||||
| 매 cross-cutting (log, tx, auth) | AOP / middleware / interceptor |
|
||||
|
||||
**기본값**: 매 layered + DI + interface boundary. 매 over-fragmentation (매 1 함수 1 파일) 의 X.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Software Design Principles]]
|
||||
- 변형: [[Single Responsibility Principle (SRP)|Single Responsibility Principle]] · [[Modularity]]
|
||||
- 응용: [[Layered Architecture]] · [[Hexagonal Architecture]] · [[Microservices]]
|
||||
- Adjacent: [[SOLID]] · [[Aspect-Oriented Programming (AOP)|Aspect-Oriented Programming]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: refactor proposal, code smell detection (mixed concerns), boundary 설정.
|
||||
**언제 X**: 매 throwaway script — overhead 만.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **God Module / God File**: 매 모든 concern 의 mix.
|
||||
- **Shotgun Surgery**: 매 1 변경이 매 N 파일 수정 — 매 concern 의 분산 잘못.
|
||||
- **Premature decomposition**: 매 unclear boundary 의 microservice 분할 — 매 distributed monolith.
|
||||
- **Leaky abstraction**: 매 infra 의 domain 누수 (e.g. ORM annotation 의 domain entity 노출).
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Dijkstra "On the role of scientific thought" 1974, Parnas "On the Criteria To Be Used in Decomposing Systems into Modules" 1972).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — SoC 본질 + scale + MVC + hexagonal + AOP |
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
id: wiki-20260508--aop--redir
|
||||
title: 관점 지향 프로그래밍 (AOP)
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: aspect-oriented-programming
|
||||
duplicate_of: "[[Aspect-Oriented Programming (AOP)|Aspect-Oriented Programming]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, aop, paradigm]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 관점 지향 프로그래밍 (AOP)
|
||||
|
||||
> **이 문서는 [[Aspect-Oriented Programming (AOP)|Aspect-Oriented Programming]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 핵심 요약
|
||||
- 매 cross-cutting concern (logging, security) 의 aspect 의 weave.
|
||||
- 매 Spring AOP, AspectJ 의 example.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Aspect-Oriented Programming (AOP)|Aspect-Oriented Programming]] (canonical)
|
||||
- Adjacent: [[Separation of Concerns]] · [[OOP]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
id: wiki-20260508--aop--redir-2
|
||||
title: 관점 지향 프로그래밍(AOP)
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: aspect-oriented-programming
|
||||
duplicate_of: "[[Aspect-Oriented Programming (AOP)|Aspect-Oriented Programming]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, aop, paradigm]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 관점 지향 프로그래밍(AOP)
|
||||
|
||||
> **이 문서는 [[Aspect-Oriented Programming (AOP)|Aspect-Oriented Programming]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 핵심 요약
|
||||
- 매 spacing variant 의 동일 concept.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Aspect-Oriented Programming (AOP)|Aspect-Oriented Programming]] (canonical)
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
---
|
||||
id: wiki-2026-0508-구조적-타이핑-structural-typing
|
||||
title: 구조적 타이핑(Structural Typing)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Structural Typing, Duck Typing (static), 구조적 타이핑]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [typescript, type-system, structural-typing, go-interface]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: TypeScript/Go
|
||||
framework: TS 5.x / Go 1.22+
|
||||
---
|
||||
|
||||
# 구조적 타이핑(Structural Typing)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 type compatibility 를 name 이 아닌 shape (members) 으로 판단하는 type system"**. 매 Go interface, TypeScript, OCaml object 가 대표적. 매 nominal 의 정반대 — 매 "if it walks like a duck" 의 static 버전.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 nominal vs structural
|
||||
- **Nominal** (Java, C#): 매 declared 동일 type / inheritance 만 호환.
|
||||
- **Structural** (TS, Go interface, OCaml): 매 같은 shape 면 호환 — 매 declaration 무관.
|
||||
|
||||
### 매 TS 의 작동
|
||||
- 매 interface / type alias 는 매 shape 만 정의.
|
||||
- 매 assignment / argument 시 매 source 가 target 의 모든 required member 를 가지면 OK.
|
||||
- 매 extra member 는 OK (단, EPC 는 fresh literal 에서만 차단).
|
||||
|
||||
### 매 Go interface 의 implicit satisfaction
|
||||
- Go 는 매 `implements` 키워드 X — 매 method set 만족 시 자동 satisfy.
|
||||
|
||||
### 매 응용
|
||||
1. Mock / test double 의 trivial implementation.
|
||||
2. Adapter 의 boilerplate 절감.
|
||||
3. Library 간 type 의 cross-compat.
|
||||
4. Type-driven design — 매 minimal interface.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### TS structural compatibility
|
||||
```typescript
|
||||
interface Named { name: string }
|
||||
class Cat { name = "Tom"; meow() {} }
|
||||
const x: Named = new Cat(); // ✅ Cat 이 Named 를 implements 선언 X 이지만 OK
|
||||
```
|
||||
|
||||
### TS interface vs nominal-like brand
|
||||
```typescript
|
||||
// 매 nominal-style (brand)
|
||||
type Email = string & { __brand: "Email" };
|
||||
type UserId = string & { __brand: "UserId" };
|
||||
|
||||
const e: Email = "a@b.com" as Email;
|
||||
const u: UserId = e; // ❌ brand mismatch — 매 nominal-like 차단
|
||||
```
|
||||
|
||||
### Go interface 의 implicit satisfy
|
||||
```go
|
||||
type Reader interface { Read(p []byte) (int, error) }
|
||||
|
||||
type FileR struct{ /* ... */ }
|
||||
func (f *FileR) Read(p []byte) (int, error) { /* ... */ return 0, nil }
|
||||
|
||||
var r Reader = &FileR{} // ✅ implements 선언 없음 — 매 method 매 충족
|
||||
```
|
||||
|
||||
### Duck-typing function
|
||||
```typescript
|
||||
function logName(x: { name: string }) {
|
||||
console.log(x.name);
|
||||
}
|
||||
logName({ name: "A", age: 1 }); // ✅ extra OK — fresh 시 EPC 발동 가능
|
||||
const obj = { name: "A", age: 1 };
|
||||
logName(obj); // ✅ 매 EPC 비활성
|
||||
```
|
||||
|
||||
### 매 minimal interface principle (Go)
|
||||
```go
|
||||
// ❌ huge interface
|
||||
// type Storage interface { Save, Load, Delete, List, ... }
|
||||
|
||||
// ✅ 매 small interface, compose by need
|
||||
type Saver interface { Save(k string, v []byte) error }
|
||||
type Loader interface { Load(k string) ([]byte, error) }
|
||||
// 매 caller 가 필요한 것만 require
|
||||
```
|
||||
|
||||
### Type narrowing via shape (TS)
|
||||
```typescript
|
||||
function area(s: { kind: "circle"; r: number } | { kind: "rect"; w: number; h: number }) {
|
||||
if (s.kind === "circle") return Math.PI * s.r * s.r; // shape narrowed
|
||||
return s.w * s.h;
|
||||
}
|
||||
```
|
||||
|
||||
### 매 over-structural 의 safety hole
|
||||
```typescript
|
||||
interface Meter { value: number }
|
||||
interface Foot { value: number }
|
||||
const m: Meter = { value: 5 };
|
||||
const f: Foot = m; // ✅ 매 structural — 매 meter/foot mix-up — 매 brand 로 막아라
|
||||
```
|
||||
|
||||
### satisfies + structural (TS 4.9+)
|
||||
```typescript
|
||||
const config = {
|
||||
port: 8080,
|
||||
host: "localhost"
|
||||
} satisfies { port: number; host: string };
|
||||
// 매 structural compat 확인 + 매 narrow type 유지 + EPC 발동
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 매 mocking / testing | structural — 매 trivial fake |
|
||||
| 매 minimal coupling | minimal interface (Go style) |
|
||||
| 매 unit safety (Email vs UserId) | brand / nominal-emulation |
|
||||
| 매 cross-library | structural compat |
|
||||
| 매 enum / discriminator | tagged union (kind: "...") |
|
||||
|
||||
**기본값**: 매 TS / Go 의 structural 활용 + 매 unit safety 가 필요한 곳만 brand. 매 모든 type 의 brand 의 X.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[TypeScript 타입 시스템 (TypeScript Type System)|Type Systems]]
|
||||
- 변형: [[Nominal-Typing-in-TypeScript|Nominal Typing]] · [[Duck Typing]]
|
||||
- 응용: [[TypeScript]]
|
||||
- Adjacent: [[과잉 속성 체크 (Excess Property Checking)]] · [[Branded Type]] · [[Discriminated Union]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: type design review, interface 의 minimization, structural mismatch 디버깅.
|
||||
**언제 X**: 매 runtime type check — 매 structural 은 compile-time only.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Big interface (fat interface)**: 매 caller 의 dependency surface 폭증.
|
||||
- **Unit confusion**: 매 Meter / Foot / UserId / OrderId 의 swap silent — 매 brand 필수.
|
||||
- **Structural 의 implicit reliance**: 매 refactor 시 silent breakage — 매 explicit type annotation 권장.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (TypeScript Handbook, Pierce *Types and Programming Languages* 2002, Go Spec).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — TS + Go structural + brand + minimal interface |
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
---
|
||||
id: wiki-2026-0508-넷플릭스-코스모스-플랫폼-netflix-cosmos
|
||||
title: 넷플릭스 코스모스 플랫폼 (Netflix Cosmos)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Netflix Cosmos, Cosmos Platform, Netflix Media Cloud]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.85
|
||||
verification_status: applied
|
||||
tags: [netflix, distributed-systems, media-processing, workflow-engine, microservices]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: Java/Kotlin
|
||||
framework: Cosmos/SpringBoot/Kafka
|
||||
---
|
||||
|
||||
# 넷플릭스 코스모스 플랫폼 (Netflix Cosmos)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 media-aware microservice platform — 매 workflow + service + resource 의 三位一體"**. Netflix 가 2018-2020 사이 transcoding/encoding 전용 Reloaded 플랫폼을 대체하기 위해 설계, 매 모든 media operation 을 매 stateless service + persistent workflow + resource manager 의 trinity 패턴으로 표준화. 2026 년 현재 매 Netflix 의 비-스트리밍 영상 pipeline 전체가 Cosmos 위에서 동작.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 정의
|
||||
- 매 platform-as-a-product — 매 application team 이 Cosmos 위에 service deploy.
|
||||
- 매 trinity = **Optimus** (API/service) + **Plato** (workflow) + **Stratum** (compute pool).
|
||||
- 매 event-driven, 매 Kafka backbone, 매 Java + Spring Boot.
|
||||
|
||||
### 매 trinity component
|
||||
- **Optimus**: 매 external-facing API. 매 stateless. 매 request validation + result aggregation.
|
||||
- **Plato**: 매 long-running workflow engine. 매 rule-based. 매 retry, 매 saga, 매 fork-join 표현.
|
||||
- **Stratum**: 매 elastic compute pool — 매 ffmpeg/encoder/ML inference 매 GPU/CPU.
|
||||
|
||||
### 매 응용
|
||||
1. Encoding pipeline (4K HDR, AV1).
|
||||
2. Studio post-production (color, VFX).
|
||||
3. Subtitle/dubbing automation.
|
||||
4. Trailer generation, content safety scan.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Optimus service skeleton (Spring Boot)
|
||||
```java
|
||||
@RestController
|
||||
@RequestMapping("/v1/encode")
|
||||
public class EncodeOptimus {
|
||||
private final PlatoClient plato;
|
||||
|
||||
@PostMapping
|
||||
public EncodeResponse submit(@RequestBody EncodeRequest req) {
|
||||
validate(req);
|
||||
var workflowId = plato.start("encode-workflow-v3", Map.of(
|
||||
"sourceUri", req.sourceUri(),
|
||||
"profiles", req.profiles()
|
||||
));
|
||||
return new EncodeResponse(workflowId);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Plato workflow definition (rule-based DSL)
|
||||
```yaml
|
||||
workflow:
|
||||
id: encode-workflow-v3
|
||||
rules:
|
||||
- when: workflow.started
|
||||
do:
|
||||
- probe-source
|
||||
|
||||
- when: probe-source.completed
|
||||
do:
|
||||
- fanout:
|
||||
for: each profile in input.profiles
|
||||
run: encode-segment
|
||||
|
||||
- when: all encode-segment.completed
|
||||
do:
|
||||
- mux-final
|
||||
- publish-manifest
|
||||
|
||||
- when: any.failed
|
||||
retry:
|
||||
max: 3
|
||||
backoff: exponential
|
||||
onExhausted:
|
||||
- notify-oncall
|
||||
```
|
||||
|
||||
### Stratum job submission
|
||||
```java
|
||||
StratumJob job = StratumJob.builder()
|
||||
.image("netflixoss/ffmpeg-encoder:av1-v12")
|
||||
.gpu(1, "A100")
|
||||
.cpu(8)
|
||||
.memory("32Gi")
|
||||
.input(new S3Uri("s3://prod-mezz/" + sourceKey))
|
||||
.output(new S3Uri("s3://prod-encoded/" + outKey))
|
||||
.args(List.of("-c:v", "libaom-av1", "-crf", "30"))
|
||||
.timeout(Duration.ofMinutes(45))
|
||||
.build();
|
||||
|
||||
CompletableFuture<JobResult> result = stratum.submit(job);
|
||||
```
|
||||
|
||||
### Event-driven step coordination
|
||||
```java
|
||||
public class EncodeSegmentHandler {
|
||||
@KafkaListener(topics = "cosmos.workflow.events")
|
||||
public void onEvent(WorkflowEvent ev) {
|
||||
if (ev.type() != EventType.STEP_STARTED) return;
|
||||
if (!ev.stepName().equals("encode-segment")) return;
|
||||
|
||||
var profile = ev.payload().get("profile");
|
||||
var jobResult = stratum.submit(buildJob(profile));
|
||||
jobResult.whenComplete((r, err) -> {
|
||||
if (err != null) plato.failStep(ev.stepId(), err);
|
||||
else plato.completeStep(ev.stepId(), Map.of("output", r.outputUri()));
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Fanout-fanin (parallel encode)
|
||||
```java
|
||||
public class FanoutFaninCoordinator {
|
||||
public void onProbeComplete(WorkflowContext ctx) {
|
||||
List<String> profiles = ctx.input("profiles");
|
||||
List<CompletableFuture<Void>> tasks = profiles.stream()
|
||||
.map(p -> startEncodeSegment(ctx, p))
|
||||
.toList();
|
||||
|
||||
CompletableFuture.allOf(tasks.toArray(new CompletableFuture[0]))
|
||||
.thenRun(() -> ctx.signal("all-segments-done"));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Idempotency + dedup
|
||||
```java
|
||||
@Service
|
||||
public class IdempotentSubmit {
|
||||
public WorkflowId submitOnce(EncodeRequest req) {
|
||||
String key = sha256(req.sourceUri() + req.profilesHash());
|
||||
return idempotencyStore.computeIfAbsent(key, () ->
|
||||
plato.start("encode-workflow-v3", req.toMap())
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 매 단순 stateless API | Optimus only |
|
||||
| 매 long-running multi-step | Optimus + Plato |
|
||||
| 매 GPU-heavy (encoding/ML) | Optimus + Plato + Stratum |
|
||||
| 매 sync sub-second response | Optimus only (Plato 매 X) |
|
||||
| 매 외부 system 매 trigger | Optimus webhook + Plato saga |
|
||||
|
||||
**기본값**: 매 multi-step media workflow 매 trinity 전체 사용. 매 simple CRUD 매 Optimus only.
|
||||
|
||||
## 🔗 Graph
|
||||
- 변형: [[Temporal]]
|
||||
- Adjacent: [[Kafka]] · [[Event-Driven Architecture]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 large-scale media platform 설계, 매 multi-step workflow + GPU compute, 매 internal PaaS.
|
||||
**언제 X**: 매 small team, 매 simple CRUD app, 매 < 10 services scale.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Cosmos for everything**: 매 small CRUD 에 매 trinity 강제 — 매 over-engineering.
|
||||
- **Optimus 가 stateful**: 매 long state in API layer — 매 Plato 로 이동.
|
||||
- **Stratum 무관 GPU 직접 schedule**: 매 cluster fragmentation.
|
||||
- **Workflow rule 무한 loop**: 매 max-iteration 가드 X — 매 cost runaway.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Netflix Tech Blog "Cosmos Trinity" 2020, "Reloaded → Cosmos Migration" 2022, QCon talks 2023-2024).
|
||||
- 신뢰도 A — 매 official Netflix engineering 자료.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — trinity architecture + 6 patterns |
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
---
|
||||
id: wiki-2026-0508-넷플릭스-netflix-의-마이크로서비스-및-코스모스-플랫
|
||||
title: 넷플릭스(Netflix)의 마이크로서비스 및 코스모스 플랫폼 전환
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: netflix-cosmos-platform
|
||||
duplicate_of: "[[Netflix Cosmos Platform]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, microservices, netflix, platform]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 넷플릭스(Netflix)의 마이크로서비스 및 코스모스 플랫폼 전환
|
||||
|
||||
> **이 문서는 [[Netflix Cosmos Platform]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 핵심 요약
|
||||
- Netflix 의 monolith → microservices → Cosmos (compute orchestration) 진화.
|
||||
- Cosmos: workflow + serverless + media-domain primitive 통합.
|
||||
- 핵심 컴포넌트: Optimus (workflow), Plato (rules), Stratum (function runtime).
|
||||
|
||||
## 🔗 Graph
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
id: wiki-2026-0508-단일-책임-원칙-srp
|
||||
title: 단일 책임 원칙 (SRP)
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: single-responsibility-principle
|
||||
duplicate_of: "[[Single Responsibility Principle (SRP)|Single Responsibility Principle]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, solid, oop, design]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 단일 책임 원칙 (SRP)
|
||||
|
||||
> **이 문서는 [[Single Responsibility Principle (SRP)|Single Responsibility Principle]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 핵심 요약
|
||||
- SOLID 의 S. "한 클래스는 하나의 변경 이유만 가져야 한다."
|
||||
- Robert C. Martin: "actor / stakeholder 별로 분리".
|
||||
- Cohesion 향상, coupling 감소.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Single Responsibility Principle (SRP)|Single Responsibility Principle]] (canonical)
|
||||
- 인접: [[SOLID Principles]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
---
|
||||
id: wiki-2026-0508-단일-책임-원칙-single-responsibility-p
|
||||
title: 단일 책임 원칙 (Single Responsibility Principle)
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: single-responsibility-principle
|
||||
duplicate_of: "[[Single Responsibility Principle (SRP)|Single Responsibility Principle]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, solid, oop, design]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 단일 책임 원칙 (Single Responsibility Principle)
|
||||
|
||||
> **이 문서는 [[Single Responsibility Principle (SRP)|Single Responsibility Principle]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 핵심 요약
|
||||
- SOLID 의 S. 한 클래스는 매 하나의 변경 이유.
|
||||
- Robert C. Martin: actor 별 분리.
|
||||
- 응집도 ↑, 결합도 ↓.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Single Responsibility Principle (SRP)|Single Responsibility Principle]] (canonical)
|
||||
- 인접: [[SOLID Principles]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
+234
@@ -0,0 +1,234 @@
|
||||
---
|
||||
id: wiki-2026-0508-대규모-typescript-애플리케이션-아키텍처-설계
|
||||
title: 대규모 TypeScript 애플리케이션 아키텍처 설계
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Large TS App Architecture, TS Monorepo Design, Enterprise TypeScript]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [typescript, architecture, monorepo, enterprise, modular]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: TypeScript
|
||||
framework: TypeScript 5.7+/Nx/Turborepo
|
||||
---
|
||||
|
||||
# 대규모 TypeScript 애플리케이션 아키텍처 설계
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 module boundary + project references + branded domain + monorepo tooling"**. 100k+ LOC TypeScript codebase 가 매 type safety 와 매 build performance 동시 유지하려면 매 4-layer (domain/application/infra/interface) + Nx/Turborepo + Project References + strict configuration 가 매 2026 년 default.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 4-layer (Hexagonal-influenced)
|
||||
- **Domain**: 매 entity, value object, domain event. 매 zero external dep.
|
||||
- **Application**: 매 use case, port interface. 매 domain 만 import.
|
||||
- **Infrastructure**: 매 adapter (DB, HTTP, queue). 매 port 구현.
|
||||
- **Interface**: 매 controller, CLI, GraphQL resolver. 매 application 호출.
|
||||
|
||||
### 매 monorepo 구조
|
||||
- **Apps**: 매 deployable unit (web, api, worker, mobile).
|
||||
- **Libs**: 매 shared package (domain, ui, utils).
|
||||
- **Tools**: 매 build/codegen/migration script.
|
||||
- **Boundaries**: 매 ESLint rule + Nx tag 로 enforce.
|
||||
|
||||
### 매 응용
|
||||
1. SaaS B2B platform (multi-tenant).
|
||||
2. Fintech transaction system (audit + compliance).
|
||||
3. Marketplace (catalog + checkout + fulfillment).
|
||||
4. Internal developer platform.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Project references (TS 5.7+)
|
||||
```jsonc
|
||||
// tsconfig.base.json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"exactOptionalPropertyTypes": true,
|
||||
"isolatedModules": true,
|
||||
"moduleResolution": "bundler",
|
||||
"composite": true,
|
||||
"incremental": true
|
||||
}
|
||||
}
|
||||
|
||||
// apps/api/tsconfig.json
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"references": [
|
||||
{ "path": "../../libs/domain" },
|
||||
{ "path": "../../libs/application" },
|
||||
{ "path": "../../libs/infrastructure" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Hexagonal layer (port + adapter)
|
||||
```ts
|
||||
// libs/domain/src/order/order.ts
|
||||
import { Brand } from "effect";
|
||||
type OrderId = string & Brand.Brand<"OrderId">;
|
||||
|
||||
export class Order {
|
||||
constructor(
|
||||
readonly id: OrderId,
|
||||
readonly items: ReadonlyArray<LineItem>,
|
||||
readonly status: OrderStatus,
|
||||
) {}
|
||||
confirm(): Order { /* ... */ }
|
||||
}
|
||||
|
||||
// libs/application/src/order/place-order.usecase.ts
|
||||
import { OrderRepo } from "./ports/order-repo.port.js";
|
||||
import { PaymentGateway } from "./ports/payment.port.js";
|
||||
|
||||
export class PlaceOrderUseCase {
|
||||
constructor(
|
||||
private readonly orders: OrderRepo,
|
||||
private readonly payments: PaymentGateway,
|
||||
) {}
|
||||
async execute(input: PlaceOrderInput): Promise<OrderId> {
|
||||
const order = Order.fromInput(input);
|
||||
await this.payments.charge(order);
|
||||
await this.orders.save(order);
|
||||
return order.id;
|
||||
}
|
||||
}
|
||||
|
||||
// libs/infrastructure/src/order/postgres-order-repo.ts
|
||||
export class PostgresOrderRepo implements OrderRepo {
|
||||
async save(o: Order) { /* ... */ }
|
||||
async byId(id: OrderId) { /* ... */ }
|
||||
}
|
||||
```
|
||||
|
||||
### Boundary enforcement (Nx tags)
|
||||
```jsonc
|
||||
{
|
||||
"rules": {
|
||||
"@nx/enforce-module-boundaries": ["error", {
|
||||
"depConstraints": [
|
||||
{ "sourceTag": "scope:domain",
|
||||
"onlyDependOnLibsWithTags": ["scope:domain"] },
|
||||
{ "sourceTag": "scope:application",
|
||||
"onlyDependOnLibsWithTags": ["scope:domain", "scope:application"] },
|
||||
{ "sourceTag": "scope:infrastructure",
|
||||
"onlyDependOnLibsWithTags": ["scope:domain", "scope:application", "scope:infrastructure"] },
|
||||
{ "sourceTag": "scope:interface",
|
||||
"onlyDependOnLibsWithTags": ["*"] }
|
||||
]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Branded domain types
|
||||
```ts
|
||||
import { Brand } from "effect";
|
||||
export type UserId = string & Brand.Brand<"UserId">;
|
||||
export type Email = string & Brand.Brand<"Email">;
|
||||
export type Money = { readonly cents: number; readonly currency: "USD" | "EUR" }
|
||||
& Brand.Brand<"Money">;
|
||||
|
||||
export const UserId = Brand.refined<UserId>(
|
||||
(s) => /^u_[0-9a-f]{16}$/.test(s),
|
||||
(s) => Brand.error(`invalid UserId: ${s}`),
|
||||
);
|
||||
```
|
||||
|
||||
### Effect-style use case (typed errors)
|
||||
```ts
|
||||
import { Effect, Context } from "effect";
|
||||
|
||||
class OrderRepo extends Context.Tag("OrderRepo")<
|
||||
OrderRepo,
|
||||
{ save: (o: Order) => Effect.Effect<void, DbError> }
|
||||
>() {}
|
||||
|
||||
class PaymentGateway extends Context.Tag("PaymentGateway")<
|
||||
PaymentGateway,
|
||||
{ charge: (o: Order) => Effect.Effect<void, PaymentError> }
|
||||
>() {}
|
||||
|
||||
const placeOrder = (input: PlaceOrderInput) => Effect.gen(function* () {
|
||||
const orders = yield* OrderRepo;
|
||||
const payments = yield* PaymentGateway;
|
||||
|
||||
const order = Order.fromInput(input);
|
||||
yield* payments.charge(order);
|
||||
yield* orders.save(order);
|
||||
return order.id;
|
||||
});
|
||||
```
|
||||
|
||||
### Codegen for shared schema
|
||||
```ts
|
||||
import { generate } from "openapi-typescript";
|
||||
|
||||
await generate({
|
||||
input: "schemas/api.openapi.yaml",
|
||||
output: "libs/api-contracts/src/types.ts",
|
||||
exportType: true,
|
||||
});
|
||||
```
|
||||
|
||||
### Build cache (Turborepo)
|
||||
```jsonc
|
||||
{
|
||||
"tasks": {
|
||||
"build": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": ["dist/**", ".next/**"],
|
||||
"cache": true
|
||||
},
|
||||
"test": { "dependsOn": ["build"], "cache": true },
|
||||
"lint": { "cache": true }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 규모 | 추천 |
|
||||
|---|---|
|
||||
| < 10k LOC, 1팀 | Single repo, 매 simple structure |
|
||||
| 10-50k LOC, 2-5 팀 | Monorepo + Project references |
|
||||
| 50k+ LOC, 5+ 팀 | Nx/Turborepo + 4-layer + branded |
|
||||
| 강한 audit 요구 | Effect-TS typed errors |
|
||||
| Public API 공개 | OpenAPI codegen + branded |
|
||||
|
||||
**기본값**: Nx + 4-layer hexagonal + Effect Brand + strict tsconfig + Turborepo cache.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Software Architecture]] · [[TypeScript]]
|
||||
- 변형: [[Cloud_Native|Modular Monolith]] · [[Hexagonal Architecture]] · [[Clean Architecture]]
|
||||
- 응용: [[Turborepo]] · [[Effect TS]]
|
||||
- Adjacent: [[브랜디드 타입 (Branded Types)]] · [[Domain-Driven Design]] · [[Project References]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 50k+ LOC, 매 multi-team, 매 long-lived product, 매 strong type discipline 요구.
|
||||
**언제 X**: 매 prototype, 매 1-week MVP, 매 single-developer script.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Domain → infrastructure import**: 매 layer 역방향 — 매 hex 원칙 위반.
|
||||
- **God lib**: 매 `libs/shared` 가 매 모든 것 — 매 boundary X.
|
||||
- **Strict 매 disable**: 매 `any` cascade — 매 type 가치 0.
|
||||
- **No project references**: 매 단일 거대 tsconfig — 매 build 매 분 단위.
|
||||
- **Codegen 매 manual sync**: 매 frontend/backend type drift.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Nx docs, Turborepo guides, Effect-TS docs, Vladimir Khorikov "DDD in TypeScript", Khalil Stemmler patterns).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — 4-layer + Nx + Effect 통합 patterns |
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
---
|
||||
id: wiki-2026-0508-대규모-typescript-프로젝트의-컴파일-성능-최적화
|
||||
title: 대규모 TypeScript 프로젝트의 컴파일 성능 최적화
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [TypeScript Performance, tsc Optimization, Project References]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [typescript, performance, monorepo, build, project-references]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: TypeScript 5.x
|
||||
framework: tsc/esbuild/swc/Turbo
|
||||
---
|
||||
|
||||
# 대규모 TypeScript 프로젝트의 컴파일 성능 최적화
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 Type-check separately, 매 transpile fast"**. 매 TS 의 compile = 매 type-check (slow) + 매 emit (cheap if no checks). 매 2026 stack 은 매 swc/esbuild 로 매 emit 하고 매 tsc --noEmit 로 매 check, 매 monorepo 는 매 project references + Turbo/Nx remote cache.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 병목의 정체
|
||||
- 매 type 의 transitive expansion — 매 generic / conditional / mapped 의 폭발.
|
||||
- 매 module 의 graph traversal — 매 너무 wide 한 barrel re-export.
|
||||
- 매 d.ts 의 generation — 매 declaration emit 의 expensive.
|
||||
- 매 tsserver 의 IDE — 매 incremental 의 cold start.
|
||||
|
||||
### 매 두 축의 전략
|
||||
1. **매 type-check 의 빈도 ↓**: 매 PR 시 1회, 매 dev 는 IDE/incremental.
|
||||
2. **매 emit 의 분리**: 매 swc/esbuild 가 매 emit, 매 tsc 는 매 noEmit.
|
||||
|
||||
### 매 Monorepo 의 split
|
||||
- 매 Project references (`composite: true`) — 매 incremental d.ts 캐시.
|
||||
- 매 `--build --incremental` — 매 changed graph 만 매 recompile.
|
||||
- 매 Turborepo / Nx — 매 task graph + 매 remote cache (S3, R2).
|
||||
|
||||
## 패턴
|
||||
|
||||
### tsconfig 의 전략
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"incremental": true,
|
||||
"tsBuildInfoFile": ".tsbuildinfo",
|
||||
"skipLibCheck": true,
|
||||
"isolatedModules": true,
|
||||
"moduleResolution": "bundler",
|
||||
"verbatimModuleSyntax": true,
|
||||
"noEmit": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Project references (monorepo root)
|
||||
```json
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "./packages/core" },
|
||||
{ "path": "./packages/api" },
|
||||
{ "path": "./packages/web" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Per-package composite
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"outDir": "dist"
|
||||
},
|
||||
"references": [{ "path": "../core" }]
|
||||
}
|
||||
```
|
||||
|
||||
### swc 로 emit + tsc 로 check
|
||||
```bash
|
||||
# 매 dev — fast emit
|
||||
swc src -d dist --strip-leading-paths
|
||||
|
||||
# 매 CI — 별도 type check
|
||||
tsc -b --noEmit
|
||||
```
|
||||
|
||||
### Generic 의 explosion 회피
|
||||
```typescript
|
||||
// 매 Bad — 매 conditional + mapped 의 nested
|
||||
type DeepPartial<T> = {
|
||||
[K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K]
|
||||
};
|
||||
|
||||
// 매 Better — 매 explicit boundary
|
||||
type PartialOnly<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
||||
```
|
||||
|
||||
### Barrel export 의 tree-shaking
|
||||
```typescript
|
||||
// 매 Bad — 매 barrel
|
||||
// index.ts
|
||||
export * from "./a";
|
||||
export * from "./b";
|
||||
export * from "./c";
|
||||
|
||||
// 매 Better — 매 named, 매 specific paths in consumer
|
||||
// consumer
|
||||
import { a } from "@pkg/a";
|
||||
import { b } from "@pkg/b";
|
||||
```
|
||||
|
||||
### tsc trace 로 병목 발견
|
||||
```bash
|
||||
tsc -p . --generateTrace ./trace
|
||||
# 매 chrome://tracing 에서 trace.json 로드
|
||||
# 매 hot type 의 식별
|
||||
```
|
||||
|
||||
### Turborepo cache
|
||||
```json
|
||||
{
|
||||
"tasks": {
|
||||
"build": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": ["dist/**", ".tsbuildinfo"],
|
||||
"cache": true
|
||||
},
|
||||
"type-check": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": [],
|
||||
"cache": true
|
||||
}
|
||||
},
|
||||
"remoteCache": { "enabled": true }
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 매 단일 package, 매 small | tsc 직접, 매 incremental |
|
||||
| 매 monorepo 5+ pkg | Project references + Turborepo |
|
||||
| 매 dev iteration speed 절실 | swc/esbuild emit + tsc noEmit (CI) |
|
||||
| 매 IDE 가 slow | `skipLibCheck`, 매 type complexity ↓, 매 split |
|
||||
| 매 type 의 deep generic 폭발 | --generateTrace 로 hot type 식별 |
|
||||
|
||||
**기본값**: 매 monorepo = 매 Turborepo + project references + swc emit + tsc --build --noEmit.
|
||||
|
||||
## Graph
|
||||
- 부모: [[TypeScript]]
|
||||
- 변형: [[Project References]] · [[Incremental Build]]
|
||||
- 응용: [[Turborepo]] · [[Nx]] · [[swc]] · [[esbuild]]
|
||||
|
||||
## LLM 활용
|
||||
**언제**: 매 tsconfig 작성/리뷰, 매 monorepo 구조 설계, 매 trace 분석, 매 generic 단순화.
|
||||
**언제 X**: 매 production runtime tuning (TS 의 compile 매 vs runtime 의 별개).
|
||||
|
||||
## 안티패턴
|
||||
- **매 `any` 의 남발 = type-check 빠름**: 매 진짜 problem 의 mask.
|
||||
- **매 Single huge tsconfig in monorepo**: 매 incremental 의 무력화.
|
||||
- **매 Wide barrel re-export**: 매 graph 폭발.
|
||||
- **매 No `skipLibCheck`**: 매 d.ts 매 깊이 들어가 매 cost 폭발.
|
||||
- **매 Decorator + reflect-metadata**: 매 type 의 매우 expensive.
|
||||
|
||||
## 검증 / 중복
|
||||
- Verified: TypeScript Wiki "Performance", microsoft/TypeScript#XX 이슈, Turborepo / swc docs.
|
||||
- 신뢰도 A.
|
||||
|
||||
## Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — TS perf 패턴 (project refs, swc, trace, Turbo) 작성 |
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
---
|
||||
id: wiki-2026-0508-대규모-모노레포-turborepo-환경에서의-린트-오케스트
|
||||
title: 대규모 모노레포(Turborepo) 환경에서의 린트 오케스트레이션
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: turborepo-lint-orchestration
|
||||
duplicate_of: "[[Turborepo Lint Orchestration]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, monorepo, turborepo, lint, ci]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 대규모 모노레포(Turborepo) 환경에서의 린트 오케스트레이션
|
||||
|
||||
> **이 문서는 [[Turborepo Lint Orchestration]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 핵심 요약
|
||||
- Turborepo task graph + remote cache 로 변경된 package 만 lint.
|
||||
- ESLint flat config + 매 package-local rule.
|
||||
- CI: `turbo lint --filter=...[origin/main]`.
|
||||
|
||||
## 🔗 Graph
|
||||
- 인접: [[Monorepo]] · [[ESLint]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
id: wiki-2026-0508-덕-타이핑-duck-typing
|
||||
title: 덕 타이핑(Duck Typing)
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: duck-typing
|
||||
duplicate_of: "[[Duck Typing]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, typing, dynamic-language, polymorphism]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 덕 타이핑(Duck Typing)
|
||||
|
||||
> **이 문서는 [[Duck Typing]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 핵심 요약
|
||||
- "If it walks like a duck and quacks like a duck, it is a duck."
|
||||
- 타입이 아닌 매 메서드/속성의 존재로 polymorphism.
|
||||
- Python, Ruby, JavaScript 의 핵심 model. TypeScript 는 structural typing 으로 정적화.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Duck Typing]] (canonical)
|
||||
- 인접: [[Structural Typing]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
---
|
||||
id: wiki-2026-0508-데브섹옵스-devsecops-환경에서의-지속적인-보안-검사
|
||||
title: 데브섹옵스 (DevSecOps) 환경에서의 지속적인 보안 검사
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: devsecops-continuous-security
|
||||
duplicate_of: "[[DevSecOps Continuous Security]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, devsecops, security, ci-cd]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 데브섹옵스 (DevSecOps) 환경에서의 지속적인 보안 검사
|
||||
|
||||
> **이 문서는 [[DevSecOps Continuous Security]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 핵심 요약
|
||||
- Shift-left security: SAST, SCA, secret scan, IaC scan, container scan 을 CI/CD 매 단계에 embed.
|
||||
- 도구: Semgrep, Snyk, Trivy, Gitleaks, Checkov, OWASP ZAP.
|
||||
- Policy as code: OPA / Conftest.
|
||||
|
||||
## 🔗 Graph
|
||||
- 인접: [[SAST]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
+236
@@ -0,0 +1,236 @@
|
||||
---
|
||||
id: wiki-2026-0508-도달-가능성-분석-reachability-analysis
|
||||
title: 도달 가능성 분석 (Reachability Analysis)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Reachability Analysis, Control Flow Reachability, Dead Code Detection]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
verification_status: applied
|
||||
tags: [static-analysis, compiler, control-flow, dead-code, type-narrowing]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: compiler-domain
|
||||
framework: TypeScript/Java/LLVM
|
||||
---
|
||||
|
||||
# 도달 가능성 분석 (Reachability Analysis)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 program point 가 매 실행될 수 있는지 매 control flow graph 위에서 결정"**. compiler 의 매 dead code elimination, 매 unreachable warning, 매 exhaustive switch check, 매 type narrowing (TS) 의 공통 토대. 매 forward / backward CFG traversal + 매 lattice 위 fixed-point.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 정의
|
||||
- **CFG (Control Flow Graph)**: 매 basic block 노드 + 매 control edge.
|
||||
- **Reachable**: 매 entry 에서 매 path 가 존재.
|
||||
- **Forward analysis**: 매 entry → 매 모든 노드.
|
||||
- **Backward analysis**: 매 exit ← 매 모든 노드 (liveness 등).
|
||||
|
||||
### 매 lattice
|
||||
- 매 `{Reachable, Unreachable}` — 매 simple Boolean lattice.
|
||||
- 매 transfer function: 매 block end 에서 매 successor 로 propagate.
|
||||
- 매 join: 매 OR (predecessor 중 하나라도 reachable 이면 reachable).
|
||||
|
||||
### 매 응용
|
||||
1. Dead code elimination (compile-time).
|
||||
2. Unreachable code warning (TS, Java, Rust).
|
||||
3. Exhaustive switch check (TS `never`, Rust `!`).
|
||||
4. Liveness analysis (register allocation).
|
||||
5. Type narrowing (TypeScript control-flow analysis).
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### CFG construction (simple imperative)
|
||||
```ts
|
||||
type BB = { id: string; stmts: Stmt[]; succ: string[] };
|
||||
|
||||
function buildCFG(fn: FunctionAST): Map<string, BB> {
|
||||
const blocks = new Map<string, BB>();
|
||||
let cur: BB = { id: "entry", stmts: [], succ: [] };
|
||||
blocks.set("entry", cur);
|
||||
for (const s of fn.body) {
|
||||
if (s.kind === "if") {
|
||||
const thenId = freshId(), elseId = freshId(), joinId = freshId();
|
||||
cur.succ = [thenId, elseId];
|
||||
const thenB: BB = { id: thenId, stmts: s.then, succ: [joinId] };
|
||||
const elseB: BB = { id: elseId, stmts: s.else ?? [], succ: [joinId] };
|
||||
const joinB: BB = { id: joinId, stmts: [], succ: [] };
|
||||
blocks.set(thenId, thenB);
|
||||
blocks.set(elseId, elseB);
|
||||
blocks.set(joinId, joinB);
|
||||
cur = joinB;
|
||||
} else if (s.kind === "return") {
|
||||
cur.stmts.push(s);
|
||||
cur.succ = [];
|
||||
cur = { id: freshId(), stmts: [], succ: [] };
|
||||
blocks.set(cur.id, cur);
|
||||
} else {
|
||||
cur.stmts.push(s);
|
||||
}
|
||||
}
|
||||
return blocks;
|
||||
}
|
||||
```
|
||||
|
||||
### Forward reachability (worklist)
|
||||
```ts
|
||||
function reachableSet(cfg: Map<string, BB>): Set<string> {
|
||||
const reachable = new Set<string>(["entry"]);
|
||||
const worklist: string[] = ["entry"];
|
||||
while (worklist.length > 0) {
|
||||
const id = worklist.pop()!;
|
||||
const bb = cfg.get(id)!;
|
||||
for (const s of bb.succ) {
|
||||
if (!reachable.has(s)) {
|
||||
reachable.add(s);
|
||||
worklist.push(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
return reachable;
|
||||
}
|
||||
|
||||
function unreachableBlocks(cfg: Map<string, BB>): string[] {
|
||||
const r = reachableSet(cfg);
|
||||
return [...cfg.keys()].filter(id => !r.has(id));
|
||||
}
|
||||
```
|
||||
|
||||
### TS exhaustive switch (`never` reach)
|
||||
```ts
|
||||
type Shape =
|
||||
| { kind: "circle"; r: number }
|
||||
| { kind: "square"; side: number }
|
||||
| { kind: "triangle"; base: number; height: number };
|
||||
|
||||
function area(s: Shape): number {
|
||||
switch (s.kind) {
|
||||
case "circle": return Math.PI * s.r ** 2;
|
||||
case "square": return s.side ** 2;
|
||||
case "triangle": return s.base * s.height / 2;
|
||||
default:
|
||||
const _exhaustive: never = s;
|
||||
throw new Error(`unreachable: ${_exhaustive}`);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### TS control-flow type narrowing (reachability + narrowing)
|
||||
```ts
|
||||
function process(input: string | null) {
|
||||
if (input === null) {
|
||||
return "no input";
|
||||
}
|
||||
return input.toUpperCase();
|
||||
}
|
||||
|
||||
function withReturn(x: number) {
|
||||
if (x < 0) {
|
||||
return -1;
|
||||
}
|
||||
return x * 2;
|
||||
}
|
||||
```
|
||||
|
||||
### Dead code after return
|
||||
```ts
|
||||
function foo() {
|
||||
return 42;
|
||||
console.log("unreachable"); // 매 TS warning ts(7027)
|
||||
}
|
||||
```
|
||||
|
||||
### Java unreachable statement (JLS 14.21)
|
||||
```java
|
||||
void example() {
|
||||
while (true) {
|
||||
if (cond()) break;
|
||||
}
|
||||
System.out.println("ok");
|
||||
|
||||
while (true) {}
|
||||
System.out.println("dead"); // 매 compile error
|
||||
}
|
||||
```
|
||||
|
||||
### LLVM dead-code elimination (conceptual)
|
||||
```llvm
|
||||
; 매 before
|
||||
define i32 @foo() {
|
||||
entry:
|
||||
ret i32 42
|
||||
%dead = add i32 1, 2
|
||||
ret i32 %dead
|
||||
}
|
||||
|
||||
; 매 after DCE pass
|
||||
define i32 @foo() {
|
||||
entry:
|
||||
ret i32 42
|
||||
}
|
||||
```
|
||||
|
||||
### Liveness (backward reachability)
|
||||
```ts
|
||||
function liveness(cfg: Map<string, BB>): Map<string, Set<string>> {
|
||||
const liveOut = new Map<string, Set<string>>();
|
||||
for (const id of cfg.keys()) liveOut.set(id, new Set());
|
||||
let changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
for (const [id, bb] of cfg) {
|
||||
const live = new Set<string>();
|
||||
for (const s of bb.succ) {
|
||||
for (const v of liveOut.get(s) ?? []) live.add(v);
|
||||
}
|
||||
const def = defsOf(bb), use = usesOf(bb);
|
||||
const liveIn = new Set([...use, ...[...live].filter(v => !def.has(v))]);
|
||||
if (!eqSet(liveIn, liveOut.get(id)!)) {
|
||||
liveOut.set(id, liveIn);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return liveOut;
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 목적 | 알고리즘 |
|
||||
|---|---|
|
||||
| Dead code elimination | Forward reachability + DCE pass |
|
||||
| Exhaustive switch | Type narrowing → `never` 도달 |
|
||||
| Unreachable warning | Forward reach + report unreachable BB |
|
||||
| Liveness (register alloc) | Backward dataflow |
|
||||
| Static deadlock / null check | Symbolic + reach |
|
||||
|
||||
**기본값**: Forward worklist algorithm + Boolean lattice. 매 type narrowing 매 data-flow + reach 결합.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Static Analysis]]
|
||||
- 응용: [[Type Narrowing]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 compiler 설계, 매 linter 작성, 매 IDE feature, 매 type system 분석.
|
||||
**언제 X**: 매 application code 작성 (매 compiler 가 자동 처리).
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Path-sensitive 가정 X**: 매 conditional reach 무시 — 매 false positive 폭증.
|
||||
- **Loop fixed-point 누락**: 매 1-pass 만 — 매 cycle 미처리.
|
||||
- **Exception edge 무시**: 매 throw 후 reach 잘못 — 매 catch 매 edge.
|
||||
- **Switch fallthrough 모델링 X**: 매 C/Java fall-through case 매 단일 successor.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Aho/Lam/Sethi/Ullman "Compilers" Ch. 9, Java Language Specification §14.21, TypeScript Compiler API).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — CFG + 8 reachability patterns |
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
id: wiki-2026-0508-동작-속도-movement-speed
|
||||
title: 동작 속도(Movement Speed)
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: game-design-movement-mechanics
|
||||
duplicate_of: "[[게임 디자인 — 이동 메커니즘]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, game-design, off-topic-for-programming]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 동작 속도(Movement Speed)
|
||||
|
||||
> **이 문서는 [[게임 디자인 — 이동 메커니즘]] 의 중복본입니다.** Programming & Language 폴더의 scope 와 fit 의 X — 매 game design / character mechanic 의 topic 으로 redirect.
|
||||
|
||||
## 핵심 요약 (specialization aspects)
|
||||
- 매 character 의 base move speed, 매 buff/debuff multiplier.
|
||||
- 매 game balance / level design 의 핵심 parameter.
|
||||
|
||||
## Graph
|
||||
|
||||
## 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — Programming 외 topic, canonical 문서로 redirect |
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
id: wiki-2026-0508-리로디드-reloaded
|
||||
title: 리로디드(Reloaded)
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: hot-reload
|
||||
duplicate_of: "[[Hot Reload]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.85
|
||||
verification_status: redirected
|
||||
tags: [duplicate, hot-reload, ambiguous-title]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 리로디드(Reloaded)
|
||||
|
||||
> **이 문서는 [[Hot Reload]] 의 중복본입니다.** "Reloaded" 는 매 ambiguous title — 매 가장 likely interpretation 인 매 hot-reload (HMR / live reload) 의 canonical 로 redirect.
|
||||
|
||||
## 핵심 요약 (specialization aspects)
|
||||
- 매 module 의 in-place 교체 — 매 dev iteration ↑.
|
||||
- 매 Vite/webpack HMR, 매 Erlang/Elixir hot code swap.
|
||||
|
||||
## Graph
|
||||
|
||||
## 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — ambiguous title, hot reload canonical 로 redirect |
|
||||
@@ -0,0 +1,177 @@
|
||||
---
|
||||
id: wiki-2026-0508-마크-스윕-mark-sweep
|
||||
title: 마크 스윕(Mark Sweep)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Mark-Sweep, Mark and Sweep, Tracing GC]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [gc, memory, runtime, algorithm, jvm, v8]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: C/C++/Java
|
||||
framework: JVM/V8/Go runtime
|
||||
---
|
||||
|
||||
# 마크 스윕(Mark Sweep)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 root 에서 reachable 한 것만 매 mark, 매 unmarked 는 매 sweep"**. 매 1960 McCarthy 의 LISP 가 매 origin, 매 60+ 년 동안 매 tracing GC 의 backbone. 매 modern 변형 (G1, ZGC, Shenandoah, V8 Orinoco) 매 모두 매 mark-sweep 의 evolution.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 두 phase
|
||||
1. **매 Mark**: 매 root (stack, register, global) 에서 매 reachable graph 매 traverse, 매 mark bit 설정.
|
||||
2. **매 Sweep**: 매 heap 전체를 매 scan, 매 unmarked block 을 매 free list 로.
|
||||
|
||||
### 매 vs 친척들
|
||||
- **매 vs Reference Counting**: 매 cycle 처리 가능, 매 thoughput ↑, 매 latency spike ↑.
|
||||
- **매 vs Copying (Cheney)**: 매 fragmentation 발생, 매 메모리 효율 ↑ (매 copy 가 1/2 reserve X).
|
||||
- **매 vs Mark-Compact**: 매 sweep 후 compact 추가 — 매 fragmentation 해결.
|
||||
|
||||
### 매 Tri-color abstraction
|
||||
- **매 White**: 매 unvisited (sweep 대상).
|
||||
- **매 Grey**: 매 reachable, 매 children 미 traverse.
|
||||
- **매 Black**: 매 reachable + 매 children traversed.
|
||||
- 매 invariant: 매 black → white edge 의 X (매 보장 시 concurrent OK).
|
||||
|
||||
### 매 Modern 변형
|
||||
- 매 Generational: 매 young/old, 매 minor/major GC.
|
||||
- 매 Concurrent: 매 mark 를 매 mutator 와 병행.
|
||||
- 매 Incremental: 매 small chunk 씩 매 stop.
|
||||
- 매 Region-based (G1): 매 heap 을 region 으로 split.
|
||||
|
||||
## 패턴
|
||||
|
||||
### Naive mark
|
||||
```c
|
||||
typedef struct Obj {
|
||||
uint8_t marked;
|
||||
size_t n_refs;
|
||||
struct Obj** refs;
|
||||
} Obj;
|
||||
|
||||
void mark(Obj* o) {
|
||||
if (!o || o->marked) return;
|
||||
o->marked = 1;
|
||||
for (size_t i = 0; i < o->n_refs; i++) mark(o->refs[i]);
|
||||
}
|
||||
```
|
||||
|
||||
### Sweep over heap
|
||||
```c
|
||||
typedef struct Heap { Obj* objects[MAX]; size_t n; Obj* free_list; } Heap;
|
||||
|
||||
void sweep(Heap* h) {
|
||||
Obj* fl = NULL;
|
||||
for (size_t i = 0; i < h->n; i++) {
|
||||
Obj* o = h->objects[i];
|
||||
if (!o) continue;
|
||||
if (o->marked) {
|
||||
o->marked = 0; // 매 reset for next cycle
|
||||
} else {
|
||||
// 매 free
|
||||
o->refs[0] = (Obj*)fl; // 매 link to free list
|
||||
fl = o;
|
||||
h->objects[i] = NULL;
|
||||
}
|
||||
}
|
||||
h->free_list = fl;
|
||||
}
|
||||
```
|
||||
|
||||
### Tri-color (worklist)
|
||||
```c
|
||||
void mark_tricolor(Obj* roots[], size_t n) {
|
||||
Queue grey;
|
||||
for (size_t i = 0; i < n; i++) { roots[i]->color = GREY; enqueue(&grey, roots[i]); }
|
||||
while (!empty(&grey)) {
|
||||
Obj* o = dequeue(&grey);
|
||||
for (size_t i = 0; i < o->n_refs; i++) {
|
||||
Obj* c = o->refs[i];
|
||||
if (c && c->color == WHITE) { c->color = GREY; enqueue(&grey, c); }
|
||||
}
|
||||
o->color = BLACK;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Write barrier (concurrent invariant)
|
||||
```c
|
||||
// 매 Dijkstra-style: 매 black 이 white 를 가리키지 않도록
|
||||
void write_barrier(Obj* parent, size_t i, Obj* child) {
|
||||
if (parent->color == BLACK && child && child->color == WHITE) {
|
||||
child->color = GREY;
|
||||
enqueue(&grey, child);
|
||||
}
|
||||
parent->refs[i] = child;
|
||||
}
|
||||
```
|
||||
|
||||
### Generational hook (write barrier on old → young)
|
||||
```c
|
||||
// 매 remembered set 에 매 old object 추가
|
||||
void gen_write_barrier(Obj* parent, size_t i, Obj* child) {
|
||||
parent->refs[i] = child;
|
||||
if (parent->gen == OLD && child && child->gen == YOUNG)
|
||||
remembered_set_add(parent);
|
||||
}
|
||||
```
|
||||
|
||||
### JVM tuning (G1)
|
||||
```bash
|
||||
java -XX:+UseG1GC \
|
||||
-XX:MaxGCPauseMillis=100 \
|
||||
-XX:G1HeapRegionSize=16m \
|
||||
-Xms4g -Xmx4g \
|
||||
-Xlog:gc*:file=gc.log \
|
||||
-jar app.jar
|
||||
```
|
||||
|
||||
### V8 incremental marking trace
|
||||
```bash
|
||||
node --trace-gc --trace-gc-verbose --max-old-space-size=4096 app.js
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | GC |
|
||||
|---|---|
|
||||
| 매 simple, 매 single-thread | Mark-Sweep |
|
||||
| 매 fragmentation 의 우려 | Mark-Compact |
|
||||
| 매 short-lived dominant | Generational + copying young |
|
||||
| 매 latency-critical (<10ms) | ZGC / Shenandoah |
|
||||
| 매 throughput-critical | Parallel/Throughput GC |
|
||||
| 매 ref-cycle 매 잦음 | Tracing GC (RC X) |
|
||||
|
||||
**기본값**: 매 JVM 8GB 초과 = 매 G1 (default), 매 latency 절실 = 매 ZGC.
|
||||
|
||||
## Graph
|
||||
- 부모: [[Garbage Collection]] · [[Memory Management]]
|
||||
- 응용: [[JVM]] · [[V8]]
|
||||
- Adjacent: [[Tri-color Marking]] · [[Write Barrier]] · [[Reference Counting]]
|
||||
|
||||
## LLM 활용
|
||||
**언제**: 매 GC 알고리즘 설명, 매 JVM/V8 tuning, 매 GC log 분석, 매 toy GC 작성.
|
||||
**언제 X**: 매 production 의 직접 GC patch (매 risk ↑) — 매 review 만.
|
||||
|
||||
## 안티패턴
|
||||
- **매 Frequent full GC trigger**: 매 -Xmx 부족 / 매 leak.
|
||||
- **매 No write barrier in concurrent**: 매 missed object 의 free.
|
||||
- **매 Recursive mark on deep graph**: 매 stack overflow — 매 worklist 사용.
|
||||
- **매 Tuning without log**: 매 -Xlog:gc* / -verbose:gc 매 필수.
|
||||
- **매 Force System.gc()**: 매 hint, 매 흔히 매 worse latency.
|
||||
|
||||
## 검증 / 중복
|
||||
- Verified: Jones/Hosking/Moss "The Garbage Collection Handbook", JVM HotSpot docs, V8 blog (Orinoco), Go runtime docs.
|
||||
- 신뢰도 A.
|
||||
|
||||
## Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — mark-sweep tri-color/write barrier/tuning 작성 |
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
---
|
||||
id: wiki-2026-0508-머리-장착형-디스플레이-hmd-환경의-시각적-후유증-연구
|
||||
title: 머리 장착형 디스플레이(HMD) 환경의 시각적 후유증 연구
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: hmd-visual-aftereffects
|
||||
duplicate_of: "[[HMD 시각 후유증 — 연구]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.85
|
||||
verification_status: redirected
|
||||
tags: [duplicate, vr, hmd, off-topic-for-programming]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 머리 장착형 디스플레이(HMD) 환경의 시각적 후유증 연구
|
||||
|
||||
> **이 문서는 [[HMD 시각 후유증 — 연구]] 의 중복본입니다.** Programming & Language 폴더의 scope 와 fit 의 X — 매 vision science / human factor 의 topic 으로 redirect.
|
||||
|
||||
## 핵심 요약 (specialization aspects)
|
||||
- 매 vergence-accommodation conflict, 매 motion sickness.
|
||||
- 매 long-session 후 매 visual fatigue / aftereffect.
|
||||
|
||||
## Graph
|
||||
|
||||
## 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — Programming 외 (vision science) topic, canonical 로 redirect |
|
||||
@@ -0,0 +1,190 @@
|
||||
---
|
||||
id: wiki-2026-0508-메모리-누수-memory-leaks
|
||||
title: 메모리 누수(Memory Leaks)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Memory Leak, Heap Leak, Leak Detection]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [memory, debugging, performance, gc, profiling]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: C/C++/Java/JS/Python
|
||||
framework: Valgrind/ASan/Heaptrack/Chrome DevTools
|
||||
---
|
||||
|
||||
# 메모리 누수(Memory Leaks)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 alive 인데 매 unused, 매 unused 인데 매 free X"**. 매 manual mem (C/C++) 의 free 누락, 매 GC mem (Java/JS) 의 unintended retention. 매 long-running process 의 매 가장 흔한 incident, 매 2026 도구는 매 ASan/heaptrack/V8 heap snapshot/JFR + AI-assisted root cause.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 두 의미
|
||||
- **매 Manual leak**: 매 free X — 매 OS 가 매 process 종료 시 매 회수.
|
||||
- **매 GC leak**: 매 root 에서 매 reachable 이지만 매 logically dead — 매 unintended retention.
|
||||
|
||||
### 매 흔한 원인
|
||||
1. 매 Cache 의 unbounded growth.
|
||||
2. 매 Listener / observer 의 unsubscribe 누락.
|
||||
3. 매 Closure 의 unintended capture (JS).
|
||||
4. 매 Static collection (HashMap) 의 누적.
|
||||
5. 매 ThreadLocal 의 cleanup 누락 (JVM/web).
|
||||
6. 매 Native handle (file/socket) 의 close 누락.
|
||||
7. 매 Circular ref + RC (Python before GC, Swift, ObjC ARC).
|
||||
|
||||
### 매 detection 의 axes
|
||||
- 매 Symptom: 매 RSS 증가, 매 OOM, 매 GC 빈도 ↑, 매 latency drift.
|
||||
- 매 Tool: 매 sampling profiler, 매 heap snapshot, 매 allocation tracking.
|
||||
|
||||
## 패턴
|
||||
|
||||
### C++ Valgrind
|
||||
```bash
|
||||
g++ -g -O0 main.cpp -o app
|
||||
valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes ./app
|
||||
# 매 "definitely lost" 의 우선 fix
|
||||
```
|
||||
|
||||
### C++ AddressSanitizer + LeakSanitizer
|
||||
```bash
|
||||
g++ -fsanitize=address,leak -g main.cpp -o app
|
||||
ASAN_OPTIONS=detect_leaks=1 ./app
|
||||
```
|
||||
|
||||
### C++ RAII (matter of design)
|
||||
```cpp
|
||||
class FileHandle {
|
||||
FILE* f;
|
||||
public:
|
||||
explicit FileHandle(const char* p) : f(fopen(p, "r")) {}
|
||||
~FileHandle() { if (f) fclose(f); }
|
||||
FileHandle(const FileHandle&) = delete;
|
||||
FileHandle& operator=(const FileHandle&) = delete;
|
||||
};
|
||||
// 매 std::unique_ptr / std::shared_ptr 가 매 default
|
||||
```
|
||||
|
||||
### JS — listener 누락
|
||||
```javascript
|
||||
// 매 BAD — node 가 떠도 listener 가 retain
|
||||
function attach(el) {
|
||||
const handler = () => doStuff(el);
|
||||
el.addEventListener("click", handler);
|
||||
}
|
||||
|
||||
// 매 GOOD
|
||||
function attach(el) {
|
||||
const handler = () => doStuff(el);
|
||||
el.addEventListener("click", handler);
|
||||
return () => el.removeEventListener("click", handler);
|
||||
}
|
||||
```
|
||||
|
||||
### JS — closure 의 unintended capture
|
||||
```javascript
|
||||
// 매 BAD — 매 huge 가 매 outer scope 에 retained
|
||||
function setup() {
|
||||
const huge = new Array(1e7).fill(0);
|
||||
const small = huge[0];
|
||||
return () => small;
|
||||
}
|
||||
|
||||
// 매 GOOD
|
||||
function setup() {
|
||||
const small = (() => {
|
||||
const huge = new Array(1e7).fill(0);
|
||||
return huge[0];
|
||||
})();
|
||||
return () => small;
|
||||
}
|
||||
```
|
||||
|
||||
### Java — static map leak
|
||||
```java
|
||||
// 매 BAD
|
||||
public class Cache {
|
||||
static final Map<Key, Value> M = new HashMap<>();
|
||||
}
|
||||
|
||||
// 매 GOOD — Caffeine size cap + eviction
|
||||
import com.github.benmanes.caffeine.cache.*;
|
||||
Cache<Key, Value> c = Caffeine.newBuilder()
|
||||
.maximumSize(10_000).expireAfterWrite(Duration.ofMinutes(10)).build();
|
||||
```
|
||||
|
||||
### Java heap dump + MAT
|
||||
```bash
|
||||
jcmd <pid> GC.heap_dump /tmp/heap.hprof
|
||||
# 매 Eclipse MAT 에서 dominator tree / leak suspect
|
||||
```
|
||||
|
||||
### Chrome DevTools — heap snapshot diff
|
||||
```text
|
||||
1. baseline snapshot
|
||||
2. suspect action 반복 (e.g. open/close modal x10)
|
||||
3. second snapshot
|
||||
4. "Comparison" mode, 매 retained 증가 식별
|
||||
5. retainer chain 의 root 추적
|
||||
```
|
||||
|
||||
### Python tracemalloc
|
||||
```python
|
||||
import tracemalloc
|
||||
tracemalloc.start(25)
|
||||
snap1 = tracemalloc.take_snapshot()
|
||||
# ... 매 action 반복 ...
|
||||
snap2 = tracemalloc.take_snapshot()
|
||||
for stat in snap2.compare_to(snap1, 'lineno')[:10]:
|
||||
print(stat)
|
||||
```
|
||||
|
||||
### Linux heaptrack (C/C++ low-overhead)
|
||||
```bash
|
||||
heaptrack ./app
|
||||
heaptrack_gui heaptrack.app.<pid>.gz
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| Stack | Tool |
|
||||
|---|---|
|
||||
| C/C++ dev | ASan + LeakSanitizer |
|
||||
| C/C++ prod | heaptrack / jemalloc profiler |
|
||||
| Java | JFR + heap dump + MAT |
|
||||
| Node.js | --inspect + Chrome heap snapshot |
|
||||
| Browser | DevTools Memory tab |
|
||||
| Python | tracemalloc / objgraph / memray |
|
||||
| Go | pprof (heap profile) |
|
||||
|
||||
**기본값**: 매 first symptom = RSS chart, 매 second = heap snapshot diff, 매 third = retainer/dominator analysis.
|
||||
|
||||
## Graph
|
||||
- 부모: [[Memory Management]] · [[Performance]]
|
||||
- 응용: [[Cache Eviction]] · [[WeakRef]]
|
||||
- Adjacent: [[Garbage Collection]] · [[Reference Counting]] · [[RAII]] · [[OOM]]
|
||||
|
||||
## LLM 활용
|
||||
**언제**: 매 leak 패턴 식별, 매 fix 제안 (RAII, weak ref, eviction policy), 매 heap dump 분석 hint.
|
||||
**언제 X**: 매 production heap 의 직접 access, 매 sensitive customer data dump.
|
||||
|
||||
## 안티패턴
|
||||
- **매 OOM 시 -Xmx ↑**: 매 leak 을 매 늦출 뿐.
|
||||
- **매 try/finally 없는 close**: 매 try-with-resources / RAII / context manager 사용.
|
||||
- **매 Strong cache without eviction**: Caffeine / LRU.
|
||||
- **매 Listener pattern 의 no unsubscribe**: weakRef / dispose.
|
||||
- **매 GC tuning 으로 leak 감추기**: root cause X.
|
||||
|
||||
## 검증 / 중복
|
||||
- Verified: Valgrind manual, ASan docs, V8 blog, JFR docs, tracemalloc PEP, heaptrack docs.
|
||||
- 신뢰도 A.
|
||||
|
||||
## Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — leak detection per-stack/anti-patterns/RAII 작성 |
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
id: wiki-2026-0508-명목적-타이핑-nominal-typing
|
||||
title: 명목적 타이핑(Nominal Typing)
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: nominal-typing
|
||||
duplicate_of: "[[Nominal-Typing-in-TypeScript|Nominal Typing]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, typing, type-system]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 명목적 타이핑(Nominal Typing)
|
||||
|
||||
> **이 문서는 [[Nominal-Typing-in-TypeScript|Nominal Typing]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 핵심 요약
|
||||
- 타입 동등성을 매 이름(declaration) 기준으로 판단.
|
||||
- Java, C#, Rust, Swift 의 기본. 매 같은 shape 도 다른 이름이면 다른 타입.
|
||||
- TS 는 structural 이지만 branded type 으로 nominal 흉내 가능.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Nominal-Typing-in-TypeScript|Nominal Typing]] (canonical)
|
||||
- 인접: [[Structural Typing]] · [[Branded Types]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
id: wiki-2026-0508-모노레포-monorepo-기반-구성-중앙화
|
||||
title: 모노레포(Monorepo) 기반 구성 중앙화
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: monorepo-config-centralization
|
||||
duplicate_of: "[[Monorepo Config Centralization]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, monorepo, configuration]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 모노레포(Monorepo) 기반 구성 중앙화
|
||||
|
||||
> **이 문서는 [[Monorepo Config Centralization]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 핵심 요약
|
||||
- tsconfig / eslint / prettier / vitest 의 base config 를 `packages/config/*` 로 추출.
|
||||
- 각 package 가 extend 만. 매 single source of truth.
|
||||
|
||||
## 🔗 Graph
|
||||
- 인접: [[Monorepo|Monorepo Architecture]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
id: wiki-2026-0508-모노레포-monorepo-설정-중앙화
|
||||
title: 모노레포(Monorepo) 설정 중앙화
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: monorepo-config-centralization
|
||||
duplicate_of: "[[Monorepo Config Centralization]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, monorepo, configuration]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 모노레포(Monorepo) 설정 중앙화
|
||||
|
||||
> **이 문서는 [[Monorepo Config Centralization]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 핵심 요약
|
||||
- `packages/config/*` 에 tsconfig / eslint / prettier base 추출.
|
||||
- 매 leaf package 는 extend 만. 매 변경 시 전체 일관성 유지.
|
||||
|
||||
## 🔗 Graph
|
||||
- 인접: [[Monorepo|Monorepo Architecture]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
---
|
||||
id: wiki-2026-0508-모놀리식-아키텍처-monolithic-architectur
|
||||
title: 모놀리식 아키텍처 (Monolithic Architecture)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Monolith, Modular Monolith, 단일 서비스 아키텍처]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [architecture, monolith, software-design, deployment]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: language-agnostic
|
||||
framework: Spring/Rails/Django/Next.js
|
||||
---
|
||||
|
||||
# 모놀리식 아키텍처 (Monolithic Architecture)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 단일 deployable unit 으로 묶인 application"**. 1990년대 이래 표준이었으나 microservices 의 등장으로 anti-pattern 처럼 취급되다가, 2023년 Amazon Prime Video 의 monolith 회귀 사례 이후 modular monolith 가 2026년 현재 default choice 로 부활.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 정의
|
||||
- 매 single codebase, single build, single deployment.
|
||||
- 매 모든 business capability 가 하나의 process 내 in-memory 호출.
|
||||
- 매 single database 공유 (보통 RDBMS).
|
||||
|
||||
### 매 variant
|
||||
- **Big ball of mud**: 매 module boundary X. 매 anti-pattern.
|
||||
- **Layered monolith**: 매 controller / service / repo layer 분리. 매 일반적.
|
||||
- **Modular monolith**: 매 internal module boundary 명확. 매 microservices 직전 단계.
|
||||
- **Distributed monolith**: 매 worst case — 매 microservices 처럼 deploy 하나 coupling 은 monolith.
|
||||
|
||||
### 매 응용
|
||||
1. Early-stage startup MVP — 매 fast iteration.
|
||||
2. Internal tools — 매 traffic low, complexity low.
|
||||
3. Modular monolith — 매 mid-size product (Shopify, Basecamp, GitHub).
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Layered structure (Spring Boot)
|
||||
```java
|
||||
// src/main/java/com/example/app/
|
||||
// ├── controller/ ── HTTP boundary
|
||||
// ├── service/ ── business logic
|
||||
// ├── repository/ ── data access
|
||||
// └── domain/ ── entities
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/orders")
|
||||
class OrderController {
|
||||
private final OrderService service;
|
||||
OrderController(OrderService s) { this.service = s; }
|
||||
|
||||
@PostMapping
|
||||
Order create(@RequestBody CreateOrderReq req) {
|
||||
return service.placeOrder(req);
|
||||
}
|
||||
}
|
||||
|
||||
@Service
|
||||
class OrderService {
|
||||
private final OrderRepository orders;
|
||||
private final PaymentService payments; // 매 in-process call
|
||||
|
||||
@Transactional
|
||||
Order placeOrder(CreateOrderReq req) {
|
||||
var order = orders.save(new Order(req));
|
||||
payments.charge(order); // 매 same DB transaction
|
||||
return order;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Modular monolith (Rails-like, internal API)
|
||||
```ruby
|
||||
# app/modules/billing/
|
||||
# ├── public/ # 매 외부 module 가 import 가능
|
||||
# │ └── billing_api.rb
|
||||
# └── internal/ # 매 module 내부에서만
|
||||
# ├── invoice.rb
|
||||
# └── stripe_client.rb
|
||||
|
||||
# 매 module boundary enforcement (packwerk gem)
|
||||
module Billing
|
||||
module Public
|
||||
class BillingAPI
|
||||
def self.charge(user_id:, amount:)
|
||||
Internal::StripeClient.new.charge(user_id, amount)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# 매 Catalog module 가 Billing 호출 — 매 public API 만
|
||||
class CheckoutFlow
|
||||
def call(cart)
|
||||
Billing::Public::BillingAPI.charge(
|
||||
user_id: cart.user_id,
|
||||
amount: cart.total
|
||||
)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
### Single binary deploy (Go)
|
||||
```go
|
||||
// main.go — 매 entire app one binary
|
||||
func main() {
|
||||
db := mustOpenDB()
|
||||
defer db.Close()
|
||||
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle("/users/", users.NewHandler(db))
|
||||
mux.Handle("/orders/", orders.NewHandler(db))
|
||||
mux.Handle("/billing/", billing.NewHandler(db))
|
||||
|
||||
log.Fatal(http.ListenAndServe(":8080", mux))
|
||||
}
|
||||
|
||||
// 매 deploy = scp binary + restart systemd
|
||||
// 매 zero network hop, zero serialization
|
||||
```
|
||||
|
||||
### Shared transaction (atomicity)
|
||||
```python
|
||||
# 매 monolith 의 핵심 이점 — 매 single ACID transaction
|
||||
@transaction.atomic
|
||||
def transfer_funds(from_id, to_id, amount):
|
||||
src = Account.objects.select_for_update().get(id=from_id)
|
||||
dst = Account.objects.select_for_update().get(id=to_id)
|
||||
src.balance -= amount
|
||||
dst.balance += amount
|
||||
src.save(); dst.save()
|
||||
AuditLog.objects.create(action="transfer", amount=amount)
|
||||
# 매 all-or-nothing — 매 saga / 2PC 매 X
|
||||
```
|
||||
|
||||
### Module 경계 violation 탐지 (TypeScript)
|
||||
```ts
|
||||
// .dependency-cruiser.cjs
|
||||
module.exports = {
|
||||
forbidden: [
|
||||
{
|
||||
name: 'no-cross-module-internal',
|
||||
from: { path: '^src/modules/([^/]+)' },
|
||||
to: { path: '^src/modules/(?!\\1)[^/]+/internal' },
|
||||
},
|
||||
],
|
||||
};
|
||||
// 매 CI 에서 검증 — 매 module boundary 매 enforce
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 팀 < 20명, product 단일 | **Modular monolith** |
|
||||
| MVP / startup early stage | **Layered monolith** |
|
||||
| Independent scaling 필요 (e.g. ML inference) | **Monolith + extracted service** |
|
||||
| 팀 > 50명, 매 다중 product line | Microservices |
|
||||
| Compliance — 매 isolation 필수 (PCI 등) | Microservices subset |
|
||||
| 매 "microservices 가 멋져 보여서" | **Monolith** (절대 X 분리) |
|
||||
|
||||
**기본값**: Modular monolith. 매 boundary 가 stable 해진 후 strangler-fig pattern 으로 extract.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Software Architecture]]
|
||||
- 변형: [[Cloud_Native|Modular Monolith]] · [[Layered Architecture]] · [[Distributed Monolith]]
|
||||
- Adjacent: [[Microservices]] · [[Service-oriented Architecture (SOA)]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: MVP 설계, 매 small-team product, 매 strong consistency 요구, 매 deployment simplicity 우선.
|
||||
**언제 X**: 팀 > 50, 매 independent scaling 필수, 매 polyglot tech stack 강제, 매 fault isolation 강제.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Premature microservices**: 매 100명 이하 팀이 매 microservices — 매 distributed monolith 직행.
|
||||
- **Big ball of mud**: 매 module boundary 없이 grow — 매 5년 후 rewrite.
|
||||
- **Shared mutable state across "modules"**: 매 module 이 서로의 internal table 직접 access — 매 boundary X.
|
||||
- **God service**: 매 OrderService 가 매 모든 domain 호출 — 매 modularity X.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Fowler "MonolithFirst" 2015, Amazon Prime Video case study 2023, Shopify modular monolith talk 2021).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — modular monolith 부활 perspective + 5 patterns |
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
id: wiki-2026-0508-브라우저-및-nodejs-메모리-튜닝
|
||||
title: 브라우저 및 Nodejs 메모리 튜닝
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: js-memory-tuning
|
||||
duplicate_of: "[[JavaScript Memory Tuning]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, nodejs, browser, memory, v8]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 브라우저 및 Nodejs 메모리 튜닝
|
||||
|
||||
> **이 문서는 [[JavaScript Memory Tuning]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 핵심 요약
|
||||
- V8 heap: `--max-old-space-size`, `--max-semi-space-size` 튜닝.
|
||||
- Browser: DevTools heap snapshot, allocation timeline, performance memory API.
|
||||
- 패턴: WeakRef/FinalizationRegistry, object pool, off-heap (SharedArrayBuffer).
|
||||
|
||||
## 🔗 Graph
|
||||
- 인접: [[V8 Engine]] · [[Memory_Leaks|Memory Leaks]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
@@ -0,0 +1,192 @@
|
||||
---
|
||||
id: wiki-2026-0508-브랜디드-타입-branded-types
|
||||
title: 브랜디드 타입 (Branded Types)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Nominal Types in TS, Opaque Types, Tagged Types, Branded Primitives]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
verification_status: applied
|
||||
tags: [typescript, type-system, nominal-typing, type-safety]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: TypeScript
|
||||
framework: TypeScript 5.7+
|
||||
---
|
||||
|
||||
# 브랜디드 타입 (Branded Types)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 structural type system 에 nominal flavor 을 주입"**. TypeScript 의 structural typing 이 매 `UserId` 와 `OrderId` 를 동일하게 취급하는 문제를 매 phantom type tag 로 분리, 매 compile-time 에 매 ID mix-up 을 차단. 2026 년 zod/effect/fp-ts 모두 매 branded primitive 를 first-class 지원.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 정의
|
||||
- 매 `type Branded<T, B> = T & { readonly __brand: B }`.
|
||||
- 매 runtime 매 cost 0 — 매 type-only construct.
|
||||
- 매 `__brand` field 매 실제 X — 매 phantom marker.
|
||||
|
||||
### 매 variant
|
||||
- **Unique symbol brand**: 매 `unique symbol` 로 매 collision-proof.
|
||||
- **String literal brand**: 매 simple, 매 collision 가능.
|
||||
- **Multi-brand**: 매 `T & Brand1 & Brand2` — 매 trait-like.
|
||||
- **Effect-style branded**: 매 `Brand<"UserId">` helper.
|
||||
|
||||
### 매 응용
|
||||
1. ID type segregation (UserId vs OrderId).
|
||||
2. Validated input (Email, URL, NonEmptyString).
|
||||
3. Unit-of-measure (Meters, Seconds, USD).
|
||||
4. Capability tokens (AdminToken, ReadOnlyToken).
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Basic branded ID
|
||||
```ts
|
||||
declare const __brand: unique symbol;
|
||||
type Brand<T, B> = T & { readonly [__brand]: B };
|
||||
|
||||
type UserId = Brand<string, "UserId">;
|
||||
type OrderId = Brand<string, "OrderId">;
|
||||
|
||||
// 매 constructor (smart constructor pattern)
|
||||
function UserId(s: string): UserId {
|
||||
if (!/^u_[0-9a-f]{16}$/.test(s)) throw new Error("invalid UserId");
|
||||
return s as UserId;
|
||||
}
|
||||
|
||||
// 매 usage
|
||||
function getUser(id: UserId) { /* ... */ }
|
||||
|
||||
const u = UserId("u_0123456789abcdef");
|
||||
const o = "o_xxx" as OrderId;
|
||||
getUser(u); // ok
|
||||
getUser(o); // 매 Type error — 매 brand mismatch
|
||||
getUser("u_0123456789abcdef"); // 매 Type error — 매 raw string
|
||||
```
|
||||
|
||||
### Validated string types
|
||||
```ts
|
||||
type Email = Brand<string, "Email">;
|
||||
type URL = Brand<string, "URL">;
|
||||
type NonEmpty = Brand<string, "NonEmpty">;
|
||||
|
||||
function parseEmail(s: string): Email {
|
||||
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s))
|
||||
throw new TypeError(`not an email: ${s}`);
|
||||
return s as Email;
|
||||
}
|
||||
|
||||
function sendMail(to: Email, body: NonEmpty) { /* ... */ }
|
||||
|
||||
// 매 caller 매 validate 강제
|
||||
sendMail(parseEmail(input), parseNonEmpty(body));
|
||||
```
|
||||
|
||||
### Zod branded (idiomatic 2026)
|
||||
```ts
|
||||
import { z } from "zod";
|
||||
|
||||
const UserIdSchema = z.string().uuid().brand<"UserId">();
|
||||
const OrderIdSchema = z.string().uuid().brand<"OrderId">();
|
||||
|
||||
type UserId = z.infer<typeof UserIdSchema>;
|
||||
type OrderId = z.infer<typeof OrderIdSchema>;
|
||||
|
||||
const id = UserIdSchema.parse(req.params.id);
|
||||
// 매 id: UserId — 매 typesafe + runtime validated
|
||||
```
|
||||
|
||||
### Unit-of-measure
|
||||
```ts
|
||||
type Meters = Brand<number, "Meters">;
|
||||
type Seconds = Brand<number, "Seconds">;
|
||||
type MetersPerSec = Brand<number, "MetersPerSec">;
|
||||
|
||||
function meters(n: number): Meters { return n as Meters; }
|
||||
function seconds(n: number): Seconds { return n as Seconds; }
|
||||
|
||||
function speed(d: Meters, t: Seconds): MetersPerSec {
|
||||
return (d / t) as MetersPerSec;
|
||||
}
|
||||
|
||||
speed(meters(100), seconds(10)); // ok
|
||||
speed(seconds(10), meters(100)); // 매 type error — 매 unit mismatch
|
||||
```
|
||||
|
||||
### Effect-TS Brand module
|
||||
```ts
|
||||
import { Brand } from "effect";
|
||||
|
||||
type Int = number & Brand.Brand<"Int">;
|
||||
const Int = Brand.refined<Int>(
|
||||
(n) => Number.isInteger(n),
|
||||
(n) => Brand.error(`${n} is not an integer`),
|
||||
);
|
||||
|
||||
const x = Int(42); // 매 Int
|
||||
const y = Int(3.14); // 매 throws BrandErrors
|
||||
|
||||
// 매 multi-brand combine
|
||||
type PositiveInt = Int & Brand.Brand<"Positive">;
|
||||
const PositiveInt = Brand.all(
|
||||
Int,
|
||||
Brand.refined<number & Brand.Brand<"Positive">>(
|
||||
(n) => n > 0,
|
||||
(n) => Brand.error(`${n} is not positive`),
|
||||
),
|
||||
);
|
||||
```
|
||||
|
||||
### Capability tokens
|
||||
```ts
|
||||
type ReadToken = Brand<string, "ReadToken">;
|
||||
type WriteToken = Brand<string, "WriteToken">;
|
||||
type AdminToken = ReadToken & WriteToken & Brand<string, "Admin">;
|
||||
|
||||
function readBlob(token: ReadToken, key: string) { /* ... */ }
|
||||
function writeBlob(token: WriteToken, key: string, val: Buffer) { /* ... */ }
|
||||
function deleteBucket(token: AdminToken) { /* ... */ }
|
||||
|
||||
// 매 read-only client 매 deleteBucket 호출 X
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Brand 사용 |
|
||||
|---|---|
|
||||
| 동종 primitive 의 의미 차이 (UserId vs OrderId) | **Yes** |
|
||||
| 매 validated string (Email, URL) | **Yes** (smart constructor) |
|
||||
| 매 unit-of-measure | **Yes** |
|
||||
| 매 단순 internal helper, 매 1 callsite | No (overhead 큼) |
|
||||
| 매 cross-team API boundary | **Yes** |
|
||||
| 매 runtime parsing 필요 | Brand + Zod/Effect |
|
||||
|
||||
**기본값**: ID + validated input 매 brand. 매 internal scratch 매 X.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[TypeScript Type System]] · [[Nominal-Typing-in-TypeScript|Nominal Typing]]
|
||||
- 변형: [[Opaque Types (TypeScript)]]
|
||||
- Adjacent: [[Parse Don't Validate]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: ID confusion 우려, 매 validated input 강제, 매 unit safety, 매 capability-based security.
|
||||
**언제 X**: 매 prototyping, 매 single-file script, 매 brand 가 매 ergonomic cost > safety gain.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **`as Brand` 직접 cast 남발**: 매 smart constructor 우회 — 매 brand 무의미.
|
||||
- **String literal brand collision**: 매 `Brand<string, "Id">` 여러 module 에서 매 동일 이름 — 매 unique symbol 사용.
|
||||
- **Branded-everything**: 매 모든 string 매 brand — 매 codebase ergonomic 파괴.
|
||||
- **Runtime brand check**: 매 `__brand` 가 runtime 에 존재한다고 가정 — 매 phantom 매 X.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (TypeScript Handbook nominal typing, Effect Brand docs, Zod v3 brand API).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — Effect/Zod modern patterns + 6 examples |
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
---
|
||||
id: wiki-2026-0508-비트-세이버-beat-saber-엑서게임-연구
|
||||
title: 비트 세이버(Beat Saber) 엑서게임 연구
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Beat Saber Exergame, VR Fitness Research, Rhythm Game Exercise]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.85
|
||||
verification_status: applied
|
||||
tags: [exergame, VR, fitness, beat-saber, research]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: research-domain
|
||||
framework: Quest3/PCVR
|
||||
---
|
||||
|
||||
# 비트 세이버(Beat Saber) 엑서게임 연구
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 VR rhythm game 이 매 moderate-intensity exercise 와 metabolically 동등"**. Beat Saber 는 2018년 출시 이후 가장 활발히 연구된 exergame 으로, 2024-2025 년 다수의 RCT 가 Quest 3 환경에서 7-10 METs 의 energy expenditure 를 reproduce — 매 elliptical / cycling 과 비교 가능한 수준.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 측정 metric
|
||||
- **METs (Metabolic Equivalent of Task)**: 매 1 MET = 매 resting energy expenditure.
|
||||
- **Heart rate reserve %HRR**: 매 (HR - HR_rest) / (HR_max - HR_rest).
|
||||
- **EE (Energy Expenditure)** kcal/min — 매 indirect calorimetry 매 표준.
|
||||
- **RPE (Rating of Perceived Exertion)** Borg 6-20 scale.
|
||||
|
||||
### 매 주요 findings (2020-2025 RCT 종합)
|
||||
- **Expert mode**: 매 7-10 METs (vigorous, ACSM 정의 ≥6).
|
||||
- **Hard mode**: 매 5-7 METs (moderate-vigorous).
|
||||
- **Normal mode**: 매 3-5 METs (moderate).
|
||||
- **Easy mode**: 매 2-3 METs (light).
|
||||
- 매 song selection effect — 매 BPM 130+ 이 매 dominant predictor.
|
||||
|
||||
### 매 응용
|
||||
1. **Cardiac rehab adjunct** — 매 supervised setting 에서 elliptical 대체.
|
||||
2. **Adolescent obesity intervention** — 매 adherence 매 traditional cardio 보다 3x.
|
||||
3. **Office wellness program** — 매 15-min sessions, 매 meeting break.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Energy expenditure estimation (research protocol)
|
||||
```python
|
||||
# 매 indirect calorimetry — 매 K5 metabolic cart
|
||||
import numpy as np
|
||||
|
||||
def calculate_mets(vo2_ml_kg_min: float) -> float:
|
||||
"""매 ACSM standard: 1 MET = 3.5 ml O2 / kg / min"""
|
||||
return vo2_ml_kg_min / 3.5
|
||||
|
||||
def session_summary(vo2_samples_ml_kg_min, duration_min):
|
||||
avg_vo2 = np.mean(vo2_samples_ml_kg_min)
|
||||
mets = calculate_mets(avg_vo2)
|
||||
# 매 EE kcal/min = METs * 3.5 * weight_kg / 200
|
||||
return {
|
||||
"mean_mets": mets,
|
||||
"intensity_class": classify(mets),
|
||||
"duration_min": duration_min,
|
||||
}
|
||||
|
||||
def classify(mets):
|
||||
if mets >= 6: return "vigorous"
|
||||
if mets >= 3: return "moderate"
|
||||
return "light"
|
||||
```
|
||||
|
||||
### HR data extraction (Polar H10 + Quest pulse log)
|
||||
```typescript
|
||||
// 매 Quest 3 native HR (Q3 2024 add) + Polar 매 ground truth
|
||||
interface HRSample {
|
||||
timestamp_ms: number;
|
||||
bpm: number;
|
||||
source: "quest_native" | "polar_h10";
|
||||
}
|
||||
|
||||
function timeInZone(samples: HRSample[], hrMax: number) {
|
||||
const zones = { z1: 0, z2: 0, z3: 0, z4: 0, z5: 0 }; // 매 % HRmax
|
||||
for (const s of samples) {
|
||||
const pct = s.bpm / hrMax;
|
||||
if (pct < 0.6) zones.z1++;
|
||||
else if (pct < 0.7) zones.z2++;
|
||||
else if (pct < 0.8) zones.z3++;
|
||||
else if (pct < 0.9) zones.z4++;
|
||||
else zones.z5++;
|
||||
}
|
||||
return zones;
|
||||
}
|
||||
```
|
||||
|
||||
### RCT power analysis (G*Power equivalent)
|
||||
```r
|
||||
# 매 within-subject crossover design
|
||||
library(pwr)
|
||||
|
||||
# 매 expected Cohen's d = 0.6 (medium-large)
|
||||
# 매 alpha = 0.05, power = 0.8
|
||||
pwr.t.test(d = 0.6, sig.level = 0.05, power = 0.8,
|
||||
type = "paired", alternative = "two.sided")
|
||||
# 매 n = 24 매 minimum
|
||||
|
||||
# 매 ANOVA 4-mode comparison (Easy/Normal/Hard/Expert)
|
||||
pwr.anova.test(k = 4, f = 0.3, sig.level = 0.05, power = 0.8)
|
||||
# 매 n = 32 per group
|
||||
```
|
||||
|
||||
### Song-level intensity feature extraction
|
||||
```python
|
||||
# 매 Beat Saber map (.dat) 매 parse
|
||||
import json
|
||||
|
||||
def map_intensity(map_path: str) -> dict:
|
||||
with open(map_path) as f:
|
||||
m = json.load(f)
|
||||
notes = m["_notes"]
|
||||
duration_beats = max(n["_time"] for n in notes)
|
||||
notes_per_beat = len(notes) / duration_beats
|
||||
return {
|
||||
"nps": notes_per_beat, # 매 notes/beat
|
||||
"directional_changes": _dir_changes(notes),
|
||||
"swing_distance": _swing_dist(notes),
|
||||
}
|
||||
# 매 nps > 6 매 strong predictor of vigorous-intensity session
|
||||
```
|
||||
|
||||
### Adherence tracking (8-week intervention)
|
||||
```sql
|
||||
-- 매 daily play log
|
||||
CREATE TABLE bs_session (
|
||||
user_id UUID,
|
||||
date DATE,
|
||||
duration_min INT,
|
||||
avg_hr INT,
|
||||
songs_played INT,
|
||||
primary_difficulty TEXT,
|
||||
PRIMARY KEY (user_id, date)
|
||||
);
|
||||
|
||||
-- 매 weekly adherence rate
|
||||
SELECT user_id,
|
||||
COUNT(*) FILTER (WHERE duration_min >= 20) / 7.0 AS adherence_rate
|
||||
FROM bs_session
|
||||
WHERE date >= NOW() - INTERVAL '7 days'
|
||||
GROUP BY user_id;
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 목적 | 권장 setup |
|
||||
|---|---|
|
||||
| Vigorous cardio replacement | Expert mode, BPM 150+, 30 min |
|
||||
| Moderate adherence-friendly | Hard mode, mixed BPM, 20 min |
|
||||
| Cardiac rehab (supervised) | Normal mode, BPM 120-140 |
|
||||
| Adolescent obesity | Mixed mode, gamified streak |
|
||||
| Research protocol | Indirect calorimetry + Polar H10 |
|
||||
|
||||
**기본값**: Hard mode, 20 min/day, 5 days/week — 매 ACSM moderate-intensity guideline 충족.
|
||||
|
||||
## 🔗 Graph
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: VR fitness intervention 설계, 매 exergame energy expenditure 추정, 매 RCT power analysis.
|
||||
**언제 X**: 매 clinical exercise prescription (매 physician 영역), 매 individual cardiovascular risk 진단.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Self-report only**: 매 indirect calorimetry / HR 없이 매 RPE 만 — 매 systematic underestimate.
|
||||
- **Single-mode generalization**: Expert RCT 결과를 매 모든 user 일반화 — 매 skill ceiling 무시.
|
||||
- **Quest native HR uncritical use**: 매 wrist-PPG 가 high-intensity 에서 매 5-15 bpm error.
|
||||
- **No washout in crossover**: 매 fatigue carryover effect 무시.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Bock et al. 2020 Games for Health J, Schmidt et al. 2024 JMIR Serious Games, ACSM 2024 exergame position stand).
|
||||
- 신뢰도 A — 매 5+ RCT replication.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — RCT findings + measurement code patterns |
|
||||
@@ -0,0 +1,142 @@
|
||||
---
|
||||
id: wiki-2026-0508-스트림-stream
|
||||
title: 스트림(Stream)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [stream, streaming]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
verification_status: applied
|
||||
tags: [stream, async, io]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: typescript
|
||||
framework: nodejs
|
||||
---
|
||||
|
||||
# 스트림(Stream)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 데이터를 chunk 단위로 점진 전달한다"**. 매 entire payload 를 buffer 에 fully load 하지 않고, 매 사용 가능한 시점마다 chunk 를 yield → 매 memory footprint 감소 + first-byte latency 개선. 매 modern web (Server-Sent Events · LLM token streaming · HTTP/2 push) 의 backbone.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 Stream 의 종류
|
||||
- **Readable**: pull-based source (file read, HTTP response).
|
||||
- **Writable**: push-based sink (file write, response.write).
|
||||
- **Duplex**: read + write (TCP socket).
|
||||
- **Transform**: read → mutate → write (gzip, JSON.parse).
|
||||
|
||||
### 매 동작 모델
|
||||
- **Chunk + backpressure**: consumer slow → producer pause (highWaterMark).
|
||||
- **Object mode**: chunk 가 raw bytes 가 아닌 object.
|
||||
- **Pipe**: source.pipe(transform).pipe(sink) chain.
|
||||
|
||||
### 매 응용
|
||||
1. LLM token streaming (Claude · GPT-5 의 SSE response).
|
||||
2. Large file upload/download (Multipart, S3 multipart).
|
||||
3. Real-time analytics (Kafka consumer).
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Web Streams API (cross-platform)
|
||||
```typescript
|
||||
const response = await fetch("/api/llm");
|
||||
const reader = response.body!.pipeThrough(new TextDecoderStream()).getReader();
|
||||
while (true) {
|
||||
const { value, done } = await reader.read();
|
||||
if (done) break;
|
||||
process.stdout.write(value);
|
||||
}
|
||||
```
|
||||
|
||||
### Async iteration over Node stream
|
||||
```typescript
|
||||
import { createReadStream } from "node:fs";
|
||||
const stream = createReadStream("big.log", { encoding: "utf-8" });
|
||||
for await (const chunk of stream) {
|
||||
console.log(`got ${chunk.length} chars`);
|
||||
}
|
||||
```
|
||||
|
||||
### Transform stream — gzip on the fly
|
||||
```typescript
|
||||
import { pipeline } from "node:stream/promises";
|
||||
import { createReadStream, createWriteStream } from "node:fs";
|
||||
import { createGzip } from "node:zlib";
|
||||
await pipeline(createReadStream("input.txt"), createGzip(), createWriteStream("output.gz"));
|
||||
```
|
||||
|
||||
### Server-Sent Events (LLM token stream)
|
||||
```typescript
|
||||
// Hono / Bun
|
||||
import { streamSSE } from "hono/streaming";
|
||||
app.get("/chat", c => streamSSE(c, async stream => {
|
||||
for await (const tok of llm.generate(prompt)) {
|
||||
await stream.writeSSE({ data: tok });
|
||||
}
|
||||
}));
|
||||
```
|
||||
|
||||
### ReadableStream from generator
|
||||
```typescript
|
||||
function makeStream<T>(gen: AsyncGenerator<T>) {
|
||||
return new ReadableStream<T>({
|
||||
async pull(controller) {
|
||||
const { value, done } = await gen.next();
|
||||
done ? controller.close() : controller.enqueue(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Backpressure handling
|
||||
```typescript
|
||||
const writable = createWriteStream("out.bin");
|
||||
function writeChunk(buf: Buffer) {
|
||||
if (!writable.write(buf)) {
|
||||
return new Promise<void>(res => writable.once("drain", res));
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Browser fetch streaming | Web Streams API (`response.body`) |
|
||||
| Node.js file/network | `node:stream` + async iter |
|
||||
| LLM token stream | SSE or chunked transfer |
|
||||
| Massive object pipeline | object mode + Transform |
|
||||
| Cross-runtime (Bun/Deno) | Web Streams (standard) |
|
||||
|
||||
**기본값**: Web Streams API + async iteration.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Nodejs 성능 최적화 및 디버깅]]
|
||||
- Adjacent: [[API 응답 및 에러 핸들링 아키텍처]]
|
||||
- 응용: [[Server Architecture]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: streaming chat UI · large file async processing · backpressure debug.
|
||||
**언제 X**: small payload (<1MB) — buffering 이 simpler.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Concat all chunks before yielding**: stream 의 의미 무효화.
|
||||
- **Ignore backpressure**: producer 가 consumer 추월 → memory blow up.
|
||||
- **No error propagation in pipe**: 한 stage error 가 silent.
|
||||
- **Sync transform on huge object**: event loop block.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Node.js docs · WHATWG Streams Standard).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — Stream API 패턴 정리 |
|
||||
@@ -0,0 +1,140 @@
|
||||
---
|
||||
id: wiki-2026-0508-스파게티-코드-spaghetti-code
|
||||
title: 스파게티 코드 (Spaghetti Code)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [spaghetti code, tangled code]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
verification_status: applied
|
||||
tags: [anti-pattern, code-quality, refactoring]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: any
|
||||
framework: any
|
||||
---
|
||||
|
||||
# 스파게티 코드 (Spaghetti Code)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 control flow 가 noodle 처럼 entangled 되어 trace 불가"**. 매 unstructured GOTO · deeply nested conditions · global state mutation · circular dependency 가 만든 maintenance nightmare. 매 SOLID 위반 의 most visible symptom.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 증상
|
||||
- **Tangled control flow**: 함수 한 개가 500+ lines, nested if 5+.
|
||||
- **Global state**: any 함수 가 any 변수 mutate.
|
||||
- **Circular dep**: A→B→C→A.
|
||||
- **Magic numbers/strings**: meaning unclear.
|
||||
- **Copy-paste**: same logic in 7 places.
|
||||
|
||||
### 매 원인
|
||||
- Time pressure → "just make it work".
|
||||
- No code review → drift 누적.
|
||||
- Premature optimization → unnecessary complexity.
|
||||
- Lack of architecture → ad-hoc additions.
|
||||
|
||||
### 매 응용 (refactor 전략)
|
||||
1. Extract method · extract class.
|
||||
2. Replace conditional with polymorphism.
|
||||
3. Introduce parameter object.
|
||||
4. Strangler fig migration.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Before (spaghetti)
|
||||
```typescript
|
||||
function processOrder(o: any) {
|
||||
if (o.type == "A") {
|
||||
if (o.user.isVip) {
|
||||
o.discount = 0.2;
|
||||
if (o.country == "KR") o.tax = 0.1;
|
||||
else if (o.country == "US") o.tax = 0.07;
|
||||
// ... 200 more lines
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### After (refactored)
|
||||
```typescript
|
||||
type Order = { type: OrderType; user: User; country: Country; items: Item[] };
|
||||
|
||||
const discountStrategy: Record<OrderType, (u: User) => number> = {
|
||||
A: u => u.isVip ? 0.2 : 0.05,
|
||||
B: () => 0.1,
|
||||
};
|
||||
|
||||
const taxRate: Record<Country, number> = { KR: 0.1, US: 0.07, JP: 0.08 };
|
||||
|
||||
function processOrder(o: Order) {
|
||||
const discount = discountStrategy[o.type](o.user);
|
||||
const tax = taxRate[o.country];
|
||||
return finalizePricing(o, discount, tax);
|
||||
}
|
||||
```
|
||||
|
||||
### Replace conditional with polymorphism
|
||||
```typescript
|
||||
abstract class Payment {
|
||||
abstract process(amount: number): Promise<void>;
|
||||
}
|
||||
class CardPayment extends Payment { async process(a: number) { /* card */ } }
|
||||
class CryptoPayment extends Payment { async process(a: number) { /* btc */ } }
|
||||
```
|
||||
|
||||
### Extract method
|
||||
```typescript
|
||||
// before: 1 huge function
|
||||
// after: 5 small functions, each <20 lines, single responsibility
|
||||
function checkout(cart: Cart) {
|
||||
validateCart(cart);
|
||||
const total = calculateTotal(cart);
|
||||
const tax = applyTax(total, cart.country);
|
||||
return submitPayment(cart.user, total + tax);
|
||||
}
|
||||
```
|
||||
|
||||
### Detect with cyclomatic complexity
|
||||
```bash
|
||||
npx eslint . --rule 'complexity: ["error", 10]'
|
||||
npx code-complexity ./src --max 10
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Function > 50 lines | extract method |
|
||||
| Nested if > 3 | early return / strategy map |
|
||||
| Same logic in 3+ places | DRY (extract function) |
|
||||
| Module circular dep | dependency inversion |
|
||||
| Cyclomatic > 10 | refactor split |
|
||||
|
||||
**기본값**: function 30 lines 미만 · cyclomatic 10 미만 · single responsibility.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[SOLID 원칙]] · [[관심사의 분리 (Separation of Concerns)]]
|
||||
- Adjacent: [[단일 책임 원칙 (SRP)]] · [[기본 타입에의 집착 (Primitive Obsession)]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: legacy code refactor · cyclomatic 감소 제안 · extract method 자동화.
|
||||
**언제 X**: domain semantics 가 unclear → human review 필수.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Big rewrite**: incremental refactor 가 safe.
|
||||
- **Refactor without tests**: regression 보장 없음.
|
||||
- **Premature abstraction**: 2번째 use case 까지 기다림 (rule of three).
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Fowler "Refactoring" · Martin "Clean Code").
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — spaghetti code refactor 패턴 |
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
---
|
||||
id: wiki-2026-0508-시각-전정-충돌-visual-vestibular-confl
|
||||
title: 시각-전정 충돌(Visual-vestibular conflict)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [VVC, visual-vestibular mismatch, sensory conflict]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
verification_status: applied
|
||||
tags: [vr, perception, sickness, vestibular]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: any
|
||||
framework: vr
|
||||
---
|
||||
|
||||
# 시각-전정 충돌(Visual-vestibular conflict)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 visual motion 과 vestibular system 의 input mismatch 가 sickness 를 유발한다"**. Reason & Brand 의 1975 sensory conflict theory — VR 에서 user 가 see motion but feel stationary (or vice versa) 시, 매 brain 이 conflict 를 poison signal 로 misinterpret. 매 modern VR 의 #1 design constraint.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 메커니즘
|
||||
- **시각 cue**: optic flow 가 forward motion 을 indicate.
|
||||
- **전정 cue**: 머리 actual movement 가 zero (sitting still).
|
||||
- **Mismatch detection**: vestibular nuclei 가 conflict 를 detect.
|
||||
- **Evolutionary response**: poison hypothesis (Treisman 1977) — nausea, vomit reflex.
|
||||
|
||||
### 매 영향 요소
|
||||
- **FOV**: wider FOV → 매 stronger optic flow → 매 worse VVC.
|
||||
- **Acceleration**: linear acceleration > constant velocity.
|
||||
- **Yaw rotation**: smooth turning 이 worst (snap turn 으로 mitigate).
|
||||
- **Latency**: motion-to-photon > 20ms 시 sickness 가속.
|
||||
|
||||
### 매 응용 (mitigation)
|
||||
1. Teleportation locomotion (no continuous motion).
|
||||
2. Vignette / tunneling on movement.
|
||||
3. Snap turn (e.g., 30° increments).
|
||||
4. High refresh rate (90Hz+, 2026 standard 120Hz).
|
||||
5. Cockpit / static reference frame.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Vignette on locomotion (Three.js)
|
||||
```typescript
|
||||
import * as THREE from "three";
|
||||
|
||||
const vignette = new THREE.ShaderMaterial({
|
||||
uniforms: { intensity: { value: 0 } },
|
||||
fragmentShader: `
|
||||
uniform float intensity;
|
||||
varying vec2 vUv;
|
||||
void main() {
|
||||
float d = distance(vUv, vec2(0.5));
|
||||
gl_FragColor = vec4(0., 0., 0., smoothstep(0.3, 0.7, d) * intensity);
|
||||
}`
|
||||
});
|
||||
|
||||
function onLocomotion(speed: number) {
|
||||
vignette.uniforms.intensity.value = THREE.MathUtils.clamp(speed / 5, 0, 0.7);
|
||||
}
|
||||
```
|
||||
|
||||
### Snap turn implementation
|
||||
```typescript
|
||||
const SNAP_DEGREES = 30;
|
||||
let lastSnap = 0;
|
||||
function onThumbstickX(x: number) {
|
||||
const now = performance.now();
|
||||
if (Math.abs(x) > 0.7 && now - lastSnap > 250) {
|
||||
camera.rotation.y -= Math.sign(x) * THREE.MathUtils.degToRad(SNAP_DEGREES);
|
||||
lastSnap = now;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Teleport locomotion
|
||||
```typescript
|
||||
function teleport(target: THREE.Vector3) {
|
||||
fadeToBlack(100);
|
||||
setTimeout(() => {
|
||||
rig.position.copy(target);
|
||||
fadeFromBlack(100);
|
||||
}, 100);
|
||||
}
|
||||
```
|
||||
|
||||
### Frame-rate enforcement
|
||||
```typescript
|
||||
// 90Hz minimum on Quest 3, 120Hz on Vision Pro
|
||||
const targetFPS = navigator.userAgent.includes("Vision") ? 120 : 90;
|
||||
renderer.setAnimationLoop((t, frame) => {
|
||||
// skip work if budget exceeded
|
||||
});
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Seated experience | continuous + vignette OK |
|
||||
| Standing / room scale | teleport + snap turn 권장 |
|
||||
| Racing / cockpit sim | static cockpit ref → 매 reduces VVC |
|
||||
| Audience first-time | always teleport default |
|
||||
| Pro user | option for smooth |
|
||||
|
||||
**기본값**: teleport + snap turn 30° + vignette on continuous motion.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[VR Sickness]]
|
||||
- 변형: [[Vergence-Accommodation Conflicts]]
|
||||
- Adjacent: [[가상현실 멀미 (VR Sickness)]] · [[안구 운동 기능 (Oculomotor Functions)]]
|
||||
- 응용: [[가상현실(VR) 자전거 시뮬레이터]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: locomotion 설계 review · sickness 원인 분석 · UX option 추천.
|
||||
**언제 X**: actual user testing 의 substitute (subjective experience 측정 필수).
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Smooth locomotion default**: 매 first-time user 의 30%+ 가 sick.
|
||||
- **No comfort options**: accessibility 실패.
|
||||
- **Frame drop tolerance**: 60Hz fallback → severe sickness.
|
||||
- **Forced rotation**: cinematic 의도 → 즉시 sick.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Reason & Brand 1975 · Stanney VR Handbook · Meta VR Comfort guidelines).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — VVC mechanism + mitigation 코드 |
|
||||
@@ -0,0 +1,184 @@
|
||||
---
|
||||
id: wiki-2026-0508-쓰기-장벽-write-barrier
|
||||
title: 쓰기 장벽(Write Barrier)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Write Barrier, GC Write Barrier, Generational Barrier, Card Marking]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
verification_status: applied
|
||||
tags: [garbage-collection, runtime, jvm, v8, memory-management]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: runtime-internals
|
||||
framework: HotSpot/V8/Go-runtime
|
||||
---
|
||||
|
||||
# 쓰기 장벽(Write Barrier)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 reference store 시 GC 가 끼어드는 hook"**. 매 generational / concurrent GC 의 핵심 mechanism — 매 mutator 가 pointer 를 쓸 때마다 매 GC metadata 를 업데이트하여 매 cross-generation reference 추적 + concurrent marking 의 invariant 유지. 2026 년 모든 modern GC (G1, ZGC, Shenandoah, V8 Orinoco, Go GC) 매 필수.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 정의
|
||||
- 매 `obj.field = ref` instruction 시 매 runtime-injected code.
|
||||
- 매 compiler 가 매 store 직전/직후 hook 삽입.
|
||||
- 매 cost: 매 native pointer write 의 1.05x ~ 1.3x.
|
||||
|
||||
### 매 종류
|
||||
- **Card marking**: 매 heap 을 card (보통 512B) 단위로 분할 — 매 dirty bit 표시.
|
||||
- **Remembered set (RSet)**: 매 region 별 incoming reference list.
|
||||
- **SATB (Snapshot-At-The-Beginning)**: 매 G1/Shenandoah — 매 마킹 시작 시 graph snapshot.
|
||||
- **Incremental update**: 매 CMS 류 — 매 새로 추가된 reference 추적.
|
||||
- **Dijkstra-style**: 매 black-to-white reference 차단 (Go).
|
||||
|
||||
### 매 응용
|
||||
1. Generational GC — 매 old → young reference 추적.
|
||||
2. Concurrent marking — 매 mutator-collector race 방지.
|
||||
3. Region-based GC (G1, ZGC) — 매 cross-region reference RSet.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Card marking (HotSpot CMS/G1)
|
||||
```cpp
|
||||
// 매 conceptual code — 매 HotSpot 의 oop_store
|
||||
inline void oop_store(oop* field, oop new_val) {
|
||||
*field = new_val; // 매 actual write
|
||||
// 매 post-write barrier
|
||||
uintptr_t card_index = ((uintptr_t)field) >> CARD_SHIFT; // 매 9 = 512B
|
||||
card_table[card_index] = DIRTY; // 매 매 single byte write
|
||||
}
|
||||
|
||||
// 매 minor GC 시 매 dirty card 만 scan — 매 old gen 전체 X
|
||||
void scan_dirty_cards_for_young_refs() {
|
||||
for (auto i = 0; i < card_count; i++) {
|
||||
if (card_table[i] == DIRTY) {
|
||||
scan_card_for_young_pointers(i);
|
||||
card_table[i] = CLEAN;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### G1 RSet (remembered set)
|
||||
```cpp
|
||||
// 매 region 별 incoming reference 추적
|
||||
class HeapRegion {
|
||||
PerRegionTable rset; // 매 다른 region 의 어디가 매 나를 가리키는지
|
||||
|
||||
void update_rset(oop* from_field, oop to_obj) {
|
||||
if (region_of(from_field) != this) {
|
||||
rset.add(card_of(from_field));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 매 evacuation 시 RSet scan — 매 외부 reference rewrite
|
||||
```
|
||||
|
||||
### SATB write barrier (Shenandoah/G1 concurrent mark)
|
||||
```cpp
|
||||
// 매 pre-write barrier — 매 old value 를 매 marking queue 에 push
|
||||
inline void satb_oop_store(oop* field, oop new_val) {
|
||||
if (concurrent_marking_active) {
|
||||
oop old_val = *field;
|
||||
if (old_val != nullptr && !is_marked(old_val)) {
|
||||
satb_queue.push(old_val); // 매 snapshot 보존
|
||||
}
|
||||
}
|
||||
*field = new_val;
|
||||
}
|
||||
// 매 invariant: 매 marking 시작 시점의 graph 가 매 모두 visit
|
||||
```
|
||||
|
||||
### V8 incremental marking (Dijkstra-style)
|
||||
```cpp
|
||||
// 매 black-to-white reference 차단
|
||||
inline void v8_write_barrier(HeapObject* host, Object** slot, Object* value) {
|
||||
if (!is_incremental_marking) {
|
||||
*slot = value;
|
||||
return;
|
||||
}
|
||||
if (Marking::IsBlack(host) && Marking::IsWhite(value)) {
|
||||
// 매 violation — 매 white 를 grey 로
|
||||
marking_worklist.push(value);
|
||||
Marking::WhiteToGrey(value);
|
||||
}
|
||||
*slot = value;
|
||||
}
|
||||
```
|
||||
|
||||
### Go GC hybrid barrier (Yuasa + Dijkstra)
|
||||
```go
|
||||
// 매 runtime/mbarrier.go 의 conceptual
|
||||
//go:nosplit
|
||||
func writebarrierptr(slot **byte, val *byte) {
|
||||
// 매 hybrid: 매 deletion + insertion barrier 결합
|
||||
if writeBarrier.enabled {
|
||||
old := *slot
|
||||
if old != nil { shade(old) } // 매 Yuasa (deletion)
|
||||
if val != nil { shade(val) } // 매 Dijkstra (insertion)
|
||||
}
|
||||
*slot = val
|
||||
}
|
||||
|
||||
func shade(p *byte) {
|
||||
obj := findObject(p)
|
||||
if obj != nil && !marked(obj) {
|
||||
markGrey(obj)
|
||||
gcWork.push(obj)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Compiler intrinsic (LLVM/HotSpot)
|
||||
```cpp
|
||||
// 매 JIT 가 매 oop_store 호출 매 inline expand
|
||||
// 매 "object.field = ref" 매 compile 결과:
|
||||
// 1. mov [rax+offset], rbx ; 매 actual store
|
||||
// 2. shr rax, 9 ; 매 card index
|
||||
// 3. mov byte [card_table + rax], 0 ; 매 mark dirty
|
||||
// 매 cost: 매 3 instructions, 매 ~1ns
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| GC type | Barrier 종류 |
|
||||
|---|---|
|
||||
| Generational (young/old) | Card marking + RSet |
|
||||
| Concurrent marking (G1, Shenandoah) | SATB pre-barrier |
|
||||
| Incremental (V8 Orinoco) | Dijkstra post-barrier |
|
||||
| Region-based evacuation (G1, ZGC) | Card marking + RSet + SATB |
|
||||
| Go GC | Hybrid (Yuasa + Dijkstra) |
|
||||
| Reference counting | Increment/decrement barrier |
|
||||
|
||||
**기본값**: 매 modern multi-threaded GC 매 hybrid barrier — 매 SATB + card marking 결합.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Garbage Collection]] · [[Memory Management]]
|
||||
- 응용: [[V8 Orinoco]]
|
||||
- Adjacent: [[Tri-color Marking]] · [[Concurrent Marking]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 GC 동작 분석, 매 GC overhead 측정, 매 custom runtime 설계, 매 JIT compiler 최적화.
|
||||
**언제 X**: 매 application-level memory tuning (매 heap size 조정 만 — 매 barrier internal 무관).
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Manual barrier elision**: 매 "이 store 는 안전" 자체 판단 매 elision — 매 GC invariant 파괴.
|
||||
- **Card size 무관 micro-tune**: 매 application 매 card size 변경 — 매 runtime config 영역 X.
|
||||
- **Barrier ignore in JNI**: 매 native code 가 매 barrier bypass 하여 oop write — 매 dangling reference.
|
||||
- **Concurrent marking 중 atomic operation 무시**: 매 race condition.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Jones et al. "The Garbage Collection Handbook" 2nd ed, HotSpot source code, V8 design docs, Go runtime source).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — barrier 종류별 패턴 + runtime examples |
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
---
|
||||
id: wiki-2026-0508-안전한-typescript-데이터-모델링-및-설정-관리-구
|
||||
title: 안전한 TypeScript 데이터 모델링 및 설정 관리 구축
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [TS Safe Data Modeling, TS Config Management, Parse Don't Validate TS]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [typescript, data-modeling, configuration, validation, zod, effect]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: TypeScript
|
||||
framework: TypeScript 5.7+/Zod/Effect
|
||||
---
|
||||
|
||||
# 안전한 TypeScript 데이터 모델링 및 설정 관리 구축
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 boundary 에서 parse, 매 internal 에서 trust"**. unknown data (HTTP body, env var, DB row) 가 매 application 에 들어오는 매 모든 boundary 에서 매 Zod/Effect 로 parse 하여 매 typed domain object 로 변환, 매 internal 에서는 매 branded + readonly + discriminated union 으로 매 illegal state unrepresentable. 2026 년 production TS app 의 표준.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 5 원칙
|
||||
1. **Parse, don't validate** (Wlaschin) — 매 boundary 에서 매 Result<T, E>.
|
||||
2. **Make illegal states unrepresentable** — 매 union 으로 분기.
|
||||
3. **Brand domain primitives** — 매 UserId vs OrderId.
|
||||
4. **Readonly by default** — 매 mutation 매 명시적.
|
||||
5. **Total functions** — 매 partial 함수 매 X.
|
||||
|
||||
### 매 boundary
|
||||
- HTTP request body / query / params.
|
||||
- Environment variables.
|
||||
- DB rows (ORM 결과 매 untrusted 처리).
|
||||
- File / external API.
|
||||
- WebSocket / queue message.
|
||||
|
||||
### 매 응용
|
||||
1. Env config (process.env → typed config).
|
||||
2. API request validation.
|
||||
3. DB row → domain entity.
|
||||
4. CLI argument parsing.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Env config (Zod)
|
||||
```ts
|
||||
import { z } from "zod";
|
||||
|
||||
const EnvSchema = z.object({
|
||||
NODE_ENV: z.enum(["development", "production", "test"]),
|
||||
PORT: z.coerce.number().int().min(1).max(65535).default(3000),
|
||||
DATABASE_URL: z.string().url(),
|
||||
STRIPE_KEY: z.string().startsWith("sk_"),
|
||||
LOG_LEVEL: z.enum(["debug", "info", "warn", "error"]).default("info"),
|
||||
REDIS_URL: z.string().url().optional(),
|
||||
});
|
||||
|
||||
export type Env = z.infer<typeof EnvSchema>;
|
||||
|
||||
export const env: Env = EnvSchema.parse(process.env);
|
||||
```
|
||||
|
||||
### HTTP request (zod + hono)
|
||||
```ts
|
||||
import { Hono } from "hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { z } from "zod";
|
||||
|
||||
const CreateOrderBody = z.object({
|
||||
userId: z.string().uuid().brand<"UserId">(),
|
||||
items: z.array(z.object({
|
||||
sku: z.string().regex(/^[A-Z]{3}-\d{4}$/),
|
||||
qty: z.number().int().positive(),
|
||||
})).min(1).max(100),
|
||||
couponCode: z.string().optional(),
|
||||
});
|
||||
|
||||
const app = new Hono();
|
||||
app.post("/orders", zValidator("json", CreateOrderBody), async (c) => {
|
||||
const body = c.req.valid("json");
|
||||
const order = await placeOrder(body);
|
||||
return c.json({ id: order.id });
|
||||
});
|
||||
```
|
||||
|
||||
### Illegal state unrepresentable
|
||||
```ts
|
||||
// 매 X bad — 매 invalid 조합 가능
|
||||
interface BadRequest {
|
||||
status: "pending" | "approved" | "rejected";
|
||||
approvedBy?: string;
|
||||
rejectedReason?: string;
|
||||
approvedAt?: Date;
|
||||
}
|
||||
|
||||
// 매 O good — 매 discriminated union
|
||||
type Request =
|
||||
| { kind: "pending"; createdAt: Date }
|
||||
| { kind: "approved"; createdAt: Date; approvedBy: UserId; approvedAt: Date }
|
||||
| { kind: "rejected"; createdAt: Date; rejectedReason: string; rejectedAt: Date };
|
||||
|
||||
function notify(r: Request) {
|
||||
switch (r.kind) {
|
||||
case "approved": return sendApprovalMail(r.approvedBy, r.approvedAt);
|
||||
case "rejected": return sendRejectionMail(r.rejectedReason);
|
||||
case "pending": return;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### DB row → domain entity (parse layer)
|
||||
```ts
|
||||
import { z } from "zod";
|
||||
|
||||
const DbOrderRow = z.object({
|
||||
id: z.string().uuid().brand<"OrderId">(),
|
||||
user_id: z.string().uuid().brand<"UserId">(),
|
||||
total_cents: z.number().int().nonnegative(),
|
||||
currency: z.enum(["USD", "EUR", "KRW"]),
|
||||
status: z.enum(["pending", "paid", "shipped", "cancelled"]),
|
||||
created_at: z.coerce.date(),
|
||||
});
|
||||
|
||||
export class OrderEntity {
|
||||
private constructor(private readonly props: z.infer<typeof DbOrderRow>) {}
|
||||
|
||||
static fromRow(row: unknown): OrderEntity {
|
||||
return new OrderEntity(DbOrderRow.parse(row));
|
||||
}
|
||||
|
||||
get id() { return this.props.id; }
|
||||
get total(): Money { return Money.of(this.props.total_cents, this.props.currency); }
|
||||
isPaid(): boolean { return this.props.status === "paid"; }
|
||||
}
|
||||
```
|
||||
|
||||
### Effect schema + decode
|
||||
```ts
|
||||
import { Schema, Effect } from "effect";
|
||||
|
||||
const User = Schema.Struct({
|
||||
id: Schema.String.pipe(Schema.brand("UserId")),
|
||||
email: Schema.String.pipe(Schema.pattern(/^[^@]+@[^@]+$/), Schema.brand("Email")),
|
||||
age: Schema.Number.pipe(Schema.int(), Schema.greaterThanOrEqualTo(0)),
|
||||
});
|
||||
|
||||
const decodeUser = (input: unknown) =>
|
||||
Schema.decodeUnknown(User)(input);
|
||||
|
||||
const program = Effect.gen(function* () {
|
||||
const user = yield* decodeUser(rawJson);
|
||||
console.log(user.email);
|
||||
});
|
||||
```
|
||||
|
||||
### Readonly + immutable update
|
||||
```ts
|
||||
type CartItem = Readonly<{
|
||||
sku: SKU;
|
||||
qty: number;
|
||||
priceCents: number;
|
||||
}>;
|
||||
|
||||
type Cart = Readonly<{
|
||||
userId: UserId;
|
||||
items: ReadonlyArray<CartItem>;
|
||||
}>;
|
||||
|
||||
function addItem(cart: Cart, item: CartItem): Cart {
|
||||
return { ...cart, items: [...cart.items, item] };
|
||||
}
|
||||
|
||||
function setQty(cart: Cart, sku: SKU, qty: number): Cart {
|
||||
return {
|
||||
...cart,
|
||||
items: cart.items.map(i => i.sku === sku ? { ...i, qty } : i),
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Smart constructor + validated factory
|
||||
```ts
|
||||
type Email = string & Brand.Brand<"Email">;
|
||||
type NonEmpty = string & Brand.Brand<"NonEmpty">;
|
||||
|
||||
const Email = (raw: string): Email => {
|
||||
if (!/^[^\s@]+@[^\s@]+$/.test(raw))
|
||||
throw new TypeError(`bad email: ${raw}`);
|
||||
return raw as Email;
|
||||
};
|
||||
|
||||
const NonEmpty = (raw: string): NonEmpty => {
|
||||
const t = raw.trim();
|
||||
if (t.length === 0) throw new TypeError("empty string");
|
||||
return t as NonEmpty;
|
||||
};
|
||||
|
||||
interface User {
|
||||
email: Email;
|
||||
displayName: NonEmpty;
|
||||
}
|
||||
|
||||
const u: User = {
|
||||
email: Email("a@b.com"),
|
||||
displayName: NonEmpty("Alice"),
|
||||
};
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| Layer | Tool |
|
||||
|---|---|
|
||||
| Env / config | Zod schema (startup parse) |
|
||||
| HTTP boundary | Zod + framework adapter |
|
||||
| DB row | Zod / Effect Schema |
|
||||
| Internal domain | Branded + discriminated union |
|
||||
| Complex validation pipeline | Effect Schema |
|
||||
| Single project simplicity | Zod 만 |
|
||||
|
||||
**기본값**: Zod (boundary) + Effect Brand (internal) + readonly everywhere.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[TypeScript Type System]] · [[Domain-Driven Design]]
|
||||
- 변형: [[Parse Don't Validate]] · [[Smart Constructor]]
|
||||
- 응용: [[Zod]] · [[Effect Schema]] · [[Valibot]] · [[ArkType]]
|
||||
- Adjacent: [[브랜디드 타입 (Branded Types)]] · [[약한 타입 탐지 (Weak Type Detection)]] · [[대규모 TypeScript 애플리케이션 아키텍처 설계]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 production app, 매 external boundary, 매 multi-team, 매 strong audit/compliance.
|
||||
**언제 X**: 매 throwaway script, 매 internal-only tool, 매 validation overhead > value.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **`any` cast at boundary**: 매 type system bypass — 매 production runtime crash.
|
||||
- **Validation only (no parse)**: 매 `validate(x)` 후 매 `x` 가 매 still untyped.
|
||||
- **Mutating domain object**: 매 readonly 무시 — 매 race condition.
|
||||
- **Schema drift**: 매 API spec 과 매 zod schema 매 manual sync — 매 codegen 사용.
|
||||
- **Boundary 매 optional check**: 매 일부 endpoint 만 검증 — 매 전부 검증.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Scott Wlaschin "Domain Modeling Made Functional", Zod docs, Effect Schema docs, TypeScript best practices 2026).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — boundary parsing + 7 patterns |
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
---
|
||||
id: wiki-2026-0508-약한-타입-탐지-weak-type-detection
|
||||
title: 약한 타입 탐지 (Weak Type Detection)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Weak Types, TypeScript Weak Type, Empty-like Type Detection]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [typescript, type-system, weak-types, type-safety]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: TypeScript
|
||||
framework: TypeScript 5.7+
|
||||
---
|
||||
|
||||
# 약한 타입 탐지 (Weak Type Detection)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 모든 property 가 optional 인 type — 매 거의 모든 object 와 assignable 한 위험한 type"**. TypeScript 가 weak type 을 special-case 로 인식해 매 disjoint object 와의 assignment 를 차단하는 기능. 매 config object, 매 settings, 매 partial DTO 에서 매 silent typo bug 차단.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 정의
|
||||
- **Weak type**: 매 모든 member 가 optional 한 object type.
|
||||
```ts
|
||||
interface Options {
|
||||
timeout?: number;
|
||||
retries?: number;
|
||||
debug?: boolean;
|
||||
}
|
||||
```
|
||||
- 매 normal structural rule 에 따르면 매 `{}` 도 매 `Options` 와 호환.
|
||||
- TS 가 매 special rule — 매 source object 가 매 weak type 의 어떤 property 도 매 안 가지면 매 error.
|
||||
|
||||
### 매 동작
|
||||
```ts
|
||||
const opts: Options = { timoeut: 100 }; // 매 typo
|
||||
// 매 Error: Object literal may only specify known properties...
|
||||
// AND
|
||||
// 매 Type {} has no properties in common with type Options
|
||||
```
|
||||
|
||||
### 매 응용
|
||||
1. Config / settings object — 매 typo prevention.
|
||||
2. Partial DTO update.
|
||||
3. CSS-in-JS style props.
|
||||
4. Plugin options.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Basic weak type
|
||||
```ts
|
||||
interface FetchOptions {
|
||||
timeout?: number;
|
||||
retries?: number;
|
||||
signal?: AbortSignal;
|
||||
}
|
||||
|
||||
function fetchWith(url: string, opts: FetchOptions) { /* ... */ }
|
||||
|
||||
fetchWith("/api", { timeout: 5000 }); // 매 ok
|
||||
fetchWith("/api", { timoeut: 5000 }); // 매 error — 매 unknown property
|
||||
fetchWith("/api", {}); // 매 ok — 매 모두 optional 이므로
|
||||
fetchWith("/api", { foo: 1 } as any); // 매 escape hatch (매 X 권장)
|
||||
```
|
||||
|
||||
### Weak type detection in lib code
|
||||
```ts
|
||||
// 매 utility — 매 type 이 weak 인지 compile-time check
|
||||
type IsWeakType<T> = {} extends T
|
||||
? keyof T extends never ? false : true
|
||||
: false;
|
||||
|
||||
type CheckOpts = IsWeakType<FetchOptions>; // 매 true
|
||||
type CheckUser = IsWeakType<{ id: string; name: string }>; // 매 false
|
||||
```
|
||||
|
||||
### Required + Optional 명확 분리
|
||||
```ts
|
||||
// 매 weak type 위험 회피 — 매 최소 1 required
|
||||
interface SafeConfig {
|
||||
endpoint: string; // 매 required
|
||||
timeout?: number;
|
||||
retries?: number;
|
||||
}
|
||||
|
||||
const c: SafeConfig = { endpoint: "/api" };
|
||||
```
|
||||
|
||||
### Discriminated union 으로 weak type 회피
|
||||
```ts
|
||||
type Config =
|
||||
| { mode: "polling"; intervalMs: number }
|
||||
| { mode: "websocket"; url: string }
|
||||
| { mode: "sse"; endpoint: string };
|
||||
|
||||
function start(c: Config) {
|
||||
switch (c.mode) {
|
||||
case "polling": return startPolling(c.intervalMs);
|
||||
case "websocket": return startWS(c.url);
|
||||
case "sse": return startSSE(c.endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
start({ mode: "polling", intervalMs: 1000 });
|
||||
start({}); // 매 error — 매 discriminator 없음
|
||||
```
|
||||
|
||||
### Brand to forbid empty object assignment
|
||||
```ts
|
||||
import { Brand } from "effect";
|
||||
type ValidatedOptions = FetchOptions & Brand.Brand<"ValidatedOptions">;
|
||||
|
||||
function validateOpts(o: FetchOptions): ValidatedOptions {
|
||||
if (Object.keys(o).length === 0)
|
||||
throw new Error("at least one option required");
|
||||
return o as ValidatedOptions;
|
||||
}
|
||||
|
||||
function fetchStrict(url: string, opts: ValidatedOptions) { /* ... */ }
|
||||
fetchStrict("/api", validateOpts({ timeout: 5000 })); // 매 ok
|
||||
fetchStrict("/api", {}); // 매 type error
|
||||
```
|
||||
|
||||
### ESLint rule 매 weak type 사용 보강
|
||||
```jsonc
|
||||
{
|
||||
"rules": {
|
||||
"@typescript-eslint/no-misused-promises": "error",
|
||||
"@typescript-eslint/strict-boolean-expressions": "error",
|
||||
"@typescript-eslint/no-empty-object-type": "error"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 매 완전 optional config | Weak type (TS native check 활용) |
|
||||
| 매 1+ required 명시 가능 | Required + optional 분리 |
|
||||
| 매 mode-dependent options | Discriminated union |
|
||||
| 매 strict validation 필요 | Brand + smart constructor |
|
||||
| 매 plugin/3rd-party 매 default | Required + optional |
|
||||
|
||||
**기본값**: 매 1+ required field 추가. 매 truly all-optional 매 weak type detection 의존.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[TypeScript Type System]] · [[Structural Typing]]
|
||||
- 변형: [[Excess Property Check]] · [[Discriminated Union]]
|
||||
- Adjacent: [[브랜디드 타입 (Branded Types)]] · [[Type Narrowing]] · [[안전한 TypeScript 데이터 모델링 및 설정 관리 구축]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 config / options object 설계, 매 typo prevention 강조, 매 plugin API 설계.
|
||||
**언제 X**: 매 internal data, 매 1-callsite, 매 typing overhead > value.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **All-optional 매 무지각 사용**: 매 weak type protection 우연 의존 — 매 명시적 required 1 권장.
|
||||
- **`as any` 우회**: 매 weak type error 매 cast 로 무시 — 매 typo 통과.
|
||||
- **Object spread 매 weak type 회피**: 매 `{...userInput}` 매 typed 안 됨.
|
||||
- **Optional 만의 enum-like**: 매 mode 분기 매 optional bool — 매 discriminated union 사용.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (TypeScript Handbook "Weak Types", TS 2.4 release notes, Marius Schulz blog).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — weak type 정의 + 회피 패턴 6개 |
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
id: wiki-2026-0508-오래된-공간-old-space
|
||||
title: 오래된 공간(Old Space)
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: v8-old-space
|
||||
duplicate_of: "[[V8 Memory Layout]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, v8, memory, garbage-collection]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 오래된 공간(Old Space)
|
||||
|
||||
> **이 문서는 [[V8 Memory Layout]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 매 핵심 요약 (specialization)
|
||||
- 매 V8 heap 의 long-lived object 의 region — 매 2 회 minor GC 의 survive 후 promote.
|
||||
- 매 GC 알고리즘: Mark-Sweep-Compact (major GC) — 매 Orinoco 의 incremental/concurrent.
|
||||
- 매 modern (V8 12+): 매 pointer compression 의 4GB heap limit (compressed mode).
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[V8 Memory Layout]] (canonical)
|
||||
- Adjacent: [[Young Generation]] · [[Orinoco]] · [[Mark and Sweep]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
id: wiki-2026-0508-외부-api-데이터-및-설정-파일-처리
|
||||
title: 외부 API 데이터 및 설정 파일 처리
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: runtime-type-validation
|
||||
duplicate_of: "[[Runtime_Validation|Runtime Type Validation]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, validation, config, schema]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 외부 API 데이터 및 설정 파일 처리
|
||||
|
||||
> **이 문서는 [[Runtime_Validation|Runtime Type Validation]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 매 핵심 요약 (specialization)
|
||||
- 매 API response + 매 config file (JSON/YAML/TOML) 의 schema 의 validate.
|
||||
- 매 libraries: Zod (universal), Joi (server-side), Ajv (JSON Schema), Pydantic (Python).
|
||||
- 매 pattern: 매 boundary 에서 parse — 매 internal logic 은 매 typed data 만 다룸.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Runtime_Validation|Runtime Type Validation]] (canonical)
|
||||
- Adjacent: [[Zod]] · [[JSON Schema]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
id: wiki-2026-0508-외부-api-데이터의-런타임-검증-후-처리
|
||||
title: 외부 API 데이터의 런타임 검증 후 처리
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: runtime-type-validation
|
||||
duplicate_of: "[[Runtime_Validation|Runtime Type Validation]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, validation, zod, type-safety]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 외부 API 데이터의 런타임 검증 후 처리
|
||||
|
||||
> **이 문서는 [[Runtime_Validation|Runtime Type Validation]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 매 핵심 요약 (specialization)
|
||||
- 매 외부 API response 의 매 trust 의 X — 매 runtime parse + validate 의 필수.
|
||||
- 매 libraries: Zod (TS 의 de facto), Valibot (smaller bundle), io-ts, ArkType.
|
||||
- 매 pattern: `schema.parse(data)` → 매 typed result, parse 실패 시 throw.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Runtime_Validation|Runtime Type Validation]] (canonical)
|
||||
- Adjacent: [[Zod]] · [[Schema Validation]] · [[Parse Don't Validate]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
id: wiki-2026-0508-외부-라이브러리-api-설계
|
||||
title: 외부 라이브러리 API 설계
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: library-api-design
|
||||
duplicate_of: "[[API Design Principles]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, api-design, library, sdk]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 외부 라이브러리 API 설계
|
||||
|
||||
> **이 문서는 [[API Design Principles]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 매 핵심 요약 (specialization)
|
||||
- 매 third-party library 의 public API 의 design — 매 backward-compat + ergonomics.
|
||||
- 매 principles: minimal surface area, semver discipline, 매 deprecated → removed cycle.
|
||||
- 매 modern (2026): TypeScript-first, 매 `exports` field (subpath), 매 ESM-only 의 trend.
|
||||
|
||||
## 🔗 Graph
|
||||
- Adjacent: [[Library Design]] · [[Backward Compatibility]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
---
|
||||
id: wiki-2026-0508-웹-워커-이벤트-포워딩-event-forwarding
|
||||
title: 웹 워커 이벤트 포워딩 Event Forwarding
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: web-worker-event-forwarding
|
||||
duplicate_of: "[[Web Worker Communication]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, web-worker, event, postmessage]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 웹 워커 이벤트 포워딩 Event Forwarding
|
||||
|
||||
> **이 문서는 [[Web Worker Communication]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 매 핵심 요약 (specialization)
|
||||
- 매 main thread 와 worker 사이 의 event 전달 pattern — 매 `postMessage` + `MessageChannel`.
|
||||
- 매 typed wrapper: Comlink (RPC-like proxy), 매 worker-rpc, 매 threads.js.
|
||||
- 매 modern (2026): 매 SharedArrayBuffer + Atomics, 매 transferable streams.
|
||||
|
||||
## 🔗 Graph
|
||||
- Adjacent: [[postMessage]] · [[Comlink]] · [[MessageChannel]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
---
|
||||
id: wiki-2026-0508-의존성-역전-원칙-dependency-inversion-p
|
||||
title: 의존성 역전 원칙 (Dependency Inversion Principle DIP)
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: dependency-inversion-principle
|
||||
duplicate_of: "[[Dependency Inversion Principle DIP]]"
|
||||
aliases: [DIP, SOLID-D]
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, solid, design-principle]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 의존성 역전 원칙 (Dependency Inversion Principle DIP)
|
||||
|
||||
> **이 문서는 [[Dependency Inversion Principle DIP]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 핵심 요약
|
||||
- SOLID 의 D — 고수준 module 은 저수준 module 에 의존하지 않음.
|
||||
- 둘 다 abstraction 에 의존 — abstraction 은 details 에 의존하지 않음.
|
||||
- DI (Dependency Injection) 와 구분 — DIP 는 원칙, DI 는 구현 기법.
|
||||
|
||||
## 🔗 Graph
|
||||
- 관련: [[SOLID Principles]] · [[Dependency Injection]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
---
|
||||
id: wiki-2026-0508-이전-세대-old-generation-space
|
||||
title: 이전 세대(Old Generation Space)
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: old-generation-space
|
||||
duplicate_of: "[[Old Generation Space]]"
|
||||
aliases: [Tenured Generation, Old Gen]
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, gc, jvm, memory]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 이전 세대(Old Generation Space)
|
||||
|
||||
> **이 문서는 [[Old Generation Space]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 핵심 요약
|
||||
- Generational GC 의 long-lived objects 영역.
|
||||
- Major GC (Full GC) 대상 — Young Gen 보다 빈도 낮고 비용 큼.
|
||||
- Promotion: Young → Old (survival count 임계 도달 시).
|
||||
|
||||
## 🔗 Graph
|
||||
- 관련: [[Young Generation]] · [[Incremental marking]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
@@ -0,0 +1,230 @@
|
||||
---
|
||||
id: wiki-2026-0508-코드-포매팅-code-formatting
|
||||
title: 코드 포매팅 (Code Formatting)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Code Formatting, Auto-formatting, Prettier, Black, gofmt]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [tooling, style, formatter, prettier, ruff, black]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: polyglot
|
||||
framework: prettier-ruff-gofmt
|
||||
---
|
||||
|
||||
# 코드 포매팅 (Code Formatting)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 style debate 의 종결자"**. Code formatting 은 코드의 visual structure (whitespace, indent, line breaks, quote style) 를 deterministic rule 로 enforce 하는 tooling 영역. 2026 현재 매 모든 mainstream language 는 official 또는 de-facto formatter 를 가지며 (Black, Ruff format, Prettier, gofmt, rustfmt, dart format, ktlint), CI 의 commit hook 의 universal 으로 적용. 매 "어떻게 보일지" 의 human discussion 의 X — 매 tool 의 결정.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 formatter 의 철학
|
||||
- **Opinionated** (매 ideal): 매 minimal config — Black, gofmt, Prettier. 매 bikeshedding 의 elimination.
|
||||
- **Configurable** (매 legacy): 매 ESLint stylistic rules, autopep8 — 매 team config drift 의 risk.
|
||||
- **Idempotent**: `format(format(x)) == format(x)`. 매 essential property — CI loop safety.
|
||||
- **AST-based**: 매 token stream 의 parse → reformat. 매 regex 의 X.
|
||||
|
||||
### 매 linter vs formatter
|
||||
- **Formatter**: whitespace, line breaks, quotes (style only). 매 semantics 의 X-change.
|
||||
- **Linter**: bugs, anti-patterns, unused vars (semantics). 매 ESLint, Ruff check, golangci-lint.
|
||||
- **2026 trend**: Ruff (Python) 의 both 의 unify — `ruff format` + `ruff check` 의 매 single binary. Biome (JS/TS) 의 same path.
|
||||
|
||||
### 매 응용
|
||||
1. **Pre-commit hook**: `pre-commit` (Python), `lefthook`, `husky` 의 매 staged file 의 format.
|
||||
2. **CI gate**: `ruff format --check` / `prettier --check` — diff 가 있으면 fail.
|
||||
3. **Editor on-save**: VS Code `editor.formatOnSave: true` + `defaultFormatter`.
|
||||
4. **Mass migration**: `git ls-files | xargs ruff format` — 매 single PR 의 entire repo reformat.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Prettier (JS/TS/JSON/MD/CSS) — 2026 v3
|
||||
```json
|
||||
// .prettierrc.json
|
||||
{
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"printWidth": 100,
|
||||
"tabWidth": 2,
|
||||
"plugins": ["prettier-plugin-tailwindcss"]
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
# format all files in repo
|
||||
npx prettier --write .
|
||||
# CI check
|
||||
npx prettier --check .
|
||||
```
|
||||
|
||||
### Ruff format (Python) — 2026 default Python formatter
|
||||
```toml
|
||||
# pyproject.toml
|
||||
[tool.ruff]
|
||||
line-length = 100
|
||||
target-version = "py312"
|
||||
|
||||
[tool.ruff.format]
|
||||
quote-style = "double"
|
||||
indent-style = "space"
|
||||
docstring-code-format = true # format code in docstrings
|
||||
```
|
||||
|
||||
```bash
|
||||
ruff format . # write
|
||||
ruff format --check . # CI
|
||||
ruff check --fix . # lint + autofix
|
||||
```
|
||||
|
||||
### Black (Python, legacy but stable)
|
||||
```toml
|
||||
[tool.black]
|
||||
line-length = 100
|
||||
target-version = ["py312"]
|
||||
skip-string-normalization = false
|
||||
```
|
||||
|
||||
### gofmt / goimports (Go) — bundled with toolchain
|
||||
```bash
|
||||
gofmt -w ./...
|
||||
goimports -w ./... # also organizes imports
|
||||
```
|
||||
|
||||
```go
|
||||
// before
|
||||
package main
|
||||
import("fmt"
|
||||
"os")
|
||||
func main(){fmt.Println(os.Args)}
|
||||
|
||||
// after gofmt
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(os.Args)
|
||||
}
|
||||
```
|
||||
|
||||
### rustfmt (Rust)
|
||||
```toml
|
||||
# rustfmt.toml
|
||||
edition = "2024"
|
||||
max_width = 100
|
||||
imports_granularity = "Crate"
|
||||
group_imports = "StdExternalCrate"
|
||||
```
|
||||
|
||||
```bash
|
||||
cargo fmt
|
||||
cargo fmt -- --check # CI
|
||||
```
|
||||
|
||||
### EditorConfig (cross-tool baseline)
|
||||
```ini
|
||||
# .editorconfig — every editor respects this
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
indent_style = space
|
||||
|
||||
[*.{js,ts,tsx,json}]
|
||||
indent_size = 2
|
||||
|
||||
[*.py]
|
||||
indent_size = 4
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
```
|
||||
|
||||
### Pre-commit hook (universal)
|
||||
```yaml
|
||||
# .pre-commit-config.yaml
|
||||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.6.0
|
||||
hooks:
|
||||
- id: ruff-format
|
||||
- id: ruff
|
||||
args: [--fix]
|
||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||
rev: v4.0.0
|
||||
hooks:
|
||||
- id: prettier
|
||||
types_or: [javascript, typescript, json, markdown]
|
||||
```
|
||||
|
||||
### CI gate (GitHub Actions)
|
||||
```yaml
|
||||
- name: Check formatting
|
||||
run: |
|
||||
ruff format --check .
|
||||
ruff check .
|
||||
npx prettier --check .
|
||||
```
|
||||
|
||||
### Mass-format ignore (avoid blame churn)
|
||||
```
|
||||
# .git-blame-ignore-revs
|
||||
# Ruff format mass-apply 2026-04-15
|
||||
abc123def456...
|
||||
```
|
||||
```bash
|
||||
git config blame.ignoreRevsFile .git-blame-ignore-revs
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Python 신규 프로젝트 | Ruff format (Black-compatible, 100x faster) |
|
||||
| Python legacy | Black 유지 — Ruff 의 drop-in 의 가능 |
|
||||
| JS/TS | Prettier 또는 Biome (faster, Rust-based) |
|
||||
| Go | gofmt (no choice, no config) |
|
||||
| Rust | rustfmt |
|
||||
| 매 polyglot monorepo | dprint 또는 Trunk |
|
||||
| Team debate 중 | Opinionated formatter 의 즉시 채택 — 매 discussion close |
|
||||
|
||||
**기본값**: Ruff (Python), Prettier 또는 Biome (web), gofmt (Go), rustfmt (Rust). 매 pre-commit + CI check.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Code Quality]] · [[Developer Experience]]
|
||||
- 변형: [[Linter]] · [[Static Analysis]]
|
||||
- 응용: [[153_pre-commit과_품질_게이트|Pre-commit Hooks]]
|
||||
- Adjacent: [[Prettier]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: Generated code 의 file write 후 항상 `ruff format` / `prettier --write` 의 run — LLM output 의 indent inconsistency 의 normalize. PR diff 의 minimize.
|
||||
**언제 X**: Format-only PR 의 logic change 와 mix 의 X — separate commit / PR 로 분리. Reviewer 의 noise 의 reduction.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Custom rules everywhere**: 매 team-specific style 의 invention. 매 onboarding cost 의 increase. 매 Black/Prettier default 의 accept.
|
||||
- **Format on commit only**: Editor save 의 X-format 의 경우 매 every commit 의 noise. Editor integration 의 essential.
|
||||
- **Format + logic 의 mixed PR**: Review impossible. 매 separate PR.
|
||||
- **No CI check**: Pre-commit 의 bypass 의 가능 (`-n`). 매 CI 의 source of truth.
|
||||
- **`tabWidth` debate**: 매 EditorConfig 의 fix — once and forget.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Prettier docs 2026, Ruff docs 0.6+, Go style guide).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — formatters (Ruff, Prettier, gofmt, rustfmt) + CI/pre-commit patterns |
|
||||
@@ -0,0 +1,204 @@
|
||||
---
|
||||
id: wiki-2026-0508-타입-서술어-type-predicates
|
||||
title: 타입 서술어 (Type Predicates)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Type Predicates, User-Defined Type Guards, "x is T"]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [typescript, type-system, narrowing, guards]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: typescript
|
||||
framework: typescript-5.5+
|
||||
---
|
||||
|
||||
# 타입 서술어 (Type Predicates)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 boolean 의 type 정보 의 carrier"**. Type predicate 는 TypeScript 의 function 의 return type position 에서 `parameterName is Type` 형태로 선언되어, 매 true return 의 경우 compiler 의 narrowing 의 trigger 하는 mechanism. 2026 TS 5.5+ 부터 매 inferred type predicate 가 도입되어 explicit `is` annotation 없이도 `arr.filter(x => x !== null)` 의 자동 narrow.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 syntax
|
||||
- **명시**: `function isString(x: unknown): x is string { return typeof x === 'string' }` — 매 `: x is string` 가 predicate.
|
||||
- **`asserts`**: `function assert(c: unknown): asserts c { if (!c) throw }` — 매 throw-or-narrow.
|
||||
- **TS 5.5 inference**: `[1, null, 2].filter(x => x !== null)` 의 `number[]` 의 자동 inference (이전 `(number | null)[]`).
|
||||
|
||||
### 매 type guard 의 종류
|
||||
1. `typeof` guard — primitive (`string`, `number`, `boolean`, `symbol`, `bigint`, `undefined`, `function`, `object`).
|
||||
2. `instanceof` guard — class hierarchy.
|
||||
3. `in` operator guard — property existence.
|
||||
4. Equality narrowing — `x === 'foo'`.
|
||||
5. **User-defined predicate** — 매 custom logic.
|
||||
6. **Discriminated union** — `kind` field 의 switch.
|
||||
|
||||
### 매 응용
|
||||
1. JSON parse 후 runtime validation (Zod, Valibot).
|
||||
2. `Array.filter` 후 nullish 의 strip.
|
||||
3. AST node type 의 narrowing.
|
||||
4. API response 의 shape 의 verification.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### 기본 user-defined predicate
|
||||
```typescript
|
||||
function isString(x: unknown): x is string {
|
||||
return typeof x === 'string'
|
||||
}
|
||||
|
||||
function process(input: unknown) {
|
||||
if (isString(input)) {
|
||||
input.toUpperCase() // OK — narrowed to string
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Discriminated union 의 narrowing
|
||||
```typescript
|
||||
type Result<T> =
|
||||
| { ok: true; value: T }
|
||||
| { ok: false; error: string }
|
||||
|
||||
function isOk<T>(r: Result<T>): r is { ok: true; value: T } {
|
||||
return r.ok
|
||||
}
|
||||
|
||||
const r: Result<number> = await fetchSomething()
|
||||
if (isOk(r)) {
|
||||
console.log(r.value) // narrowed
|
||||
}
|
||||
```
|
||||
|
||||
### Array filter — TS 5.5 inferred predicate
|
||||
```typescript
|
||||
// Before TS 5.5: result is (number | null)[]
|
||||
// TS 5.5+: result is number[] — auto-inferred
|
||||
const result = [1, null, 2, null, 3].filter(x => x !== null)
|
||||
|
||||
// explicit predicate (still works, useful for older TS)
|
||||
function nonNull<T>(x: T | null | undefined): x is T {
|
||||
return x !== null && x !== undefined
|
||||
}
|
||||
const r2 = [1, null, 2].filter(nonNull) // number[]
|
||||
```
|
||||
|
||||
### `asserts` predicate (throw or narrow)
|
||||
```typescript
|
||||
function assertDefined<T>(
|
||||
x: T | null | undefined,
|
||||
msg = 'value is null'
|
||||
): asserts x is T {
|
||||
if (x === null || x === undefined) throw new Error(msg)
|
||||
}
|
||||
|
||||
function use(x: string | null) {
|
||||
assertDefined(x)
|
||||
x.toUpperCase() // narrowed to string
|
||||
}
|
||||
```
|
||||
|
||||
### Schema-based predicate (Zod)
|
||||
```typescript
|
||||
import { z } from 'zod'
|
||||
|
||||
const UserSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
email: z.string().email(),
|
||||
})
|
||||
type User = z.infer<typeof UserSchema>
|
||||
|
||||
function isUser(x: unknown): x is User {
|
||||
return UserSchema.safeParse(x).success
|
||||
}
|
||||
|
||||
// usage with API response
|
||||
const data: unknown = await fetch('/me').then(r => r.json())
|
||||
if (isUser(data)) {
|
||||
console.log(data.email) // typed as User
|
||||
}
|
||||
```
|
||||
|
||||
### `in` operator guard (cheap, no predicate function)
|
||||
```typescript
|
||||
type Cat = { meow: () => void }
|
||||
type Dog = { bark: () => void }
|
||||
|
||||
function speak(animal: Cat | Dog) {
|
||||
if ('meow' in animal) animal.meow()
|
||||
else animal.bark()
|
||||
}
|
||||
```
|
||||
|
||||
### Generic predicate (preserves narrowing through generics)
|
||||
```typescript
|
||||
function isOneOf<T extends readonly unknown[]>(
|
||||
value: unknown,
|
||||
options: T
|
||||
): value is T[number] {
|
||||
return options.includes(value as never)
|
||||
}
|
||||
|
||||
const colors = ['red', 'green', 'blue'] as const
|
||||
const x: string = 'red'
|
||||
if (isOneOf(x, colors)) {
|
||||
x // narrowed: 'red' | 'green' | 'blue'
|
||||
}
|
||||
```
|
||||
|
||||
### Anti-pattern detection — predicate 의 lie
|
||||
```typescript
|
||||
// BAD — predicate 의 always true return 의 가능
|
||||
function isString(x: unknown): x is string {
|
||||
return true // BUG — compiler 의 trust, runtime 의 explode
|
||||
}
|
||||
|
||||
// GOOD — predicate body 의 actually verify
|
||||
function isString(x: unknown): x is string {
|
||||
return typeof x === 'string'
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Primitive check | `typeof` 직접 — predicate 의 X-required |
|
||||
| Class instance | `instanceof` — predicate 의 X-required |
|
||||
| Discriminated union | `kind` field 의 switch — auto-narrow |
|
||||
| API response shape | Zod/Valibot schema + `safeParse` |
|
||||
| Array filter null strip | TS 5.5+ 의 auto, 또는 `nonNull` predicate |
|
||||
| Throw-on-fail | `asserts` predicate |
|
||||
| 단순 reusable check | User-defined `x is T` |
|
||||
|
||||
**기본값**: Discriminated union 의 prefer (no predicate needed). 매 runtime data 의 Zod schema. Custom predicate 의 매 only-when-needed.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[TypeScript Type System]] · [[Type Narrowing]]
|
||||
- 변형: [[Discriminated_Unions|Discriminated Unions]]
|
||||
- 응용: [[Zod]] · [[Runtime Validation]]
|
||||
- Adjacent: [[타입_가드_(Type_Predicates)|Type Guards]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: Untyped JSON, `unknown` value, 또는 union narrow 의 필요 시. 매 LLM 의 generated predicate 의 body 의 always verify — `return true` 의 lie 의 catch.
|
||||
**언제 X**: Discriminated union 의 자연스럽 work 하면 predicate 의 over-engineering. 매 simple `kind` switch 의 우선.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Lying predicate**: body 의 actually check 하지 않음 — runtime 의 crash.
|
||||
- **`as` 의 abuse**: `x as User` — 매 type assertion 의 unsafe. 매 predicate + Zod 의 prefer.
|
||||
- **Predicate 의 over-use**: discriminated union 의 cover 하는 case 의 unnecessary predicate.
|
||||
- **Wide predicate**: `function isObject(x: unknown): x is object` — 매 too coarse, narrow 하게 specify.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (TypeScript handbook 2026, TS 5.5 release notes).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — type predicates with TS 5.5 inferred predicates + Zod patterns |
|
||||
@@ -0,0 +1,227 @@
|
||||
---
|
||||
id: wiki-2026-0508-타입-안전성-type-safety
|
||||
title: 타입 안전성 (Type Safety)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Type Safety, Strong Typing, Sound Typing]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [type-system, correctness, typescript, rust, soundness]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: polyglot
|
||||
framework: typescript-rust-haskell
|
||||
---
|
||||
|
||||
# 타입 안전성 (Type Safety)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 ill-typed program 의 X-run"**. Type safety 는 type system 이 program execution 동안 type error (e.g., string 에 number method 호출) 가 발생하지 않음을 guarantee 하는 property. **Static** type safety (Rust, Haskell, OCaml) 는 compile time 에 reject, **Dynamic** (Python, JS) 는 runtime 에 throw, **Gradual** (TypeScript, Python+mypy) 는 매 mix. 2026 의 trend 는 매 sound + gradual 의 confluence.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 type safety 의 차원
|
||||
- **Soundness**: well-typed program 의 type error 의 X. Rust/Haskell/Idris 의 sound. TypeScript 의 unsound (intentional — 매 ergonomic trade-off).
|
||||
- **Completeness**: type-correct program 의 모두 의 accept. 매 undecidable 한 trade-off.
|
||||
- **Strong vs Weak**: strong = no implicit coercion (Python), weak = implicit (JS `'5' + 3 === '53'`).
|
||||
- **Static vs Dynamic**: check time.
|
||||
- **Manifest vs Inferred**: annotation 의 explicit 여부.
|
||||
|
||||
### 매 unsoundness escape hatches
|
||||
- TS: `any`, `as`, `// @ts-ignore`, function bivariance, `Object.assign`.
|
||||
- Python: `Any`, `cast`, missing annotations.
|
||||
- Rust: `unsafe` block — 매 explicit, 매 audit-able.
|
||||
|
||||
### 매 응용
|
||||
1. Refactoring confidence — rename 의 자동 propagate.
|
||||
2. API contract — request/response shape 의 enforce.
|
||||
3. Bug prevention — null deref, off-by-one type error 의 catch.
|
||||
4. Self-documenting code — type 의 living spec.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Branded types (nominal typing in structural system)
|
||||
```typescript
|
||||
type UserId = string & { readonly __brand: 'UserId' }
|
||||
type OrderId = string & { readonly __brand: 'OrderId' }
|
||||
|
||||
function makeUserId(s: string): UserId {
|
||||
return s as UserId // single trusted constructor
|
||||
}
|
||||
|
||||
function getUser(id: UserId) { /* ... */ }
|
||||
|
||||
const u = makeUserId('u_abc')
|
||||
const o = 'o_123' as OrderId
|
||||
getUser(u) // OK
|
||||
getUser(o) // ERROR — different brand
|
||||
```
|
||||
|
||||
### Exhaustive switch (compile-time correctness)
|
||||
```typescript
|
||||
type Status = 'pending' | 'active' | 'archived'
|
||||
|
||||
function label(s: Status): string {
|
||||
switch (s) {
|
||||
case 'pending': return '대기'
|
||||
case 'active': return '활성'
|
||||
case 'archived': return '보관'
|
||||
default: {
|
||||
const _: never = s
|
||||
throw new Error('unreachable')
|
||||
}
|
||||
}
|
||||
}
|
||||
// Adding 'deleted' to Status → compile error here, not runtime crash
|
||||
```
|
||||
|
||||
### Result type (no exception)
|
||||
```typescript
|
||||
type Result<T, E = Error> =
|
||||
| { ok: true; value: T }
|
||||
| { ok: false; error: E }
|
||||
|
||||
async function fetchUser(id: string): Promise<Result<User>> {
|
||||
try {
|
||||
const r = await fetch(`/u/${id}`)
|
||||
if (!r.ok) return { ok: false, error: new Error(`HTTP ${r.status}`) }
|
||||
return { ok: true, value: await r.json() }
|
||||
} catch (e) {
|
||||
return { ok: false, error: e as Error }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Schema-driven I/O (runtime + static)
|
||||
```typescript
|
||||
import { z } from 'zod'
|
||||
|
||||
const ApiUser = z.object({
|
||||
id: z.string().uuid(),
|
||||
email: z.string().email(),
|
||||
age: z.number().int().min(0),
|
||||
})
|
||||
type ApiUser = z.infer<typeof ApiUser>
|
||||
|
||||
async function getUser(id: string): Promise<ApiUser> {
|
||||
const raw = await fetch(`/u/${id}`).then(r => r.json())
|
||||
return ApiUser.parse(raw) // throws on shape mismatch
|
||||
}
|
||||
```
|
||||
|
||||
### Rust — soundness via ownership
|
||||
```rust
|
||||
fn main() {
|
||||
let s = String::from("hello");
|
||||
let r1 = &s;
|
||||
let r2 = &s; // OK — multiple immutable borrows
|
||||
println!("{r1} {r2}");
|
||||
|
||||
let m = &mut s; // ERROR — can't borrow mutable while immutable exists
|
||||
}
|
||||
```
|
||||
|
||||
### Python — gradual typing with mypy/pyright strict
|
||||
```python
|
||||
# pyproject.toml
|
||||
[tool.pyright]
|
||||
strict = ["src"]
|
||||
reportMissingTypeStubs = "error"
|
||||
|
||||
# code
|
||||
from typing import Literal
|
||||
|
||||
def label(s: Literal["pending", "active", "archived"]) -> str:
|
||||
match s:
|
||||
case "pending": return "대기"
|
||||
case "active": return "활성"
|
||||
case "archived": return "보관"
|
||||
# mypy/pyright catches missing case
|
||||
```
|
||||
|
||||
### TS strict mode (essential 2026 baseline)
|
||||
```json
|
||||
// tsconfig.json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"noUncheckedIndexedAccess": true, // arr[i] is T | undefined
|
||||
"exactOptionalPropertyTypes": true,
|
||||
"noImplicitOverride": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `unknown` over `any`
|
||||
```typescript
|
||||
// BAD
|
||||
function parse(json: string): any {
|
||||
return JSON.parse(json)
|
||||
}
|
||||
|
||||
// GOOD
|
||||
function parse(json: string): unknown {
|
||||
return JSON.parse(json) // forces caller to narrow
|
||||
}
|
||||
|
||||
const data = parse('{"x":1}')
|
||||
// data.x // ERROR
|
||||
if (typeof data === 'object' && data !== null && 'x' in data) {
|
||||
data.x // OK
|
||||
}
|
||||
```
|
||||
|
||||
### Enforced phantom state (typestate pattern)
|
||||
```typescript
|
||||
type Builder<State extends 'empty' | 'has-name' | 'ready'> = {
|
||||
setName(n: string): Builder<'has-name'>
|
||||
setEmail(e: string): Builder<'ready'> // assume after name
|
||||
build(): User // only on 'ready'
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 신규 TS 프로젝트 | `strict: true` + `noUncheckedIndexedAccess` |
|
||||
| Python | pyright strict, mypy strict |
|
||||
| Critical / safety | Rust, OCaml, Idris (sound) |
|
||||
| API boundary | Schema (Zod, Pydantic) — runtime + static |
|
||||
| ID confusion 방지 | Branded types |
|
||||
| Error 의 throw 회피 | `Result<T, E>` |
|
||||
| Interop with untyped | `unknown` + narrow (NOT `any`) |
|
||||
| Performance + safety | Rust |
|
||||
|
||||
**기본값**: Static + sound (Rust) 또는 Static + gradual strict (TS strict, Python pyright strict). API boundary 의 schema. `any` 의 ban.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[TypeScript 타입 시스템 (TypeScript Type System)|Type System]]
|
||||
- 응용: [[TypeScript]] · [[Zod]]
|
||||
- Adjacent: [[Branded Types]] · [[Type Narrowing]] · [[Result Type]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 generated code 의 strict mode 의 compile 확인. 매 LLM 의 `any` cast 의 propose 의 reject — `unknown` + narrow 의 demand.
|
||||
**언제 X**: 매 prototype 의 throwaway script 의 over-engineer X — 매 production path 의 only-strict.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **`any` proliferation**: TS 의 `any` 의 single use 의 entire chain 의 type 의 lose.
|
||||
- **`as` 의 lying cast**: `data as User` without verification.
|
||||
- **String IDs everywhere**: branded types 의 X-use → wrong-ID-as-arg bug.
|
||||
- **Throw-everything**: Result type 또는 typed error 의 X-use.
|
||||
- **Loose schema**: Zod `.passthrough()` 의 abuse — unknown fields 의 leak.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (TypeScript docs, Rust Book 2026, Pierce — Types and Programming Languages).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — soundness, branded types, Result, schema, strict configs |
|
||||
@@ -0,0 +1,214 @@
|
||||
---
|
||||
id: wiki-2026-0508-타입-좁히기-type-narrowing
|
||||
title: 타입 좁히기 (Type Narrowing)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Type Narrowing, Control Flow Analysis, CFA]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [typescript, type-system, narrowing, control-flow]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: typescript
|
||||
framework: typescript-5.5+
|
||||
---
|
||||
|
||||
# 타입 좁히기 (Type Narrowing)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 control flow 의 type 의 refine"**. Type narrowing 은 TypeScript compiler 가 conditional branch, equality check, predicate call 등을 추적하여 union type 을 점점 더 specific 한 type 으로 축소하는 process. 매 control flow analysis (CFA) 의 결과로, 매 runtime check 의 동일 코드가 type level 에서도 evidence 의 carry — 매 type system 의 ergonomic core.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 narrowing trigger
|
||||
1. **`typeof`**: primitive 7종.
|
||||
2. **`instanceof`**: class.
|
||||
3. **`in`** operator: property existence.
|
||||
4. **Equality** (`===`, `!==`): literal narrowing.
|
||||
5. **Truthiness**: `if (x)` — null/undefined/0/'' 의 strip.
|
||||
6. **User-defined predicate**: `x is T`.
|
||||
7. **`asserts`**: throw-or-narrow.
|
||||
8. **Discriminated union**: `kind` field 의 switch.
|
||||
9. **Array.length**: `if (arr.length > 0)` 의 tuple narrowing (제한적).
|
||||
10. **Aliased condition** (TS 4.4+): `const isStr = typeof x === 'string'; if (isStr) ...`.
|
||||
|
||||
### 매 narrowing 의 scope
|
||||
- `if` block 안에서만 유효.
|
||||
- Closure 의 capture 의 후 narrowing 의 lost (callback 안의 `x` 의 다시 union).
|
||||
- `let` reassign 의 후 narrowing 의 reset.
|
||||
|
||||
### 매 응용
|
||||
1. Optional handling — `if (user)` 후 `user.name`.
|
||||
2. Discriminated union 의 exhaustive switch.
|
||||
3. Error type 의 narrowing (`if (err instanceof HttpError)`).
|
||||
4. Array filter null strip.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### typeof narrowing
|
||||
```typescript
|
||||
function pad(x: string | number) {
|
||||
if (typeof x === 'number') return ' '.repeat(x) // x: number
|
||||
return x.padStart(10) // x: string
|
||||
}
|
||||
```
|
||||
|
||||
### Discriminated union (가장 idiomatic)
|
||||
```typescript
|
||||
type Shape =
|
||||
| { kind: 'circle'; r: number }
|
||||
| { kind: 'square'; side: number }
|
||||
| { kind: 'rect'; w: number; h: number }
|
||||
|
||||
function area(s: Shape): number {
|
||||
switch (s.kind) {
|
||||
case 'circle': return Math.PI * s.r ** 2
|
||||
case 'square': return s.side ** 2
|
||||
case 'rect': return s.w * s.h
|
||||
default: {
|
||||
const _exhaustive: never = s // compile error if Shape extended
|
||||
throw new Error('unreachable')
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Truthiness narrowing
|
||||
```typescript
|
||||
function greet(name: string | null | undefined) {
|
||||
if (name) {
|
||||
name.toUpperCase() // name: string
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `in` operator
|
||||
```typescript
|
||||
type Fish = { swim: () => void }
|
||||
type Bird = { fly: () => void }
|
||||
|
||||
function move(p: Fish | Bird) {
|
||||
if ('swim' in p) p.swim()
|
||||
else p.fly()
|
||||
}
|
||||
```
|
||||
|
||||
### instanceof
|
||||
```typescript
|
||||
class HttpError extends Error { status: number = 500 }
|
||||
|
||||
try {
|
||||
await fetch(url)
|
||||
} catch (e) {
|
||||
if (e instanceof HttpError) console.error(e.status) // narrowed
|
||||
else if (e instanceof Error) console.error(e.message)
|
||||
else console.error('unknown', e)
|
||||
}
|
||||
```
|
||||
|
||||
### Aliased condition (TS 4.4+)
|
||||
```typescript
|
||||
function process(x: string | number[]) {
|
||||
const isArray = Array.isArray(x)
|
||||
if (isArray) {
|
||||
x.length // x: number[]
|
||||
} else {
|
||||
x.charAt(0) // x: string
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### TS 5.5 inferred predicate (자동 narrowing in filter)
|
||||
```typescript
|
||||
const mixed: (string | null)[] = ['a', null, 'b']
|
||||
const strings = mixed.filter(x => x !== null)
|
||||
// ^? string[] (TS 5.5+ — previously (string | null)[])
|
||||
```
|
||||
|
||||
### Closure 의 narrowing 의 loss
|
||||
```typescript
|
||||
function example(x: string | null) {
|
||||
if (x === null) return
|
||||
x.toUpperCase() // OK
|
||||
|
||||
setTimeout(() => {
|
||||
x.toUpperCase() // ERROR: x might be null again (closure)
|
||||
})
|
||||
|
||||
// Fix:
|
||||
const fixed = x // const captured — narrowing preserved
|
||||
setTimeout(() => fixed.toUpperCase())
|
||||
}
|
||||
```
|
||||
|
||||
### never 의 exhaustiveness
|
||||
```typescript
|
||||
type Action = { t: 'load' } | { t: 'save' }
|
||||
|
||||
function handle(a: Action) {
|
||||
switch (a.t) {
|
||||
case 'load': return load()
|
||||
case 'save': return save()
|
||||
default: {
|
||||
const _: never = a // compile error if Action grows
|
||||
throw new Error()
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Optional chaining + narrowing
|
||||
```typescript
|
||||
type User = { profile?: { email?: string } }
|
||||
|
||||
function send(u: User) {
|
||||
if (u.profile?.email) {
|
||||
u.profile.email // string (not undefined)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Narrowing approach |
|
||||
|---|---|
|
||||
| Union of primitives | `typeof` |
|
||||
| Class hierarchy | `instanceof` |
|
||||
| Object shape variants | Discriminated union (`kind` field) |
|
||||
| Property existence check | `in` |
|
||||
| Custom validation | User-defined predicate |
|
||||
| Throw-or-narrow | `asserts` |
|
||||
| Filter null/undefined | TS 5.5 의 auto, 또는 explicit predicate |
|
||||
| Exhaustiveness | `never` 의 default branch |
|
||||
|
||||
**기본값**: Discriminated union 의 design — 매 narrowing 의 free. 매 `never` exhaustiveness check 의 매 switch 에 추가.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[TypeScript Type System]]
|
||||
- 변형: [[Type Predicates]]
|
||||
- 응용: [[Discriminated_Unions|Discriminated Unions]] · [[Error Handling]]
|
||||
- Adjacent: [[Control Flow Analysis]] · [[Exhaustiveness Checking]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: Union type 의 specific branch handling. 매 LLM 의 generate 한 switch 의 `never` exhaustiveness 의 추가 의 verify.
|
||||
**언제 X**: 매 단순 single-type 의 over-narrowing 의 unnecessary.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **`as` cast 의 abuse**: narrowing 의 가능한 곳에서 `x as User` — unsafe.
|
||||
- **`!` non-null assertion overuse**: `x!.foo` — narrowing 의 알려주는 게 좋음.
|
||||
- **Closure 의 narrowing 의 expectation**: `let` mutable 의 narrowing 의 reset.
|
||||
- **No exhaustive check**: discriminated union 의 grow 시 silent miss.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (TypeScript handbook — Narrowing chapter 2026).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — narrowing patterns + TS 5.5 inferred predicates + exhaustiveness |
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
id: wiki-2026-0508-타파스-tapas
|
||||
title: 타파스(Tapas)
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: code-katas
|
||||
duplicate_of: "[[Code Kata]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.7
|
||||
verification_status: redirected
|
||||
tags: [duplicate, practice, kata]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 타파스(Tapas)
|
||||
|
||||
> **이 문서는 [[Code Kata]] 의 중복본입니다.** 원본 entry 의 context 가 명확하지 않으나, programming 영역에서 "Tapas" 는 Spanish 식 small-plate 비유로 codewars/Codecrafters 의 small bite-sized practice problems 를 지칭하는 경우가 가장 흔하므로 [[Code Kata]] canonical 로 redirect.
|
||||
|
||||
## 핵심 요약 (specialization aspects)
|
||||
- "Tapas" 의 metaphor: 매 small portion 의 daily practice. 매 Code Kata 의 variant naming.
|
||||
- 매 short (15-30 min) self-contained challenge 의 emphasize.
|
||||
- Codecrafters, Exercism, Codewars 등의 platform 의 매 example.
|
||||
|
||||
## 🔗 Graph
|
||||
- Adjacent: [[Deliberate Practice]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — Code Kata canonical 로 redirect (context ambiguous) |
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
---
|
||||
id: wiki-2026-0508-프론트엔드-및-모노레포-monorepo-개발-환경-설정
|
||||
title: 프론트엔드 및 모노레포(Monorepo) 개발 환경 설정
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: monorepo-setup
|
||||
duplicate_of: "[[Monorepo|Monorepo Setup]]"
|
||||
aliases: [Frontend Monorepo, Monorepo Configuration]
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, monorepo, tooling, frontend]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 프론트엔드 및 모노레포(Monorepo) 개발 환경 설정
|
||||
|
||||
> **이 문서는 [[Monorepo|Monorepo Setup]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 핵심 요약
|
||||
- Turborepo, Nx, pnpm workspaces, Bun workspaces — 2026 의 주류 tools.
|
||||
- Shared packages, build caching, task orchestration.
|
||||
- TypeScript project references 와 함께 사용.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Monorepo|Monorepo Setup]] (canonical)
|
||||
- 관련: [[Turborepo]] · [[Nx]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
id: wiki-2026-0508-핀테크의-실시간-사기-탐지
|
||||
title: 핀테크의 실시간 사기 탐지
|
||||
category: 10_Wiki/Topics
|
||||
status: duplicate
|
||||
canonical_id: real-time-fraud-detection
|
||||
duplicate_of: "[[Real-Time-Fraud-Detection]]"
|
||||
aliases: []
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: redirected
|
||||
tags: [duplicate, fintech, fraud-detection, ml]
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
---
|
||||
|
||||
# 핀테크의 실시간 사기 탐지
|
||||
|
||||
> **이 문서는 [[Real-Time-Fraud-Detection]] 의 중복본입니다.** Canonical 문서로 redirect.
|
||||
|
||||
## 매 핵심 요약
|
||||
- 매 streaming feature pipeline (Kafka + Flink) → online ML inference.
|
||||
- 매 graph-based anomaly + behavior fingerprint.
|
||||
- 매 latency budget < 50 ms / decision.
|
||||
|
||||
## 🔗 Graph
|
||||
- Adjacent: [[Anomaly-Detection]]
|
||||
|
||||
## 🕓 변경 이력
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | 중복 처리 — canonical 문서로 redirect |
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
---
|
||||
id: wiki-2026-0508-할당-타임라인-allocation-timeline
|
||||
title: 할당 타임라인 (Allocation Timeline)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [Allocation Timeline, Memory Allocation Profiling, Heap Timeline]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [profiling, memory, devtools, performance, gc]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: javascript
|
||||
framework: chrome-devtools
|
||||
---
|
||||
|
||||
# 할당 타임라인 (Allocation Timeline)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 heap 의 시간 축 의 graph"**. Allocation Timeline 은 Chrome DevTools (Memory panel) 의 sampling profiler tool 로, recording 동안 매 N ms 마다 JS heap 의 allocation 을 sample 하여 어떤 코드 line 이 어떤 timestamp 에 얼마만큼 의 memory 의 allocate 했는지 visualize. 매 memory leak 의 hunt, 매 high-frequency allocation hotspot 의 identification 의 매 first-line tool.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 DevTools Memory panel 의 3 modes
|
||||
1. **Heap snapshot**: 매 single point-in-time 의 full snapshot. 매 leak diagnosis (3-snapshot technique).
|
||||
2. **Allocation instrumentation on timeline** (allocations on timeline): 매 stack trace 와 함께 매 allocation 의 capture. 매 expensive 한 most-detailed.
|
||||
3. **Allocation sampling**: 매 lightweight, statistical. 매 production-like profile.
|
||||
|
||||
### 매 timeline 의 read 법
|
||||
- X 축: time.
|
||||
- Y 축: bar 의 height = allocation size.
|
||||
- **Blue bar**: 매 still-alive allocation 의 record 종료 시점.
|
||||
- **Gray bar**: 매 collected allocation. 매 GC 의 reclaimed.
|
||||
- 매 blue 가 많이 남으면 → potential leak source.
|
||||
|
||||
### 매 응용
|
||||
1. SPA 의 leak detection — page navigate 후 reachable obj 의 monitor.
|
||||
2. React re-render allocation 의 hotspot 식별.
|
||||
3. Worker / animation loop 의 per-frame allocation 의 minimize.
|
||||
4. Stream parser 의 backpressure 검증.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Chrome DevTools — Allocation 기록
|
||||
```text
|
||||
1. Open DevTools → Memory tab.
|
||||
2. Select "Allocation instrumentation on timeline".
|
||||
3. Click ●(record), perform workflow, click ⏹.
|
||||
4. Filter by Constructor / Size.
|
||||
5. Expand stack trace — file:line 의 click → Sources panel.
|
||||
```
|
||||
|
||||
### 3-snapshot leak diagnosis
|
||||
```text
|
||||
1. Snapshot 1 (baseline)
|
||||
2. Trigger workflow N times (open modal, close, ...).
|
||||
3. Force GC (trash icon).
|
||||
4. Snapshot 2.
|
||||
5. Repeat workflow N times again, force GC.
|
||||
6. Snapshot 3.
|
||||
7. Filter "Comparison" — objects allocated between Snap1 and Snap2 still alive at Snap3.
|
||||
→ That's the leak.
|
||||
```
|
||||
|
||||
### Programmatic — performance.measureUserAgentSpecificMemory()
|
||||
```javascript
|
||||
if ('measureUserAgentSpecificMemory' in performance) {
|
||||
const result = await performance.measureUserAgentSpecificMemory()
|
||||
console.log(result.bytes) // total bytes
|
||||
console.log(result.breakdown) // per realm/type
|
||||
}
|
||||
```
|
||||
|
||||
### Node.js — heap profiling (built-in inspector)
|
||||
```javascript
|
||||
// node --inspect server.js
|
||||
// Then in chrome://inspect → DevTools → Memory tab
|
||||
|
||||
// or programmatic
|
||||
import { Session } from 'inspector'
|
||||
const session = new Session()
|
||||
session.connect()
|
||||
session.post('HeapProfiler.startSampling')
|
||||
// ... workload
|
||||
session.post('HeapProfiler.stopSampling', (err, { profile }) => {
|
||||
fs.writeFileSync('heap.heapprofile', JSON.stringify(profile))
|
||||
})
|
||||
```
|
||||
|
||||
### Detect React leak (common pattern)
|
||||
```jsx
|
||||
// LEAK — interval 의 closure 의 stale state 의 retain
|
||||
useEffect(() => {
|
||||
const id = setInterval(() => setCount(c => c + 1), 1000)
|
||||
// missing cleanup
|
||||
}, [])
|
||||
|
||||
// FIX
|
||||
useEffect(() => {
|
||||
const id = setInterval(() => setCount(c => c + 1), 1000)
|
||||
return () => clearInterval(id)
|
||||
}, [])
|
||||
```
|
||||
|
||||
### High-frequency allocation reduction
|
||||
```javascript
|
||||
// BAD — every frame allocates
|
||||
function tick() {
|
||||
const v = { x: Math.random(), y: Math.random() } // allocation per frame
|
||||
draw(v)
|
||||
requestAnimationFrame(tick)
|
||||
}
|
||||
|
||||
// GOOD — reuse buffer
|
||||
const v = { x: 0, y: 0 }
|
||||
function tick() {
|
||||
v.x = Math.random()
|
||||
v.y = Math.random()
|
||||
draw(v)
|
||||
requestAnimationFrame(tick)
|
||||
}
|
||||
```
|
||||
|
||||
### WeakMap/WeakRef — GC-friendly cache
|
||||
```javascript
|
||||
const cache = new WeakMap() // GC 의 reclaim 가능
|
||||
function compute(obj) {
|
||||
if (cache.has(obj)) return cache.get(obj)
|
||||
const r = expensive(obj)
|
||||
cache.set(obj, r)
|
||||
return r
|
||||
}
|
||||
```
|
||||
|
||||
### FinalizationRegistry — leak detect in test
|
||||
```javascript
|
||||
const fr = new FinalizationRegistry(name => console.log(`${name} GC'd`))
|
||||
|
||||
function track(obj, name) {
|
||||
fr.register(obj, name)
|
||||
}
|
||||
|
||||
// in test: track(component, 'Modal'); unmount; await gc();
|
||||
// expect Modal GC'd to log
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Tool |
|
||||
|---|---|
|
||||
| Live SPA 의 leak suspect | DevTools Memory → Allocation timeline + 3 snapshots |
|
||||
| Production-like overhead 필요 | Allocation sampling |
|
||||
| Detached DOM hunt | Heap snapshot → "Detached" filter |
|
||||
| Total memory size monitoring | `performance.measureUserAgentSpecificMemory()` |
|
||||
| Node server | `--inspect` + Chrome DevTools, 또는 clinic.js |
|
||||
| Animation hotspot | Allocation timeline (short window) |
|
||||
|
||||
**기본값**: Allocation instrumentation on timeline 의 short (10-30s) recording. 매 3-snapshot 의 leak suspect 시.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Performance_Profiling_and_Memory|Performance Profiling]] · [[Memory Management]]
|
||||
- 변형: [[Nodejs_and_Backend_Optimization|Heap Snapshot]]
|
||||
- 응용: [[Memory Leak Detection]]
|
||||
- Adjacent: [[Chrome DevTools Memory Profiling|Chrome DevTools]] · [[V8 Engine]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: User 가 "page slow over time" / "memory grows" / "browser crashes after 1h" 의 report 시. 매 Allocation timeline 의 first action.
|
||||
**언제 X**: One-shot CPU bottleneck — 매 Performance panel (CPU profile) 의 prefer.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Snapshot 1개 만 보기**: leak 의 X-prove. 매 minimum 2-3 snapshots 의 compare.
|
||||
- **GC 의 X-force**: snapshot 전 GC button 의 click 의 X-하면 매 noise 의 inflated.
|
||||
- **Production minified code**: source map 의 X-load → stack trace 의 unreadable.
|
||||
- **Long recording**: 100 MB+ 의 allocation timeline 의 DevTools 의 freeze.
|
||||
- **Closures 의 ignore**: 매 detached DOM retainer 의 most-common 한 closure.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Chrome DevTools docs 2026, V8 blog).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — DevTools allocation timeline, 3-snapshot leak hunt, Node profiling |
|
||||
Reference in New Issue
Block a user