@su-record/vibe 2.4.33 → 2.4.35

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.
Files changed (101) hide show
  1. package/CLAUDE.md +345 -345
  2. package/LICENSE +21 -21
  3. package/README.md +210 -210
  4. package/agents/compounder.md +261 -261
  5. package/agents/diagrammer.md +178 -178
  6. package/agents/e2e-tester.md +266 -266
  7. package/agents/explorer.md +48 -48
  8. package/agents/implementer.md +53 -53
  9. package/agents/research/best-practices-agent.md +139 -139
  10. package/agents/research/codebase-patterns-agent.md +147 -147
  11. package/agents/research/framework-docs-agent.md +178 -178
  12. package/agents/research/security-advisory-agent.md +164 -164
  13. package/agents/review/architecture-reviewer.md +107 -107
  14. package/agents/review/complexity-reviewer.md +116 -116
  15. package/agents/review/data-integrity-reviewer.md +88 -88
  16. package/agents/review/git-history-reviewer.md +103 -103
  17. package/agents/review/performance-reviewer.md +86 -86
  18. package/agents/review/python-reviewer.md +150 -150
  19. package/agents/review/rails-reviewer.md +139 -139
  20. package/agents/review/react-reviewer.md +144 -144
  21. package/agents/review/security-reviewer.md +80 -80
  22. package/agents/review/simplicity-reviewer.md +140 -140
  23. package/agents/review/test-coverage-reviewer.md +116 -116
  24. package/agents/review/typescript-reviewer.md +127 -127
  25. package/agents/searcher.md +54 -54
  26. package/agents/simplifier.md +119 -119
  27. package/agents/tester.md +49 -49
  28. package/agents/ui-previewer.md +129 -129
  29. package/commands/vibe.analyze.md +260 -260
  30. package/commands/vibe.reason.md +223 -223
  31. package/commands/vibe.review.md +213 -213
  32. package/commands/vibe.run.md +931 -931
  33. package/commands/vibe.spec.md +442 -442
  34. package/commands/vibe.utils.md +101 -101
  35. package/commands/vibe.verify.md +282 -282
  36. package/dist/cli/collaborator.js +52 -52
  37. package/dist/cli/detect.js +32 -32
  38. package/dist/cli/index.js +137 -137
  39. package/dist/cli/llm.js +147 -147
  40. package/dist/cli/llm.js.map +1 -1
  41. package/dist/cli/setup.d.ts +1 -1
  42. package/dist/cli/setup.d.ts.map +1 -1
  43. package/dist/cli/setup.js +11 -17
  44. package/dist/cli/setup.js.map +1 -1
  45. package/dist/lib/MemoryManager.d.ts +4 -0
  46. package/dist/lib/MemoryManager.d.ts.map +1 -1
  47. package/dist/lib/MemoryManager.js +21 -2
  48. package/dist/lib/MemoryManager.js.map +1 -1
  49. package/dist/lib/PythonParser.js +108 -108
  50. package/dist/lib/gemini-api.d.ts +13 -3
  51. package/dist/lib/gemini-api.d.ts.map +1 -1
  52. package/dist/lib/gemini-api.js +198 -7
  53. package/dist/lib/gemini-api.js.map +1 -1
  54. package/dist/lib/gpt-api.d.ts +5 -4
  55. package/dist/lib/gpt-api.d.ts.map +1 -1
  56. package/dist/lib/gpt-api.js +168 -12
  57. package/dist/lib/gpt-api.js.map +1 -1
  58. package/dist/tools/memory/saveMemory.js +1 -1
  59. package/dist/tools/memory/saveMemory.js.map +1 -1
  60. package/dist/tools/reasoning/applyReasoningFramework.js +56 -56
  61. package/hooks/hooks.json +195 -195
  62. package/languages/dart-flutter.md +509 -0
  63. package/languages/go.md +396 -0
  64. package/languages/java-spring.md +586 -0
  65. package/languages/kotlin-android.md +491 -0
  66. package/languages/python-django.md +371 -0
  67. package/languages/python-fastapi.md +386 -0
  68. package/languages/rust.md +425 -0
  69. package/languages/swift-ios.md +516 -0
  70. package/languages/typescript-nextjs.md +441 -0
  71. package/languages/typescript-node.md +375 -0
  72. package/languages/typescript-nuxt.md +521 -0
  73. package/languages/typescript-react-native.md +446 -0
  74. package/languages/typescript-react.md +525 -0
  75. package/languages/typescript-vue.md +353 -0
  76. package/package.json +88 -87
  77. package/skills/context7-usage.md +82 -82
  78. package/skills/git-worktree.md +181 -181
  79. package/skills/multi-llm-orchestration.md +92 -92
  80. package/skills/parallel-research.md +77 -77
  81. package/skills/priority-todos.md +239 -239
  82. package/skills/tool-fallback.md +126 -126
  83. package/skills/vibe-capabilities.md +129 -129
  84. package/{.claude/vibe → vibe}/config.json +3 -3
  85. package/{.claude/vibe → vibe}/constitution.md +184 -184
  86. package/{.claude/vibe → vibe}/rules/core/communication-guide.md +104 -104
  87. package/{.claude/vibe → vibe}/rules/core/development-philosophy.md +52 -52
  88. package/{.claude/vibe → vibe}/rules/core/quick-start.md +120 -120
  89. package/{.claude/vibe → vibe}/rules/quality/bdd-contract-testing.md +388 -388
  90. package/{.claude/vibe → vibe}/rules/quality/checklist.md +276 -276
  91. package/{.claude/vibe → vibe}/rules/quality/testing-strategy.md +437 -437
  92. package/{.claude/vibe → vibe}/rules/standards/anti-patterns.md +369 -369
  93. package/{.claude/vibe → vibe}/rules/standards/code-structure.md +291 -291
  94. package/{.claude/vibe → vibe}/rules/standards/complexity-metrics.md +312 -312
  95. package/{.claude/vibe → vibe}/rules/standards/naming-conventions.md +198 -198
  96. package/{.claude/vibe → vibe}/setup.sh +31 -31
  97. package/{.claude/vibe → vibe}/templates/constitution-template.md +184 -184
  98. package/{.claude/vibe → vibe}/templates/contract-backend-template.md +517 -517
  99. package/{.claude/vibe → vibe}/templates/contract-frontend-template.md +594 -594
  100. package/{.claude/vibe → vibe}/templates/feature-template.md +96 -96
  101. package/{.claude/vibe → vibe}/templates/spec-template.md +199 -199
@@ -1,369 +1,369 @@
1
- # 🚫 자동 안티패턴 회피
2
-
3
- ## TypeScript 안티패턴
4
-
5
- ### 1. any 타입 사용
6
-
7
- ```typescript
8
- // ❌ any 사용
9
- function processData(data: any) {
10
- return data.value; // 타입 안전성 상실
11
- }
12
-
13
- // ✅ unknown + type guard
14
- function processData(data: unknown) {
15
- if (isValidData(data)) {
16
- return data.value; // 타입 안전
17
- }
18
- throw new Error('Invalid data');
19
- }
20
-
21
- function isValidData(data: unknown): data is { value: string } {
22
- return typeof data === 'object' && data !== null && 'value' in data;
23
- }
24
- ```
25
-
26
- ### 2. as any 강제 타입 캐스팅
27
-
28
- ```typescript
29
- // ❌ as any로 타입 우회
30
- const user = response as any;
31
- user.name; // 런타임 에러 위험
32
-
33
- // ✅ 적절한 타입 정의
34
- interface User {
35
- name: string;
36
- email: string;
37
- }
38
-
39
- const user = response as User;
40
- user.name; // 타입 안전
41
- ```
42
-
43
- ### 3. @ts-ignore 남용
44
-
45
- ```typescript
46
- // ❌ @ts-ignore로 에러 무시
47
- // @ts-ignore
48
- const result = problematicCode();
49
-
50
- // ✅ 타입 문제 근본 해결
51
- interface Expected {
52
- id: string;
53
- }
54
-
55
- const result: Expected = {
56
- id: String(problematicCode()),
57
- };
58
- ```
59
-
60
- ## React 안티패턴
61
-
62
- ### 1. dangerouslySetInnerHTML 사용
63
-
64
- ```typescript
65
- // ❌ XSS 취약점
66
- function Component({ html }: { html: string }) {
67
- return <div dangerouslySetInnerHTML={{ __html: html }} />;
68
- }
69
-
70
- // ✅ 안전한 렌더링
71
- import DOMPurify from 'dompurify';
72
-
73
- function Component({ html }: { html: string }) {
74
- const sanitized = DOMPurify.sanitize(html);
75
- return <div dangerouslySetInnerHTML={{ __html: sanitized }} />;
76
- }
77
-
78
- // ✅ 더 나은 방법: 마크다운 라이브러리 사용
79
- import ReactMarkdown from 'react-markdown';
80
-
81
- function Component({ markdown }: { markdown: string }) {
82
- return <ReactMarkdown>{markdown}</ReactMarkdown>;
83
- }
84
- ```
85
-
86
- ### 2. Props Drilling (3단계 이상)
87
-
88
- ```typescript
89
- // ❌ Props drilling
90
- function App() {
91
- const [user, setUser] = useState<User>();
92
- return <Parent user={user} />;
93
- }
94
-
95
- function Parent({ user }: { user: User }) {
96
- return <Child user={user} />;
97
- }
98
-
99
- function Child({ user }: { user: User }) {
100
- return <GrandChild user={user} />;
101
- }
102
-
103
- function GrandChild({ user }: { user: User }) {
104
- return <div>{user.name}</div>;
105
- }
106
-
107
- // ✅ Context API 사용
108
- const UserContext = createContext<User | undefined>(undefined);
109
-
110
- function App() {
111
- const [user, setUser] = useState<User>();
112
- return (
113
- <UserContext.Provider value={user}>
114
- <Parent />
115
- </UserContext.Provider>
116
- );
117
- }
118
-
119
- function GrandChild() {
120
- const user = useContext(UserContext);
121
- return <div>{user?.name}</div>;
122
- }
123
- ```
124
-
125
- ### 3. useEffect 의존성 배열 누락
126
-
127
- ```typescript
128
- // ❌ 의존성 누락
129
- function Component({ userId }: { userId: string }) {
130
- const [user, setUser] = useState<User>();
131
-
132
- useEffect(() => {
133
- fetchUser(userId).then(setUser);
134
- }, []); // userId 의존성 누락!
135
-
136
- return <div>{user?.name}</div>;
137
- }
138
-
139
- // ✅ 모든 의존성 명시
140
- function Component({ userId }: { userId: string }) {
141
- const [user, setUser] = useState<User>();
142
-
143
- useEffect(() => {
144
- fetchUser(userId).then(setUser);
145
- }, [userId]); // 의존성 명시
146
-
147
- return <div>{user?.name}</div>;
148
- }
149
- ```
150
-
151
- ## JavaScript 안티패턴
152
-
153
- ### 1. var 사용
154
-
155
- ```typescript
156
- // ❌ var 사용
157
- var count = 0;
158
- if (true) {
159
- var count = 1; // 같은 변수!
160
- }
161
- console.log(count); // 1
162
-
163
- // ✅ const/let 사용
164
- let count = 0;
165
- if (true) {
166
- let count = 1; // 블록 스코프
167
- }
168
- console.log(count); // 0
169
- ```
170
-
171
- ### 2. == 사용 (느슨한 비교)
172
-
173
- ```typescript
174
- // ❌ == 사용
175
- if (value == null) { } // undefined도 매칭
176
- if ('5' == 5) { } // true (타입 강제 변환)
177
-
178
- // ✅ === 사용
179
- if (value === null) { }
180
- if (value === undefined) { }
181
- if ('5' === 5) { } // false
182
- ```
183
-
184
- ### 3. eval() 사용
185
-
186
- ```typescript
187
- // ❌ eval() 사용 (보안 위험)
188
- const code = userInput;
189
- eval(code); // 임의 코드 실행 가능
190
-
191
- // ✅ 대안 구현
192
- const allowedOperations = {
193
- add: (a: number, b: number) => a + b,
194
- subtract: (a: number, b: number) => a - b,
195
- };
196
-
197
- const operation = allowedOperations[userInput];
198
- if (operation) {
199
- result = operation(a, b);
200
- }
201
- ```
202
-
203
- ## CSS 안티패턴
204
-
205
- ### 1. !important 남용
206
-
207
- ```css
208
- /* ❌ !important 남용 */
209
- .button {
210
- color: blue !important;
211
- background: red !important;
212
- }
213
-
214
- /* ✅ 구체적인 선택자 사용 */
215
- .navigation .button.primary {
216
- color: blue;
217
- background: red;
218
- }
219
- ```
220
-
221
- ### 2. 인라인 스타일 남용
222
-
223
- ```typescript
224
- // ❌ 인라인 스타일
225
- function Button() {
226
- return (
227
- <button
228
- style={{
229
- backgroundColor: 'blue',
230
- color: 'white',
231
- padding: '10px',
232
- borderRadius: '5px',
233
- }}
234
- >
235
- Click me
236
- </button>
237
- );
238
- }
239
-
240
- // ✅ CSS 클래스 사용
241
- function Button() {
242
- return <button className="btn-primary">Click me</button>;
243
- }
244
-
245
- // styles.css
246
- .btn-primary {
247
- background-color: blue;
248
- color: white;
249
- padding: 10px;
250
- border-radius: 5px;
251
- }
252
- ```
253
-
254
- ## 성능 안티패턴
255
-
256
- ### 1. 불필요한 리렌더링
257
-
258
- ```typescript
259
- // ❌ 매번 새 객체/함수 생성
260
- function Parent() {
261
- return <Child config={{ theme: 'dark' }} onClick={() => {}} />;
262
- // 매 렌더마다 새 객체/함수 생성 → Child 리렌더
263
- }
264
-
265
- // ✅ useMemo/useCallback 사용
266
- function Parent() {
267
- const config = useMemo(() => ({ theme: 'dark' }), []);
268
- const handleClick = useCallback(() => {}, []);
269
-
270
- return <Child config={config} onClick={handleClick} />;
271
- }
272
- ```
273
-
274
- ### 2. 동기적 무거운 연산
275
-
276
- ```typescript
277
- // ❌ 메인 스레드 블로킹
278
- function Component({ data }: { data: number[] }) {
279
- const result = data
280
- .map(heavyComputation)
281
- .filter(x => x > 0)
282
- .reduce((a, b) => a + b);
283
-
284
- return <div>{result}</div>;
285
- }
286
-
287
- // ✅ useMemo로 메모이제이션
288
- function Component({ data }: { data: number[] }) {
289
- const result = useMemo(
290
- () =>
291
- data
292
- .map(heavyComputation)
293
- .filter(x => x > 0)
294
- .reduce((a, b) => a + b),
295
- [data]
296
- );
297
-
298
- return <div>{result}</div>;
299
- }
300
- ```
301
-
302
- ## 보안 안티패턴
303
-
304
- ### 1. 민감 정보 하드코딩
305
-
306
- ```typescript
307
- // ❌ API 키 하드코딩
308
- const API_KEY = 'sk-1234567890abcdef';
309
-
310
- // ✅ 환경 변수 사용
311
- const API_KEY = process.env.NEXT_PUBLIC_API_KEY;
312
- ```
313
-
314
- ### 2. SQL Injection 취약점
315
-
316
- ```typescript
317
- // ❌ 직접 문자열 연결
318
- const query = `SELECT * FROM users WHERE id = ${userId}`;
319
-
320
- // ✅ 파라미터화된 쿼리
321
- const query = 'SELECT * FROM users WHERE id = ?';
322
- db.execute(query, [userId]);
323
- ```
324
-
325
- ## 에러 처리 안티패턴
326
-
327
- ### 1. 빈 catch 블록
328
-
329
- ```typescript
330
- // ❌ 에러 무시
331
- try {
332
- riskyOperation();
333
- } catch (e) {
334
- // 아무것도 안 함
335
- }
336
-
337
- // ✅ 적절한 에러 처리
338
- try {
339
- riskyOperation();
340
- } catch (error) {
341
- console.error('Operation failed:', error);
342
- showErrorNotification(error);
343
- trackError(error);
344
- }
345
- ```
346
-
347
- ### 2. 에러 타입 확인 없이 처리
348
-
349
- ```typescript
350
- // ❌ 모든 에러 동일하게 처리
351
- try {
352
- await fetchData();
353
- } catch (error) {
354
- showError('Failed'); // 구체적이지 않음
355
- }
356
-
357
- // ✅ 에러 타입별 처리
358
- try {
359
- await fetchData();
360
- } catch (error) {
361
- if (error instanceof NetworkError) {
362
- showError('네트워크 연결을 확인해주세요');
363
- } else if (error instanceof AuthError) {
364
- redirectToLogin();
365
- } else {
366
- showError('알 수 없는 오류가 발생했습니다');
367
- }
368
- }
369
- ```
1
+ # 🚫 자동 안티패턴 회피
2
+
3
+ ## TypeScript 안티패턴
4
+
5
+ ### 1. any 타입 사용
6
+
7
+ ```typescript
8
+ // ❌ any 사용
9
+ function processData(data: any) {
10
+ return data.value; // 타입 안전성 상실
11
+ }
12
+
13
+ // ✅ unknown + type guard
14
+ function processData(data: unknown) {
15
+ if (isValidData(data)) {
16
+ return data.value; // 타입 안전
17
+ }
18
+ throw new Error('Invalid data');
19
+ }
20
+
21
+ function isValidData(data: unknown): data is { value: string } {
22
+ return typeof data === 'object' && data !== null && 'value' in data;
23
+ }
24
+ ```
25
+
26
+ ### 2. as any 강제 타입 캐스팅
27
+
28
+ ```typescript
29
+ // ❌ as any로 타입 우회
30
+ const user = response as any;
31
+ user.name; // 런타임 에러 위험
32
+
33
+ // ✅ 적절한 타입 정의
34
+ interface User {
35
+ name: string;
36
+ email: string;
37
+ }
38
+
39
+ const user = response as User;
40
+ user.name; // 타입 안전
41
+ ```
42
+
43
+ ### 3. @ts-ignore 남용
44
+
45
+ ```typescript
46
+ // ❌ @ts-ignore로 에러 무시
47
+ // @ts-ignore
48
+ const result = problematicCode();
49
+
50
+ // ✅ 타입 문제 근본 해결
51
+ interface Expected {
52
+ id: string;
53
+ }
54
+
55
+ const result: Expected = {
56
+ id: String(problematicCode()),
57
+ };
58
+ ```
59
+
60
+ ## React 안티패턴
61
+
62
+ ### 1. dangerouslySetInnerHTML 사용
63
+
64
+ ```typescript
65
+ // ❌ XSS 취약점
66
+ function Component({ html }: { html: string }) {
67
+ return <div dangerouslySetInnerHTML={{ __html: html }} />;
68
+ }
69
+
70
+ // ✅ 안전한 렌더링
71
+ import DOMPurify from 'dompurify';
72
+
73
+ function Component({ html }: { html: string }) {
74
+ const sanitized = DOMPurify.sanitize(html);
75
+ return <div dangerouslySetInnerHTML={{ __html: sanitized }} />;
76
+ }
77
+
78
+ // ✅ 더 나은 방법: 마크다운 라이브러리 사용
79
+ import ReactMarkdown from 'react-markdown';
80
+
81
+ function Component({ markdown }: { markdown: string }) {
82
+ return <ReactMarkdown>{markdown}</ReactMarkdown>;
83
+ }
84
+ ```
85
+
86
+ ### 2. Props Drilling (3단계 이상)
87
+
88
+ ```typescript
89
+ // ❌ Props drilling
90
+ function App() {
91
+ const [user, setUser] = useState<User>();
92
+ return <Parent user={user} />;
93
+ }
94
+
95
+ function Parent({ user }: { user: User }) {
96
+ return <Child user={user} />;
97
+ }
98
+
99
+ function Child({ user }: { user: User }) {
100
+ return <GrandChild user={user} />;
101
+ }
102
+
103
+ function GrandChild({ user }: { user: User }) {
104
+ return <div>{user.name}</div>;
105
+ }
106
+
107
+ // ✅ Context API 사용
108
+ const UserContext = createContext<User | undefined>(undefined);
109
+
110
+ function App() {
111
+ const [user, setUser] = useState<User>();
112
+ return (
113
+ <UserContext.Provider value={user}>
114
+ <Parent />
115
+ </UserContext.Provider>
116
+ );
117
+ }
118
+
119
+ function GrandChild() {
120
+ const user = useContext(UserContext);
121
+ return <div>{user?.name}</div>;
122
+ }
123
+ ```
124
+
125
+ ### 3. useEffect 의존성 배열 누락
126
+
127
+ ```typescript
128
+ // ❌ 의존성 누락
129
+ function Component({ userId }: { userId: string }) {
130
+ const [user, setUser] = useState<User>();
131
+
132
+ useEffect(() => {
133
+ fetchUser(userId).then(setUser);
134
+ }, []); // userId 의존성 누락!
135
+
136
+ return <div>{user?.name}</div>;
137
+ }
138
+
139
+ // ✅ 모든 의존성 명시
140
+ function Component({ userId }: { userId: string }) {
141
+ const [user, setUser] = useState<User>();
142
+
143
+ useEffect(() => {
144
+ fetchUser(userId).then(setUser);
145
+ }, [userId]); // 의존성 명시
146
+
147
+ return <div>{user?.name}</div>;
148
+ }
149
+ ```
150
+
151
+ ## JavaScript 안티패턴
152
+
153
+ ### 1. var 사용
154
+
155
+ ```typescript
156
+ // ❌ var 사용
157
+ var count = 0;
158
+ if (true) {
159
+ var count = 1; // 같은 변수!
160
+ }
161
+ console.log(count); // 1
162
+
163
+ // ✅ const/let 사용
164
+ let count = 0;
165
+ if (true) {
166
+ let count = 1; // 블록 스코프
167
+ }
168
+ console.log(count); // 0
169
+ ```
170
+
171
+ ### 2. == 사용 (느슨한 비교)
172
+
173
+ ```typescript
174
+ // ❌ == 사용
175
+ if (value == null) { } // undefined도 매칭
176
+ if ('5' == 5) { } // true (타입 강제 변환)
177
+
178
+ // ✅ === 사용
179
+ if (value === null) { }
180
+ if (value === undefined) { }
181
+ if ('5' === 5) { } // false
182
+ ```
183
+
184
+ ### 3. eval() 사용
185
+
186
+ ```typescript
187
+ // ❌ eval() 사용 (보안 위험)
188
+ const code = userInput;
189
+ eval(code); // 임의 코드 실행 가능
190
+
191
+ // ✅ 대안 구현
192
+ const allowedOperations = {
193
+ add: (a: number, b: number) => a + b,
194
+ subtract: (a: number, b: number) => a - b,
195
+ };
196
+
197
+ const operation = allowedOperations[userInput];
198
+ if (operation) {
199
+ result = operation(a, b);
200
+ }
201
+ ```
202
+
203
+ ## CSS 안티패턴
204
+
205
+ ### 1. !important 남용
206
+
207
+ ```css
208
+ /* ❌ !important 남용 */
209
+ .button {
210
+ color: blue !important;
211
+ background: red !important;
212
+ }
213
+
214
+ /* ✅ 구체적인 선택자 사용 */
215
+ .navigation .button.primary {
216
+ color: blue;
217
+ background: red;
218
+ }
219
+ ```
220
+
221
+ ### 2. 인라인 스타일 남용
222
+
223
+ ```typescript
224
+ // ❌ 인라인 스타일
225
+ function Button() {
226
+ return (
227
+ <button
228
+ style={{
229
+ backgroundColor: 'blue',
230
+ color: 'white',
231
+ padding: '10px',
232
+ borderRadius: '5px',
233
+ }}
234
+ >
235
+ Click me
236
+ </button>
237
+ );
238
+ }
239
+
240
+ // ✅ CSS 클래스 사용
241
+ function Button() {
242
+ return <button className="btn-primary">Click me</button>;
243
+ }
244
+
245
+ // styles.css
246
+ .btn-primary {
247
+ background-color: blue;
248
+ color: white;
249
+ padding: 10px;
250
+ border-radius: 5px;
251
+ }
252
+ ```
253
+
254
+ ## 성능 안티패턴
255
+
256
+ ### 1. 불필요한 리렌더링
257
+
258
+ ```typescript
259
+ // ❌ 매번 새 객체/함수 생성
260
+ function Parent() {
261
+ return <Child config={{ theme: 'dark' }} onClick={() => {}} />;
262
+ // 매 렌더마다 새 객체/함수 생성 → Child 리렌더
263
+ }
264
+
265
+ // ✅ useMemo/useCallback 사용
266
+ function Parent() {
267
+ const config = useMemo(() => ({ theme: 'dark' }), []);
268
+ const handleClick = useCallback(() => {}, []);
269
+
270
+ return <Child config={config} onClick={handleClick} />;
271
+ }
272
+ ```
273
+
274
+ ### 2. 동기적 무거운 연산
275
+
276
+ ```typescript
277
+ // ❌ 메인 스레드 블로킹
278
+ function Component({ data }: { data: number[] }) {
279
+ const result = data
280
+ .map(heavyComputation)
281
+ .filter(x => x > 0)
282
+ .reduce((a, b) => a + b);
283
+
284
+ return <div>{result}</div>;
285
+ }
286
+
287
+ // ✅ useMemo로 메모이제이션
288
+ function Component({ data }: { data: number[] }) {
289
+ const result = useMemo(
290
+ () =>
291
+ data
292
+ .map(heavyComputation)
293
+ .filter(x => x > 0)
294
+ .reduce((a, b) => a + b),
295
+ [data]
296
+ );
297
+
298
+ return <div>{result}</div>;
299
+ }
300
+ ```
301
+
302
+ ## 보안 안티패턴
303
+
304
+ ### 1. 민감 정보 하드코딩
305
+
306
+ ```typescript
307
+ // ❌ API 키 하드코딩
308
+ const API_KEY = 'sk-1234567890abcdef';
309
+
310
+ // ✅ 환경 변수 사용
311
+ const API_KEY = process.env.NEXT_PUBLIC_API_KEY;
312
+ ```
313
+
314
+ ### 2. SQL Injection 취약점
315
+
316
+ ```typescript
317
+ // ❌ 직접 문자열 연결
318
+ const query = `SELECT * FROM users WHERE id = ${userId}`;
319
+
320
+ // ✅ 파라미터화된 쿼리
321
+ const query = 'SELECT * FROM users WHERE id = ?';
322
+ db.execute(query, [userId]);
323
+ ```
324
+
325
+ ## 에러 처리 안티패턴
326
+
327
+ ### 1. 빈 catch 블록
328
+
329
+ ```typescript
330
+ // ❌ 에러 무시
331
+ try {
332
+ riskyOperation();
333
+ } catch (e) {
334
+ // 아무것도 안 함
335
+ }
336
+
337
+ // ✅ 적절한 에러 처리
338
+ try {
339
+ riskyOperation();
340
+ } catch (error) {
341
+ console.error('Operation failed:', error);
342
+ showErrorNotification(error);
343
+ trackError(error);
344
+ }
345
+ ```
346
+
347
+ ### 2. 에러 타입 확인 없이 처리
348
+
349
+ ```typescript
350
+ // ❌ 모든 에러 동일하게 처리
351
+ try {
352
+ await fetchData();
353
+ } catch (error) {
354
+ showError('Failed'); // 구체적이지 않음
355
+ }
356
+
357
+ // ✅ 에러 타입별 처리
358
+ try {
359
+ await fetchData();
360
+ } catch (error) {
361
+ if (error instanceof NetworkError) {
362
+ showError('네트워크 연결을 확인해주세요');
363
+ } else if (error instanceof AuthError) {
364
+ redirectToLogin();
365
+ } else {
366
+ showError('알 수 없는 오류가 발생했습니다');
367
+ }
368
+ }
369
+ ```