Code Review Checklist
Comprehensive checklist for reviewing code changes to ensure quality, security, and maintainability.
Quick Review Checklist
Before approving code:
- Code is simple and readable
- Functions/variables well-named
- No duplicated code
- Proper error handling
- No hardcoded secrets
- Input validation implemented
- Tests included
- No console.log statements
Security Checks (CRITICAL)
Secrets & Credentials
- No hardcoded API keys
- No hardcoded passwords/tokens
- No credentials in comments
- .env in .gitignore
- Secrets in environment variables
Input Validation
- All user input validated
- SQL queries parameterized
- Output escaped (XSS prevention)
- File uploads validated
- Path traversal prevented
Authentication & Authorization
- Auth required on protected routes
- Users can only access their data
- Admin routes require admin role
- JWT properly validated
- Sessions secure
Code Quality (HIGH)
Function Quality
- Functions < 50 lines
- Single responsibility
- Clear, descriptive names
- Minimal parameters (< 5)
- No deeply nested logic (< 4 levels)
File Organization
- Files < 800 lines
- Logical grouping
- Clear directory structure
- Related code together
- Separation of concerns
Code Clarity
- Self-documenting code
- Comments explain "why", not "what"
- No magic numbers
- Consistent naming conventions
- No abbreviations (unless standard)
Error Handling
- Try-catch blocks where needed
- Errors logged properly
- User-friendly error messages
- Error propagation correct
- No swallowed errors
Immutability
- No object mutation
- Use spread operator for copies
- Array methods (map, filter, reduce)
- No direct array modification
- Const by default
Example:
// ❌ BAD: Mutation
function updateUser(user, name) {
user.name = name // Mutates!
return user
}
// ✅ GOOD: Immutability
function updateUser(user, name) {
return {
...user,
name
}
}
Testing (HIGH)
Test Coverage
- New code has tests
- Edge cases covered
- Error paths tested
- Integration tests for APIs
- E2E tests for critical flows
Test Quality
- Tests are independent
- No flaky tests
- Clear test names
- Proper setup/teardown
- Mocks used appropriately
Performance (MEDIUM)
Algorithms
- Time complexity acceptable
- No O(n²) when O(n log n) possible
- Efficient data structures used
- No unnecessary iterations
- Database queries optimized
React Performance
- No unnecessary re-renders
- useMemo for expensive calculations
- useCallback for stable callbacks
- Keys on list items
- Code splitting where appropriate
Database
- Indexes on queried columns
- No N+1 queries
- Pagination for large datasets
- Connection pooling used
- Query limits set
Caching
- Cache expensive operations
- Cache invalidation strategy
- No stale data issues
- Cache keys well-designed
Best Practices (MEDIUM)
Dependencies
- No unnecessary dependencies
- Dependencies up to date
-
npm auditclean - License compatibility checked
- Bundle size considered
Accessibility
- ARIA labels where needed
- Keyboard navigation works
- Color contrast sufficient
- Screen reader friendly
- Focus management correct
Code Style
- Consistent formatting
- Linter passing
- TypeScript types correct
- No
anytypes - No TODO comments without tickets
Documentation
- Public APIs documented
- README updated if needed
- Complex logic explained
- Breaking changes noted
- Migration guide if breaking
Common Issues to Flag
Anti-Patterns
// ❌ Magic numbers
if (status === 200) { }
// ✅ Named constants
const HTTP_OK = 200
if (status === HTTP_OK) { }
// ❌ Nested ternaries
const result = a ? b ? c : d : e
// ✅ If-else or early return
if (!a) return e
return b ? c : d
// ❌ Large objects in state
const [user, setUser] = useState(bigObject)
// ✅ Only store what's needed
const [userId, setUserId] = useState(id)
Security Anti-Patterns
// ❌ String concatenation in queries
db.query(`SELECT * FROM users WHERE id = ${id}`)
// ✅ Parameterized queries
db.query('SELECT * FROM users WHERE id = ?', [id])
// ❌ Eval with user input
eval(userCode)
// ✅ Don't use eval at all
// ❌ innerHTML with user data
div.innerHTML = userComment
// ✅ textContent or framework escaping
div.textContent = userComment
Performance Anti-Patterns
// ❌ Filter then map
items.filter(x => x.active).map(x => x.name)
// ✅ Reduce or single pass
items.reduce((acc, x) => {
if (x.active) acc.push(x.name)
return acc
}, [])
// ❌ useEffect without dependencies
useEffect(() => fetchData())
// ✅ Specify dependencies
useEffect(() => fetchData(), [userId])
Review Priority Levels
CRITICAL (Must Fix)
- Security vulnerabilities
- Data corruption risks
- Breaking changes without migration
- Secrets exposure
- Authentication bypass
- SQL injection
HIGH (Should Fix)
- Performance bottlenecks
- Missing tests for new features
- Incorrect error handling
- Large functions (>50 lines)
- Deep nesting (>4 levels)
- Mutation patterns
MEDIUM (Consider Fixing)
- Style inconsistencies
- Missing documentation
- Optimization opportunities
- TODO without tickets
- Minor accessibility issues
LOW (Nice to Have)
- Refactoring suggestions
- Additional examples
- Minor improvements
- Naming improvements
Review Output Format
For each issue found:
[PRIORITY] Brief description
File: path/to/file.ts:line
Issue: Detailed explanation
Fix: How to resolve
// ❌ Current code
// ✅ Suggested code
Example:
[CRITICAL] Hardcoded API key
File: src/api/client.ts:42
Issue: API key exposed in source code
Fix: Move to environment variable
const apiKey = "sk-abc123" // ❌ Bad
const apiKey = process.env.OPENAI_API_KEY // ✅ Good
Approval Criteria
- ✅ Approve: No CRITICAL or HIGH issues
- ⚠️ Warning: Only MEDIUM issues (can merge with caution)
- ❌ Block: CRITICAL or HIGH issues found
When to Use This Checklist
- ✅ After writing new code
- ✅ Before creating pull request
- ✅ During code review
- ✅ After bug fixes
- ✅ After refactoring
- ✅ Before merging to main
Review Workflow
Quick scan
- Run linter
- Check for obvious issues
- Verify tests pass
Security review
- Check for secrets
- Validate input handling
- Verify auth/authorization
Quality review
- Function sizes
- Code complexity
- Error handling
Test review
- Coverage adequate
- Edge cases tested
- Tests passing
Performance review
- Algorithms efficient
- No obvious bottlenecks
- Database queries optimized
Tools to Use
Linting
npm run lint
npx eslint . --fix
Type Checking
npm run typecheck
npx tsc --noEmit
Testing
npm test
npm run test:coverage
Security
npm audit
npx eslint . --plugin security
Bundle Size
npm run build
npx bundle-analyzer
Common Mistakes
- Forgetting to validate input
- Hardcoding configuration
- Not handling errors
- Writing tests after code (should be TDD)
- Creating large files/functions
- Using mutation instead of immutability
- Leaving console.log statements
- Not updating documentation
- Ignoring accessibility
- Adding unnecessary dependencies
Quick Reference
Good Practices Checklist
- KISS (Keep It Simple)
- DRY (Don't Repeat Yourself)
- YAGNI (You Aren't Gonna Need It)
- Single Responsibility
- Small Functions & Files
- Immutability
- Error Handling
- Input Validation
- Test Coverage
- Clear Naming
File Size Guidelines
- Typical: 200-400 lines
- Maximum: 800 lines
- If larger: Extract utilities, split by concern
Function Size Guidelines
- Typical: 10-20 lines
- Maximum: 50 lines
- If larger: Extract helper functions
Nesting Guidelines
- Maximum: 4 levels
- If deeper: Extract functions, use early returns
Resources
Converted and distributed by TomeVault — claim your Tome and manage your conversions.