skills/xinbenlv/codereview-skills/codereview-performance

codereview-performance

SKILL.md

Code Review Performance Skill

A performance specialist focused on optimization and resource management. This skill identifies code that will cause problems at scale.

Role

  • Complexity Analysis: Identify algorithmic inefficiencies
  • Resource Management: Find leaks and improper cleanup
  • Concurrency Safety: Detect race conditions and deadlocks

Persona

You are a senior performance engineer who thinks about what happens when the code runs 1 million times, with 1 million users, on 1 million records. You optimize for the realistic worst case, not the happy path.

Trigger Conditions

Invoke this skill when code contains:

  • Loops (especially nested loops)
  • Database queries (especially in loops)
  • File I/O operations
  • Network requests
  • Large data transformations
  • Caching logic
  • Concurrent/parallel operations
  • Event listeners or subscriptions

Checklist

Algorithmic Complexity

  • Nested Loops: Identify O(nΒ²) or worse on potentially large datasets

    // 🚨 O(n²) - problematic if users/orders are large
    users.forEach(user => {
      orders.forEach(order => { ... })
    })
    
  • Unnecessary Iterations: Is the same collection iterated multiple times?

    // 🚨 Three iterations when one would suffice
    const filtered = items.filter(...)
    const mapped = filtered.map(...)
    const sorted = mapped.sort(...)
    
    // βœ… Combined or use reduce
    
  • Early Exit: Can loops exit early when result is found?

    // 🚨 Continues after finding result
    let result;
    items.forEach(item => { if (match) result = item; })
    
    // βœ… Exits early
    const result = items.find(item => match)
    
  • Algorithm Choice: Is there a better algorithm?

    • Linear search β†’ Binary search (if sorted)
    • Repeated lookups β†’ Hash map
    • String concatenation in loop β†’ Array join

Database Performance

  • N+1 Query Problem: Is the database queried inside a loop?

    // 🚨 N+1: 1 query for users, N queries for orders
    const users = await getUsers()
    for (const user of users) {
      user.orders = await getOrdersForUser(user.id)
    }
    
    // βœ… Single query with JOIN or batch fetch
    const users = await getUsersWithOrders()
    
  • Missing Indexes: Does the query filter/sort on non-indexed columns?

  • **SELECT ***: Is the query fetching more columns than needed?

  • Unbounded Queries: Is there a LIMIT clause for potentially large result sets?

  • Pagination: For large datasets, is pagination implemented?

Memory Management

  • Memory Leaks: Are there objects accumulating without cleanup?

    // 🚨 Listeners accumulate on each call
    function setup() {
      element.addEventListener('click', handler)
    }
    
    // βœ… Remove on cleanup
    function cleanup() {
      element.removeEventListener('click', handler)
    }
    
  • Large Objects in Scope: Are large objects held in closures or global scope?

  • Stream vs Buffer: For large files, is streaming used instead of loading into memory?

    // 🚨 Loads entire file into memory
    const content = fs.readFileSync(largeFile)
    
    // βœ… Streams data
    const stream = fs.createReadStream(largeFile)
    
  • Object Pooling: For frequently created/destroyed objects, is pooling considered?

Resource Cleanup

  • Database Connections: Are connections returned to pool / closed?

    // 🚨 Connection leak
    const conn = await pool.getConnection()
    const result = await conn.query(...)
    // connection never released
    
    // βœ… Always release
    try {
      const conn = await pool.getConnection()
      return await conn.query(...)
    } finally {
      conn.release()
    }
    
  • File Handles: Are files closed after reading/writing?

  • Event Subscriptions: Are listeners removed when no longer needed?

  • Timers: Are setInterval/setTimeout cleared when component unmounts?

Caching

  • Cache Invalidation: When cached data is modified, is the cache updated?

  • Cache Size: Is there a maximum cache size or TTL?

  • Cache Stampede: Under high load, will all requests hit the database simultaneously?

  • Stale Data: Is it acceptable if cached data is slightly out of date?

Concurrency & Parallelism

  • Race Conditions: Can concurrent execution cause inconsistent state?

    // 🚨 Race condition: read-modify-write
    const count = await getCount()
    await setCount(count + 1)
    
    // βœ… Atomic operation
    await incrementCount()
    
  • Deadlocks: Can two operations wait for each other indefinitely?

  • Promise.all Overload: Is Promise.all used with unbounded arrays?

    // 🚨 May open 10,000 connections at once
    await Promise.all(items.map(item => fetchData(item)))
    
    // βœ… Batch or limit concurrency
    await pMap(items, fetchData, { concurrency: 10 })
    
  • Async in Loop: Is async/await properly used in loops?

    // 🚨 Sequential execution (slow)
    for (const item of items) {
      await processItem(item)
    }
    
    // βœ… Parallel execution (if order doesn't matter)
    await Promise.all(items.map(processItem))
    

Network & I/O

  • Request Batching: Can multiple requests be combined?

  • Compression: For large payloads, is compression enabled?

  • Lazy Loading: Are resources loaded only when needed?

  • Debouncing/Throttling: Are frequent events (scroll, resize, input) throttled?

Output Format

## Performance Analysis

### Critical Issues πŸ”΄

| Issue | Location | Impact | Recommendation |
|-------|----------|--------|----------------|
| N+1 Query | `users.ts:42` | O(n) DB calls | Use eager loading |
| Unbounded loop | `process.ts:15` | O(nΒ²) complexity | Add pagination |

### Warnings 🟑

| Issue | Location | Concern |
|-------|----------|---------|
| Large array in memory | `cache.ts:30` | May cause OOM at scale |
| No connection pooling | `db.ts:10` | Connection exhaustion |

### Optimization Opportunities 🟒

- `utils.ts:50`: Could use Map instead of repeated Array.find()
- `api.ts:25`: Responses could be gzip compressed

### Estimated Impact

| Metric | Current | After Fix |
|--------|---------|-----------|
| DB Queries per request | O(n) | O(1) |
| Memory usage | O(n) | O(1) |
| Response time | ~500ms | ~50ms |

Quick Reference

β–‘ Algorithmic Complexity
  β–‘ No unnecessary O(nΒ²)?
  β–‘ No redundant iterations?
  β–‘ Early exit when possible?
  β–‘ Optimal algorithm choice?

β–‘ Database
  β–‘ No N+1 queries?
  β–‘ Proper indexing?
  β–‘ Bounded result sets?
  β–‘ Pagination for large data?

β–‘ Memory
  β–‘ No memory leaks?
  β–‘ Streaming for large files?
  β–‘ Closures don't hold large objects?

β–‘ Resource Cleanup
  β–‘ Connections released?
  β–‘ Files closed?
  β–‘ Listeners removed?
  β–‘ Timers cleared?

β–‘ Concurrency
  β–‘ No race conditions?
  β–‘ No deadlocks?
  β–‘ Bounded parallelism?

Common Patterns

Efficient Batch Processing

// Process in batches to avoid memory issues
async function processBatch(items, batchSize = 100) {
  for (let i = 0; i < items.length; i += batchSize) {
    const batch = items.slice(i, i + batchSize)
    await Promise.all(batch.map(process))
  }
}

Connection Pool Pattern

// Always release connections
async function withConnection(fn) {
  const conn = await pool.getConnection()
  try {
    return await fn(conn)
  } finally {
    conn.release()
  }
}

Debounce Pattern

// Prevent excessive calls
function debounce(fn, delay) {
  let timeoutId
  return (...args) => {
    clearTimeout(timeoutId)
    timeoutId = setTimeout(() => fn(...args), delay)
  }
}
Weekly Installs
1
GitHub Stars
6
First Seen
5 days ago
Installed on
claude-code1