@kood/claude-code 0.6.6 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +7 -1
- package/package.json +1 -1
- package/templates/.claude/agents/analyst.md +5 -0
- package/templates/.claude/agents/architect.md +5 -0
- package/templates/.claude/agents/build-fixer.md +1 -0
- package/templates/.claude/agents/code-reviewer.md +1 -0
- package/templates/.claude/agents/critic.md +4 -0
- package/templates/.claude/agents/deep-executor.md +1 -0
- package/templates/.claude/agents/dependency-manager.md +2 -0
- package/templates/.claude/agents/deployment-validator.md +2 -0
- package/templates/.claude/agents/designer.md +2 -0
- package/templates/.claude/agents/document-writer.md +3 -0
- package/templates/.claude/agents/explore.md +1 -0
- package/templates/.claude/agents/git-operator.md +2 -0
- package/templates/.claude/agents/implementation-executor.md +2 -0
- package/templates/.claude/agents/ko-to-en-translator.md +3 -0
- package/templates/.claude/agents/lint-fixer.md +2 -0
- package/templates/.claude/agents/planner.md +3 -0
- package/templates/.claude/agents/pm.md +349 -0
- package/templates/.claude/agents/qa-tester.md +1 -0
- package/templates/.claude/agents/refactor-advisor.md +4 -0
- package/templates/.claude/agents/researcher.md +9 -1
- package/templates/.claude/agents/scientist.md +1 -0
- package/templates/.claude/agents/security-reviewer.md +1 -0
- package/templates/.claude/agents/tdd-guide.md +1 -0
- package/templates/.claude/agents/vision.md +1 -0
- package/templates/.claude/instructions/agent-patterns/agent-teams-usage.md +376 -0
- package/templates/.claude/instructions/sourcing/reliable-search.md +49 -2
- package/templates/.claude/scripts/agent-teams/check-availability.sh +238 -0
- package/templates/.claude/scripts/agent-teams/setup-tmux.sh +125 -0
- package/templates/.claude/skills/agent-teams-setup/SKILL.md +460 -0
- package/templates/.claude/skills/brainstorm/SKILL.md +1 -0
- package/templates/.claude/skills/bug-fix/SKILL.md +1 -0
- package/templates/.claude/skills/crawler/SKILL.md +2 -0
- package/templates/.claude/skills/docs-creator/SKILL.md +1 -0
- package/templates/.claude/skills/docs-fetch/SKILL.md +6 -4
- package/templates/.claude/skills/docs-refactor/SKILL.md +1 -0
- package/templates/.claude/skills/elon-musk/SKILL.md +1 -0
- package/templates/.claude/skills/execute/SKILL.md +1 -0
- package/templates/.claude/skills/feedback/SKILL.md +1 -0
- package/templates/.claude/skills/figma-to-code/SKILL.md +1 -0
- package/templates/.claude/skills/genius-thinking/SKILL.md +1 -0
- package/templates/.claude/skills/global-uiux-design/SKILL.md +1 -0
- package/templates/.claude/skills/korea-uiux-design/SKILL.md +1 -0
- package/templates/.claude/skills/nextjs-react-best-practices/SKILL.md +1 -0
- package/templates/.claude/skills/plan/SKILL.md +1 -0
- package/templates/.claude/skills/prd/SKILL.md +1 -0
- package/templates/.claude/skills/project-optimizer/AGENTS.md +275 -0
- package/templates/.claude/skills/project-optimizer/SKILL.md +375 -0
- package/templates/.claude/skills/project-optimizer/rules/arch-config-centralize.md +66 -0
- package/templates/.claude/skills/project-optimizer/rules/arch-hot-path.md +35 -0
- package/templates/.claude/skills/project-optimizer/rules/arch-interface-segregation.md +51 -0
- package/templates/.claude/skills/project-optimizer/rules/arch-module-boundary.md +42 -0
- package/templates/.claude/skills/project-optimizer/rules/build-cache.md +57 -0
- package/templates/.claude/skills/project-optimizer/rules/build-code-split.md +56 -0
- package/templates/.claude/skills/project-optimizer/rules/build-incremental.md +65 -0
- package/templates/.claude/skills/project-optimizer/rules/build-minify.md +61 -0
- package/templates/.claude/skills/project-optimizer/rules/build-tree-shake.md +60 -0
- package/templates/.claude/skills/project-optimizer/rules/code-complexity.md +65 -0
- package/templates/.claude/skills/project-optimizer/rules/code-dead-elimination.md +32 -0
- package/templates/.claude/skills/project-optimizer/rules/code-duplication.md +54 -0
- package/templates/.claude/skills/project-optimizer/rules/code-error-handling.md +75 -0
- package/templates/.claude/skills/project-optimizer/rules/code-naming.md +52 -0
- package/templates/.claude/skills/project-optimizer/rules/concurrency-defer-await.md +54 -0
- package/templates/.claude/skills/project-optimizer/rules/concurrency-parallel.md +90 -0
- package/templates/.claude/skills/project-optimizer/rules/concurrency-pipeline.md +68 -0
- package/templates/.claude/skills/project-optimizer/rules/concurrency-pool.md +68 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-lightweight-alt.md +37 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-peer-align.md +44 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-security-audit.md +45 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-unused-removal.md +25 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-version-pin.md +40 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-ci-speed.md +47 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-dev-server.md +35 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-lint-config.md +36 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-test-coverage.md +34 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-type-safety.md +49 -0
- package/templates/.claude/skills/project-optimizer/rules/io-batch-queries.md +67 -0
- package/templates/.claude/skills/project-optimizer/rules/io-cache-layer.md +67 -0
- package/templates/.claude/skills/project-optimizer/rules/io-connection-reuse.md +67 -0
- package/templates/.claude/skills/project-optimizer/rules/io-serialize-minimal.md +61 -0
- package/templates/.claude/skills/project-optimizer/rules/io-stream.md +75 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-bounded-cache.md +65 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-large-data.md +64 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-lazy-init.md +78 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-leak-prevention.md +79 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-pool-reuse.md +70 -0
- package/templates/.claude/skills/ralph/SKILL.md +1 -0
- package/templates/.claude/skills/refactor/SKILL.md +1 -0
- package/templates/.claude/skills/research/SKILL.md +1 -0
- package/templates/.claude/skills/sql-optimizer/SKILL.md +438 -0
- package/templates/.claude/skills/sql-optimizer/orm-patterns.md +218 -0
- package/templates/.claude/skills/startup-validator/SKILL.md +1 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/AGENTS.md +53 -14
- package/templates/.claude/skills/tanstack-start-react-best-practices/SKILL.md +94 -27
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-defer-third-party.md +42 -19
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-optimistic-updates.md +109 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-suspense-query.md +74 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-use-hook.md +81 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-react-compiler.md +81 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-beforeload-auth.md +121 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-file-conventions.md +104 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-link-navigation.md +119 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-nested-layouts.md +155 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-path-params.md +89 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-pending-component.md +110 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-preload-strategy.md +91 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-router-context.md +120 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-search-params.md +114 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-deferred-data.md +1 -1
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-error-boundaries.md +79 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-middleware.md +85 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-serialization.md +56 -21
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-streaming.md +84 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-validator.md +71 -0
- package/templates/.claude/skills/tauri-react-best-practices/AGENTS.md +527 -0
- package/templates/.claude/skills/tauri-react-best-practices/SKILL.md +571 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-barrel-imports.md +140 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-cargo-profile.md +96 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-frontend-treeshake.md +242 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-lazy-components.md +255 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-remove-unused-commands.md +160 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/deploy-ci-pipeline.md +269 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/deploy-signing.md +207 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/deploy-updater.md +226 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-async-commands.md +172 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-batch-commands.md +133 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-binary-response.md +198 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-channel-streaming.md +186 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-error-handling.md +250 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-type-safe.md +227 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/perf-derived-state.md +231 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/perf-functional-setstate.md +191 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/perf-index-maps.md +276 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/perf-lazy-state-init.md +196 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/plugin-lifecycle.md +265 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/plugin-mobile-compat.md +199 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/plugin-permission-scope.md +193 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-error-boundary.md +239 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-event-listener.md +151 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-file-src.md +155 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-invoke-hook.md +139 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-optimistic-update.md +211 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-capability-split.md +205 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-csp.md +207 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-least-privilege.md +106 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-no-wildcard.md +253 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-scope-paths.md +160 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/state-async-mutex.md +270 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/state-mutex-pattern.md +265 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/state-react-sync.md +375 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/state-single-container.md +275 -0
- package/templates/tanstack-start/docs/architecture.md +238 -167
- package/templates/tanstack-start/docs/library/tanstack-router/error-handling.md +777 -38
- package/templates/tanstack-start/docs/library/tanstack-router/hooks.md +549 -37
- package/templates/tanstack-start/docs/library/tanstack-router/index.md +895 -111
- package/templates/tanstack-start/docs/library/tanstack-router/navigation.md +641 -43
- package/templates/tanstack-start/docs/library/tanstack-router/route-context.md +889 -38
- package/templates/tanstack-start/docs/library/tanstack-router/search-params.md +891 -29
- package/templates/tanstack-start/docs/library/tanstack-start/auth-patterns.md +972 -36
- package/templates/tanstack-start/docs/library/tanstack-start/index.md +1525 -881
- package/templates/tanstack-start/docs/library/tanstack-start/middleware.md +1099 -20
- package/templates/tanstack-start/docs/library/tanstack-start/routing.md +796 -30
- package/templates/tanstack-start/docs/library/tanstack-start/server-functions.md +953 -35
- package/templates/tanstack-start/docs/library/tanstack-start/setup.md +371 -15
- package/templates/tauri/CLAUDE.md +189 -0
- package/templates/tauri/docs/guides/distribution.md +261 -0
- package/templates/tauri/docs/guides/getting-started.md +302 -0
- package/templates/tauri/docs/guides/mobile.md +288 -0
- package/templates/tauri/docs/library/tauri/index.md +510 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Enable Incremental Builds
|
|
3
|
+
impact: CRITICAL
|
|
4
|
+
impactDescription: 50-90% build time reduction on repeat builds
|
|
5
|
+
tags: build, incremental, cache, compile
|
|
6
|
+
languages: all
|
|
7
|
+
related: [build-cache, dx-ci-speed]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 증분 빌드 활성화
|
|
11
|
+
|
|
12
|
+
전체 재빌드 대신 변경된 파일만 컴파일하여 빌드 시간을 대폭 줄입니다.
|
|
13
|
+
|
|
14
|
+
**❌ 잘못된 예시 (매번 전체 빌드):**
|
|
15
|
+
|
|
16
|
+
```json
|
|
17
|
+
// tsconfig.json - incremental 비활성화
|
|
18
|
+
{ "compilerOptions": { "incremental": false } }
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```toml
|
|
22
|
+
# Cargo.toml - release에서 증분 비활성화
|
|
23
|
+
[profile.release]
|
|
24
|
+
incremental = false
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**✅ 올바른 예시:**
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
// TypeScript
|
|
31
|
+
{ "compilerOptions": { "incremental": true, "tsBuildInfoFile": ".tsbuildinfo" } }
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```toml
|
|
35
|
+
# Rust
|
|
36
|
+
[profile.dev]
|
|
37
|
+
incremental = true
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
# Python (mypy)
|
|
42
|
+
[tool.mypy]
|
|
43
|
+
incremental = true
|
|
44
|
+
cache_dir = ".mypy_cache"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
```gradle
|
|
48
|
+
// Gradle
|
|
49
|
+
org.gradle.caching=true
|
|
50
|
+
org.gradle.parallel=true
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```yaml
|
|
54
|
+
# CI 캐시 (GitHub Actions)
|
|
55
|
+
- uses: actions/cache@v4
|
|
56
|
+
with:
|
|
57
|
+
path: |
|
|
58
|
+
node_modules/.cache
|
|
59
|
+
.tsbuildinfo
|
|
60
|
+
target/
|
|
61
|
+
~/.cargo/registry
|
|
62
|
+
key: ${{ runner.os }}-build-${{ hashFiles('**/lockfile') }}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**효과:** TypeScript 50-70% 감소, Rust dev 40-60% 감소, Gradle 30-50% 감소.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Minify and Compress Production Output
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: 30-50% output size reduction
|
|
5
|
+
tags: build, minify, compression, production
|
|
6
|
+
languages: [js, ts, css]
|
|
7
|
+
related: [build-tree-shake, build-code-split]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 프로덕션 출력 최소화
|
|
11
|
+
|
|
12
|
+
프로덕션 빌드에서 minification, compression을 활성화하여 배포 크기를 줄입니다.
|
|
13
|
+
|
|
14
|
+
**✅ 올바른 예시:**
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
// Vite
|
|
18
|
+
export default defineConfig({
|
|
19
|
+
build: {
|
|
20
|
+
minify: 'terser', // 또는 'esbuild' (빠름)
|
|
21
|
+
cssMinify: true,
|
|
22
|
+
rollupOptions: {
|
|
23
|
+
output: { manualChunks: { vendor: ['react', 'react-dom'] } }
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```toml
|
|
30
|
+
# Rust
|
|
31
|
+
[profile.release]
|
|
32
|
+
opt-level = "z" # 크기 최적화 (또는 "3" 속도 최적화)
|
|
33
|
+
lto = "thin" # LTO
|
|
34
|
+
strip = "symbols"
|
|
35
|
+
panic = "abort" # unwind 코드 제거
|
|
36
|
+
codegen-units = 1 # 최적화 극대화 (빌드 느려짐)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```go
|
|
40
|
+
// Go
|
|
41
|
+
// go build -ldflags="-s -w" -trimpath ./cmd/app
|
|
42
|
+
// -s: 심볼 테이블 제거, -w: DWARF 제거, -trimpath: 경로 정보 제거
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
```dockerfile
|
|
46
|
+
# Docker 멀티스테이지 빌드
|
|
47
|
+
FROM golang:1.22 AS builder
|
|
48
|
+
RUN CGO_ENABLED=0 go build -ldflags="-s -w" -o /app
|
|
49
|
+
|
|
50
|
+
FROM scratch
|
|
51
|
+
COPY --from=builder /app /app
|
|
52
|
+
ENTRYPOINT ["/app"]
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**서버 압축:**
|
|
56
|
+
|
|
57
|
+
| 방법 | 감소율 | 도구 |
|
|
58
|
+
|------|--------|------|
|
|
59
|
+
| gzip | ~70% | Nginx, CDN 기본 |
|
|
60
|
+
| Brotli | ~80% | Nginx, Cloudflare |
|
|
61
|
+
| 빌드 시 사전 압축 | 서버 CPU 절약 | `vite-plugin-compression` |
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Enable Tree Shaking / Dead Code Elimination
|
|
3
|
+
impact: CRITICAL
|
|
4
|
+
impactDescription: 20-60% bundle size reduction
|
|
5
|
+
tags: build, tree-shaking, dead-code, bundle-size
|
|
6
|
+
languages: [js, ts, rust, go]
|
|
7
|
+
related: [build-code-split, code-dead-elimination, deps-unused-removal]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 미사용 코드 자동 제거
|
|
11
|
+
|
|
12
|
+
번들러/컴파일러의 dead code elimination을 활성화하여 실제 사용하는 코드만 출력에 포함합니다.
|
|
13
|
+
|
|
14
|
+
**❌ 잘못된 예시:**
|
|
15
|
+
|
|
16
|
+
```json
|
|
17
|
+
// package.json - sideEffects 미지정
|
|
18
|
+
{ "name": "my-lib" }
|
|
19
|
+
// 번들러가 어떤 코드가 부작용 있는지 몰라서 전부 포함
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
// 배럴 파일에서 전체 import
|
|
24
|
+
import { oneUtil } from './utils' // utils/index.ts가 50개 모듈 re-export
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**✅ 올바른 예시:**
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
// package.json - sideEffects 지정
|
|
31
|
+
{ "name": "my-lib", "sideEffects": false }
|
|
32
|
+
// 또는 특정 파일만: "sideEffects": ["*.css", "./src/polyfill.js"]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
// 직접 import (배럴 파일 우회)
|
|
37
|
+
import { oneUtil } from './utils/oneUtil'
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
```toml
|
|
41
|
+
# Rust - release 최적화
|
|
42
|
+
[profile.release]
|
|
43
|
+
lto = "thin" # Link-Time Optimization
|
|
44
|
+
strip = "symbols" # 심볼 제거
|
|
45
|
+
opt-level = "z" # 크기 최적화
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```go
|
|
49
|
+
// Go - 기본 활성화. 추가 최적화:
|
|
50
|
+
// go build -ldflags="-s -w" # 심볼 테이블, DWARF 디버그 정보 제거
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**도구별 설정:**
|
|
54
|
+
|
|
55
|
+
| 빌드 도구 | 설정 |
|
|
56
|
+
|-----------|------|
|
|
57
|
+
| Vite/Rollup | 기본 활성화 (`build.rollupOptions`) |
|
|
58
|
+
| webpack | `mode: 'production'`, `usedExports: true` |
|
|
59
|
+
| esbuild | `--tree-shaking=true` (기본) |
|
|
60
|
+
| tsup | `treeshake: true` |
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Reduce Cyclomatic Complexity
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Easier testing, fewer bugs, better readability
|
|
5
|
+
tags: code, complexity, early-return, guard-clause, extract
|
|
6
|
+
languages: all
|
|
7
|
+
related: [code-duplication, code-error-handling]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 순환 복잡도 감소
|
|
11
|
+
|
|
12
|
+
깊은 중첩, 긴 if-else 체인, 복잡한 조건문을 단순화합니다.
|
|
13
|
+
|
|
14
|
+
**❌ 잘못된 예시 (깊은 중첩):**
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
def process(request):
|
|
18
|
+
if request:
|
|
19
|
+
if request.user:
|
|
20
|
+
if request.user.is_active:
|
|
21
|
+
if request.data:
|
|
22
|
+
return do_work(request.data)
|
|
23
|
+
else:
|
|
24
|
+
return Error("no data")
|
|
25
|
+
else:
|
|
26
|
+
return Error("inactive")
|
|
27
|
+
else:
|
|
28
|
+
return Error("no user")
|
|
29
|
+
else:
|
|
30
|
+
return Error("no request")
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**✅ 올바른 예시 (guard clause + early return):**
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
def process(request):
|
|
37
|
+
if not request:
|
|
38
|
+
return Error("no request")
|
|
39
|
+
if not request.user:
|
|
40
|
+
return Error("no user")
|
|
41
|
+
if not request.user.is_active:
|
|
42
|
+
return Error("inactive")
|
|
43
|
+
if not request.data:
|
|
44
|
+
return Error("no data")
|
|
45
|
+
return do_work(request.data)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**✅ 올바른 예시 (table-driven):**
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
# ❌ 긴 if-else 체인
|
|
52
|
+
def get_discount(tier):
|
|
53
|
+
if tier == "bronze": return 0.05
|
|
54
|
+
elif tier == "silver": return 0.10
|
|
55
|
+
elif tier == "gold": return 0.15
|
|
56
|
+
elif tier == "platinum": return 0.20
|
|
57
|
+
else: return 0
|
|
58
|
+
|
|
59
|
+
# ✅ 맵/딕셔너리
|
|
60
|
+
DISCOUNTS = {"bronze": 0.05, "silver": 0.10, "gold": 0.15, "platinum": 0.20}
|
|
61
|
+
def get_discount(tier):
|
|
62
|
+
return DISCOUNTS.get(tier, 0)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**목표:** 함수당 순환 복잡도 10 이하, 중첩 깊이 3 이하.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Remove Dead Code and Unused Imports
|
|
3
|
+
impact: MEDIUM-HIGH
|
|
4
|
+
impactDescription: Cleaner codebase, smaller bundles, faster comprehension
|
|
5
|
+
tags: code, dead-code, unused, imports, cleanup
|
|
6
|
+
languages: all
|
|
7
|
+
related: [build-tree-shake, deps-unused-removal]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 미사용 코드/변수/import 제거
|
|
11
|
+
|
|
12
|
+
사용되지 않는 코드는 혼란을 주고 번들 크기를 증가시킵니다. 도구로 감지하고 즉시 제거합니다.
|
|
13
|
+
|
|
14
|
+
**감지 도구:**
|
|
15
|
+
|
|
16
|
+
| 언어 | 도구 | 명령어 |
|
|
17
|
+
|------|------|--------|
|
|
18
|
+
| **JS/TS** | `knip` | `npx knip` |
|
|
19
|
+
| **JS/TS** | ESLint `no-unused-vars` | 자동 |
|
|
20
|
+
| **Python** | `vulture` | `vulture src/` |
|
|
21
|
+
| **Python** | `autoflake` | `autoflake --remove-all-unused-imports` |
|
|
22
|
+
| **Go** | 컴파일러 (내장) | 미사용 import/변수 = 컴파일 에러 |
|
|
23
|
+
| **Rust** | 컴파일러 (내장) | `#[warn(dead_code)]` 기본 활성화 |
|
|
24
|
+
| **Java** | IntelliJ / SonarQube | 자동 감지 |
|
|
25
|
+
|
|
26
|
+
**제거 대상:**
|
|
27
|
+
- 미사용 import/require
|
|
28
|
+
- 미사용 변수/상수
|
|
29
|
+
- 호출되지 않는 함수/메서드
|
|
30
|
+
- 도달 불가능한 코드 (unreachable after return/throw)
|
|
31
|
+
- 주석 처리된 코드 블록 (Git 히스토리에 보존됨)
|
|
32
|
+
- 미사용 타입/인터페이스 정의
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Extract Duplicated Code (Rule of Three)
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Reduced maintenance burden, single source of truth
|
|
5
|
+
tags: code, duplication, dry, extract, refactor
|
|
6
|
+
languages: all
|
|
7
|
+
related: [code-complexity, arch-interface-segregation]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 중복 코드 추출 (3회 이상부터)
|
|
11
|
+
|
|
12
|
+
동일/유사 코드가 3회 이상 반복되면 함수/모듈로 추출합니다. 2회까지는 허용 (premature abstraction 방지).
|
|
13
|
+
|
|
14
|
+
**❌ 잘못된 예시 (3곳에서 반복):**
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
# file_a.py
|
|
18
|
+
data = json.loads(response.text)
|
|
19
|
+
if "error" in data:
|
|
20
|
+
logger.error(f"API error: {data['error']}")
|
|
21
|
+
raise ApiError(data["error"])
|
|
22
|
+
|
|
23
|
+
# file_b.py (동일 패턴 반복)
|
|
24
|
+
data = json.loads(response.text)
|
|
25
|
+
if "error" in data:
|
|
26
|
+
logger.error(f"API error: {data['error']}")
|
|
27
|
+
raise ApiError(data["error"])
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**✅ 올바른 예시 (추출):**
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
# utils/api.py
|
|
34
|
+
def parse_api_response(response: Response) -> dict:
|
|
35
|
+
data = response.json()
|
|
36
|
+
if "error" in data:
|
|
37
|
+
logger.error(f"API error: {data['error']}")
|
|
38
|
+
raise ApiError(data["error"])
|
|
39
|
+
return data
|
|
40
|
+
|
|
41
|
+
# file_a.py, file_b.py
|
|
42
|
+
data = parse_api_response(response)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**감지 도구:**
|
|
46
|
+
|
|
47
|
+
| 언어 | 도구 |
|
|
48
|
+
|------|------|
|
|
49
|
+
| **범용** | `jscpd` (Copy/Paste Detector) |
|
|
50
|
+
| **Python** | `pylint --disable=all --enable=duplicate-code` |
|
|
51
|
+
| **Java** | PMD CPD |
|
|
52
|
+
| **Go** | `dupl` |
|
|
53
|
+
|
|
54
|
+
**주의:** 비슷해 보이지만 다른 의도의 코드는 추출하지 않음. 추상화 비용 > 중복 비용이면 중복 허용.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Consistent Error Handling Pattern
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Predictable error flow, easier debugging
|
|
5
|
+
tags: code, error, exception, result, handling
|
|
6
|
+
languages: all
|
|
7
|
+
related: [code-complexity, memory-leak-prevention]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 일관된 에러 처리 패턴
|
|
11
|
+
|
|
12
|
+
프로젝트 전체에서 하나의 에러 처리 패턴을 일관되게 사용합니다.
|
|
13
|
+
|
|
14
|
+
**언어별 권장 패턴:**
|
|
15
|
+
|
|
16
|
+
| 언어 | 패턴 | 핵심 |
|
|
17
|
+
|------|------|------|
|
|
18
|
+
| **Go** | `(value, error)` | 항상 err 체크, sentinel errors |
|
|
19
|
+
| **Rust** | `Result<T, E>` | `?` 연산자, 커스텀 Error enum |
|
|
20
|
+
| **Python** | Exception 계층 | 커스텀 Exception, `raise from` |
|
|
21
|
+
| **JS/TS** | 커스텀 Error / Result | Error 서브클래스 또는 Result 타입 |
|
|
22
|
+
| **Java** | Unchecked 선호 | RuntimeException 서브클래스 |
|
|
23
|
+
|
|
24
|
+
**✅ 올바른 예시:**
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
// JS/TS - 커스텀 Error 클래스
|
|
28
|
+
class AppError extends Error {
|
|
29
|
+
constructor(
|
|
30
|
+
message: string,
|
|
31
|
+
public code: string,
|
|
32
|
+
public statusCode: number = 500
|
|
33
|
+
) {
|
|
34
|
+
super(message)
|
|
35
|
+
this.name = 'AppError'
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
class NotFoundError extends AppError {
|
|
39
|
+
constructor(resource: string) {
|
|
40
|
+
super(`${resource} not found`, 'NOT_FOUND', 404)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
```go
|
|
46
|
+
// Go - sentinel errors + wrapping
|
|
47
|
+
var ErrNotFound = errors.New("not found")
|
|
48
|
+
var ErrUnauthorized = errors.New("unauthorized")
|
|
49
|
+
|
|
50
|
+
func getUser(id string) (*User, error) {
|
|
51
|
+
user, err := db.Find(id)
|
|
52
|
+
if err != nil {
|
|
53
|
+
return nil, fmt.Errorf("getUser(%s): %w", id, err)
|
|
54
|
+
}
|
|
55
|
+
if user == nil {
|
|
56
|
+
return nil, ErrNotFound
|
|
57
|
+
}
|
|
58
|
+
return user, nil
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```rust
|
|
63
|
+
// Rust - thiserror
|
|
64
|
+
#[derive(Debug, thiserror::Error)]
|
|
65
|
+
enum AppError {
|
|
66
|
+
#[error("not found: {0}")]
|
|
67
|
+
NotFound(String),
|
|
68
|
+
#[error("unauthorized")]
|
|
69
|
+
Unauthorized,
|
|
70
|
+
#[error(transparent)]
|
|
71
|
+
Database(#[from] sqlx::Error),
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**원칙:** 에러는 발생 지점에서 컨텍스트를 추가하고, 처리 지점에서 변환/로깅합니다.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Intent-Revealing Names
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Self-documenting code, reduced cognitive load
|
|
5
|
+
tags: code, naming, readability, maintainability
|
|
6
|
+
languages: all
|
|
7
|
+
related: [code-complexity, dx-type-safety]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 의도를 드러내는 이름 사용
|
|
11
|
+
|
|
12
|
+
변수/함수/클래스 이름만으로 역할과 의도를 파악할 수 있게 합니다.
|
|
13
|
+
|
|
14
|
+
**❌ 잘못된 예시:**
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
d = {} # 무엇의 딕셔너리?
|
|
18
|
+
tmp = get() # 임시? 무엇을 가져옴?
|
|
19
|
+
flag = True # 어떤 플래그?
|
|
20
|
+
def proc(x): # 무엇을 처리?
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
for i in lst: # i와 lst가 무엇?
|
|
24
|
+
if i.s == 1: # s가 무엇? 1이 무엇?
|
|
25
|
+
do(i)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**✅ 올바른 예시:**
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
user_scores = {}
|
|
32
|
+
active_user = get_current_user()
|
|
33
|
+
is_premium = True
|
|
34
|
+
def calculate_shipping_cost(order):
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
STATUS_ACTIVE = 1
|
|
38
|
+
for user in users:
|
|
39
|
+
if user.status == STATUS_ACTIVE:
|
|
40
|
+
send_notification(user)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**명명 패턴:**
|
|
44
|
+
|
|
45
|
+
| 유형 | 패턴 | 예시 |
|
|
46
|
+
|------|------|------|
|
|
47
|
+
| **Boolean** | `is_`, `has_`, `can_`, `should_` | `is_valid`, `has_permission` |
|
|
48
|
+
| **함수** | 동사 + 목적어 | `calculate_total`, `send_email` |
|
|
49
|
+
| **컬렉션** | 복수형 | `users`, `order_items` |
|
|
50
|
+
| **맵/딕셔너리** | `x_by_y` | `user_by_id`, `orders_by_date` |
|
|
51
|
+
| **상수** | `UPPER_SNAKE` | `MAX_RETRY_COUNT` |
|
|
52
|
+
| **축약 금지** | 풀네임 사용 | `transaction` (not `txn`) |
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Defer Await to Point of Use
|
|
3
|
+
impact: CRITICAL
|
|
4
|
+
impactDescription: Eliminates unnecessary blocking, enables overlap
|
|
5
|
+
tags: concurrency, async, await, deferred
|
|
6
|
+
languages: all
|
|
7
|
+
related: [concurrency-parallel, memory-lazy-init]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## await/블로킹을 사용 지점으로 이동
|
|
11
|
+
|
|
12
|
+
비동기 작업의 결과를 기다리는 시점을 실제 사용 지점으로 미뤄서, 그 사이에 다른 작업이 실행될 수 있게 합니다.
|
|
13
|
+
|
|
14
|
+
**❌ 잘못된 예시 (즉시 대기):**
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
// 결과가 10줄 뒤에서 필요한데 즉시 await
|
|
18
|
+
const data = await fetchData()
|
|
19
|
+
// ... 다른 동기 작업 10줄 ...
|
|
20
|
+
processData(data)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
data = await fetch_data() # 여기서 블로킹
|
|
25
|
+
# ... 다른 동기 작업 ...
|
|
26
|
+
process_data(data)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**✅ 올바른 예시 (사용 시점에서 대기):**
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
// Promise를 먼저 시작, 나중에 await
|
|
33
|
+
const dataPromise = fetchData() // 시작만 함
|
|
34
|
+
// ... 다른 동기 작업 (이 동안 fetch 진행) ...
|
|
35
|
+
const data = await dataPromise // 실제 필요 시점에 await
|
|
36
|
+
processData(data)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
import asyncio
|
|
41
|
+
task = asyncio.create_task(fetch_data()) # 시작만 함
|
|
42
|
+
# ... 다른 동기 작업 ...
|
|
43
|
+
data = await task # 실제 필요 시점에 await
|
|
44
|
+
process_data(data)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
```go
|
|
48
|
+
ch := make(chan *Data, 1)
|
|
49
|
+
go func() { ch <- fetchData(ctx) }() // 시작
|
|
50
|
+
// ... 다른 작업 ...
|
|
51
|
+
data := <-ch // 실제 필요 시점에 수신
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**핵심:** 작업 시작과 결과 소비 사이에 다른 유용한 작업이 있으면 defer 적용.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Parallelize Independent Operations
|
|
3
|
+
impact: CRITICAL
|
|
4
|
+
impactDescription: 2-10x improvement on I/O-bound workloads
|
|
5
|
+
tags: concurrency, parallelization, async, performance
|
|
6
|
+
languages: all
|
|
7
|
+
related: [concurrency-defer-await, concurrency-pool, io-batch-queries]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 독립 작업 병렬 실행
|
|
11
|
+
|
|
12
|
+
서로 의존성이 없는 I/O 작업은 동시에 실행하여 총 대기 시간을 최장 작업 1개 수준으로 줄입니다.
|
|
13
|
+
|
|
14
|
+
**❌ 잘못된 예시 (순차 실행, 3번 왕복):**
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
// JS/TS
|
|
18
|
+
const user = await fetchUser()
|
|
19
|
+
const posts = await fetchPosts()
|
|
20
|
+
const comments = await fetchComments()
|
|
21
|
+
// 총 시간: T(user) + T(posts) + T(comments)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
# Python
|
|
26
|
+
user = await fetch_user()
|
|
27
|
+
posts = await fetch_posts()
|
|
28
|
+
comments = await fetch_comments()
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```go
|
|
32
|
+
// Go
|
|
33
|
+
user, _ := fetchUser(ctx)
|
|
34
|
+
posts, _ := fetchPosts(ctx)
|
|
35
|
+
comments, _ := fetchComments(ctx)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**✅ 올바른 예시 (병렬 실행, 1번 왕복):**
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
// JS/TS
|
|
42
|
+
const [user, posts, comments] = await Promise.all([
|
|
43
|
+
fetchUser(), fetchPosts(), fetchComments()
|
|
44
|
+
])
|
|
45
|
+
// 총 시간: max(T(user), T(posts), T(comments))
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
# Python
|
|
50
|
+
user, posts, comments = await asyncio.gather(
|
|
51
|
+
fetch_user(), fetch_posts(), fetch_comments()
|
|
52
|
+
)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
```go
|
|
56
|
+
// Go (errgroup)
|
|
57
|
+
g, ctx := errgroup.WithContext(ctx)
|
|
58
|
+
var user *User; var posts []Post; var comments []Comment
|
|
59
|
+
g.Go(func() error { var err error; user, err = fetchUser(ctx); return err })
|
|
60
|
+
g.Go(func() error { var err error; posts, err = fetchPosts(ctx); return err })
|
|
61
|
+
g.Go(func() error { var err error; comments, err = fetchComments(ctx); return err })
|
|
62
|
+
if err := g.Wait(); err != nil { return err }
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
```rust
|
|
66
|
+
// Rust (tokio)
|
|
67
|
+
let (user, posts, comments) = tokio::try_join!(
|
|
68
|
+
fetch_user(), fetch_posts(), fetch_comments()
|
|
69
|
+
)?;
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
```java
|
|
73
|
+
// Java
|
|
74
|
+
var userFuture = CompletableFuture.supplyAsync(() -> fetchUser());
|
|
75
|
+
var postsFuture = CompletableFuture.supplyAsync(() -> fetchPosts());
|
|
76
|
+
CompletableFuture.allOf(userFuture, postsFuture).join();
|
|
77
|
+
var user = userFuture.get();
|
|
78
|
+
var posts = postsFuture.get();
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```csharp
|
|
82
|
+
// C#
|
|
83
|
+
var userTask = FetchUserAsync();
|
|
84
|
+
var postsTask = FetchPostsAsync();
|
|
85
|
+
await Task.WhenAll(userTask, postsTask);
|
|
86
|
+
var user = userTask.Result;
|
|
87
|
+
var posts = postsTask.Result;
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**적용 기준:** 두 작업이 서로의 결과를 필요로 하지 않으면 병렬화 대상.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Pipeline Parallelization
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Continuous throughput for multi-stage processing
|
|
5
|
+
tags: concurrency, pipeline, streaming, producer-consumer
|
|
6
|
+
languages: all
|
|
7
|
+
related: [concurrency-parallel, io-stream, memory-large-data]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 파이프라인 병렬화
|
|
11
|
+
|
|
12
|
+
다단계 처리에서 각 단계를 동시에 실행하여 처리량을 극대화합니다. 한 단계의 출력이 다음 단계의 입력이 되는 스트리밍 방식.
|
|
13
|
+
|
|
14
|
+
**❌ 잘못된 예시 (단계별 전체 처리):**
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
# 모든 데이터를 한 단계 완료 후 다음 단계
|
|
18
|
+
items = fetch_all() # 10초 대기
|
|
19
|
+
processed = [process(i) for i in items] # 10초 대기
|
|
20
|
+
results = [save(p) for p in processed] # 10초 대기
|
|
21
|
+
# 총 30초, 메모리에 전체 데이터 적재
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**✅ 올바른 예시 (스트리밍 파이프라인):**
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
# Python (async generator)
|
|
28
|
+
async def fetch_stream():
|
|
29
|
+
async for item in db.stream_query("SELECT ..."):
|
|
30
|
+
yield item
|
|
31
|
+
|
|
32
|
+
async def process_stream(items):
|
|
33
|
+
async for item in items:
|
|
34
|
+
yield transform(item)
|
|
35
|
+
|
|
36
|
+
async def save_stream(items):
|
|
37
|
+
batch = []
|
|
38
|
+
async for item in items:
|
|
39
|
+
batch.append(item)
|
|
40
|
+
if len(batch) >= 100:
|
|
41
|
+
await db.bulk_insert(batch)
|
|
42
|
+
batch.clear()
|
|
43
|
+
if batch:
|
|
44
|
+
await db.bulk_insert(batch)
|
|
45
|
+
|
|
46
|
+
# 파이프라인 연결
|
|
47
|
+
await save_stream(process_stream(fetch_stream()))
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
```go
|
|
51
|
+
// Go (channel pipeline)
|
|
52
|
+
func fetch(ctx context.Context) <-chan Item {
|
|
53
|
+
out := make(chan Item, 100)
|
|
54
|
+
go func() { defer close(out); /* fetch and send */ }()
|
|
55
|
+
return out
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
func process(in <-chan Item) <-chan Result {
|
|
59
|
+
out := make(chan Result, 100)
|
|
60
|
+
go func() { defer close(out); for item := range in { out <- transform(item) } }()
|
|
61
|
+
return out
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 파이프라인 연결
|
|
65
|
+
results := process(fetch(ctx))
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**적용 기준:** 데이터가 대량이고 단계별로 독립 처리 가능할 때.
|