moai-adk 0.5.4__py3-none-any.whl → 0.5.8__py3-none-any.whl

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.

Potentially problematic release.


This version of moai-adk might be problematic. Click here for more details.

Files changed (63) hide show
  1. moai_adk/__init__.py +1 -1
  2. moai_adk/cli/commands/init.py +4 -2
  3. moai_adk/cli/commands/status.py +4 -2
  4. moai_adk/cli/commands/update.py +4 -5
  5. moai_adk/core/project/initializer.py +13 -11
  6. moai_adk/core/project/phase_executor.py +10 -3
  7. moai_adk/core/template/processor.py +60 -1
  8. moai_adk/templates/.claude/agents/alfred/cc-manager.md +8 -0
  9. moai_adk/templates/.claude/agents/alfred/debug-helper.md +18 -0
  10. moai_adk/templates/.claude/agents/alfred/doc-syncer.md +18 -0
  11. moai_adk/templates/.claude/agents/alfred/git-manager.md +38 -2
  12. moai_adk/templates/.claude/agents/alfred/implementation-planner.md +18 -0
  13. moai_adk/templates/.claude/agents/alfred/project-manager.md +6 -0
  14. moai_adk/templates/.claude/agents/alfred/quality-gate.md +6 -0
  15. moai_adk/templates/.claude/agents/alfred/skill-factory.md +8 -0
  16. moai_adk/templates/.claude/agents/alfred/spec-builder.md +17 -0
  17. moai_adk/templates/.claude/agents/alfred/tag-agent.md +7 -1
  18. moai_adk/templates/.claude/agents/alfred/tdd-implementer.md +18 -0
  19. moai_adk/templates/.claude/agents/alfred/trust-checker.md +6 -0
  20. moai_adk/templates/.claude/commands/alfred/0-project.md +5 -1
  21. moai_adk/templates/.claude/commands/alfred/1-plan.md +18 -14
  22. moai_adk/templates/.claude/commands/alfred/2-run.md +6 -2
  23. moai_adk/templates/.claude/commands/alfred/3-sync.md +5 -1
  24. moai_adk/templates/.claude/hooks/alfred/alfred_hooks.py +5 -1
  25. moai_adk/templates/.claude/output-styles/alfred/agentic-coding.md +5 -1
  26. moai_adk/templates/.claude/output-styles/alfred/moai-adk-learning.md +5 -1
  27. moai_adk/templates/.claude/output-styles/alfred/study-with-alfred.md +5 -1
  28. moai_adk/templates/.claude/skills/moai-alfred-interactive-questions/SKILL.md +30 -273
  29. moai_adk/templates/.claude/skills/moai-alfred-interactive-questions/examples.md +487 -129
  30. moai_adk/templates/.claude/skills/moai-alfred-interactive-questions/reference.md +603 -70
  31. moai_adk/templates/.claude/skills/moai-cc-agents/SKILL.md +22 -2
  32. moai_adk/templates/.claude/skills/moai-cc-claude-md/SKILL.md +22 -2
  33. moai_adk/templates/.claude/skills/moai-cc-commands/SKILL.md +22 -2
  34. moai_adk/templates/.claude/skills/moai-cc-hooks/SKILL.md +22 -2
  35. moai_adk/templates/.claude/skills/moai-cc-mcp-plugins/SKILL.md +22 -2
  36. moai_adk/templates/.claude/skills/moai-cc-memory/SKILL.md +22 -2
  37. moai_adk/templates/.claude/skills/moai-cc-settings/SKILL.md +22 -2
  38. moai_adk/templates/.claude/skills/moai-cc-skills/SKILL.md +25 -5
  39. moai_adk/templates/.claude/skills/moai-essentials-debug/SKILL.md +152 -547
  40. moai_adk/templates/.claude/skills/moai-essentials-debug/examples.md +835 -878
  41. moai_adk/templates/.claude/skills/moai-essentials-debug/reference.md +665 -1151
  42. moai_adk/templates/.claude/skills/moai-skill-factory/SKILL.md +138 -427
  43. moai_adk/templates/.claude/skills/moai-spec-authoring/README.md +61 -53
  44. moai_adk/templates/.claude/skills/moai-spec-authoring/SKILL.md +99 -1181
  45. moai_adk/templates/.claude/skills/moai-spec-authoring/examples.md +541 -0
  46. moai_adk/templates/.claude/skills/moai-spec-authoring/reference.md +622 -0
  47. moai_adk/templates/.github/ISSUE_TEMPLATE/spec.yml +176 -0
  48. moai_adk/templates/.github/workflows/spec-issue-sync.yml +167 -0
  49. moai_adk/templates/.moai/config.json +5 -5
  50. moai_adk/templates/.moai/memory/CLAUDE-AGENTS-GUIDE.md +208 -0
  51. moai_adk/templates/.moai/memory/CLAUDE-PRACTICES.md +369 -0
  52. moai_adk/templates/.moai/memory/CLAUDE-RULES.md +539 -0
  53. moai_adk/templates/.moai/memory/{development-guide.md → DEVELOPMENT-GUIDE.md} +3 -3
  54. moai_adk/templates/.moai/memory/SKILLS-DESCRIPTION-POLICY.md +218 -0
  55. moai_adk/templates/.moai/memory/config-schema.md +444 -0
  56. moai_adk/templates/CLAUDE.md +149 -845
  57. {moai_adk-0.5.4.dist-info → moai_adk-0.5.8.dist-info}/METADATA +407 -336
  58. {moai_adk-0.5.4.dist-info → moai_adk-0.5.8.dist-info}/RECORD +63 -54
  59. /moai_adk/templates/.moai/memory/{gitflow-protection-policy.md → GITFLOW-PROTECTION-POLICY.md} +0 -0
  60. /moai_adk/templates/.moai/memory/{spec-metadata.md → SPEC-METADATA.md} +0 -0
  61. {moai_adk-0.5.4.dist-info → moai_adk-0.5.8.dist-info}/WHEEL +0 -0
  62. {moai_adk-0.5.4.dist-info → moai_adk-0.5.8.dist-info}/entry_points.txt +0 -0
  63. {moai_adk-0.5.4.dist-info → moai_adk-0.5.8.dist-info}/licenses/LICENSE +0 -0
@@ -1,1107 +1,1064 @@
1
- # MoAI Essentials Debug - Real-World Examples
2
-
3
- ## Table of Contents
4
- 1. [Async/Await Debugging (Python)](#asyncawait-debugging-python)
5
- 2. [Goroutine Leak Investigation (Go)](#goroutine-leak-investigation-go)
6
- 3. [Distributed Tracing with OpenTelemetry (Multi-service)](#distributed-tracing-with-opentelemetry-multi-service)
7
- 4. [Kubernetes Pod Crash Debugging](#kubernetes-pod-crash-debugging)
8
- 5. [Memory Leak Diagnosis (Rust)](#memory-leak-diagnosis-rust)
9
- 6. [Race Condition Detection (Go)](#race-condition-detection-go)
10
- 7. [Null Pointer Debugging (TypeScript)](#null-pointer-debugging-typescript)
11
- 8. [Database Query Performance (SQL)](#database-query-performance-sql)
1
+ # moai-essentials-debug 실전 예제
2
+
3
+ > **Version**: 2.1.0
4
+ > **Last Updated**: 2025-10-27
5
+
6
+ 문서는 언어별 스택 트레이스 분석 실전 예제와 디버깅 시나리오를 제공합니다.
12
7
 
13
8
  ---
14
9
 
15
- ## Async/Await Debugging (Python)
10
+ ## Python 디버깅 예제
16
11
 
17
- ### Problem
18
- FastAPI application experiencing intermittent timeouts and "Event loop is closed" errors.
12
+ ### 예제 1: TypeError — 타입 불일치
19
13
 
20
- ### Stack Trace
21
- ```python
14
+ **에러 메시지**:
15
+ ```
22
16
  Traceback (most recent call last):
23
- File "app.py", line 87, in process_request
24
- result = await fetch_data()
25
- File "app.py", line 42, in fetch_data
26
- async with session.get(url) as response:
27
- RuntimeError: Event loop is closed
17
+ File "app.py", line 45, in <module>
18
+ main()
19
+ File "app.py", line 38, in main
20
+ result = process_data(data)
21
+ File "app.py", line 15, in process_data
22
+ total = sum(items)
23
+ TypeError: unsupported operand type(s) for +: 'int' and 'str'
28
24
  ```
29
25
 
30
- ### Investigation Steps
26
+ **분석**:
27
+ 1. **에러 위치**: `app.py:15` (`sum(items)`)
28
+ 2. **에러 타입**: `TypeError` — 정수와 문자열을 더하려고 시도
29
+ 3. **실행 경로**: `main()` → `process_data()` → `sum()`
30
+ 4. **근본 원인**: `items` 리스트에 문자열이 포함됨
31
31
 
32
- #### 1. Reproduce with Debugger
32
+ **디버깅 단계**:
33
33
  ```python
34
- # app.py
35
- import asyncio
36
- import debugpy
34
+ # 1. 브레이크포인트 설정
35
+ import pdb; pdb.set_trace()
37
36
 
38
- # Enable remote debugging
39
- debugpy.listen(5678)
40
- print("Waiting for debugger...")
41
- debugpy.wait_for_client()
37
+ # 2. items 내용 확인
38
+ (Pdb) print(items)
39
+ [1, 2, '3', 4, 5] # '3'이 문자열!
42
40
 
43
- async def fetch_data():
44
- # Set breakpoint here
45
- breakpoint()
46
- async with session.get(url) as response:
47
- return await response.json()
41
+ # 3. 타입 검증
42
+ (Pdb) [type(x) for x in items]
43
+ [<class 'int'>, <class 'int'>, <class 'str'>, <class 'int'>, <class 'int'>]
48
44
  ```
49
45
 
50
- #### 2. Run with Async Debugging
51
- ```bash
52
- # Terminal 1: Start app
53
- python app.py
54
-
55
- # Terminal 2: Connect VSCode debugger (Remote Attach config)
56
- # Step through async code
46
+ **해결 방법**:
47
+ ```python
48
+ # Option 1: 입력 데이터 검증
49
+ def process_data(items):
50
+ # 타입 체크 및 변환
51
+ items = [int(x) if isinstance(x, str) else x for x in items]
52
+ total = sum(items)
53
+ return total
54
+
55
+ # Option 2: 타입 힌트 + mypy
56
+ def process_data(items: list[int]) -> int:
57
+ total = sum(items)
58
+ return total
57
59
  ```
58
60
 
59
- #### 3. VSCode launch.json
60
- ```json
61
- {
62
- "version": "0.2.0",
63
- "configurations": [
64
- {
65
- "name": "Python: Async Debug",
66
- "type": "debugpy",
67
- "request": "attach",
68
- "connect": {
69
- "host": "localhost",
70
- "port": 5678
71
- },
72
- "justMyCode": false,
73
- "pathMappings": [
74
- {
75
- "localRoot": "${workspaceFolder}",
76
- "remoteRoot": "."
77
- }
78
- ]
79
- }
80
- ]
81
- }
82
- ```
61
+ ---
83
62
 
84
- #### 4. Inspect Async Context
85
- ```python
86
- # In debugger console
87
- import asyncio
88
- loop = asyncio.get_event_loop()
89
- print(f"Loop running: {loop.is_running()}")
90
- print(f"Loop closed: {loop.is_closed()}")
63
+ ### 예제 2: ImportError — 모듈 미설치
91
64
 
92
- # Check pending tasks
93
- tasks = asyncio.all_tasks(loop)
94
- print(f"Pending tasks: {len(tasks)}")
95
- for task in tasks:
96
- print(task)
65
+ **에러 메시지**:
66
+ ```
67
+ Traceback (most recent call last):
68
+ File "script.py", line 3, in <module>
69
+ import requests
70
+ ModuleNotFoundError: No module named 'requests'
97
71
  ```
98
72
 
99
- ### Root Cause
100
- Multiple event loops created; old loop closed while tasks still pending.
73
+ **분석**:
74
+ 1. **에러 위치**: `script.py:3`
75
+ 2. **에러 타입**: `ModuleNotFoundError` — requests 모듈이 설치되지 않음
76
+ 3. **근본 원인**: 가상환경 활성화 안 됨 또는 의존성 미설치
101
77
 
102
- ### Fix
103
- ```python
104
- # Before (problematic)
105
- def main():
106
- loop = asyncio.new_event_loop()
107
- asyncio.set_event_loop(loop)
108
- loop.run_until_complete(fetch_data())
109
- loop.close() # ❌ Closes loop prematurely
78
+ **디버깅 단계**:
79
+ ```bash
80
+ # 1. 가상환경 확인
81
+ which python
82
+ # /usr/bin/python (시스템 Python — 잘못됨!)
110
83
 
111
- # After (correct)
112
- async def main():
113
- await fetch_data()
84
+ # 2. 가상환경 활성화
85
+ source venv/bin/activate
86
+ which python
87
+ # /path/to/venv/bin/python (올바름)
114
88
 
115
- if __name__ == "__main__":
116
- asyncio.run(main()) # Proper lifecycle management
117
- ```
89
+ # 3. 패키지 설치 확인
90
+ pip list | grep requests
91
+ # (없음)
118
92
 
119
- ### Test Case
120
- ```python
121
- # tests/test_fetch_data.py
122
- import pytest
123
- import asyncio
93
+ # 4. 의존성 설치
94
+ pip install requests
95
+ ```
124
96
 
125
- @pytest.mark.asyncio
126
- async def test_fetch_data_no_event_loop_error():
127
- """Ensure fetch_data doesn't close event loop prematurely."""
128
- result = await fetch_data()
129
- assert result is not None
97
+ **해결 방법**:
98
+ ```bash
99
+ # pyproject.toml 또는 requirements.txt에 의존성 명시
100
+ # requirements.txt
101
+ requests==2.31.0
130
102
 
131
- # Verify loop still running
132
- loop = asyncio.get_event_loop()
133
- assert not loop.is_closed()
103
+ # 설치
104
+ pip install -r requirements.txt
134
105
  ```
135
106
 
136
107
  ---
137
108
 
138
- ## Goroutine Leak Investigation (Go)
139
-
140
- ### Problem
141
- Go service memory usage growing indefinitely over time.
109
+ ### 예제 3: AttributeError — 속성 없음
142
110
 
143
- ### Stack Trace
111
+ **에러 메시지**:
144
112
  ```
145
- goroutine 1543 [chan receive]:
146
- main.processMessages()
147
- /app/worker.go:42 +0x120
148
- created by main.startWorker
149
- /app/worker.go:25 +0x80
150
-
151
- goroutine 1544 [chan receive]:
152
- main.processMessages()
153
- /app/worker.go:42 +0x120
154
- created by main.startWorker
155
- /app/worker.go:25 +0x80
156
- ... (1542 more goroutines)
113
+ Traceback (most recent call last):
114
+ File "app.py", line 28, in <module>
115
+ result = user.get_profile()
116
+ AttributeError: 'NoneType' object has no attribute 'get_profile'
157
117
  ```
158
118
 
159
- ### Investigation Steps
119
+ **분석**:
120
+ 1. **에러 위치**: `app.py:28`
121
+ 2. **에러 타입**: `AttributeError` — `user`가 `None`임
122
+ 3. **근본 원인**: `user` 객체가 생성되지 않았거나 None 반환
160
123
 
161
- #### 1. Enable Goroutine Profiling
162
- ```go
163
- // main.go
164
- import (
165
- "net/http"
166
- _ "net/http/pprof"
167
- )
168
-
169
- func main() {
170
- // Enable pprof
171
- go func() {
172
- log.Println(http.ListenAndServe("localhost:6060", nil))
173
- }()
124
+ **디버깅 단계**:
125
+ ```python
126
+ # 1. 브레이크포인트 설정
127
+ breakpoint()
128
+
129
+ # 2. user 확인
130
+ (Pdb) print(user)
131
+ None
132
+
133
+ # 3. user가 None이 된 이유 추적
134
+ (Pdb) where
135
+ app.py(20)main()
136
+ app.py(15)get_user()
137
+ -> return None # 여기서 None 반환!
138
+
139
+ # 4. get_user() 함수 확인
140
+ def get_user(user_id):
141
+ user = database.find_user(user_id)
142
+ if not user:
143
+ return None # 문제 발견!
144
+ return user
145
+ ```
174
146
 
175
- // ... rest of application
176
- }
147
+ **해결 방법**:
148
+ ```python
149
+ # Option 1: None 체크
150
+ user = get_user(user_id)
151
+ if user is None:
152
+ print("User not found")
153
+ return
154
+ result = user.get_profile()
155
+
156
+ # Option 2: Optional 타입 힌트
157
+ from typing import Optional
158
+
159
+ def get_user(user_id: int) -> Optional[User]:
160
+ user = database.find_user(user_id)
161
+ return user
162
+
163
+ # Option 3: 예외 처리
164
+ try:
165
+ result = user.get_profile()
166
+ except AttributeError:
167
+ print("User is None or has no get_profile method")
177
168
  ```
178
169
 
179
- #### 2. Capture Goroutine Dump
180
- ```bash
181
- # Get goroutine count
182
- curl http://localhost:6060/debug/pprof/goroutine?debug=1 > goroutines.txt
170
+ ---
183
171
 
184
- # Analyze goroutines
185
- go tool pprof http://localhost:6060/debug/pprof/goroutine
186
- (pprof) top
187
- (pprof) list processMessages
188
- ```
172
+ ## TypeScript 디버깅 예제
189
173
 
190
- #### 3. Debug with Delve
191
- ```bash
192
- # Attach to running process
193
- dlv attach $(pgrep myapp)
174
+ ### 예제 1: undefined 접근
194
175
 
195
- (dlv) goroutines
196
- Goroutine 1 - User: /app/main.go:15 main.main (0x10a4b20)
197
- Goroutine 2 - User: /app/worker.go:42 main.processMessages (0x10a5c30)
198
- ... (1542 more)
199
-
200
- (dlv) goroutine 2 bt
201
- 0 0x000000000043e3e5 in runtime.gopark
202
- at /usr/local/go/src/runtime/proc.go:363
203
- 1 0x000000000040b5b6 in runtime.chanrecv
204
- at /usr/local/go/src/runtime/chan.go:583
205
- 2 0x00000000010a5c30 in main.processMessages
206
- at /app/worker.go:42
207
- ```
208
-
209
- #### 4. VSCode launch.json
210
- ```json
211
- {
212
- "version": "0.2.0",
213
- "configurations": [
214
- {
215
- "name": "Debug with Goroutine Inspection",
216
- "type": "go",
217
- "request": "launch",
218
- "mode": "debug",
219
- "program": "${workspaceFolder}",
220
- "showLog": true,
221
- "logOutput": "debugger",
222
- "dlvToolPath": "/usr/local/bin/dlv"
223
- },
224
- {
225
- "name": "Attach to Process",
226
- "type": "go",
227
- "request": "attach",
228
- "mode": "local",
229
- "processId": "${command:pickProcess}"
230
- }
231
- ]
232
- }
176
+ **에러 메시지**:
177
+ ```
178
+ TypeError: Cannot read properties of undefined (reading 'name')
179
+ at processUser (app.ts:42:28)
180
+ at Array.map (<anonymous>)
181
+ at getUserNames (app.ts:35:18)
182
+ at main (app.ts:10:5)
233
183
  ```
234
184
 
235
- ### Root Cause
236
- Worker goroutines waiting on channel that never gets closed when context cancelled.
185
+ **분석**:
186
+ 1. **에러 위치**: `app.ts:42` (`user.name` 접근)
187
+ 2. **에러 타입**: `TypeError` — `user`가 `undefined`
188
+ 3. **실행 경로**: `main()` → `getUserNames()` → `map()` → `processUser()`
189
+ 4. **근본 원인**: 배열에 `undefined` 요소가 포함됨
237
190
 
238
- ```go
239
- // Before (leaking)
240
- func startWorker(ctx context.Context) {
241
- msgChan := make(chan Message)
242
- go func() {
243
- for msg := range msgChan { // ❌ Never exits if channel not closed
244
- processMessage(msg)
245
- }
246
- }()
247
- // ... no channel close on ctx.Done()
191
+ **코드**:
192
+ ```typescript
193
+ // app.ts
194
+ function processUser(user: User) {
195
+ return user.name.toUpperCase(); // 여기서 에러!
248
196
  }
249
197
 
250
- // After (fixed)
251
- func startWorker(ctx context.Context) {
252
- msgChan := make(chan Message)
253
- go func() {
254
- defer close(msgChan)
255
- for {
256
- select {
257
- case msg := <-msgChan:
258
- processMessage(msg)
259
- case <-ctx.Done():
260
- return // ✅ Proper cleanup
261
- }
262
- }
263
- }()
198
+ function getUserNames(users: User[]): string[] {
199
+ return users.map(processUser);
264
200
  }
201
+
202
+ const users = [
203
+ { id: 1, name: 'Alice' },
204
+ undefined, // 문제 발견!
205
+ { id: 2, name: 'Bob' },
206
+ ];
265
207
  ```
266
208
 
267
- ### Test Case
268
- ```go
269
- // worker_test.go
270
- func TestNoGoroutineLeak(t *testing.T) {
271
- initialCount := runtime.NumGoroutine()
209
+ **디버깅 단계**:
210
+ ```typescript
211
+ // 1. 브레이크포인트 설정 (debugger 키워드)
212
+ function processUser(user: User) {
213
+ debugger; // 여기서 중단
214
+ return user.name.toUpperCase();
215
+ }
272
216
 
273
- ctx, cancel := context.WithCancel(context.Background())
274
- startWorker(ctx)
217
+ // Chrome DevTools에서:
218
+ // user: undefined
219
+ ```
275
220
 
276
- time.Sleep(100 * time.Millisecond)
277
- cancel()
278
- time.Sleep(100 * time.Millisecond)
221
+ **해결 방법**:
222
+ ```typescript
223
+ // Option 1: 타입 가드
224
+ function processUser(user: User | undefined): string {
225
+ if (!user) {
226
+ return 'Unknown';
227
+ }
228
+ return user.name.toUpperCase();
229
+ }
230
+
231
+ // Option 2: Optional 체이닝
232
+ function processUser(user?: User): string {
233
+ return user?.name?.toUpperCase() ?? 'Unknown';
234
+ }
279
235
 
280
- finalCount := runtime.NumGoroutine()
281
- assert.Equal(t, initialCount, finalCount, "Goroutine leak detected")
236
+ // Option 3: 필터링
237
+ function getUserNames(users: (User | undefined)[]): string[] {
238
+ return users
239
+ .filter((user): user is User => user !== undefined)
240
+ .map(user => user.name.toUpperCase());
282
241
  }
283
242
  ```
284
243
 
285
244
  ---
286
245
 
287
- ## Distributed Tracing with OpenTelemetry (Multi-service)
288
-
289
- ### Problem
290
- Request slow across microservices; need to identify bottleneck.
246
+ ### 예제 2: Promise rejection
291
247
 
292
- ### Architecture
248
+ **에러 메시지**:
293
249
  ```
294
- User API Gateway → Auth Service → User Service → Database
295
- Product Service → Cache
250
+ UnhandledPromiseRejectionWarning: Error: Network request failed
251
+ at fetchData (api.ts:15:11)
252
+ at async processRequest (handler.ts:28:18)
253
+ at async main (app.ts:12:3)
296
254
  ```
297
255
 
298
- ### Investigation Steps
299
-
300
- #### 1. Instrument Services with OpenTelemetry
301
-
302
- **API Gateway (Python/FastAPI)**
303
- ```python
304
- # gateway/main.py
305
- from opentelemetry import trace
306
- from opentelemetry.sdk.trace import TracerProvider
307
- from opentelemetry.sdk.trace.export import BatchSpanProcessor
308
- from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
309
- from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
310
-
311
- # Setup tracing
312
- provider = TracerProvider()
313
- processor = BatchSpanProcessor(OTLPSpanExporter(endpoint="http://jaeger:4317"))
314
- provider.add_span_processor(processor)
315
- trace.set_tracer_provider(provider)
316
-
317
- app = FastAPI()
318
- FastAPIInstrumentor.instrument_app(app)
319
-
320
- @app.get("/users/{user_id}")
321
- async def get_user(user_id: int):
322
- tracer = trace.get_tracer(__name__)
323
-
324
- with tracer.start_as_current_span("gateway.get_user") as span:
325
- span.set_attribute("user.id", user_id)
256
+ **분석**:
257
+ 1. **에러 위치**: `api.ts:15`
258
+ 2. **에러 타입**: `UnhandledPromiseRejectionWarning` — Promise 거부가 처리되지 않음
259
+ 3. **근본 원인**: `fetchData()`에서 발생한 에러가 catch되지 않음
326
260
 
327
- # Call auth service
328
- with tracer.start_as_current_span("gateway.verify_auth"):
329
- auth_result = await verify_auth(user_id)
330
-
331
- # Call user service
332
- with tracer.start_as_current_span("gateway.fetch_user_data"):
333
- user_data = await fetch_user_data(user_id)
261
+ **코드**:
262
+ ```typescript
263
+ // api.ts
264
+ async function fetchData(url: string): Promise<Data> {
265
+ const response = await fetch(url);
266
+ if (!response.ok) {
267
+ throw new Error('Network request failed'); // 여기서 에러 발생!
268
+ }
269
+ return response.json();
270
+ }
334
271
 
335
- return user_data
272
+ // handler.ts
273
+ async function processRequest(url: string) {
274
+ const data = await fetchData(url); // 에러 처리 없음!
275
+ return data;
276
+ }
336
277
  ```
337
278
 
338
- **User Service (Go)**
339
- ```go
340
- // user-service/main.go
341
- import (
342
- "go.opentelemetry.io/otel"
343
- "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
344
- "go.opentelemetry.io/otel/sdk/trace"
345
- )
346
-
347
- func initTracing() {
348
- exporter, _ := otlptracegrpc.New(
349
- context.Background(),
350
- otlptracegrpc.WithEndpoint("jaeger:4317"),
351
- otlptracegrpc.WithInsecure(),
352
- )
353
-
354
- tp := trace.NewTracerProvider(
355
- trace.WithBatcher(exporter),
356
- )
357
- otel.SetTracerProvider(tp)
279
+ **디버깅 단계**:
280
+ ```typescript
281
+ // 1. 브레이크포인트 설정
282
+ async function fetchData(url: string): Promise<Data> {
283
+ debugger;
284
+ const response = await fetch(url);
285
+ debugger; // response 확인
286
+ // response.ok: false
287
+ // response.status: 404
288
+ if (!response.ok) {
289
+ throw new Error('Network request failed');
290
+ }
291
+ return response.json();
358
292
  }
293
+ ```
359
294
 
360
- func GetUser(w http.ResponseWriter, r *http.Request) {
361
- ctx := r.Context()
362
- tracer := otel.Tracer("user-service")
363
-
364
- ctx, span := tracer.Start(ctx, "user-service.get_user")
365
- defer span.End()
366
-
367
- userID := chi.URLParam(r, "userID")
368
- span.SetAttributes(attribute.String("user.id", userID))
295
+ **해결 방법**:
296
+ ```typescript
297
+ // Option 1: try-catch
298
+ async function processRequest(url: string): Promise<Data | null> {
299
+ try {
300
+ const data = await fetchData(url);
301
+ return data;
302
+ } catch (error) {
303
+ console.error('Failed to fetch data:', error);
304
+ return null;
305
+ }
306
+ }
369
307
 
370
- // Database query with tracing
371
- ctx, dbSpan := tracer.Start(ctx, "user-service.db_query")
372
- user, err := db.GetUser(ctx, userID)
373
- dbSpan.End()
308
+ // Option 2: Result 타입
309
+ type Result<T> = { success: true; data: T } | { success: false; error: Error };
374
310
 
375
- if err != nil {
376
- span.RecordError(err)
377
- http.Error(w, "User not found", 404)
378
- return
311
+ async function fetchData(url: string): Promise<Result<Data>> {
312
+ try {
313
+ const response = await fetch(url);
314
+ if (!response.ok) {
315
+ return { success: false, error: new Error('Network request failed') };
379
316
  }
380
-
381
- json.NewEncoder(w).Render(user)
317
+ const data = await response.json();
318
+ return { success: true, data };
319
+ } catch (error) {
320
+ return { success: false, error: error as Error };
321
+ }
382
322
  }
383
323
  ```
384
324
 
385
- #### 2. Deploy Jaeger for Trace Collection
386
- ```yaml
387
- # docker-compose.yml
388
- version: '3.8'
389
- services:
390
- jaeger:
391
- image: jaegertracing/all-in-one:1.50
392
- ports:
393
- - "16686:16686" # Jaeger UI
394
- - "4317:4317" # OTLP gRPC
395
- - "4318:4318" # OTLP HTTP
396
- environment:
397
- - COLLECTOR_OTLP_ENABLED=true
398
- ```
325
+ ---
399
326
 
400
- #### 3. Generate Load and Capture Traces
401
- ```bash
402
- # Start services
403
- docker-compose up -d
327
+ ## Java 디버깅 예제
404
328
 
405
- # Generate test traffic
406
- for i in {1..100}; do
407
- curl http://localhost:8000/users/123
408
- sleep 0.1
409
- done
329
+ ### 예제 1: NullPointerException
410
330
 
411
- # Open Jaeger UI
412
- open http://localhost:16686
331
+ **에러 메시지**:
413
332
  ```
414
-
415
- #### 4. Analyze Traces in Jaeger UI
416
- 1. Navigate to Jaeger UI
417
- 2. Select service: `api-gateway`
418
- 3. Find slow traces (> 500ms)
419
- 4. Click trace to see waterfall view
420
- 5. Identify bottleneck span
421
-
422
- **Example Trace Timeline**
333
+ Exception in thread "main" java.lang.NullPointerException: Cannot invoke "User.getName()" because "user" is null
334
+ at com.example.UserService.processUser(UserService.java:42)
335
+ at com.example.UserService.processAllUsers(UserService.java:28)
336
+ at com.example.Main.main(Main.java:15)
423
337
  ```
424
- Total: 1,245ms
425
- ├─ gateway.get_user: 1,245ms
426
- ├─ gateway.verify_auth: 45ms
427
- │ └─ auth-service.verify_token: 42ms
428
- │ └─ redis.get: 15ms
429
- ├─ gateway.fetch_user_data: 1,180ms ← BOTTLENECK
430
- └─ user-service.get_user: 1,175ms
431
- └─ user-service.db_query: 1,165ms ← ROOT CAUSE
432
- └─ postgres.query: 1,160ms
338
+
339
+ **분석**:
340
+ 1. **에러 위치**: `UserService.java:42` (`user.getName()` 호출)
341
+ 2. **에러 타입**: `NullPointerException` — `user`가 `null`
342
+ 3. **실행 경로**: `Main.main()` → `processAllUsers()` → `processUser()`
343
+ 4. **근본 원인**: `user` 객체가 `null`인 채로 메서드 호출 시도
344
+
345
+ **코드**:
346
+ ```java
347
+ // UserService.java
348
+ public class UserService {
349
+ public void processUser(User user) {
350
+ String name = user.getName(); // 여기서 NPE 발생!
351
+ System.out.println("Processing: " + name);
352
+ }
353
+
354
+ public void processAllUsers(List<User> users) {
355
+ for (User user : users) {
356
+ processUser(user);
357
+ }
358
+ }
359
+ }
433
360
  ```
434
361
 
435
- ### Root Cause
436
- Database query missing index on `users.id`.
362
+ **디버깅 단계**:
363
+ ```java
364
+ // 1. 브레이크포인트 설정 (IntelliJ/Eclipse)
365
+ // UserService.java:42에 브레이크포인트
437
366
 
438
- ### Fix
439
- ```sql
440
- -- Add missing index
441
- CREATE INDEX idx_users_id ON users(id);
367
+ // 2. 변수 확인
368
+ // user: null
369
+
370
+ // 3. 호출 스택 확인
371
+ // processUser() ← processAllUsers() ← main()
442
372
 
443
- -- Verify with EXPLAIN
444
- EXPLAIN ANALYZE SELECT * FROM users WHERE id = 123;
445
- -- Before: Seq Scan on users (cost=0.00..1245.00 rows=1 width=100) (actual time=1160.234..1160.235 rows=1 loops=1)
446
- -- After: Index Scan using idx_users_id on users (cost=0.42..8.44 rows=1 width=100) (actual time=0.023..0.024 rows=1 loops=1)
373
+ // 4. users 리스트 확인
374
+ // users: [User@123, null, User@456] // null 발견!
447
375
  ```
448
376
 
449
- ### Test Case
450
- ```python
451
- # tests/test_performance.py
452
- import pytest
453
- from opentelemetry import trace
377
+ **해결 방법**:
378
+ ```java
379
+ // Option 1: Null 체크
380
+ public void processUser(User user) {
381
+ if (user == null) {
382
+ System.out.println("User is null");
383
+ return;
384
+ }
385
+ String name = user.getName();
386
+ System.out.println("Processing: " + name);
387
+ }
454
388
 
455
- @pytest.mark.asyncio
456
- async def test_get_user_performance():
457
- """Ensure /users/{id} responds within 100ms."""
458
- tracer = trace.get_tracer(__name__)
389
+ // Option 2: Optional<T> 사용 (Java 8+)
390
+ public void processUser(Optional<User> userOpt) {
391
+ userOpt.ifPresent(user -> {
392
+ String name = user.getName();
393
+ System.out.println("Processing: " + name);
394
+ });
395
+ }
459
396
 
460
- with tracer.start_as_current_span("test.get_user_performance") as span:
461
- start = time.time()
462
- response = await client.get("/users/123")
463
- duration = time.time() - start
397
+ public void processAllUsers(List<User> users) {
398
+ users.stream()
399
+ .filter(Objects::nonNull) // null 필터링
400
+ .forEach(this::processUser);
401
+ }
464
402
 
465
- span.set_attribute("response.duration_ms", duration * 1000)
403
+ // Option 3: @NonNull 어노테이션 (Lombok, Checker Framework)
404
+ import lombok.NonNull;
466
405
 
467
- assert response.status_code == 200
468
- assert duration < 0.1, f"Request took {duration}s, expected < 0.1s"
406
+ public void processUser(@NonNull User user) {
407
+ String name = user.getName();
408
+ System.out.println("Processing: " + name);
409
+ }
469
410
  ```
470
411
 
471
412
  ---
472
413
 
473
- ## Kubernetes Pod Crash Debugging
474
-
475
- ### Problem
476
- Pod enters `CrashLoopBackOff` state with OOMKilled status.
477
-
478
- ### Symptoms
479
- ```bash
480
- kubectl get pods
481
- NAME READY STATUS RESTARTS AGE
482
- myapp-7d4f8c9b5-xyz 0/1 CrashLoopBackOff 5 10m
414
+ ### 예제 2: ClassNotFoundException
483
415
 
484
- kubectl describe pod myapp-7d4f8c9b5-xyz
485
- ...
486
- Last State: Terminated
487
- Reason: OOMKilled
488
- Exit Code: 137
416
+ **에러 메시지**:
417
+ ```
418
+ Exception in thread "main" java.lang.ClassNotFoundException: com.example.database.DatabaseDriver
419
+ at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:445)
420
+ at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:587)
421
+ at java.base/java.lang.Class.forName0(Native Method)
422
+ at java.base/java.lang.Class.forName(Class.java:467)
423
+ at com.example.Main.main(Main.java:12)
489
424
  ```
490
425
 
491
- ### Investigation Steps
426
+ **분석**:
427
+ 1. **에러 위치**: `Main.java:12` (`Class.forName()` 호출)
428
+ 2. **에러 타입**: `ClassNotFoundException` — 클래스를 찾을 수 없음
429
+ 3. **근본 원인**: JDBC 드라이버 JAR이 classpath에 없음
492
430
 
493
- #### 1. Check Logs (Current and Previous)
431
+ **디버깅 단계**:
494
432
  ```bash
495
- # Current logs
496
- kubectl logs myapp-7d4f8c9b5-xyz
433
+ # 1. Classpath 확인
434
+ echo $CLASSPATH
497
435
 
498
- # Logs before crash
499
- kubectl logs myapp-7d4f8c9b5-xyz --previous
436
+ # 2. JAR 파일 확인
437
+ ls lib/
438
+ # mysql-connector-java-8.0.33.jar (있음)
500
439
 
501
- # Output:
502
- [INFO] Application starting...
503
- [INFO] Loading dataset (1M records)...
504
- [WARNING] Memory usage: 450MB
505
- [WARNING] Memory usage: 750MB
506
- [ERROR] Out of memory
440
+ # 3. 컴파일 및 실행 명령 확인
441
+ javac -cp ".:lib/*" Main.java
442
+ java -cp ".:lib/*" Main # classpath에 lib/* 포함 필요!
507
443
  ```
508
444
 
509
- #### 2. Inspect Resource Limits
445
+ **해결 방법**:
510
446
  ```bash
511
- kubectl get pod myapp-7d4f8c9b5-xyz -o yaml | grep -A 10 resources
512
- resources:
513
- limits:
514
- memory: 512Mi # Too low
515
- requests:
516
- memory: 256Mi
447
+ # Option 1: Classpath 명시
448
+ java -cp ".:lib/*" com.example.Main
449
+
450
+ # Option 2: Maven/Gradle 사용
451
+ # pom.xml (Maven)
452
+ <dependency>
453
+ <groupId>mysql</groupId>
454
+ <artifactId>mysql-connector-java</artifactId>
455
+ <version>8.0.33</version>
456
+ </dependency>
457
+
458
+ # build.gradle (Gradle)
459
+ dependencies {
460
+ implementation 'mysql:mysql-connector-java:8.0.33'
461
+ }
462
+
463
+ # Option 3: Manifest에 Class-Path 추가
464
+ # MANIFEST.MF
465
+ Class-Path: lib/mysql-connector-java-8.0.33.jar
517
466
  ```
518
467
 
519
- #### 3. Debug with Ephemeral Container
520
- ```bash
521
- # Add debug container to running pod
522
- kubectl debug -it myapp-7d4f8c9b5-xyz --image=ubuntu --target=myapp
468
+ ---
523
469
 
524
- # In debug container
525
- apt-get update && apt-get install -y htop
526
- htop
470
+ ## Go 디버깅 예제
527
471
 
528
- # Check memory usage patterns
529
- cat /proc/meminfo
530
- free -h
472
+ ### 예제 1: nil pointer dereference
473
+
474
+ **에러 메시지**:
531
475
  ```
476
+ panic: runtime error: invalid memory address or nil pointer dereference
477
+ [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x10a4f20]
532
478
 
533
- #### 4. Profile Memory Usage
534
- ```python
535
- # Add memory profiling to application
536
- from memory_profiler import profile
479
+ goroutine 1 [running]:
480
+ main.processUser(...)
481
+ /Users/dev/project/main.go:42
482
+ main.main()
483
+ /Users/dev/project/main.go:15 +0x120
484
+ ```
537
485
 
538
- @profile
539
- def load_dataset():
540
- # This function is consuming too much memory
541
- data = [process_record(r) for r in fetch_records()] # ❌ Loads all into memory
542
- return data
486
+ **분석**:
487
+ 1. **에러 위치**: `main.go:42` (`processUser` 함수)
488
+ 2. **에러 타입**: `panic: nil pointer dereference`
489
+ 3. **근본 원인**: `nil` 포인터에 접근 시도
490
+
491
+ **코드**:
492
+ ```go
493
+ // main.go
494
+ type User struct {
495
+ Name string
496
+ Age int
497
+ }
498
+
499
+ func processUser(user *User) {
500
+ fmt.Printf("Name: %s\n", user.Name) // 여기서 panic!
501
+ }
502
+
503
+ func main() {
504
+ var user *User // nil 포인터
505
+ processUser(user)
506
+ }
543
507
  ```
544
508
 
509
+ **디버깅 단계**:
545
510
  ```bash
546
- # Run with memory profiler
547
- python -m memory_profiler app.py
511
+ # 1. Delve로 디버깅
512
+ dlv debug main.go
513
+ (dlv) break main.go:42
514
+ (dlv) continue
548
515
 
549
- # Output:
550
- Line # Mem usage Increment Line Contents
551
- ================================================
552
- 3 125.2 MiB 0.0 MiB @profile
553
- 4 def load_dataset():
554
- 5 875.4 MiB 750.2 MiB data = [process_record(r) for r in fetch_records()]
555
- 6 875.4 MiB 0.0 MiB return data
516
+ # 2. 변수 확인
517
+ (dlv) print user
518
+ nil
519
+
520
+ # 3. 호출 스택 확인
521
+ (dlv) stack
522
+ 0 0x00000000010a4f20 in main.processUser
523
+ at main.go:42
524
+ 1 0x00000000010a5040 in main.main
525
+ at main.go:15
556
526
  ```
557
527
 
558
- ### Root Cause
559
- Loading entire dataset into memory at once; exceeds pod memory limit.
528
+ **해결 방법**:
529
+ ```go
530
+ // Option 1: Nil 체크
531
+ func processUser(user *User) {
532
+ if user == nil {
533
+ fmt.Println("User is nil")
534
+ return
535
+ }
536
+ fmt.Printf("Name: %s\n", user.Name)
537
+ }
560
538
 
561
- ### Fix
562
- ```python
563
- # Before (memory-intensive)
564
- def load_dataset():
565
- data = [process_record(r) for r in fetch_records()] # ❌ 750MB
566
- return data
539
+ // Option 2: 값 타입 사용
540
+ func processUser(user User) { // 포인터 아님
541
+ fmt.Printf("Name: %s\n", user.Name)
542
+ }
567
543
 
568
- # After (streaming)
569
- def load_dataset():
570
- for record in fetch_records(): # ✅ Process one at a time
571
- yield process_record(record)
544
+ // Option 3: 생성자 패턴
545
+ func NewUser(name string, age int) *User {
546
+ return &User{Name: name, Age: age}
547
+ }
548
+
549
+ func main() {
550
+ user := NewUser("Alice", 30) // 항상 non-nil
551
+ processUser(user)
552
+ }
572
553
  ```
573
554
 
574
- **Update Kubernetes Deployment**
575
- ```yaml
576
- # deployment.yaml
577
- apiVersion: apps/v1
578
- kind: Deployment
579
- metadata:
580
- name: myapp
581
- spec:
582
- template:
583
- spec:
584
- containers:
585
- - name: myapp
586
- resources:
587
- limits:
588
- memory: 1Gi # ✅ Increased limit
589
- requests:
590
- memory: 512Mi
591
- ```
592
-
593
- ### Test Case
594
- ```python
595
- # tests/test_memory.py
596
- import tracemalloc
555
+ ---
597
556
 
598
- def test_load_dataset_memory_efficient():
599
- """Ensure load_dataset uses < 100MB memory."""
600
- tracemalloc.start()
557
+ ### 예제 2: Goroutine leak
601
558
 
602
- list(load_dataset()) # Consume generator
559
+ **문제 설명**: 고루틴이 종료되지 않고 계속 실행되어 메모리 누수 발생
603
560
 
604
- current, peak = tracemalloc.get_traced_memory()
605
- tracemalloc.stop()
561
+ **코드**:
562
+ ```go
563
+ // main.go
564
+ func worker(ch chan int) {
565
+ for {
566
+ val := <-ch // 채널이 닫히지 않으면 영원히 대기
567
+ fmt.Println(val)
568
+ }
569
+ }
606
570
 
607
- assert peak / 1024 / 1024 < 100, f"Peak memory {peak/1024/1024}MB exceeds 100MB"
571
+ func main() {
572
+ ch := make(chan int)
573
+ go worker(ch)
574
+
575
+ ch <- 1
576
+ ch <- 2
577
+ // ch를 닫지 않고 종료 → goroutine leak!
578
+ }
608
579
  ```
609
580
 
610
- ---
581
+ **디버깅 단계**:
582
+ ```bash
583
+ # 1. pprof로 고루틴 확인
584
+ go tool pprof http://localhost:6060/debug/pprof/goroutine
611
585
 
612
- ## Memory Leak Diagnosis (Rust)
586
+ # 2. 고루틴 확인
587
+ (pprof) top
588
+ Showing nodes accounting for 1000 goroutines
589
+ flat flat% sum% cum cum%
590
+ 1000 100% 100% 1000 100% main.worker
613
591
 
614
- ### Problem
615
- Long-running Rust service memory usage increasing over time.
592
+ # 3. Delve로 고루틴 확인
593
+ dlv debug main.go
594
+ (dlv) goroutines
595
+ [1000 goroutines]
616
596
 
617
- ### Stack Trace
618
- ```rust
619
- thread 'main' panicked at 'allocation error: Cannot allocate memory', src/main.rs:142:23
597
+ (dlv) goroutine 5
598
+ Goroutine 5 - User: main.worker
599
+ main.go:10 (0x10a4f20) (Waiting)
620
600
  ```
621
601
 
622
- ### Investigation Steps
623
-
624
- #### 1. Enable Memory Profiling with Valgrind
625
- ```bash
626
- # Build with debug symbols
627
- cargo build --release
602
+ **해결 방법**:
603
+ ```go
604
+ // Option 1: 채널 닫기
605
+ func main() {
606
+ ch := make(chan int)
607
+ go worker(ch)
608
+
609
+ ch <- 1
610
+ ch <- 2
611
+ close(ch) // 채널 닫기
612
+ time.Sleep(time.Second) // worker가 종료될 시간
613
+ }
628
614
 
629
- # Run with Valgrind
630
- valgrind --leak-check=full --show-leak-kinds=all ./target/release/myapp
615
+ func worker(ch chan int) {
616
+ for val := range ch { // 채널이 닫히면 종료
617
+ fmt.Println(val)
618
+ }
619
+ }
631
620
 
632
- # Output:
633
- HEAP SUMMARY:
634
- in use at exit: 1,048,576 bytes in 1,024 blocks
635
- total heap usage: 5,120 allocs, 4,096 frees, 52,428,800 bytes allocated
621
+ // Option 2: Context 사용
622
+ func worker(ctx context.Context, ch chan int) {
623
+ for {
624
+ select {
625
+ case val := <-ch:
626
+ fmt.Println(val)
627
+ case <-ctx.Done():
628
+ return // Context 취소 시 종료
629
+ }
630
+ }
631
+ }
636
632
 
637
- LEAK SUMMARY:
638
- definitely lost: 1,048,576 bytes in 1,024 blocks
633
+ func main() {
634
+ ctx, cancel := context.WithCancel(context.Background())
635
+ defer cancel()
636
+
637
+ ch := make(chan int)
638
+ go worker(ctx, ch)
639
+
640
+ ch <- 1
641
+ ch <- 2
642
+ cancel() // 고루틴 종료
643
+ time.Sleep(time.Second)
644
+ }
639
645
  ```
640
646
 
641
- #### 2. Use Rust-specific Tools
642
- ```bash
643
- # Install cargo-flamegraph
644
- cargo install flamegraph
647
+ ---
645
648
 
646
- # Generate flamegraph
647
- cargo flamegraph --bin myapp
649
+ ## Rust 디버깅 예제
648
650
 
649
- # Opens flamegraph.svg showing allocation hotspots
651
+ ### 예제 1: Borrow checker 에러
652
+
653
+ **에러 메시지**:
654
+ ```
655
+ error[E0502]: cannot borrow `data` as mutable because it is also borrowed as immutable
656
+ --> src/main.rs:8:5
657
+ |
658
+ 6 | let first = &data[0];
659
+ | -------- immutable borrow occurs here
660
+ 7 |
661
+ 8 | data.push(4);
662
+ | ^^^^^^^^^^^^ mutable borrow occurs here
663
+ 9 |
664
+ 10 | println!("First: {}", first);
665
+ | ----- immutable borrow later used here
650
666
  ```
651
667
 
652
- #### 3. Debug with rust-lldb
653
- ```bash
654
- cargo build
655
- rust-lldb target/debug/myapp
668
+ **분석**:
669
+ 1. **에러 위치**: `main.rs:8` (`data.push(4)`)
670
+ 2. **에러 타입**: Borrow checker 위반 — 불변 참조가 있는데 가변 참조 시도
671
+ 3. **근본 원인**: `first`가 `data`의 불변 참조를 보유한 상태에서 `data`를 변경하려 함
656
672
 
657
- (lldb) breakpoint set -n main
658
- (lldb) run
659
- (lldb) memory read --size 8 --format x --count 10 $rsp
673
+ **코드**:
674
+ ```rust
675
+ // main.rs
676
+ fn main() {
677
+ let mut data = vec![1, 2, 3];
678
+ let first = &data[0]; // 불변 참조
679
+
680
+ data.push(4); // 에러! 가변 참조 시도
681
+
682
+ println!("First: {}", first);
683
+ }
660
684
  ```
661
685
 
662
- #### 4. Inspect with AddressSanitizer
686
+ **디버깅 단계**:
663
687
  ```bash
664
- # Rebuild with sanitizer
665
- RUSTFLAGS="-Z sanitizer=address" cargo build --target x86_64-unknown-linux-gnu
666
-
667
- # Run
668
- ./target/x86_64-unknown-linux-gnu/debug/myapp
688
+ # 1. rust-analyzer로 에러 확인 (VSCode)
689
+ # 에러 메시지에 lifetime 정보 포함
669
690
 
670
- # Output shows leak locations
691
+ # 2. 컴파일러 설명 확인
692
+ cargo build --explain E0502
671
693
  ```
672
694
 
673
- ### Root Cause
674
- `Rc<RefCell<T>>` circular reference preventing drop.
675
-
695
+ **해결 방법**:
676
696
  ```rust
677
- // Before (memory leak)
678
- use std::rc::Rc;
679
- use std::cell::RefCell;
697
+ // Option 1: 참조 사용 범위 조정
698
+ fn main() {
699
+ let mut data = vec![1, 2, 3];
700
+ let first = data[0]; // 값 복사
701
+
702
+ data.push(4); // OK
703
+
704
+ println!("First: {}", first);
705
+ }
680
706
 
681
- struct Node {
682
- data: String,
683
- next: Option<Rc<RefCell<Node>>>,
707
+ // Option 2: 참조를 먼저 해제
708
+ fn main() {
709
+ let mut data = vec![1, 2, 3];
710
+ {
711
+ let first = &data[0];
712
+ println!("First: {}", first);
713
+ } // first가 여기서 드롭됨
714
+
715
+ data.push(4); // OK
684
716
  }
685
717
 
686
- fn create_cycle() {
687
- let node1 = Rc::new(RefCell::new(Node {
688
- data: "Node 1".to_string(),
689
- next: None,
690
- }));
718
+ // Option 3: Clone
719
+ fn main() {
720
+ let mut data = vec![1, 2, 3];
721
+ let first = data.get(0).cloned(); // Option<i32>
722
+
723
+ data.push(4); // OK
724
+
725
+ if let Some(first) = first {
726
+ println!("First: {}", first);
727
+ }
728
+ }
729
+ ```
691
730
 
692
- let node2 = Rc::new(RefCell::new(Node {
693
- data: "Node 2".to_string(),
694
- next: Some(Rc::clone(&node1)),
695
- }));
731
+ ---
696
732
 
697
- node1.borrow_mut().next = Some(Rc::clone(&node2)); // Cycle!
698
- } // node1 and node2 never dropped
733
+ ### 예제 2: Panic in thread
699
734
 
700
- // After (fixed with Weak)
701
- use std::rc::{Rc, Weak};
735
+ **에러 메시지**:
736
+ ```
737
+ thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 5', src/main.rs:5:23
738
+ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
739
+ ```
702
740
 
703
- struct Node {
704
- data: String,
705
- next: Option<Weak<RefCell<Node>>>, // Use Weak to break cycle
706
- }
741
+ **분석**:
742
+ 1. **에러 위치**: `main.rs:5` (인덱스 접근)
743
+ 2. **에러 타입**: `panic: index out of bounds`
744
+ 3. **근본 원인**: 벡터 범위를 벗어난 인덱스 접근
707
745
 
708
- fn create_no_cycle() {
709
- let node1 = Rc::new(RefCell::new(Node {
710
- data: "Node 1".to_string(),
711
- next: None,
712
- }));
746
+ **코드**:
747
+ ```rust
748
+ // main.rs
749
+ fn main() {
750
+ let data = vec![1, 2, 3];
751
+ let value = data[5]; // panic!
752
+ println!("Value: {}", value);
753
+ }
754
+ ```
713
755
 
714
- let node2 = Rc::new(RefCell::new(Node {
715
- data: "Node 2".to_string(),
716
- next: Some(Rc::downgrade(&node1)), // Weak reference
717
- }));
756
+ **디버깅 단계**:
757
+ ```bash
758
+ # 1. RUST_BACKTRACE로 전체 스택 트레이스 확인
759
+ RUST_BACKTRACE=1 cargo run
760
+ # 또는
761
+ RUST_BACKTRACE=full cargo run
718
762
 
719
- node1.borrow_mut().next = Some(Rc::downgrade(&node2));
720
- } // Properly cleaned up
763
+ # 2. rust-lldb로 디버깅
764
+ rust-lldb target/debug/myapp
765
+ (lldb) breakpoint set --file main.rs --line 5
766
+ (lldb) run
767
+ (lldb) frame variable
768
+ (Vec<i32>) data = vec![1, 2, 3]
769
+ (lldb) print data.len()
770
+ 3
721
771
  ```
722
772
 
723
- ### Test Case
773
+ **해결 방법**:
724
774
  ```rust
725
- // tests/memory_test.rs
726
- #[test]
727
- fn test_no_memory_leak() {
728
- let initial_allocs = ALLOCATOR.allocated();
775
+ // Option 1: get() 메서드 사용
776
+ fn main() {
777
+ let data = vec![1, 2, 3];
778
+ match data.get(5) {
779
+ Some(value) => println!("Value: {}", value),
780
+ None => println!("Index out of bounds"),
781
+ }
782
+ }
729
783
 
730
- {
731
- create_no_cycle();
732
- } // Scope ends, should free memory
784
+ // Option 2: 범위 체크
785
+ fn main() {
786
+ let data = vec![1, 2, 3];
787
+ let index = 5;
788
+
789
+ if index < data.len() {
790
+ let value = data[index];
791
+ println!("Value: {}", value);
792
+ } else {
793
+ println!("Index out of bounds");
794
+ }
795
+ }
733
796
 
734
- let final_allocs = ALLOCATOR.allocated();
735
- assert_eq!(initial_allocs, final_allocs, "Memory leak detected");
797
+ // Option 3: unwrap_or 사용
798
+ fn main() {
799
+ let data = vec![1, 2, 3];
800
+ let value = data.get(5).unwrap_or(&0); // 기본값 0
801
+ println!("Value: {}", value);
736
802
  }
737
803
  ```
738
804
 
739
805
  ---
740
806
 
741
- ## Race Condition Detection (Go)
807
+ ## 컨테이너 디버깅 시나리오
742
808
 
743
- ### Problem
744
- Intermittent test failures; data corruption in concurrent writes.
809
+ ### 시나리오 1: 컨테이너가 즉시 종료됨
745
810
 
746
- ### Symptoms
747
- ```
748
- panic: runtime error: invalid memory address or nil pointer dereference
749
- [signal SIGSEGV: segmentation violation]
811
+ **문제**:
812
+ ```bash
813
+ $ docker ps -a
814
+ CONTAINER ID IMAGE STATUS
815
+ abc123 myapp Exited (1) 2 seconds ago
750
816
  ```
751
817
 
752
- ### Investigation Steps
753
-
754
- #### 1. Enable Race Detector
818
+ **디버깅 단계**:
755
819
  ```bash
756
- # Run tests with race detector
757
- go test -race ./...
820
+ # 1. 로그 확인
821
+ docker logs abc123
822
+ # Error: Database connection failed
758
823
 
759
- # Output:
760
- ==================
761
- WARNING: DATA RACE
762
- Write at 0x00c0001a0180 by goroutine 7:
763
- main.updateCounter()
764
- /app/counter.go:23 +0x45
824
+ # 2. 컨테이너 재시작하지 않고 셸 접속
825
+ docker run --rm -it --entrypoint /bin/sh myapp
765
826
 
766
- Previous read at 0x00c0001a0180 by goroutine 6:
767
- main.getCounter()
768
- /app/counter.go:15 +0x38
827
+ # 3. 환경 변수 확인
828
+ env | grep DB
829
+ # DB_HOST=localhost # 문제 발견! 컨테이너 내에서는 localhost가 아님
769
830
 
770
- Goroutine 7 (running) created at:
771
- main.main()
772
- /app/main.go:42 +0x120
773
- ==================
831
+ # 4. 네트워크 확인
832
+ ping db-host
833
+ # ping: db-host: Name or service not known
774
834
  ```
775
835
 
776
- #### 2. Debug with Delve + Race Detector
836
+ **해결 방법**:
777
837
  ```bash
778
- # Build with race detection
779
- go build -race -o myapp
780
-
781
- # Debug
782
- dlv exec ./myapp
838
+ # Option 1: 환경 변수 수정
839
+ docker run -e DB_HOST=db-container myapp
783
840
 
784
- (dlv) break counter.go:23
785
- (dlv) continue
786
- (dlv) print counter
787
- (dlv) goroutines
841
+ # Option 2: Docker Compose로 네트워크 설정
842
+ # docker-compose.yml
843
+ version: '3'
844
+ services:
845
+ app:
846
+ image: myapp
847
+ environment:
848
+ DB_HOST: db
849
+ depends_on:
850
+ - db
851
+ db:
852
+ image: postgres:15
788
853
  ```
789
854
 
790
- ### Root Cause
791
- Unsynchronized access to shared counter.
792
-
793
- ```go
794
- // Before (race condition)
795
- var counter int
796
-
797
- func updateCounter() {
798
- counter++ // ❌ Not atomic
799
- }
800
-
801
- func getCounter() int {
802
- return counter // ❌ Unsynchronized read
803
- }
804
-
805
- // After (fixed with mutex)
806
- import "sync"
855
+ ---
807
856
 
808
- var (
809
- counter int
810
- mu sync.RWMutex
811
- )
857
+ ### 시나리오 2: Kubernetes Pod CrashLoopBackOff
812
858
 
813
- func updateCounter() {
814
- mu.Lock()
815
- defer mu.Unlock()
816
- counter++ // ✅ Protected
817
- }
859
+ **문제**:
860
+ ```bash
861
+ $ kubectl get pods
862
+ NAME READY STATUS RESTARTS
863
+ myapp-pod-abc123 0/1 CrashLoopBackOff 5
864
+ ```
818
865
 
819
- func getCounter() int {
820
- mu.RLock()
821
- defer mu.RUnlock()
822
- return counter // Protected
823
- }
866
+ **디버깅 단계**:
867
+ ```bash
868
+ # 1. Pod 설명 확인
869
+ kubectl describe pod myapp-pod-abc123
870
+ # Events:
871
+ # Warning BackOff kubelet Back-off restarting failed container
824
872
 
825
- // Alternative: Use atomic operations
826
- import "sync/atomic"
873
+ # 2. 로그 확인
874
+ kubectl logs myapp-pod-abc123
875
+ # panic: open /config/app.yaml: no such file or directory
827
876
 
828
- var counter int64
877
+ # 3. 이전 컨테이너 로그 확인
878
+ kubectl logs myapp-pod-abc123 --previous
829
879
 
830
- func updateCounter() {
831
- atomic.AddInt64(&counter, 1) // Atomic
832
- }
880
+ # 4. ConfigMap 확인
881
+ kubectl get configmap myapp-config -o yaml
882
+ # (ConfigMap이 없거나 잘못 마운트됨)
833
883
 
834
- func getCounter() int64 {
835
- return atomic.LoadInt64(&counter) // Atomic
836
- }
884
+ # 5. 볼륨 마운트 확인
885
+ kubectl get pod myapp-pod-abc123 -o yaml | grep -A 10 volumeMounts
837
886
  ```
838
887
 
839
- ### Test Case
840
- ```go
841
- // counter_test.go
842
- func TestConcurrentCounterAccess(t *testing.T) {
843
- counter = 0
844
-
845
- var wg sync.WaitGroup
846
- iterations := 1000
847
- goroutines := 10
848
-
849
- for i := 0; i < goroutines; i++ {
850
- wg.Add(1)
851
- go func() {
852
- defer wg.Done()
853
- for j := 0; j < iterations; j++ {
854
- updateCounter()
855
- }
856
- }()
857
- }
858
-
859
- wg.Wait()
860
- expected := iterations * goroutines
861
- assert.Equal(t, int64(expected), getCounter(), "Counter mismatch indicates race condition")
862
- }
888
+ **해결 방법**:
889
+ ```yaml
890
+ # 1. ConfigMap 생성
891
+ apiVersion: v1
892
+ kind: ConfigMap
893
+ metadata:
894
+ name: myapp-config
895
+ data:
896
+ app.yaml: |
897
+ database:
898
+ host: db-service
899
+ port: 5432
900
+
901
+ # 2. Pod에 ConfigMap 마운트
902
+ apiVersion: v1
903
+ kind: Pod
904
+ metadata:
905
+ name: myapp-pod
906
+ spec:
907
+ containers:
908
+ - name: myapp
909
+ image: myapp:latest
910
+ volumeMounts:
911
+ - name: config
912
+ mountPath: /config
913
+ volumes:
914
+ - name: config
915
+ configMap:
916
+ name: myapp-config
863
917
  ```
864
918
 
865
919
  ---
866
920
 
867
- ## Null Pointer Debugging (TypeScript)
921
+ ## 분산 시스템 디버깅 시나리오
868
922
 
869
- ### Problem
870
- Production error: `Cannot read properties of undefined (reading 'name')`.
923
+ ### 시나리오: 마이크로서비스 간 타임아웃
871
924
 
872
- ### Stack Trace
873
- ```
874
- TypeError: Cannot read properties of undefined (reading 'name')
875
- at getUserName (user.service.ts:15:23)
876
- at processUser (user.controller.ts:42:10)
877
- at async Router.handle (express.js:234:15)
878
- ```
879
-
880
- ### Investigation Steps
881
-
882
- #### 1. Add Source Maps for Debugging
883
- ```json
884
- // tsconfig.json
885
- {
886
- "compilerOptions": {
887
- "sourceMap": true,
888
- "inlineSourceMap": false,
889
- "outDir": "./dist",
890
- "rootDir": "./src"
891
- }
892
- }
893
- ```
925
+ **문제**: Service A → Service B 호출 시 타임아웃 발생
894
926
 
895
- #### 2. Debug with Node Inspector
896
- ```bash
897
- # Run with inspector
898
- node --inspect -r ts-node/register src/app.ts
927
+ **디버깅 단계**:
899
928
 
900
- # Or debug tests
901
- node --inspect-brk node_modules/.bin/jest --runInBand
902
- ```
929
+ **1. OpenTelemetry로 트레이스 수집**:
930
+ ```python
931
+ # Service A
932
+ from opentelemetry import trace
903
933
 
904
- #### 3. VSCode Debugging
905
- ```json
906
- {
907
- "version": "0.2.0",
908
- "configurations": [
909
- {
910
- "type": "node",
911
- "request": "launch",
912
- "name": "TypeScript: Debug",
913
- "runtimeArgs": ["-r", "ts-node/register"],
914
- "args": ["${file}"],
915
- "cwd": "${workspaceFolder}",
916
- "sourceMaps": true
917
- }
918
- ]
919
- }
920
- ```
934
+ tracer = trace.get_tracer(__name__)
921
935
 
922
- #### 4. Set Breakpoint and Inspect
923
- ```typescript
924
- // user.service.ts
925
- export function getUserName(user: User): string {
926
- // Set breakpoint here
927
- debugger;
928
- return user.name; // user is undefined!
929
- }
936
+ with tracer.start_as_current_span("call-service-b") as span:
937
+ response = requests.get("http://service-b/api/data", timeout=5)
938
+ span.set_attribute("http.status_code", response.status_code)
939
+ ```
930
940
 
931
- // In debugger console:
932
- // > user
933
- // undefined
934
- // > user?.name
935
- // undefined
941
+ **2. Jaeger UI에서 트레이스 분석**:
942
+ ```
943
+ Trace: request-123
944
+ ├─ Service A: call-service-b (50ms)
945
+ │ └─ HTTP GET http://service-b/api/data
946
+ │ ├─ DNS lookup: 10ms
947
+ │ ├─ TCP connect: 15ms
948
+ │ └─ Waiting for response: 5000ms ← 타임아웃!
949
+ └─ Service B: process-request (4950ms)
950
+ ├─ Database query: 4900ms ← 병목!
951
+ └─ Response serialization: 50ms
936
952
  ```
937
953
 
938
- ### Root Cause
939
- Async data not awaited; function called before user fetched.
954
+ **3. 근본 원인 식별**:
955
+ - Service B의 데이터베이스 쿼리가 4.9초 소요
956
+ - Service A의 타임아웃이 5초로 설정되어 있어 경합 상태 발생
940
957
 
941
- ```typescript
942
- // Before (bug)
943
- async function processUser(userId: string) {
944
- const user = fetchUser(userId); // ❌ Missing await
945
- const name = getUserName(user); // user is Promise<User>, not User
946
- console.log(name);
947
- }
958
+ **해결 방법**:
959
+ ```python
960
+ # Option 1: Service B의 쿼리 최적화
961
+ # 인덱스 추가
962
+ CREATE INDEX idx_user_email ON users(email);
948
963
 
949
- // After (fixed)
950
- async function processUser(userId: string) {
951
- const user = await fetchUser(userId); // ✅ Await promise
952
- if (!user) {
953
- throw new Error(`User ${userId} not found`);
954
- }
955
- const name = getUserName(user);
956
- console.log(name);
957
- }
964
+ # Option 2: Service A의 타임아웃 증가
965
+ response = requests.get("http://service-b/api/data", timeout=10)
958
966
 
959
- // Better: Use optional chaining
960
- function getUserName(user: User | undefined): string {
961
- return user?.name ?? 'Unknown'; // ✅ Safe access
962
- }
963
- ```
967
+ # Option 3: 캐싱 추가
968
+ from redis import Redis
964
969
 
965
- ### Test Case
966
- ```typescript
967
- // user.service.test.ts
968
- describe('getUserName', () => {
969
- it('should handle undefined user gracefully', () => {
970
- const result = getUserName(undefined);
971
- expect(result).toBe('Unknown');
972
- });
970
+ cache = Redis(host='redis', port=6379)
973
971
 
974
- it('should return user name when defined', () => {
975
- const user = { id: '123', name: 'Alice' };
976
- const result = getUserName(user);
977
- expect(result).toBe('Alice');
978
- });
979
- });
972
+ def get_data():
973
+ cached = cache.get('data')
974
+ if cached:
975
+ return cached
976
+
977
+ data = expensive_database_query()
978
+ cache.setex('data', 300, data) # 5분 캐시
979
+ return data
980
980
  ```
981
981
 
982
982
  ---
983
983
 
984
- ## Database Query Performance (SQL)
984
+ ## 성능 디버깅 시나리오
985
985
 
986
- ### Problem
987
- Dashboard loads slowly; query taking 5+ seconds.
986
+ ### 시나리오: 느린 API 응답
988
987
 
989
- ### Investigation Steps
988
+ **문제**: API 엔드포인트 응답 시간이 3초 이상
990
989
 
991
- #### 1. Enable Query Logging
992
- ```sql
993
- -- PostgreSQL: Enable slow query log
994
- ALTER SYSTEM SET log_min_duration_statement = 1000; -- 1 second
995
- SELECT pg_reload_conf();
990
+ **디버깅 단계**:
996
991
 
997
- -- Check logs
998
- SELECT query, calls, total_time, mean_time
999
- FROM pg_stat_statements
1000
- ORDER BY total_time DESC
1001
- LIMIT 10;
992
+ **1. py-spy로 CPU 프로파일링** (Python):
993
+ ```bash
994
+ py-spy record -o profile.svg --pid <pid>
1002
995
  ```
1003
996
 
1004
- #### 2. Analyze Query with EXPLAIN
1005
- ```sql
1006
- -- Original slow query
1007
- EXPLAIN ANALYZE
1008
- SELECT u.name, COUNT(o.id) as order_count
1009
- FROM users u
1010
- LEFT JOIN orders o ON u.id = o.user_id
1011
- WHERE u.created_at > '2024-01-01'
1012
- GROUP BY u.id, u.name
1013
- ORDER BY order_count DESC;
1014
-
1015
- -- Output:
1016
- Sort (cost=15234.56..15235.56 rows=400 width=16) (actual time=5234.123..5234.234 rows=1000 loops=1)
1017
- -> HashAggregate (cost=15210.00..15214.00 rows=400 width=16) (actual time=5233.456..5233.789 rows=1000 loops=1)
1018
- -> Hash Left Join (cost=1234.00..12345.00 rows=286500 width=8) (actual time=123.456..4567.890 rows=500000 loops=1)
1019
- -> Seq Scan on users u (cost=0.00..1245.00 rows=50000 width=8) (actual time=0.012..234.567 rows=50000 loops=1)
1020
- Filter: (created_at > '2024-01-01'::date)
1021
- -> Hash (cost=800.00..800.00 rows=30000 width=8) (actual time=123.444..123.444 rows=30000 loops=1)
1022
- -> Seq Scan on orders o (cost=0.00..800.00 rows=30000 width=8) (actual time=0.010..89.123 rows=30000 loops=1)
1023
- Planning Time: 1.234 ms
1024
- Execution Time: 5234.567 ms ← SLOW!
1025
- ```
1026
-
1027
- #### 3. Identify Missing Indexes
1028
- ```sql
1029
- -- Check existing indexes
1030
- SELECT tablename, indexname, indexdef
1031
- FROM pg_indexes
1032
- WHERE tablename IN ('users', 'orders');
1033
-
1034
- -- Missing:
1035
- -- 1. Index on users.created_at
1036
- -- 2. Index on orders.user_id
997
+ **2. Flamegraph 분석**:
998
+ ```
999
+ main() [100%]
1000
+ ├─ process_request() [95%]
1001
+ │ ├─ load_users() [80%] ← 병목!
1002
+ │ │ └─ database.query() [78%]
1003
+ │ └─ serialize_response() [15%]
1004
+ └─ logging() [5%]
1037
1005
  ```
1038
1006
 
1039
- #### 4. Add Indexes and Re-test
1007
+ **3. 데이터베이스 쿼리 분석**:
1040
1008
  ```sql
1041
- -- Add indexes
1042
- CREATE INDEX idx_users_created_at ON users(created_at);
1043
- CREATE INDEX idx_orders_user_id ON orders(user_id);
1044
-
1045
- -- Re-run EXPLAIN ANALYZE
1046
- EXPLAIN ANALYZE
1047
- SELECT u.name, COUNT(o.id) as order_count
1048
- FROM users u
1049
- LEFT JOIN orders o ON u.id = o.user_id
1050
- WHERE u.created_at > '2024-01-01'
1051
- GROUP BY u.id, u.name
1052
- ORDER BY order_count DESC;
1053
-
1054
- -- Output (improved):
1055
- Sort (cost=234.56..235.56 rows=400 width=16) (actual time=45.123..45.234 rows=1000 loops=1)
1056
- -> HashAggregate (cost=210.00..214.00 rows=400 width=16) (actual time=44.456..44.789 rows=1000 loops=1)
1057
- -> Hash Left Join (cost=123.00..200.00 rows=5000 width=8) (actual time=12.345..40.567 rows=5000 loops=1)
1058
- -> Index Scan using idx_users_created_at on users u (cost=0.42..100.00 rows=5000 width=8) (actual time=0.023..15.234 rows=5000 loops=1)
1059
- Index Cond: (created_at > '2024-01-01'::date)
1060
- -> Hash (cost=80.00..80.00 rows=3000 width=8) (actual time=12.321..12.321 rows=3000 loops=1)
1061
- -> Index Scan using idx_orders_user_id on orders o (cost=0.42..80.00 rows=3000 width=8) (actual time=0.012..8.123 rows=3000 loops=1)
1062
- Execution Time: 45.567 ms ← 100x FASTER!
1063
- ```
1064
-
1065
- ### Root Cause
1066
- Missing indexes on frequently queried columns (`users.created_at`, `orders.user_id`).
1067
-
1068
- ### Test Case
1069
- ```python
1070
- # tests/test_query_performance.py
1071
- import pytest
1072
- import time
1073
-
1074
- def test_dashboard_query_performance(db):
1075
- """Ensure dashboard query completes within 100ms."""
1076
- query = """
1077
- SELECT u.name, COUNT(o.id) as order_count
1078
- FROM users u
1079
- LEFT JOIN orders o ON u.id = o.user_id
1080
- WHERE u.created_at > '2024-01-01'
1081
- GROUP BY u.id, u.name
1082
- ORDER BY order_count DESC
1083
- """
1009
+ EXPLAIN ANALYZE SELECT * FROM users WHERE status = 'active';
1010
+ -- Seq Scan on users (cost=0.00..1234.56)
1011
+ -- 인덱스 없음!
1012
+ ```
1084
1013
 
1085
- start = time.time()
1086
- result = db.execute(query)
1087
- duration = time.time() - start
1014
+ **4. 해결 방법**:
1015
+ ```sql
1016
+ -- 인덱스 추가
1017
+ CREATE INDEX idx_users_status ON users(status);
1088
1018
 
1089
- assert duration < 0.1, f"Query took {duration}s, expected < 0.1s"
1090
- assert len(result) > 0, "Query returned no results"
1019
+ -- 쿼리 재실행
1020
+ EXPLAIN ANALYZE SELECT * FROM users WHERE status = 'active';
1021
+ -- Index Scan using idx_users_status (cost=0.28..45.67)
1022
+ -- 응답 시간: 3초 → 50ms
1091
1023
  ```
1092
1024
 
1093
1025
  ---
1094
1026
 
1095
- ## Summary
1027
+ ## 요약: 디버깅 체크리스트
1028
+
1029
+ ### 1. 재현 (Reproduce)
1030
+ - [ ] 최소 재현 예제 (MRE) 작성
1031
+ - [ ] 일관된 재현 단계 문서화
1032
+ - [ ] 환경 정보 기록 (OS, 언어 버전, 의존성)
1033
+
1034
+ ### 2. 격리 (Isolate)
1035
+ - [ ] 이진 탐색으로 문제 범위 좁히기
1036
+ - [ ] 최근 변경사항 확인 (git diff, git log)
1037
+ - [ ] 입력 데이터 및 엣지 케이스 검증
1038
+
1039
+ ### 3. 조사 (Investigate)
1040
+ - [ ] 스택 트레이스를 아래에서 위로 읽기
1041
+ - [ ] 주요 결정 지점에 로깅 추가
1042
+ - [ ] 에러 위치 이전에 브레이크포인트 설정
1043
+ - [ ] 디버거에서 변수 상태 확인
1044
+
1045
+ ### 4. 가설 (Hypothesize)
1046
+ - [ ] 근본 원인에 대한 이론 수립
1047
+ - [ ] 가장 가능성 높은 원인 2-3개 식별
1048
+ - [ ] 가설 검증 실험 설계
1049
+
1050
+ ### 5. 수정 (Fix)
1051
+ - [ ] 최소한의 수정 먼저 구현
1052
+ - [ ] 회귀 테스트 추가 (RED → GREEN)
1053
+ - [ ] 필요시 리팩토링 (REFACTOR 단계)
1054
+ - [ ] 문서 업데이트
1055
+
1056
+ ### 6. 검증 (Verify)
1057
+ - [ ] 전체 테스트 스위트 실행
1058
+ - [ ] 엣지 케이스 명시적 테스트
1059
+ - [ ] 프로덕션 유사 환경에서 수정 검증
1060
+ - [ ] 재발 모니터링
1096
1061
 
1097
- These real-world examples demonstrate:
1098
- 1. **Async debugging** with Python debugpy and asyncio inspection
1099
- 2. **Goroutine leak detection** with Delve and pprof
1100
- 3. **Distributed tracing** with OpenTelemetry across microservices
1101
- 4. **Kubernetes debugging** with ephemeral containers and memory profiling
1102
- 5. **Rust memory leaks** using Valgrind and Weak references
1103
- 6. **Go race conditions** with built-in race detector
1104
- 7. **TypeScript null pointers** with optional chaining and type guards
1105
- 8. **SQL performance** with EXPLAIN ANALYZE and index optimization
1062
+ ---
1106
1063
 
1107
- Each example follows the **Reproduce Isolate → Investigate → Fix → Verify** workflow and includes regression tests to prevent recurrence.
1064
+ **End of Examples** | moai-essentials-debug v2.1.0