--- name: performance-fundamentals description: Auto-invoke when reviewing loops, data fetching, rendering, database queries, or resource-intensive operations. Identifies N+1 queries, unnecessary re-renders, memory leaks, and scalability issues. --- # Performance Fundamentals Review > "Premature optimization is the root of all evil, but mature ignorance is worse." ## When to Apply Activate this skill when reviewing: - Database queries (especially in loops) - React/Vue render logic - API response payloads - Data transformations - File operations - Caching decisions --- ## Review Checklist ### Database Performance - [ ] **No N+1 queries**: Are related records fetched in bulk, not loops? - [ ] **Indexes**: Are frequently queried fields indexed? - [ ] **Pagination**: Do list endpoints paginate results? - [ ] **Select only needed fields**: Are we fetching entire records unnecessarily? ### Frontend Performance - [ ] **Memoization**: Are expensive computations cached? - [ ] **Re-render prevention**: Will state changes cause unnecessary re-renders? - [ ] **Bundle size**: Are heavy libraries lazy-loaded? - [ ] **Image optimization**: Are images properly sized and formatted? ### API Performance - [ ] **Response size**: Is the payload minimal? - [ ] **Compression**: Is gzip/brotli enabled? - [ ] **Caching headers**: Are cacheable responses marked? - [ ] **Async processing**: Are slow operations queued? ### Memory & Resources - [ ] **Cleanup**: Are subscriptions/timers cleaned up? - [ ] **Memory leaks**: Are event listeners removed? - [ ] **Connection pooling**: Are DB connections reused? --- ## Common Mistakes (Anti-Patterns) ### 1. The N+1 Query Problem ``` ❌ const users = await User.findAll(); for (const user of users) { user.posts = await Post.findByUserId(user.id); // N queries! } ✅ const users = await User.findAll({ include: [{ model: Post }] // 1 query with JOIN }); ``` ### 2. Unnecessary Re-renders ``` ❌ function Parent() { const handleClick = () => {}; // New function every render return ; } ✅ function Parent() { const handleClick = useCallback(() => {}, []); return ; } ``` ### 3. Computing in Render ``` ❌ function UserList({ users }) { // Runs on every render const sorted = users.sort((a, b) => a.name.localeCompare(b.name)); return ; } ✅ function UserList({ users }) { const sorted = useMemo( () => [...users].sort((a, b) => a.name.localeCompare(b.name)), [users] ); return ; } ``` ### 4. Fetching Everything ``` ❌ GET /api/users → returns 10,000 users with all fields ✅ GET /api/users?page=1&limit=20&fields=id,name,email ``` ### 5. Missing Cleanup ``` ❌ useEffect(() => { const interval = setInterval(fetchData, 5000); // No cleanup! Runs forever. }, []); ✅ useEffect(() => { const interval = setInterval(fetchData, 5000); return () => clearInterval(interval); }, []); ``` --- ## Socratic Questions Ask the junior these questions instead of giving answers: 1. **Scale**: "What happens when there are 10,000 items? 1,000,000?" 2. **Queries**: "How many database queries does this operation make?" 3. **Re-renders**: "When this state changes, what components re-render?" 4. **Memory**: "Is anything holding a reference after it's no longer needed?" 5. **Payload**: "Does the client need ALL of this data?" --- ## Big O Quick Reference | Pattern | Complexity | Example | At 10,000 items | |---------|------------|---------|-----------------| | Direct lookup | O(1) | `map.get(key)` | 1 op | | Single loop | O(n) | `array.find()` | 10,000 ops | | Nested loops | O(n²) | `for i { for j }` | 100,000,000 ops | | Sort | O(n log n) | `array.sort()` | ~130,000 ops | --- ## Performance Targets | Metric | Target | Measure With | |--------|--------|--------------| | Time to First Byte (TTFB) | < 600ms | DevTools Network | | Largest Contentful Paint (LCP) | < 2.5s | Lighthouse | | First Input Delay (FID) | < 100ms | Lighthouse | | Cumulative Layout Shift (CLS) | < 0.1 | Lighthouse | | API Response Time | < 200ms (p95) | Server metrics | --- ## Red Flags to Call Out | Flag | Question to Ask | |------|-----------------| | Query inside a loop | "Can we batch this into one query?" | | No pagination | "What if there are 100,000 records?" | | `SELECT *` | "Do we need all these fields?" | | Large JSON in localStorage | "Will this slow down page load?" | | Inline function in JSX | "Does this create a new function every render?" | | setInterval without cleanup | "What clears this when the component unmounts?" | | Synchronous file operations | "Should this be async?" | | No loading states | "What does the user see while waiting?" | --- ## Quick Wins 1. **Add indexes** to frequently queried DB columns 2. **Paginate** all list endpoints 3. **Lazy load** below-the-fold content 4. **Compress** API responses 5. **Cache** expensive computations with useMemo 6. **Debounce** search inputs 7. **Virtualize** long lists (react-window)