9148c358d0
Topic_Agent/Topic_Blog/Topics/Topics_Biz/Topics_Meeting/Topics_Rag의 마크다운 지식 문서를 Topic_General/Topic_Programming/Topic_Graphic/Topic_Business 4개 카테고리로 재분류. - 중복 제거: frontmatter의 status:duplicate/merged + duplicate_of/redirect_to 필드로 자기 자신을 중복으로 선언한 리다이렉트 stub 1032개 제거, 완전 동일 내용 파일 472개 제거, 동일 파일명·다른 내용 충돌 시 더 큰(완전한) 버전만 유지(162개 제거) — 총 1639개 중복 제거. - 분류: 폴더 단위로 명확한 항목(AI_and_ML/Coding/Architecture 등 → Programming, Comfyui/Visual_Effects → Graphic, Topics_Biz/Topics_Meeting/사업 등 → Business, Poetic_Blog_Writing/창의성/Game_Design 등 → General)은 폴더 우선순위로, 나머지 혼재 폴더(Topic_Agent/Topic_Blog/Topics 루트/Thinking & Reasoning/Other/UI_UX_Assets)는 title/tags 키워드 스코어링으로 파일 단위 분류(불명확한 경우 General로 폴백). 원본 폴더명은 "From_*" 서브폴더로 보존해 추적 가능성 유지. - 최종 배치: Programming 2784 / General 1608 / Graphic 285 / Business 249 = 4926개 문서. - 에이전트 운영 상태(.astra/.agent/.obsidian/sessions/memory/_company/docs/lessons/_shared/src)는 지식 콘텐츠가 아니므로 재분류 대상에서 제외하고 원위치 유지. - Topics/Topic_email(상위 보호 폴더 Topic_email과 파일명 100% 중복) 삭제 — 보호 폴더 자체는 미변경. - 완전히 비게 된 Topic_Agent/Topic_Blog/Topics_Biz/Topics_Rag 폴더 제거.
5.4 KiB
5.4 KiB
id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
| id | title | category | status | canonical_id | aliases | duplicate_of | source_trust_level | confidence_score | verification_status | tags | raw_sources | last_reinforced | github_commit | tech_stack | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| wiki-2026-0508-탭과-싱크-taps-and-sinks | 탭과 싱크(Taps and Sinks) | 10_Wiki/Topics | verified | self |
|
none | A | 0.85 | applied |
|
2026-05-10 | pending |
|
탭과 싱크(Taps and Sinks)
매 한 줄
"매 stream 을 손대지 않고 들여다보는 tap, 매 stream 을 끝내며 결과를 모으는 sink.". Reactive / functional stream architecture 의 매 두 핵심 primitive. Tap 은 매 transparent observer (logging, metrics) — 매 값 변형 X. Sink 는 매 terminal consumer — 매 stream 을 result 로 collapse.
매 핵심
매 Tap (passive)
- 매 stream 의 element 를 매 side-effect 로 관찰.
- 매 element 자체는 매 unchanged 통과.
- 매 logging, debugging, metrics, audit trail 의 사용.
- Effect 의
Effect.tap, RxJS 의tap(), Java Stream 의peek().
매 Sink (terminal)
- 매 stream 을 매 single value (or unit) 로 reduce.
- 매 stream 종결 시점 — 매 downstream 더 X.
- Reduction (sum, count, list), I/O write, DB insert 의 형태.
- Effect 의
Sink<A, R, E>, Akka Streams 의Sink[T, M].
매 응용
- Observability — 매 production stream 에 매 tap 으로 metrics 주입.
- Data pipeline 종착점 — 매 sink 로 file/DB write.
- Test instrumentation — 매 tap 으로 intermediate state 검증.
- Backpressure 의 demand source — 매 sink 가 매 pull rate 결정.
💻 패턴
Pattern 1 — Effect.tap
import { Effect, Console } from 'effect';
const program = Effect.succeed(42).pipe(
Effect.tap((n) => Console.log(`got ${n}`)),
Effect.map((n) => n * 2),
);
// 매 log 출력 + 매 84 반환. 매 tap 은 value 변형 X.
Pattern 2 — RxJS tap (debugging)
import { from } from 'rxjs';
import { tap, map, filter } from 'rxjs/operators';
from([1, 2, 3, 4]).pipe(
tap((v) => console.log(`before filter: ${v}`)),
filter((v) => v % 2 === 0),
tap((v) => console.log(`after filter: ${v}`)),
map((v) => v * 10),
).subscribe(console.log);
// 매 pipeline 의 각 stage 에 매 invasive 한 logging.
Pattern 3 — Effect Sink (collect)
import { Stream, Sink, Effect } from 'effect';
const result = Stream.range(1, 100).pipe(
Stream.run(Sink.sum),
);
// Effect<number> — 매 5050.
Pattern 4 — Custom Sink (foldLeft)
const collectSink = Sink.foldLeft<number[], number>(
[],
(acc, n) => [...acc, n * 2],
);
const collected = Stream.range(1, 5).pipe(
Stream.run(collectSink),
);
// Effect<[2, 4, 6, 8, 10]>.
Pattern 5 — Tap for metrics
import { Metric } from 'effect';
const requestCounter = Metric.counter('http_requests');
const handler = (req: Request) =>
Effect.succeed(req).pipe(
Effect.tap(() => Metric.increment(requestCounter)),
Effect.flatMap(processRequest),
);
// 매 모든 request 에 매 counter ++. 매 main flow 의 변형 X.
Pattern 6 — Sink to file (Node)
import { createWriteStream } from 'node:fs';
import { Stream, Sink } from 'effect';
const fileSink = Sink.fromWritable(() => createWriteStream('out.txt'));
await Stream.range(1, 1000).pipe(
Stream.map((n) => `line ${n}\n`),
Stream.run(fileSink),
Effect.runPromise,
);
// 매 1000 lines 의 file 에 sink.
Pattern 7 — tapError (failure observation)
const fetchUser = (id: string) =>
Effect.tryPromise(() => fetch(`/users/${id}`)).pipe(
Effect.tapError((err) =>
Console.error(`fetch failed: ${err}`),
),
);
// 매 error path 만 관찰 — 매 success 는 매 untouched.
Pattern 8 — Sink composition
const dualSink = Sink.zip(Sink.sum, Sink.count);
const [total, count] = await Stream.range(1, 10).pipe(
Stream.run(dualSink),
Effect.runPromise,
);
// 매 single pass 의 sum + count.
매 결정 기준
| 상황 | Tap or Sink |
|---|---|
| 값 변형 없이 관찰 | Tap |
| Stream 종결 + 결과 collect | Sink |
| 매 logging / metrics | Tap |
| 매 file / DB write | Sink |
| Error path 만 관찰 | tapError |
| 다중 결과 동시 collect | Sink.zip |
기본값: 매 observation = tap, 매 termination = sink. 매 tap 의 안에서 매 mutation 금지.
🔗 Graph
- 부모: Reactive Streams
- 응용: Backpressure
🤖 LLM 활용
언제: 매 stream pipeline 의 instrumentation, terminal consumer 설계. 언제 X: 매 tap 안에서 value mutate (매 functional contract 위반). 매 sink 를 매 중간 transformation 으로 오용.
❌ 안티패턴
- Tap 안 mutation: 매 element field 의 변경 — 매 pipeline 의 referential transparency 손상.
- Sink 누락: 매 stream 정의만 하고 매 run 안 함 — Effect 의 매 lazy 의 의해 매 nothing happens.
- 다중 sink 의 sequential 처리: 매 single pass 가능한데 매 stream 을 매 두번 traverse.
- Tap 에 heavy I/O: 매 main flow blocking — 매 fork 또는 async sink 로 분리.
🧪 검증 / 중복
- Verified (Effect docs 2026, RxJS 8, Akka Streams).
- 신뢰도 A.
🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Tap/Sink 의 distinction + 8 patterns |