@su-record/vibe 2.2.2 โ†’ 2.2.3

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 (81) hide show
  1. package/.claude/settings.json +152 -152
  2. package/.claude/vibe/constitution.md +184 -184
  3. package/.claude/vibe/rules/core/communication-guide.md +104 -104
  4. package/.claude/vibe/rules/core/development-philosophy.md +52 -52
  5. package/.claude/vibe/rules/core/quick-start.md +120 -120
  6. package/.claude/vibe/rules/quality/bdd-contract-testing.md +388 -388
  7. package/.claude/vibe/rules/quality/checklist.md +276 -276
  8. package/.claude/vibe/rules/quality/testing-strategy.md +437 -437
  9. package/.claude/vibe/rules/standards/anti-patterns.md +369 -369
  10. package/.claude/vibe/rules/standards/code-structure.md +291 -291
  11. package/.claude/vibe/rules/standards/complexity-metrics.md +312 -312
  12. package/.claude/vibe/rules/standards/naming-conventions.md +198 -198
  13. package/.claude/vibe/setup.sh +31 -31
  14. package/CLAUDE.md +323 -323
  15. package/LICENSE +21 -21
  16. package/README.md +724 -721
  17. package/agents/explorer.md +48 -0
  18. package/agents/implementer.md +53 -0
  19. package/agents/research/best-practices-agent.md +139 -0
  20. package/agents/research/codebase-patterns-agent.md +147 -0
  21. package/agents/research/framework-docs-agent.md +181 -0
  22. package/agents/research/security-advisory-agent.md +167 -0
  23. package/agents/review/architecture-reviewer.md +107 -0
  24. package/agents/review/complexity-reviewer.md +116 -0
  25. package/agents/review/data-integrity-reviewer.md +88 -0
  26. package/agents/review/git-history-reviewer.md +103 -0
  27. package/agents/review/performance-reviewer.md +86 -0
  28. package/agents/review/python-reviewer.md +152 -0
  29. package/agents/review/rails-reviewer.md +139 -0
  30. package/agents/review/react-reviewer.md +144 -0
  31. package/agents/review/security-reviewer.md +80 -0
  32. package/agents/review/simplicity-reviewer.md +140 -0
  33. package/agents/review/test-coverage-reviewer.md +116 -0
  34. package/agents/review/typescript-reviewer.md +127 -0
  35. package/agents/searcher.md +54 -0
  36. package/agents/simplifier.md +119 -0
  37. package/agents/tester.md +49 -0
  38. package/commands/vibe.analyze.md +239 -0
  39. package/commands/vibe.compound.md +261 -0
  40. package/commands/vibe.continue.md +88 -0
  41. package/commands/vibe.diagram.md +178 -0
  42. package/commands/vibe.e2e.md +266 -0
  43. package/commands/vibe.reason.md +306 -0
  44. package/commands/vibe.review.md +324 -0
  45. package/commands/vibe.run.md +836 -0
  46. package/commands/vibe.setup.md +97 -0
  47. package/commands/vibe.spec.md +383 -0
  48. package/commands/vibe.ui.md +137 -0
  49. package/commands/vibe.verify.md +238 -0
  50. package/dist/cli/index.js +389 -389
  51. package/dist/cli/index.js.map +1 -1
  52. package/dist/lib/MemoryManager.js +92 -92
  53. package/dist/lib/PythonParser.js +108 -108
  54. package/dist/lib/gemini-mcp.js +15 -15
  55. package/dist/lib/gemini-oauth.js +35 -35
  56. package/dist/lib/gpt-mcp.js +17 -17
  57. package/dist/lib/gpt-oauth.js +44 -44
  58. package/dist/tools/analytics/getUsageAnalytics.js +12 -12
  59. package/dist/tools/memory/createMemoryTimeline.js +10 -10
  60. package/dist/tools/memory/getMemoryGraph.js +12 -12
  61. package/dist/tools/memory/getSessionContext.js +9 -9
  62. package/dist/tools/memory/linkMemories.js +14 -14
  63. package/dist/tools/memory/listMemories.js +4 -4
  64. package/dist/tools/memory/recallMemory.js +4 -4
  65. package/dist/tools/memory/saveMemory.js +4 -4
  66. package/dist/tools/memory/searchMemoriesAdvanced.js +22 -22
  67. package/dist/tools/planning/generatePrd.js +46 -46
  68. package/dist/tools/prompt/enhancePromptGemini.js +160 -160
  69. package/dist/tools/reasoning/applyReasoningFramework.js +56 -56
  70. package/dist/tools/semantic/analyzeDependencyGraph.js +12 -12
  71. package/package.json +69 -66
  72. package/skills/git-worktree.md +178 -0
  73. package/skills/priority-todos.md +236 -0
  74. package/templates/constitution-template.md +184 -184
  75. package/templates/contract-backend-template.md +517 -517
  76. package/templates/contract-frontend-template.md +594 -594
  77. package/templates/feature-template.md +96 -96
  78. package/templates/hooks-template.json +103 -103
  79. package/templates/spec-template.md +199 -199
  80. package/.claude/vibe/rules/tools/mcp-hi-ai-guide.md +0 -665
  81. package/.claude/vibe/rules/tools/mcp-workflow.md +0 -51
@@ -1,291 +1,291 @@
1
- # ๐Ÿ—๏ธ ์ฝ”๋“œ ๊ตฌ์กฐ ์ž๋™ํ™” ๊ทœ์น™
2
-
3
- ## ์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐ (์—„๊ฒฉํ•œ ์ˆœ์„œ)
4
-
5
- ```typescript
6
- // 1. Import ๋ฌธ
7
- import React, { useState, useEffect } from 'react';
8
-
9
- // 2. ํƒ€์ž…/์ธํ„ฐํŽ˜์ด์Šค ์ •์˜
10
- interface Props {
11
- userId: string;
12
- }
13
-
14
- // 3. ์ปดํฌ๋„ŒํŠธ ์ •์˜
15
- function UserProfile({ userId }: Props) {
16
- // 4. State & Refs
17
- const [user, setUser] = useState<User | null>(null);
18
- const inputRef = useRef<HTMLInputElement>(null);
19
-
20
- // 5. Custom Hooks
21
- const { isAuthenticated } = useAuth();
22
- const { data, loading } = useUserData(userId);
23
-
24
- // 6. Event Handlers
25
- const handleSubmit = (e: FormEvent) => {
26
- e.preventDefault();
27
- // ...
28
- };
29
-
30
- // 7. Effects
31
- useEffect(() => {
32
- // ...
33
- }, [userId]);
34
-
35
- // 8. Early returns
36
- if (loading) return <Spinner />;
37
- if (!user) return <NotFound />;
38
-
39
- // 9. Main return JSX
40
- return (
41
- <div>
42
- {/* ... */}
43
- </div>
44
- );
45
- }
46
- ```
47
-
48
- ## ํ•จ์ˆ˜ ๋ถ„๋ฆฌ ๊ธฐ์ค€
49
-
50
- ### 1. ํ•จ์ˆ˜ ๊ธธ์ด ๊ธฐ์ค€
51
-
52
- ```typescript
53
- // โŒ 20์ค„ ์ดˆ๊ณผ - ๋ถ„๋ฆฌ ํ•„์š”
54
- function processUserData(user: User) {
55
- // 30์ค„์˜ ๋ณต์žกํ•œ ๋กœ์ง
56
- }
57
-
58
- // โœ… ๋‹จ์ผ ์ฑ…์ž„์œผ๋กœ ๋ถ„๋ฆฌ
59
- function processUserData(user: User) {
60
- const validated = validateUser(user);
61
- const transformed = transformUserData(validated);
62
- return saveUserData(transformed);
63
- }
64
-
65
- function validateUser(user: User) { /* ... */ }
66
- function transformUserData(user: User) { /* ... */ }
67
- function saveUserData(user: User) { /* ... */ }
68
- ```
69
-
70
- ### 2. ์ปดํฌ๋„ŒํŠธ JSX ๊ธธ์ด ๊ธฐ์ค€
71
-
72
- ```typescript
73
- // โŒ JSX 50์ค„ ์ดˆ๊ณผ - ๋ถ„๋ฆฌ ํ•„์š”
74
- function Dashboard() {
75
- return (
76
- <div>
77
- {/* 60์ค„์˜ ๋ณต์žกํ•œ JSX */}
78
- </div>
79
- );
80
- }
81
-
82
- // โœ… ์„œ๋ธŒ ์ปดํฌ๋„ŒํŠธ ์ถ”์ถœ
83
- function Dashboard() {
84
- return (
85
- <div>
86
- <DashboardHeader />
87
- <DashboardContent />
88
- <DashboardFooter />
89
- </div>
90
- );
91
- }
92
-
93
- function DashboardHeader() { /* ... */ }
94
- function DashboardContent() { /* ... */ }
95
- function DashboardFooter() { /* ... */ }
96
- ```
97
-
98
- ### 3. ์ค‘์ฒฉ ๊นŠ์ด ๊ธฐ์ค€
99
-
100
- ```typescript
101
- // โŒ ์ค‘์ฒฉ 3๋‹จ๊ณ„ ์ดˆ๊ณผ
102
- function processData(data: Data) {
103
- if (data) {
104
- if (data.isValid) {
105
- if (data.user) {
106
- if (data.user.isActive) {
107
- // ๋„ˆ๋ฌด ๊นŠ์€ ์ค‘์ฒฉ
108
- }
109
- }
110
- }
111
- }
112
- }
113
-
114
- // โœ… Early return์œผ๋กœ ํ‰ํƒ„ํ™”
115
- function processData(data: Data) {
116
- if (!data) return null;
117
- if (!data.isValid) return null;
118
- if (!data.user) return null;
119
- if (!data.user.isActive) return null;
120
-
121
- // ๋กœ์ง ์‹คํ–‰
122
- }
123
- ```
124
-
125
- ### 4. Cyclomatic Complexity > 10
126
-
127
- ```typescript
128
- // โŒ ๋ณต์žก๋„ ๋†’์Œ (15)
129
- function calculatePrice(item: Item) {
130
- let price = item.basePrice;
131
- if (item.discount) price *= 0.9;
132
- if (item.bulk) price *= 0.8;
133
- if (item.seasonal) price *= 0.95;
134
- if (item.member) price *= 0.85;
135
- if (item.firstTime) price *= 0.9;
136
- // ... ๋” ๋งŽ์€ ์กฐ๊ฑด
137
- return price;
138
- }
139
-
140
- // โœ… ๋ณต์žก๋„ ๊ฐ์†Œ (3)
141
- function calculatePrice(item: Item) {
142
- const basePrice = item.basePrice;
143
- const discounts = getApplicableDiscounts(item);
144
- return applyDiscounts(basePrice, discounts);
145
- }
146
- ```
147
-
148
- ### 5. Cognitive Complexity > 15
149
-
150
- ```typescript
151
- // โŒ ์ธ์ง€ ๋ณต์žก๋„ ๋†’์Œ
152
- function processOrder(order: Order) {
153
- if (order.isPremium) {
154
- for (let item of order.items) {
155
- if (item.category === 'electronics') {
156
- if (item.price > 1000) {
157
- // ์ค‘์ฒฉ๋œ ๋ณต์žกํ•œ ๋กœ์ง
158
- }
159
- }
160
- }
161
- }
162
- }
163
-
164
- // โœ… ์ธ์ง€ ๋ณต์žก๋„ ๊ฐ์†Œ
165
- function processOrder(order: Order) {
166
- if (!order.isPremium) return;
167
-
168
- const electronics = filterElectronics(order.items);
169
- const expensive = filterExpensive(electronics);
170
-
171
- processItems(expensive);
172
- }
173
- ```
174
-
175
- ## ํŒŒ์ผ ๊ตฌ์กฐ ํ‘œ์ค€
176
-
177
- ```typescript
178
- // ๐Ÿ“ user-profile.component.tsx
179
-
180
- // 1. Imports
181
- import { ... } from 'react';
182
- import { ... } from '@/lib';
183
-
184
- // 2. Types
185
- interface UserProfileProps { }
186
- type UserRole = 'admin' | 'user';
187
-
188
- // 3. Constants
189
- const MAX_BIO_LENGTH = 500;
190
- const DEFAULT_AVATAR = '/avatar.png';
191
-
192
- // 4. Helper Functions (๋‚ด๋ถ€ ์ „์šฉ)
193
- function formatUserName(name: string) { }
194
-
195
- // 5. Main Component
196
- export function UserProfile() { }
197
-
198
- // 6. Sub Components (exportํ•˜์ง€ ์•Š์Œ)
199
- function ProfileHeader() { }
200
- function ProfileContent() { }
201
- ```
202
-
203
- ## ๋ชจ๋“ˆ ๊ตฌ์„ฑ ์›์น™
204
-
205
- ### 1. ์‘์ง‘๋„ (Cohesion)
206
-
207
- ```typescript
208
- // โœ… ๋†’์€ ์‘์ง‘๋„ - ๊ด€๋ จ ๊ธฐ๋Šฅ๋งŒ ๋ชจ์Œ
209
- // ๐Ÿ“ user.service.ts
210
- export class UserService {
211
- getUser(id: string) { }
212
- updateUser(id: string, data: User) { }
213
- deleteUser(id: string) { }
214
- }
215
-
216
- // โŒ ๋‚ฎ์€ ์‘์ง‘๋„ - ๊ด€๋ จ ์—†๋Š” ๊ธฐ๋Šฅ ํ˜ผ์žฌ
217
- // ๐Ÿ“ utils.ts (์•ˆํ‹ฐํŒจํ„ด)
218
- export class Utils {
219
- validateEmail(email: string) { }
220
- formatCurrency(amount: number) { }
221
- uploadFile(file: File) { }
222
- }
223
- ```
224
-
225
- ### 2. ๊ฒฐํ•ฉ๋„ (Coupling)
226
-
227
- ```typescript
228
- // โœ… ๋А์Šจํ•œ ๊ฒฐํ•ฉ - ์ธํ„ฐํŽ˜์ด์Šค ์˜์กด
229
- interface Storage {
230
- save(key: string, value: unknown): void;
231
- load(key: string): unknown;
232
- }
233
-
234
- class UserService {
235
- constructor(private storage: Storage) { }
236
- }
237
-
238
- // โŒ ๊ฐ•ํ•œ ๊ฒฐํ•ฉ - ๊ตฌํ˜„์ฒด ์ง์ ‘ ์˜์กด
239
- class UserService {
240
- private storage = new LocalStorage(); // ์ง์ ‘ ์˜์กด
241
- }
242
- ```
243
-
244
- ## ํ•จ์ˆ˜ ๋งค๊ฐœ๋ณ€์ˆ˜ ์ œํ•œ
245
-
246
- ```typescript
247
- // โŒ ๋งค๊ฐœ๋ณ€์ˆ˜ 5๊ฐœ ์ดˆ๊ณผ
248
- function createUser(
249
- name: string,
250
- email: string,
251
- age: number,
252
- address: string,
253
- phone: string,
254
- role: string
255
- ) { }
256
-
257
- // โœ… ๊ฐ์ฒด๋กœ ๊ทธ๋ฃนํ™”
258
- interface CreateUserParams {
259
- name: string;
260
- email: string;
261
- age: number;
262
- address: string;
263
- phone: string;
264
- role: string;
265
- }
266
-
267
- function createUser(params: CreateUserParams) { }
268
- ```
269
-
270
- ## ์ˆœํ™˜ ์˜์กด์„ฑ ๋ฐฉ์ง€
271
-
272
- ```typescript
273
- // โŒ ์ˆœํ™˜ ์˜์กด์„ฑ
274
- // fileA.ts
275
- import { funcB } from './fileB';
276
- export function funcA() { funcB(); }
277
-
278
- // fileB.ts
279
- import { funcA } from './fileA'; // ์ˆœํ™˜!
280
- export function funcB() { funcA(); }
281
-
282
- // โœ… ๊ณตํ†ต ๋ชจ๋“ˆ ๋ถ„๋ฆฌ
283
- // shared.ts
284
- export function sharedFunc() { }
285
-
286
- // fileA.ts
287
- import { sharedFunc } from './shared';
288
-
289
- // fileB.ts
290
- import { sharedFunc } from './shared';
291
- ```
1
+ # ๐Ÿ—๏ธ ์ฝ”๋“œ ๊ตฌ์กฐ ์ž๋™ํ™” ๊ทœ์น™
2
+
3
+ ## ์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐ (์—„๊ฒฉํ•œ ์ˆœ์„œ)
4
+
5
+ ```typescript
6
+ // 1. Import ๋ฌธ
7
+ import React, { useState, useEffect } from 'react';
8
+
9
+ // 2. ํƒ€์ž…/์ธํ„ฐํŽ˜์ด์Šค ์ •์˜
10
+ interface Props {
11
+ userId: string;
12
+ }
13
+
14
+ // 3. ์ปดํฌ๋„ŒํŠธ ์ •์˜
15
+ function UserProfile({ userId }: Props) {
16
+ // 4. State & Refs
17
+ const [user, setUser] = useState<User | null>(null);
18
+ const inputRef = useRef<HTMLInputElement>(null);
19
+
20
+ // 5. Custom Hooks
21
+ const { isAuthenticated } = useAuth();
22
+ const { data, loading } = useUserData(userId);
23
+
24
+ // 6. Event Handlers
25
+ const handleSubmit = (e: FormEvent) => {
26
+ e.preventDefault();
27
+ // ...
28
+ };
29
+
30
+ // 7. Effects
31
+ useEffect(() => {
32
+ // ...
33
+ }, [userId]);
34
+
35
+ // 8. Early returns
36
+ if (loading) return <Spinner />;
37
+ if (!user) return <NotFound />;
38
+
39
+ // 9. Main return JSX
40
+ return (
41
+ <div>
42
+ {/* ... */}
43
+ </div>
44
+ );
45
+ }
46
+ ```
47
+
48
+ ## ํ•จ์ˆ˜ ๋ถ„๋ฆฌ ๊ธฐ์ค€
49
+
50
+ ### 1. ํ•จ์ˆ˜ ๊ธธ์ด ๊ธฐ์ค€
51
+
52
+ ```typescript
53
+ // โŒ 20์ค„ ์ดˆ๊ณผ - ๋ถ„๋ฆฌ ํ•„์š”
54
+ function processUserData(user: User) {
55
+ // 30์ค„์˜ ๋ณต์žกํ•œ ๋กœ์ง
56
+ }
57
+
58
+ // โœ… ๋‹จ์ผ ์ฑ…์ž„์œผ๋กœ ๋ถ„๋ฆฌ
59
+ function processUserData(user: User) {
60
+ const validated = validateUser(user);
61
+ const transformed = transformUserData(validated);
62
+ return saveUserData(transformed);
63
+ }
64
+
65
+ function validateUser(user: User) { /* ... */ }
66
+ function transformUserData(user: User) { /* ... */ }
67
+ function saveUserData(user: User) { /* ... */ }
68
+ ```
69
+
70
+ ### 2. ์ปดํฌ๋„ŒํŠธ JSX ๊ธธ์ด ๊ธฐ์ค€
71
+
72
+ ```typescript
73
+ // โŒ JSX 50์ค„ ์ดˆ๊ณผ - ๋ถ„๋ฆฌ ํ•„์š”
74
+ function Dashboard() {
75
+ return (
76
+ <div>
77
+ {/* 60์ค„์˜ ๋ณต์žกํ•œ JSX */}
78
+ </div>
79
+ );
80
+ }
81
+
82
+ // โœ… ์„œ๋ธŒ ์ปดํฌ๋„ŒํŠธ ์ถ”์ถœ
83
+ function Dashboard() {
84
+ return (
85
+ <div>
86
+ <DashboardHeader />
87
+ <DashboardContent />
88
+ <DashboardFooter />
89
+ </div>
90
+ );
91
+ }
92
+
93
+ function DashboardHeader() { /* ... */ }
94
+ function DashboardContent() { /* ... */ }
95
+ function DashboardFooter() { /* ... */ }
96
+ ```
97
+
98
+ ### 3. ์ค‘์ฒฉ ๊นŠ์ด ๊ธฐ์ค€
99
+
100
+ ```typescript
101
+ // โŒ ์ค‘์ฒฉ 3๋‹จ๊ณ„ ์ดˆ๊ณผ
102
+ function processData(data: Data) {
103
+ if (data) {
104
+ if (data.isValid) {
105
+ if (data.user) {
106
+ if (data.user.isActive) {
107
+ // ๋„ˆ๋ฌด ๊นŠ์€ ์ค‘์ฒฉ
108
+ }
109
+ }
110
+ }
111
+ }
112
+ }
113
+
114
+ // โœ… Early return์œผ๋กœ ํ‰ํƒ„ํ™”
115
+ function processData(data: Data) {
116
+ if (!data) return null;
117
+ if (!data.isValid) return null;
118
+ if (!data.user) return null;
119
+ if (!data.user.isActive) return null;
120
+
121
+ // ๋กœ์ง ์‹คํ–‰
122
+ }
123
+ ```
124
+
125
+ ### 4. Cyclomatic Complexity > 10
126
+
127
+ ```typescript
128
+ // โŒ ๋ณต์žก๋„ ๋†’์Œ (15)
129
+ function calculatePrice(item: Item) {
130
+ let price = item.basePrice;
131
+ if (item.discount) price *= 0.9;
132
+ if (item.bulk) price *= 0.8;
133
+ if (item.seasonal) price *= 0.95;
134
+ if (item.member) price *= 0.85;
135
+ if (item.firstTime) price *= 0.9;
136
+ // ... ๋” ๋งŽ์€ ์กฐ๊ฑด
137
+ return price;
138
+ }
139
+
140
+ // โœ… ๋ณต์žก๋„ ๊ฐ์†Œ (3)
141
+ function calculatePrice(item: Item) {
142
+ const basePrice = item.basePrice;
143
+ const discounts = getApplicableDiscounts(item);
144
+ return applyDiscounts(basePrice, discounts);
145
+ }
146
+ ```
147
+
148
+ ### 5. Cognitive Complexity > 15
149
+
150
+ ```typescript
151
+ // โŒ ์ธ์ง€ ๋ณต์žก๋„ ๋†’์Œ
152
+ function processOrder(order: Order) {
153
+ if (order.isPremium) {
154
+ for (let item of order.items) {
155
+ if (item.category === 'electronics') {
156
+ if (item.price > 1000) {
157
+ // ์ค‘์ฒฉ๋œ ๋ณต์žกํ•œ ๋กœ์ง
158
+ }
159
+ }
160
+ }
161
+ }
162
+ }
163
+
164
+ // โœ… ์ธ์ง€ ๋ณต์žก๋„ ๊ฐ์†Œ
165
+ function processOrder(order: Order) {
166
+ if (!order.isPremium) return;
167
+
168
+ const electronics = filterElectronics(order.items);
169
+ const expensive = filterExpensive(electronics);
170
+
171
+ processItems(expensive);
172
+ }
173
+ ```
174
+
175
+ ## ํŒŒ์ผ ๊ตฌ์กฐ ํ‘œ์ค€
176
+
177
+ ```typescript
178
+ // ๐Ÿ“ user-profile.component.tsx
179
+
180
+ // 1. Imports
181
+ import { ... } from 'react';
182
+ import { ... } from '@/lib';
183
+
184
+ // 2. Types
185
+ interface UserProfileProps { }
186
+ type UserRole = 'admin' | 'user';
187
+
188
+ // 3. Constants
189
+ const MAX_BIO_LENGTH = 500;
190
+ const DEFAULT_AVATAR = '/avatar.png';
191
+
192
+ // 4. Helper Functions (๋‚ด๋ถ€ ์ „์šฉ)
193
+ function formatUserName(name: string) { }
194
+
195
+ // 5. Main Component
196
+ export function UserProfile() { }
197
+
198
+ // 6. Sub Components (exportํ•˜์ง€ ์•Š์Œ)
199
+ function ProfileHeader() { }
200
+ function ProfileContent() { }
201
+ ```
202
+
203
+ ## ๋ชจ๋“ˆ ๊ตฌ์„ฑ ์›์น™
204
+
205
+ ### 1. ์‘์ง‘๋„ (Cohesion)
206
+
207
+ ```typescript
208
+ // โœ… ๋†’์€ ์‘์ง‘๋„ - ๊ด€๋ จ ๊ธฐ๋Šฅ๋งŒ ๋ชจ์Œ
209
+ // ๐Ÿ“ user.service.ts
210
+ export class UserService {
211
+ getUser(id: string) { }
212
+ updateUser(id: string, data: User) { }
213
+ deleteUser(id: string) { }
214
+ }
215
+
216
+ // โŒ ๋‚ฎ์€ ์‘์ง‘๋„ - ๊ด€๋ จ ์—†๋Š” ๊ธฐ๋Šฅ ํ˜ผ์žฌ
217
+ // ๐Ÿ“ utils.ts (์•ˆํ‹ฐํŒจํ„ด)
218
+ export class Utils {
219
+ validateEmail(email: string) { }
220
+ formatCurrency(amount: number) { }
221
+ uploadFile(file: File) { }
222
+ }
223
+ ```
224
+
225
+ ### 2. ๊ฒฐํ•ฉ๋„ (Coupling)
226
+
227
+ ```typescript
228
+ // โœ… ๋А์Šจํ•œ ๊ฒฐํ•ฉ - ์ธํ„ฐํŽ˜์ด์Šค ์˜์กด
229
+ interface Storage {
230
+ save(key: string, value: unknown): void;
231
+ load(key: string): unknown;
232
+ }
233
+
234
+ class UserService {
235
+ constructor(private storage: Storage) { }
236
+ }
237
+
238
+ // โŒ ๊ฐ•ํ•œ ๊ฒฐํ•ฉ - ๊ตฌํ˜„์ฒด ์ง์ ‘ ์˜์กด
239
+ class UserService {
240
+ private storage = new LocalStorage(); // ์ง์ ‘ ์˜์กด
241
+ }
242
+ ```
243
+
244
+ ## ํ•จ์ˆ˜ ๋งค๊ฐœ๋ณ€์ˆ˜ ์ œํ•œ
245
+
246
+ ```typescript
247
+ // โŒ ๋งค๊ฐœ๋ณ€์ˆ˜ 5๊ฐœ ์ดˆ๊ณผ
248
+ function createUser(
249
+ name: string,
250
+ email: string,
251
+ age: number,
252
+ address: string,
253
+ phone: string,
254
+ role: string
255
+ ) { }
256
+
257
+ // โœ… ๊ฐ์ฒด๋กœ ๊ทธ๋ฃนํ™”
258
+ interface CreateUserParams {
259
+ name: string;
260
+ email: string;
261
+ age: number;
262
+ address: string;
263
+ phone: string;
264
+ role: string;
265
+ }
266
+
267
+ function createUser(params: CreateUserParams) { }
268
+ ```
269
+
270
+ ## ์ˆœํ™˜ ์˜์กด์„ฑ ๋ฐฉ์ง€
271
+
272
+ ```typescript
273
+ // โŒ ์ˆœํ™˜ ์˜์กด์„ฑ
274
+ // fileA.ts
275
+ import { funcB } from './fileB';
276
+ export function funcA() { funcB(); }
277
+
278
+ // fileB.ts
279
+ import { funcA } from './fileA'; // ์ˆœํ™˜!
280
+ export function funcB() { funcA(); }
281
+
282
+ // โœ… ๊ณตํ†ต ๋ชจ๋“ˆ ๋ถ„๋ฆฌ
283
+ // shared.ts
284
+ export function sharedFunc() { }
285
+
286
+ // fileA.ts
287
+ import { sharedFunc } from './shared';
288
+
289
+ // fileB.ts
290
+ import { sharedFunc } from './shared';
291
+ ```