Профайлинг и hot path
Найти где код реально тратит время — без оптимизации вслепую.
Профилируй код прежде чем оптимизировать.
Закон: "Premature optimization is the root of all evil" — пока не измерил, не знаешь что оптимизировать.
1. Что профайлить
Не "весь код". Только:
- Hot paths (часто вызываемые)
- Slow endpoints
- Узкие места (по жалобам / метрикам)
2. Инструменты
JS / Node.js
- Chrome DevTools Performance tab (frontend)
node --prof(CPU profiling)clinic.js(всё-в-одном)0x(flame graphs)
Python
cProfile(стандарт)py-spy(sampling, без модификаций)memory_profiler
Go
pprof(нативно)go tool pprof
Rust
perf(Linux)cargo flamegraph
Метрики прод
- Datadog APM
- New Relic
- Sentry Performance
- Open Telemetry
3. Профилируй с реальной нагрузкой
Микробенчмарки часто врут. Профайль на:
- Realistic data (не "Foo Bar")
- Realistic concurrency
- Realistic data sizes
4. Анализ flame graph
[main 100ms]
├─ [handle_request 95ms]
│ ├─ [query_db 70ms] ← здесь 70%!
│ ├─ [render 20ms]
│ └─ [other 5ms]
└─ [other 5ms]
Иди от самой широкой "полки" вниз.
5. Категоризируй проблемы
| Симптом | Категория |
|---|---|
| Много CPU на одной функции | Algorithm complexity |
Много времени в malloc / GC | Memory allocation |
| Долгие waits в I/O | Database, network |
| Параллельные блокирующие операции | Concurrency |
| Кеш miss | Caching |
6. Метрики в коде
import { performance } from 'perf_hooks';
const start = performance.now();
await heavyOperation();
const duration = performance.now() - start;
logger.info('Operation took', {
operation: 'heavyOperation',
duration_ms: duration,
});
Регулярно — в hot paths.
7. Tracing (distributed)
Если запрос проходит через несколько сервисов:
Frontend → API → DB → Cache → External API
↓
trace span 1
↓
trace span 2 (parent: 1)
↓
trace span 3 (parent: 2)
OpenTelemetry даёт это в любом языке.
8. Бенчмарки
Для микро-оптимизаций сравнивай через бенчмарки:
// vitest bench
import { bench } from 'vitest';
bench('Array.map', () => {
arr.map(x => x * 2);
});
bench('for loop', () => {
const out = new Array(arr.length);
for (let i = 0; i < arr.length; i++) out[i] = arr[i] * 2;
});
Запускай несколько раз — стабильно ли?
Подходы к оптимизации
A. Кеширование
Hot calculations → cache (LRU, Redis, etc.).
B. Batching
Множество маленьких операций → одна большая (DB inserts, API calls).
C. Lazy loading
Не загружай пока не нужно.
D. Parallelism
Если операции независимы — Promise.all / threads.
E. Algorithm
O(n²) → O(n log n) / O(n). Часто самое большое улучшение.
F. Data structures
Array.includes (O(n)) → Set.has (O(1)) для частых lookups.
Когда НЕ оптимизировать
- Cold path (1 раз в год)
- Микрооптимизации с 0.1% impact
- Если ухудшает readability сильно
- Без замеров до/после
Анти-паттерны
- ❌ "Этот код выглядит медленно" → переписать
- ❌ Оптимизация в development (без production load)
- ❌ Использовать "лучший алгоритм" без бенчмарка
- ❌ Преждевременная параллелизация
- ❌ Не измерить ПОСЛЕ изменений (может стало хуже)
В конце
- Текущие hot paths с замерами
- Топ-5 кандидатов на оптимизацию
- Expected impact каждого
- Order to tackle them
Аудит производительности (Core Web Vitals)
Глубокая проверка LCP, INP, CLS с привязкой к коду и приоритизированным планом исправлений.
Мастер-аудит сайта: 6 измерений за один проход
Orchestrator-аудит по 6 направлениям: UX, accessibility, performance, SEO, brand consistency, security. Quick scan + deep dive + приоритизированный план + композитная оценка + roadmap.
Performance budget по типам страниц
Бюджеты JS/CSS/images для разных типов страниц, целевые Web Vitals, enforcement в CI с конкретными порогами.