@aicgen/aicgen 1.0.0-beta.1 → 1.0.0-beta.2

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 (136) hide show
  1. package/.vs/ProjectSettings.json +2 -2
  2. package/.vs/VSWorkspaceState.json +15 -15
  3. package/.vs/aicgen.slnx/v18/DocumentLayout.json +53 -53
  4. package/assets/icon.svg +33 -33
  5. package/bun.lock +0 -43
  6. package/data/architecture/microservices/api-gateway.md +56 -56
  7. package/data/devops/observability.md +73 -73
  8. package/dist/index.js +9299 -9299
  9. package/package.json +2 -2
  10. package/.claude/agents/architecture-reviewer.md +0 -88
  11. package/.claude/agents/guideline-checker.md +0 -73
  12. package/.claude/agents/security-auditor.md +0 -108
  13. package/.claude/guidelines/api-design.md +0 -645
  14. package/.claude/guidelines/architecture.md +0 -2503
  15. package/.claude/guidelines/best-practices.md +0 -618
  16. package/.claude/guidelines/code-style.md +0 -304
  17. package/.claude/guidelines/design-patterns.md +0 -573
  18. package/.claude/guidelines/devops.md +0 -226
  19. package/.claude/guidelines/error-handling.md +0 -413
  20. package/.claude/guidelines/language.md +0 -782
  21. package/.claude/guidelines/performance.md +0 -706
  22. package/.claude/guidelines/security.md +0 -583
  23. package/.claude/guidelines/testing.md +0 -568
  24. package/.claude/settings.json +0 -98
  25. package/.claude/settings.local.json +0 -8
  26. package/.eslintrc.json +0 -28
  27. package/.github/workflows/release.yml +0 -180
  28. package/.github/workflows/test.yml +0 -81
  29. package/CONTRIBUTING.md +0 -821
  30. package/dist/commands/init.d.ts +0 -8
  31. package/dist/commands/init.d.ts.map +0 -1
  32. package/dist/commands/init.js +0 -46
  33. package/dist/commands/init.js.map +0 -1
  34. package/dist/config/profiles.d.ts +0 -4
  35. package/dist/config/profiles.d.ts.map +0 -1
  36. package/dist/config/profiles.js +0 -30
  37. package/dist/config/profiles.js.map +0 -1
  38. package/dist/config/settings.d.ts +0 -7
  39. package/dist/config/settings.d.ts.map +0 -1
  40. package/dist/config/settings.js +0 -7
  41. package/dist/config/settings.js.map +0 -1
  42. package/dist/index.d.ts +0 -3
  43. package/dist/index.d.ts.map +0 -1
  44. package/dist/index.js.map +0 -1
  45. package/dist/models/guideline.d.ts +0 -15
  46. package/dist/models/guideline.d.ts.map +0 -1
  47. package/dist/models/guideline.js +0 -2
  48. package/dist/models/guideline.js.map +0 -1
  49. package/dist/models/preference.d.ts +0 -9
  50. package/dist/models/preference.d.ts.map +0 -1
  51. package/dist/models/preference.js +0 -2
  52. package/dist/models/preference.js.map +0 -1
  53. package/dist/models/profile.d.ts +0 -9
  54. package/dist/models/profile.d.ts.map +0 -1
  55. package/dist/models/profile.js +0 -2
  56. package/dist/models/profile.js.map +0 -1
  57. package/dist/models/project.d.ts +0 -13
  58. package/dist/models/project.d.ts.map +0 -1
  59. package/dist/models/project.js +0 -2
  60. package/dist/models/project.js.map +0 -1
  61. package/dist/services/ai/anthropic.d.ts +0 -7
  62. package/dist/services/ai/anthropic.d.ts.map +0 -1
  63. package/dist/services/ai/anthropic.js +0 -39
  64. package/dist/services/ai/anthropic.js.map +0 -1
  65. package/dist/services/generator.d.ts +0 -2
  66. package/dist/services/generator.d.ts.map +0 -1
  67. package/dist/services/generator.js +0 -4
  68. package/dist/services/generator.js.map +0 -1
  69. package/dist/services/learner.d.ts +0 -2
  70. package/dist/services/learner.d.ts.map +0 -1
  71. package/dist/services/learner.js +0 -4
  72. package/dist/services/learner.js.map +0 -1
  73. package/dist/services/scanner.d.ts +0 -3
  74. package/dist/services/scanner.d.ts.map +0 -1
  75. package/dist/services/scanner.js +0 -54
  76. package/dist/services/scanner.js.map +0 -1
  77. package/dist/utils/errors.d.ts +0 -15
  78. package/dist/utils/errors.d.ts.map +0 -1
  79. package/dist/utils/errors.js +0 -27
  80. package/dist/utils/errors.js.map +0 -1
  81. package/dist/utils/file.d.ts +0 -7
  82. package/dist/utils/file.d.ts.map +0 -1
  83. package/dist/utils/file.js +0 -32
  84. package/dist/utils/file.js.map +0 -1
  85. package/dist/utils/logger.d.ts +0 -6
  86. package/dist/utils/logger.d.ts.map +0 -1
  87. package/dist/utils/logger.js +0 -17
  88. package/dist/utils/logger.js.map +0 -1
  89. package/dist/utils/path.d.ts +0 -6
  90. package/dist/utils/path.d.ts.map +0 -1
  91. package/dist/utils/path.js +0 -14
  92. package/dist/utils/path.js.map +0 -1
  93. package/docs/planning/memory-lane.md +0 -83
  94. package/packaging/linux/aicgen.spec +0 -23
  95. package/packaging/linux/control +0 -9
  96. package/packaging/macos/scripts/postinstall +0 -12
  97. package/packaging/windows/setup.nsi +0 -92
  98. package/scripts/add-categories.ts +0 -87
  99. package/scripts/build-binary.ts +0 -46
  100. package/scripts/embed-data.ts +0 -105
  101. package/scripts/generate-version.ts +0 -150
  102. package/scripts/test-decompress.ts +0 -27
  103. package/scripts/test-extract.ts +0 -31
  104. package/src/__tests__/services/assistant-file-writer.test.ts +0 -400
  105. package/src/__tests__/services/guideline-loader.test.ts +0 -281
  106. package/src/__tests__/services/tarball-extraction.test.ts +0 -125
  107. package/src/commands/add-guideline.ts +0 -296
  108. package/src/commands/clear.ts +0 -61
  109. package/src/commands/guideline-selector.ts +0 -123
  110. package/src/commands/init.ts +0 -645
  111. package/src/commands/quick-add.ts +0 -586
  112. package/src/commands/remove-guideline.ts +0 -152
  113. package/src/commands/stats.ts +0 -49
  114. package/src/commands/update.ts +0 -240
  115. package/src/config.ts +0 -82
  116. package/src/embedded-data.ts +0 -1492
  117. package/src/index.ts +0 -67
  118. package/src/models/profile.ts +0 -24
  119. package/src/models/project.ts +0 -43
  120. package/src/services/assistant-file-writer.ts +0 -612
  121. package/src/services/config-generator.ts +0 -150
  122. package/src/services/config-manager.ts +0 -70
  123. package/src/services/data-source.ts +0 -248
  124. package/src/services/first-run-init.ts +0 -148
  125. package/src/services/guideline-loader.ts +0 -311
  126. package/src/services/hook-generator.ts +0 -178
  127. package/src/services/subagent-generator.ts +0 -310
  128. package/src/utils/banner.ts +0 -66
  129. package/src/utils/errors.ts +0 -27
  130. package/src/utils/file.ts +0 -67
  131. package/src/utils/formatting.ts +0 -172
  132. package/src/utils/logger.ts +0 -89
  133. package/src/utils/path.ts +0 -17
  134. package/src/utils/wizard-state.ts +0 -132
  135. package/tsconfig.json +0 -25
  136. /package/{CLAUDE.md → claude.md} +0 -0
@@ -1,706 +0,0 @@
1
- # Performance
2
-
3
- # Performance Basics
4
-
5
- ## Choose the Right Data Structure
6
-
7
- Different data structures have different speeds for different operations.
8
-
9
- ### Arrays vs Objects vs Maps
10
-
11
- ```pseudocode
12
- // ❌ Slow: Looking up in array (O(n))
13
- users = [
14
- { id: 1, name: 'Alice' },
15
- { id: 2, name: 'Bob' },
16
- // ... 1000 more
17
- ]
18
- user = users.find(u => u.id == 500) // Checks 500 items
19
-
20
- // ✅ Fast: Looking up in Map (O(1))
21
- users = Map()
22
- users.set(1, { id: 1, name: 'Alice' })
23
- users.set(2, { id: 2, name: 'Bob' })
24
-
25
- user = users.get(500) // Instant lookup
26
- ```
27
-
28
- ### Arrays vs Sets
29
-
30
- ```pseudocode
31
- // ❌ Slow: Checking if item exists in array
32
- items = [1, 2, 3, 4, 5, ... 1000 more]
33
- if items.contains(500): // Checks every item
34
-
35
- // ✅ Fast: Checking if item exists in Set
36
- items = Set([1, 2, 3, 4, 5, ... 1000 more])
37
- if items.has(500): // Instant check
38
- ```
39
-
40
- ### When to Use Each
41
-
42
- | Data Structure | Good For |
43
- |----------------|----------|
44
- | **Array/List** | Ordered items, iteration |
45
- | **Object/Dict** | Key-value pairs (string keys) |
46
- | **Map** | Key-value pairs (any type keys), frequent lookups |
47
- | **Set** | Unique values, membership checks |
48
-
49
- ## Avoid N+1 Queries
50
-
51
- One of the most common performance problems.
52
-
53
- ```pseudocode
54
- // ❌ BAD: N+1 queries (1 + N database calls)
55
- orders = database.query("SELECT * FROM orders")
56
-
57
- for each order in orders:
58
- // Separate query for EACH order! 😱
59
- customer = database.query(
60
- "SELECT * FROM customers WHERE id = ?",
61
- [order.customer_id]
62
- )
63
- order.customer = customer
64
- // If 100 orders = 101 database calls!
65
-
66
- // ✅ GOOD: Single query with JOIN
67
- ordersWithCustomers = database.query("
68
- SELECT
69
- orders.*,
70
- customers.name as customer_name,
71
- customers.email as customer_email
72
- FROM orders
73
- JOIN customers ON orders.customer_id = customers.id
74
- ")
75
- // Only 1 database call!
76
- ```
77
-
78
- ## Don't Load What You Don't Need
79
-
80
- ```pseudocode
81
- // ❌ Bad: Fetching entire object when you only need one field
82
- user = database.query("SELECT * FROM users WHERE id = ?", [id])
83
- print(user.email)
84
-
85
- // ✅ Good: Fetch only what you need
86
- result = database.query(
87
- "SELECT email FROM users WHERE id = ?",
88
- [id]
89
- )
90
- print(result.email)
91
-
92
- // ❌ Bad: Loading all records
93
- users = database.query("SELECT * FROM users")
94
-
95
- // ✅ Good: Add LIMIT
96
- users = database.query("SELECT * FROM users LIMIT 100")
97
- ```
98
-
99
- ## Use Async for I/O Operations
100
-
101
- Don't block the program waiting for slow operations.
102
-
103
- ```pseudocode
104
- // ❌ Slow: Blocking operations (synchronous)
105
- file1 = readFileSync("file1.txt")
106
- file2 = readFileSync("file2.txt")
107
- file3 = readFileSync("file3.txt")
108
- // Total: 300ms (100ms each, one after another)
109
-
110
- // ✅ Fast: Async operations (parallel)
111
- files = await Promise.all([
112
- readFile("file1.txt"),
113
- readFile("file2.txt"),
114
- readFile("file3.txt")
115
- ])
116
- // Total: 100ms (all at once)
117
- ```
118
-
119
- ## Avoid Unnecessary Work in Loops
120
-
121
- ```pseudocode
122
- // ❌ Bad: Work done every iteration
123
- for i in 0 to items.length:
124
- total = calculateTotal(items) // Recalculated each time!
125
- if items[i].price > total * 0.1:
126
- // ...
127
-
128
- // ✅ Good: Work done once
129
- total = calculateTotal(items)
130
- for i in 0 to items.length:
131
- if items[i].price > total * 0.1:
132
- // ...
133
-
134
- // ❌ Bad: Array length calculated each time
135
- for i in 0 to items.length:
136
- // ...
137
-
138
- // ✅ Good: Length cached (minor improvement)
139
- len = items.length
140
- for i in 0 to len:
141
- // ...
142
-
143
- // ✅ Best: Modern for-each loop
144
- for each item in items:
145
- // ...
146
- ```
147
-
148
- ## Index Your Database
149
-
150
- Indexes make lookups fast, but slow down writes.
151
-
152
- ```sql
153
- -- Without index: Checks every row
154
- SELECT * FROM users WHERE email = 'alice@example.com';
155
- -- With 1 million users: ~1 second
156
-
157
- -- Add index
158
- CREATE INDEX idx_users_email ON users(email);
159
-
160
- -- Now same query is instant
161
- SELECT * FROM users WHERE email = 'alice@example.com';
162
- -- With 1 million users: ~1 millisecond
163
- ```
164
-
165
- ### When to Add Indexes
166
-
167
- - Columns used in WHERE clauses
168
- - Columns used in JOIN conditions
169
- - Columns used in ORDER BY
170
-
171
- ```sql
172
- -- Frequently queried
173
- CREATE INDEX idx_orders_status ON orders(status);
174
- CREATE INDEX idx_users_email ON users(email);
175
-
176
- -- Used in joins
177
- CREATE INDEX idx_orders_customer_id ON orders(customer_id);
178
- ```
179
-
180
- ## Cache Expensive Results
181
-
182
- Don't recalculate the same thing repeatedly.
183
-
184
- ```pseudocode
185
- // ❌ Bad: Calculating every time
186
- function getReport(userId):
187
- data = expensiveCalculation(userId) // 5 seconds
188
- return data
189
-
190
- // Called 100 times = 500 seconds!
191
-
192
- // ✅ Good: Cache results
193
- cache = Map()
194
-
195
- function getReport(userId):
196
- if cache.has(userId):
197
- return cache.get(userId) // Instant
198
-
199
- data = expensiveCalculation(userId)
200
- cache.set(userId, data)
201
- return data
202
-
203
- // First call: 5 seconds, next 99 calls: instant
204
- ```
205
-
206
- ## Batch Operations
207
-
208
- Process multiple items together instead of one at a time.
209
-
210
- ```pseudocode
211
- // ❌ Bad: Individual database calls
212
- for each user in users:
213
- database.execute("INSERT INTO users (name) VALUES (?)", [user.name])
214
- // 100 users = 100 database calls
215
-
216
- // ✅ Good: Batch insert
217
- database.execute("
218
- INSERT INTO users (name)
219
- VALUES " + users.map(u => "(?)").join(", "),
220
- users.map(u => u.name)
221
- )
222
- // 100 users = 1 database call
223
- ```
224
-
225
- ## Profile Before Optimizing
226
-
227
- Don't guess where the problem is - measure!
228
-
229
- ```pseudocode
230
- // Measure execution time
231
- startTime = currentTime()
232
- result = await slowOperation()
233
- endTime = currentTime()
234
- print("Operation took:", endTime - startTime, "ms")
235
-
236
- // Measure specific parts
237
- startDB = currentTime()
238
- data = await database.query("...")
239
- print("Database:", currentTime() - startDB, "ms")
240
-
241
- startProcess = currentTime()
242
- processed = processData(data)
243
- print("Processing:", currentTime() - startProcess, "ms")
244
- ```
245
-
246
- ## Common Performance Mistakes
247
-
248
- ### Mistake 1: Nested Loops with Database Queries
249
-
250
- ```pseudocode
251
- // ❌ TERRIBLE: Nested queries
252
- for each user in users:
253
- for each order in orders:
254
- product = await database.query(
255
- "SELECT * FROM products WHERE id = ?",
256
- [order.product_id]
257
- )
258
- // 100 users × 50 orders = 5000 database calls!
259
-
260
- // ✅ GOOD: Load all data first
261
- products = await database.query("SELECT * FROM products")
262
- productMap = Map()
263
- for each p in products:
264
- productMap.set(p.id, p)
265
-
266
- for each user in users:
267
- for each order in orders:
268
- product = productMap.get(order.product_id) // Instant
269
- ```
270
-
271
- ### Mistake 2: Loading Everything into Memory
272
-
273
- ```pseudocode
274
- // ❌ Bad: Loading 1 million records
275
- allUsers = await database.query("SELECT * FROM users")
276
- // Crashes with out of memory!
277
-
278
- // ✅ Good: Process in batches
279
- BATCH_SIZE = 1000
280
- offset = 0
281
-
282
- while true:
283
- users = await database.query(
284
- "SELECT * FROM users LIMIT ? OFFSET ?",
285
- [BATCH_SIZE, offset]
286
- )
287
-
288
- if users.length == 0:
289
- break
290
-
291
- await processUsers(users)
292
- offset = offset + BATCH_SIZE
293
- ```
294
-
295
- ### Mistake 3: Not Using Indexes
296
-
297
- ```sql
298
- -- ❌ Slow: No index on email column
299
- SELECT * FROM users WHERE email = 'alice@example.com';
300
- -- 1 million rows: ~2 seconds
301
-
302
- -- ✅ Fast: Add index
303
- CREATE INDEX idx_users_email ON users(email);
304
- -- Same query: ~2 milliseconds
305
- ```
306
-
307
- ## Quick Performance Checklist
308
-
309
- - [ ] Use Map/Set for lookups instead of Array
310
- - [ ] Avoid N+1 queries (use JOINs)
311
- - [ ] Add database indexes on frequently queried columns
312
- - [ ] Don't load all records (use LIMIT)
313
- - [ ] Cache expensive calculations
314
- - [ ] Run independent operations in parallel
315
- - [ ] Move work outside of loops
316
- - [ ] Batch database operations
317
- - [ ] Profile before optimizing
318
-
319
- ## When to Optimize
320
-
321
- 1. **Measure first** - Is there actually a problem?
322
- 2. **Find the bottleneck** - What's slow?
323
- 3. **Fix the biggest problem** - Don't waste time on small gains
324
- 4. **Measure again** - Did it help?
325
-
326
- Don't optimize prematurely - write clear code first, optimize when needed!
327
-
328
-
329
- ---
330
-
331
- # Caching Strategies
332
-
333
- ## In-Memory Caching
334
-
335
- ```typescript
336
- class Cache<T> {
337
- private cache = new Map<string, { value: T; expiry: number }>();
338
-
339
- set(key: string, value: T, ttlMs: number = 60000): void {
340
- this.cache.set(key, {
341
- value,
342
- expiry: Date.now() + ttlMs
343
- });
344
- }
345
-
346
- get(key: string): T | null {
347
- const item = this.cache.get(key);
348
- if (!item) return null;
349
-
350
- if (Date.now() > item.expiry) {
351
- this.cache.delete(key);
352
- return null;
353
- }
354
-
355
- return item.value;
356
- }
357
- }
358
-
359
- // Usage
360
- const userCache = new Cache<User>();
361
-
362
- async function getUser(id: string): Promise<User> {
363
- const cached = userCache.get(id);
364
- if (cached) return cached;
365
-
366
- const user = await db.findUser(id);
367
- userCache.set(id, user, 300000); // 5 minutes
368
- return user;
369
- }
370
- ```
371
-
372
- ## Redis Caching
373
-
374
- ```typescript
375
- import Redis from 'ioredis';
376
-
377
- const redis = new Redis();
378
-
379
- async function getCachedUser(id: string): Promise<User | null> {
380
- const cached = await redis.get(`user:${id}`);
381
- if (cached) return JSON.parse(cached);
382
-
383
- const user = await db.findUser(id);
384
- await redis.setex(`user:${id}`, 300, JSON.stringify(user)); // 5 min TTL
385
- return user;
386
- }
387
-
388
- // Cache invalidation on update
389
- async function updateUser(id: string, data: Partial<User>) {
390
- const user = await db.updateUser(id, data);
391
- await redis.del(`user:${id}`); // Invalidate cache
392
- return user;
393
- }
394
- ```
395
-
396
- ## HTTP Caching
397
-
398
- ```typescript
399
- // Cache-Control headers
400
- app.get('/api/products', (req, res) => {
401
- res.set('Cache-Control', 'public, max-age=300'); // 5 minutes
402
- res.json(products);
403
- });
404
-
405
- // ETag for conditional requests
406
- app.get('/api/user/:id', async (req, res) => {
407
- const user = await getUser(req.params.id);
408
- const etag = generateETag(user);
409
-
410
- res.set('ETag', etag);
411
-
412
- if (req.headers['if-none-match'] === etag) {
413
- return res.status(304).end(); // Not Modified
414
- }
415
-
416
- res.json(user);
417
- });
418
- ```
419
-
420
- ## Cache-Aside Pattern
421
-
422
- ```typescript
423
- // Also called "lazy loading"
424
- async function getProduct(id: string): Promise<Product> {
425
- // 1. Check cache
426
- const cached = await redis.get(`product:${id}`);
427
- if (cached) return JSON.parse(cached);
428
-
429
- // 2. Cache miss - load from database
430
- const product = await db.findProduct(id);
431
-
432
- // 3. Store in cache
433
- await redis.setex(`product:${id}`, 600, JSON.stringify(product));
434
-
435
- return product;
436
- }
437
- ```
438
-
439
- ## Memoization
440
-
441
- ```typescript
442
- const memoize = <T extends (...args: any[]) => any>(fn: T): T => {
443
- const cache = new Map<string, ReturnType<T>>();
444
-
445
- return ((...args: any[]) => {
446
- const key = JSON.stringify(args);
447
- if (cache.has(key)) return cache.get(key);
448
-
449
- const result = fn(...args);
450
- cache.set(key, result);
451
- return result;
452
- }) as T;
453
- };
454
-
455
- // Cache expensive computations
456
- const calculateDiscount = memoize((price: number, tier: string) => {
457
- // Complex calculation
458
- return result;
459
- });
460
- ```
461
-
462
- ## Cache Invalidation Strategies
463
-
464
- ```typescript
465
- // Time-based expiry
466
- await redis.setex(key, 300, value); // Expires after 5 minutes
467
-
468
- // Event-based invalidation
469
- async function updateProduct(id: string, data: ProductUpdate) {
470
- await db.updateProduct(id, data);
471
- await redis.del(`product:${id}`);
472
- await redis.del('products:list'); // Invalidate list cache too
473
- }
474
-
475
- // Cache warming
476
- async function warmCache() {
477
- const popularProducts = await db.getMostViewed(100);
478
- for (const product of popularProducts) {
479
- await redis.setex(`product:${product.id}`, 3600, JSON.stringify(product));
480
- }
481
- }
482
- ```
483
-
484
-
485
- ---
486
-
487
- # Async Performance Patterns
488
-
489
- ## Parallel Execution
490
-
491
- ```typescript
492
- // ❌ Sequential - slow
493
- async function getUserData(userId: string) {
494
- const user = await fetchUser(userId); // 100ms
495
- const posts = await fetchPosts(userId); // 150ms
496
- const comments = await fetchComments(userId); // 120ms
497
- return { user, posts, comments }; // Total: 370ms
498
- }
499
-
500
- // ✅ Parallel - fast
501
- async function getUserData(userId: string) {
502
- const [user, posts, comments] = await Promise.all([
503
- fetchUser(userId),
504
- fetchPosts(userId),
505
- fetchComments(userId)
506
- ]);
507
- return { user, posts, comments }; // Total: 150ms
508
- }
509
-
510
- // ✅ Partial parallel with dependencies
511
- async function getOrderDetails(orderId: string) {
512
- const order = await fetchOrder(orderId); // Must fetch first
513
-
514
- const [customer, items, shipping] = await Promise.all([
515
- fetchCustomer(order.customerId),
516
- fetchOrderItems(orderId),
517
- fetchShippingInfo(orderId)
518
- ]);
519
-
520
- return { order, customer, items, shipping };
521
- }
522
- ```
523
-
524
- ## Promise.allSettled for Partial Failures
525
-
526
- ```typescript
527
- // Return partial data instead of complete failure
528
- async function getDashboard(userId: string) {
529
- const [user, orders, stats] = await Promise.allSettled([
530
- getUser(userId),
531
- getOrders(userId),
532
- getStats(userId)
533
- ]);
534
-
535
- return {
536
- user: user.status === 'fulfilled' ? user.value : null,
537
- orders: orders.status === 'fulfilled' ? orders.value : [],
538
- stats: stats.status === 'fulfilled' ? stats.value : null,
539
- errors: {
540
- user: user.status === 'rejected' ? user.reason.message : null,
541
- orders: orders.status === 'rejected' ? orders.reason.message : null,
542
- stats: stats.status === 'rejected' ? stats.reason.message : null
543
- }
544
- };
545
- }
546
- ```
547
-
548
- ## Batch Processing
549
-
550
- ```typescript
551
- // ❌ One at a time - slow
552
- async function processUsers(userIds: string[]) {
553
- for (const id of userIds) {
554
- await updateUser(id);
555
- }
556
- }
557
-
558
- // ✅ Batch processing
559
- async function processUsers(userIds: string[]) {
560
- const BATCH_SIZE = 50;
561
-
562
- for (let i = 0; i < userIds.length; i += BATCH_SIZE) {
563
- const batch = userIds.slice(i, i + BATCH_SIZE);
564
- await Promise.all(batch.map(id => updateUser(id)));
565
- }
566
- }
567
-
568
- // ✅ Bulk database operations
569
- async function createUsers(users: User[]) {
570
- await db.query(`
571
- INSERT INTO users (name, email)
572
- VALUES ${users.map(() => '(?, ?)').join(', ')}
573
- `, users.flatMap(u => [u.name, u.email]));
574
- }
575
- ```
576
-
577
- ## Debouncing and Throttling
578
-
579
- ```typescript
580
- // Debounce: Wait until user stops typing
581
- const debounce = <T extends (...args: any[]) => any>(
582
- fn: T,
583
- delay: number
584
- ): ((...args: Parameters<T>) => void) => {
585
- let timeoutId: NodeJS.Timeout;
586
-
587
- return (...args: Parameters<T>) => {
588
- clearTimeout(timeoutId);
589
- timeoutId = setTimeout(() => fn(...args), delay);
590
- };
591
- };
592
-
593
- // Throttle: Execute at most once per interval
594
- const throttle = <T extends (...args: any[]) => any>(
595
- fn: T,
596
- limit: number
597
- ): ((...args: Parameters<T>) => void) => {
598
- let inThrottle: boolean;
599
-
600
- return (...args: Parameters<T>) => {
601
- if (!inThrottle) {
602
- fn(...args);
603
- inThrottle = true;
604
- setTimeout(() => (inThrottle = false), limit);
605
- }
606
- };
607
- };
608
-
609
- // Usage
610
- const searchUsers = debounce(query => api.search(query), 300);
611
- const handleScroll = throttle(() => console.log('scroll'), 100);
612
- ```
613
-
614
- ## Rate Limiting Concurrent Operations
615
-
616
- ```typescript
617
- async function processWithLimit<T>(
618
- items: T[],
619
- fn: (item: T) => Promise<void>,
620
- concurrency: number
621
- ): Promise<void> {
622
- const chunks = [];
623
- for (let i = 0; i < items.length; i += concurrency) {
624
- chunks.push(items.slice(i, i + concurrency));
625
- }
626
-
627
- for (const chunk of chunks) {
628
- await Promise.all(chunk.map(fn));
629
- }
630
- }
631
-
632
- // Usage: Process 100 items, max 10 at a time
633
- await processWithLimit(users, updateUser, 10);
634
- ```
635
-
636
-
637
- ---
638
-
639
- # Caching Strategies
640
-
641
- ## Cache Patterns
642
-
643
- ### Cache-Aside (Lazy Loading)
644
- ```typescript
645
- async function getUser(id: string): Promise<User> {
646
- const cached = await cache.get(`user:${id}`);
647
- if (cached) return cached;
648
-
649
- const user = await db.findUser(id);
650
- await cache.set(`user:${id}`, user, { ttl: 3600 });
651
- return user;
652
- }
653
- ```
654
-
655
- ### Write-Through
656
- ```typescript
657
- async function updateUser(user: User): Promise<void> {
658
- await db.saveUser(user);
659
- await cache.set(`user:${user.id}`, user);
660
- }
661
- ```
662
-
663
- ### Write-Behind (Write-Back)
664
- ```typescript
665
- async function updateUser(user: User): Promise<void> {
666
- await cache.set(`user:${user.id}`, user);
667
- await queue.add('sync-to-db', { user }); // Async persistence
668
- }
669
- ```
670
-
671
- ## Cache Invalidation
672
-
673
- ```typescript
674
- // Time-based expiration
675
- await cache.set('key', value, { ttl: 3600 });
676
-
677
- // Event-based invalidation
678
- eventBus.on('user.updated', async (userId) => {
679
- await cache.delete(`user:${userId}`);
680
- });
681
-
682
- // Pattern-based invalidation
683
- await cache.deleteByPattern('user:*');
684
- ```
685
-
686
- ## HTTP Caching
687
-
688
- ```typescript
689
- // Cache-Control headers
690
- res.setHeader('Cache-Control', 'public, max-age=3600');
691
- res.setHeader('ETag', etag(content));
692
-
693
- // Conditional requests
694
- if (req.headers['if-none-match'] === currentEtag) {
695
- return res.status(304).end();
696
- }
697
- ```
698
-
699
- ## Best Practices
700
-
701
- - Cache at appropriate layers (CDN, app, DB)
702
- - Use consistent cache keys
703
- - Set appropriate TTLs
704
- - Monitor cache hit rates
705
- - Plan for cache failures (fallback to source)
706
- - Avoid caching sensitive data