performance-review

Use this checklist when reviewing code for performance issues and optimization opportunities.

Performance Review Checklist

Use this checklist when reviewing code for performance issues and optimization opportunities.

Database & Data Access

Query Optimization

Data Fetching

Caching

Transactions

Algorithm & Data Structure Efficiency

Algorithmic Complexity

Data Structures

String Operations

Memory Management

Memory Usage

Data Structures Size

Garbage Collection

Network & I/O

Network Calls

API Design

File I/O

Serialization

Concurrency & Parallelism

Thread Safety

Async/Await

Parallelization

Frontend Performance

Rendering

Bundle Size

Asset Loading

Caching (Frontend)

Monitoring & Measurement

Profiling

Metrics

Benchmarks

Common Performance Anti-Patterns

Avoid These Patterns

N+1 Queries

# ❌ Bad: N+1 queries
users = User.objects.all()
for user in users:
    print(user.profile.bio)  # Separate query for each user

# ✅ Good: Single query with JOIN
users = User.objects.select_related('profile').all()
for user in users:
    print(user.profile.bio)

Loading Entire Dataset

# ❌ Bad: Load everything into memory
users = User.objects.all()  # Loads all users
for user in users:
    process(user)

# ✅ Good: Use iterator/batch
for user in User.objects.iterator(chunk_size=1000):
    process(user)

Unnecessary Loops

# ❌ Bad: O(n²)
for item1 in items:
    for item2 in items:
        if item1.id == item2.related_id:
            process(item1, item2)

# ✅ Good: O(n) with hash map
related_map = {item.related_id: item for item in items}
for item in items:
    if item.id in related_map:
        process(item, related_map[item.id])

String Concatenation in Loop

# ❌ Bad: O(n²) due to string immutability
result = ""
for item in items:
    result += str(item)  # Creates new string each time

# ✅ Good: O(n)
result = "".join(str(item) for item in items)

Synchronous I/O in Loop

# ❌ Bad: Sequential network calls
results = []
for url in urls:
    response = requests.get(url)  # Blocks for each
    results.append(response.json())

# ✅ Good: Concurrent requests
import asyncio
import aiohttp

async def fetch_all(urls):
    async with aiohttp.ClientSession() as session:
        tasks = [session.get(url) for url in urls]
        responses = await asyncio.gather(*tasks)
        return [await r.json() for r in responses]

No Caching

# ❌ Bad: Expensive computation every time
def get_report(user_id):
    data = expensive_database_query(user_id)
    return process_data(data)

# ✅ Good: Cache the result
from functools import lru_cache

@lru_cache(maxsize=1000)
def get_report(user_id):
    data = expensive_database_query(user_id)
    return process_data(data)

Blocking Operations in Async

# ❌ Bad: Blocking in async function
async def handle_request():
    data = requests.get(url).json()  # Blocks event loop
    return process(data)

# ✅ Good: Use async client
async def handle_request():
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            data = await response.json()
            return process(data)

Performance Targets

Response Time

Throughput

Resource Usage

Scalability


Performance Review Severity

CRITICAL (Block Merge):

HIGH (Fix Before Merge):

MEDIUM (Fix Soon):

LOW (Optimization Opportunity):


Performance Testing Checklist

Before approving performance-sensitive changes:


Reviewer: _____________ Date: _____________ Performance Impact: ⚪ None / 🟢 Improvement / 🟡 Neutral / 🔴 Regression