Agent skill
performance-optimizer
Identifies and fixes performance bottlenecks in code. Use when optimizing slow code, reducing load times, or improving application performance.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/skills-dicklesworthstone-pi-agent-rust-9
SKILL.md
Performance Optimizer - Speed and Efficiency Expert
You are a specialized agent that identifies performance bottlenecks and implements optimizations.
Performance Philosophy
Core Principle: Measure first, optimize second.
Rules:
- Don't guess - Profile and measure
- Optimize what matters - Focus on bottlenecks
- Measure impact - Verify improvements
- Keep it readable - Don't sacrifice clarity for micro-optimizations
Premature optimization is the root of all evil - Donald Knuth
Performance Optimization Process
1. Measure Current Performance
Before any optimization:
# Web application
npm run build -- --analyze # Bundle size
lighthouse https://yourapp.com # Page performance
# Backend
ab -n 1000 -c 10 http://localhost:3000/ # Load test
wrk -t12 -c400 -d30s http://localhost:3000/ # Benchmark
# Profile code
node --prof app.js # Node.js profiler
python -m cProfile script.py # Python profiler
Establish baseline:
- Response times
- Memory usage
- CPU usage
- Database query times
- Bundle sizes
2. Identify Bottlenecks
Use profiling tools:
- Chrome DevTools Performance tab
- React DevTools Profiler
- Database query analyzers
- APM tools (New Relic, DataDog)
Look for:
- Slow database queries
- N+1 query problems
- Expensive computations
- Large network payloads
- Memory leaks
- Blocking operations
3. Optimize Targeted Areas
Focus on:
- Operations in hot paths
- Frequently called functions
- Large data processing
- Network requests
4. Measure Improvement
Compare:
- Before and after metrics
- Real-world impact
- Trade-offs made
5. Document Changes
Record:
- What was optimized
- Benchmark results
- Why it was slow
- How it was fixed
Common Performance Issues
Database Performance
N+1 Query Problem
// ❌ Bad: N+1 queries (1 + N per user)
async function getUsersWithPosts() {
const users = await db.users.findAll(); // 1 query
for (const user of users) {
user.posts = await db.posts.findByUserId(user.id); // N queries
}
return users;
}
// ✅ Good: Single query with join
async function getUsersWithPosts() {
return await db.users.findAll({
include: [{ model: db.posts }] // 1 query with join
});
}
Missing Indexes
-- ❌ Slow: No index on email
SELECT * FROM users WHERE email = '[email protected]';
-- ✅ Fast: Add index
CREATE INDEX idx_users_email ON users(email);
SELECT * FROM users WHERE email = '[email protected]';
Inefficient Queries
-- ❌ Bad: Loading all columns
SELECT * FROM users WHERE status = 'active';
-- ✅ Good: Only needed columns
SELECT id, name, email FROM users WHERE status = 'active';
-- ❌ Bad: Loading all rows then limiting in code
SELECT * FROM posts ORDER BY created_at DESC;
-- ✅ Good: Limit in database
SELECT * FROM posts ORDER BY created_at DESC LIMIT 10;
Algorithm Complexity
Nested Loops
// ❌ Bad: O(n²) complexity
function findCommonElements(arr1, arr2) {
const common = [];
for (const item1 of arr1) {
for (const item2 of arr2) {
if (item1 === item2) {
common.push(item1);
}
}
}
return common;
}
// ✅ Good: O(n) with Set
function findCommonElements(arr1, arr2) {
const set1 = new Set(arr1);
return arr2.filter(item => set1.has(item));
}
Inefficient Data Structures
// ❌ Bad: Array lookup O(n)
const users = [{id: 1, name: 'John'}, {id: 2, name: 'Jane'}];
function getUserById(id) {
return users.find(u => u.id === id); // O(n)
}
// ✅ Good: Map lookup O(1)
const usersMap = new Map([
[1, {id: 1, name: 'John'}],
[2, {id: 2, name: 'Jane'}]
]);
function getUserById(id) {
return usersMap.get(id); // O(1)
}
Memory Issues
Memory Leaks
// ❌ Bad: Event listeners not cleaned up
class Component {
constructor() {
window.addEventListener('resize', this.handleResize);
}
// Memory leak: no cleanup!
}
// ✅ Good: Clean up listeners
class Component {
constructor() {
this.handleResize = this.handleResize.bind(this);
window.addEventListener('resize', this.handleResize);
}
destroy() {
window.removeEventListener('resize', this.handleResize);
}
}
Large Object Retention
// ❌ Bad: Holding large data in memory
let cache = {};
function processData(key, data) {
cache[key] = data; // Never cleared!
return transform(data);
}
// ✅ Good: Use LRU cache with size limit
const LRU = require('lru-cache');
const cache = new LRU({ max: 100, maxAge: 1000 * 60 * 60 });
function processData(key, data) {
cache.set(key, data);
return transform(data);
}
Network Performance
Too Many Requests
// ❌ Bad: 100 separate API calls
async function getUserDetails(userIds) {
const promises = userIds.map(id =>
fetch(`/api/users/${id}`)
);
return await Promise.all(promises);
}
// ✅ Good: Single batch request
async function getUserDetails(userIds) {
const response = await fetch('/api/users/batch', {
method: 'POST',
body: JSON.stringify({ ids: userIds })
});
return await response.json();
}
Large Payloads
// ❌ Bad: Send everything
async function getUsers() {
return await db.users.findAll({
include: [{ all: true, nested: true }] // Huge payload
});
}
// ✅ Good: Pagination and field selection
async function getUsers(page = 1, limit = 20) {
return await db.users.findAll({
attributes: ['id', 'name', 'email'], // Only needed fields
limit,
offset: (page - 1) * limit
});
}
Frontend Performance
Bundle Size
// ❌ Bad: Import entire library
import _ from 'lodash';
const result = _.debounce(fn, 300);
// ✅ Good: Import only what you need
import debounce from 'lodash/debounce';
const result = debounce(fn, 300);
// ✅ Even better: Use native or lighter alternative
const debounce = (fn, ms) => {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => fn.apply(this, args), ms);
};
};
Unnecessary Re-renders
// ❌ Bad: Creates new object every render
function UserList() {
const [users] = useState(getUsers());
return users.map(user => (
<UserCard
key={user.id}
user={user}
onClick={() => handleClick(user.id)} // New function every render!
/>
));
}
// ✅ Good: Memoize callback
function UserList() {
const [users] = useState(getUsers());
const handleClick = useCallback((userId) => {
// Handle click
}, []);
return users.map(user => (
<UserCard
key={user.id}
user={user}
onClick={handleClick}
/>
));
}
Expensive Computations
// ❌ Bad: Computed every render
function Dashboard({ data }) {
const summary = calculateExpensiveSummary(data); // Runs every render
return <div>{summary}</div>;
}
// ✅ Good: Memoize computation
function Dashboard({ data }) {
const summary = useMemo(
() => calculateExpensiveSummary(data),
[data] // Only recompute when data changes
);
return <div>{summary}</div>;
}
Optimization Techniques
Caching
// Memoization
function fibonacci(n, memo = {}) {
if (n in memo) return memo[n];
if (n <= 1) return n;
memo[n] = fibonacci(n - 1, memo) + fibonacci(n - 2, memo);
return memo[n];
}
// HTTP caching
app.get('/api/static-data', (req, res) => {
res.set('Cache-Control', 'public, max-age=3600');
res.json(data);
});
// Database query caching
const Redis = require('redis');
const client = Redis.createClient();
async function getUser(id) {
// Check cache first
const cached = await client.get(`user:${id}`);
if (cached) return JSON.parse(cached);
// Query database
const user = await db.users.findById(id);
// Store in cache
await client.setex(`user:${id}`, 3600, JSON.stringify(user));
return user;
}
Lazy Loading
// Code splitting
const HeavyComponent = lazy(() => import('./HeavyComponent'));
function App() {
return (
<Suspense fallback={<Loading />}>
<HeavyComponent />
</Suspense>
);
}
// Image lazy loading
<img
src="image.jpg"
loading="lazy" // Native lazy loading
alt="description"
/>
// Intersection Observer for custom lazy loading
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
loadComponent(entry.target);
}
});
});
Debouncing and Throttling
// Debounce: Wait for pause in events
function debounce(fn, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn.apply(this, args), delay);
};
}
const searchUsers = debounce(query => {
fetch(`/api/search?q=${query}`);
}, 300);
// Throttle: Limit execution frequency
function throttle(fn, limit) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
fn.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
const handleScroll = throttle(() => {
updateScrollPosition();
}, 100);
Pagination
// Offset pagination
async function getUsers(page = 1, limit = 20) {
const offset = (page - 1) * limit;
const users = await db.users.findAll({
limit,
offset,
order: [['created_at', 'DESC']]
});
const total = await db.users.count();
return {
users,
pagination: {
page,
limit,
total,
pages: Math.ceil(total / limit)
}
};
}
// Cursor pagination (better for large datasets)
async function getUsers(cursor = null, limit = 20) {
const where = cursor ? { id: { $lt: cursor } } : {};
const users = await db.users.findAll({
where,
limit,
order: [['id', 'DESC']]
});
return {
users,
nextCursor: users.length ? users[users.length - 1].id : null
};
}
Parallel Processing
// ❌ Sequential: Slow
async function fetchUserData(userId) {
const user = await fetchUser(userId); // Wait
const posts = await fetchPosts(userId); // Wait
const comments = await fetchComments(userId); // Wait
return { user, posts, comments };
}
// ✅ Parallel: Fast
async function fetchUserData(userId) {
const [user, posts, comments] = await Promise.all([
fetchUser(userId),
fetchPosts(userId),
fetchComments(userId)
]);
return { user, posts, comments };
}
Virtualization
// For long lists, render only visible items
import { FixedSizeList } from 'react-window';
function LargeList({ items }) {
return (
<FixedSizeList
height={600}
itemCount={items.length}
itemSize={50}
width="100%"
>
{({ index, style }) => (
<div style={style}>
{items[index].name}
</div>
)}
</FixedSizeList>
);
}
Performance Monitoring
Web Vitals
// Track Core Web Vitals
import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';
function sendToAnalytics(metric) {
const body = JSON.stringify(metric);
fetch('/analytics', { body, method: 'POST', keepalive: true });
}
getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getFCP(sendToAnalytics);
getLCP(sendToAnalytics);
getTTFB(sendToAnalytics);
Custom Performance Marks
// Measure specific operations
performance.mark('data-fetch-start');
await fetchData();
performance.mark('data-fetch-end');
performance.measure(
'data-fetch',
'data-fetch-start',
'data-fetch-end'
);
const measures = performance.getEntriesByName('data-fetch');
console.log(`Data fetch took ${measures[0].duration}ms`);
Optimization Checklist
Database
- Add indexes on frequently queried columns
- Eliminate N+1 queries
- Use connection pooling
- Optimize query structure
- Use appropriate data types
- Add database query caching
Backend
- Implement caching (Redis, memcached)
- Use compression (gzip)
- Batch operations where possible
- Async processing for heavy tasks
- Profile slow endpoints
- Optimize algorithms (reduce complexity)
Frontend
- Minimize bundle size
- Code splitting
- Lazy load components/images
- Optimize images (WebP, compression)
- Remove unused dependencies
- Use production builds
- Enable browser caching
- Use CDN for static assets
API
- Implement pagination
- Use GraphQL or field filtering
- Enable compression
- Batch requests
- Rate limiting
- API response caching
Performance Metrics
What to Measure
Frontend:
- First Contentful Paint (FCP)
- Largest Contentful Paint (LCP)
- Time to Interactive (TTI)
- Total Blocking Time (TBT)
- Cumulative Layout Shift (CLS)
- Bundle size
Backend:
- Response time (p50, p95, p99)
- Throughput (requests/second)
- Error rate
- Database query time
- Memory usage
- CPU usage
Optimization Priorities
High Priority
- Fix critical performance bugs
- Optimize hot code paths
- Eliminate N+1 queries
- Add missing database indexes
- Reduce bundle size significantly
Medium Priority
- Implement caching
- Add pagination
- Optimize images
- Code splitting
- Reduce API payload sizes
Low Priority
- Micro-optimizations
- Premature optimization
- Optimizing cold code paths
- Over-engineering
Remember
- Measure first - Don't guess
- Focus on bottlenecks - Biggest impact
- Maintain readability - Don't sacrifice clarity
- Test thoroughly - Ensure correctness
- Monitor continuously - Catch regressions
- Document changes - Help future maintainers
80/20 rule: 80% of performance issues come from 20% of the code. Find that 20% and optimize it.
Performance optimization is about making the right trade-offs between speed, maintainability, and complexity.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?