5 мин

Claude Code для расследований производительности: измеримый рабочий цикл

Используйте Claude Code для расследований производительности в повторяемом цикле: измерить, выдвинуть гипотезу, изменить минимально и переизмерить перед выпуском.

Claude Code для расследований производительности: измеримый рабочий цикл

Почему работа над производительностью проваливается без измерений

Ошибки производительности порождают догадки. Кто‑то замечает, что страница «кажется медленной» или API таймаутится, и быстрейшее решение — «прибрать» код, добавить кэш или переписать цикл. Проблема в том, что «кажется медленным» — не метрика, а «чище» — не значит быстрее.

Без измерений команды тратят часы на правку не той части. Горячий путь может быть в базе данных, в сети или в одной неожиданный аллокации, в то время как команда шлифует код, который почти не влияет на производительность. Хуже того, изменение, кажущееся разумным, может ухудшить ситуацию: лишний лог в tight‑цикле, кэш, увеличивающий давление на память, или параллельная работа, создающая конкуренцию за блокировки.

Догадки также рискуют повредить поведение. Меняя код ради скорости, вы можете изменить результаты, обработку ошибок, порядок выполнения или повторные попытки. Если вы не проверяете корректность и скорость вместе, можно «выиграть» бенчмарк и тихо выпустить баг.

Относитесь к работе над производительностью как к эксперименту, а не к спору. Цикл прост и повторяем:

  • Выберите одну метрику, которая отражает боль (latency, throughput, CPU, память, время БД).
  • Зафиксируйте базовую метрику в одинаковых условиях.
  • Измените одну небольшую вещь.
  • Измерьте снова и сравните.

Многие улучшения скромны: срезать 8% с p95, снизить пик памяти на 50 МБ или убрать один запрос к базе. Эти выигрыши важны, но только если они измерены, проверены и повторяемы.

Рабочий процесс: измерить — выдвинуть гипотезу — изменить — переизмерить

Это работает лучше как цикл, а не как разовый запрос «сделать быстрее». Цикл держит вас честными, потому что каждое действие привязано к доказательству и числу, за которым можно следить.

Чёткая последовательность:

  • Измерьте: выберите метрику и запишите baseline.
  • Гипотеза: опишите, что, по вашему мнению, медлит и почему.
  • Изменение: внесите минимальную правку, проверяющую гипотезу.
  • Переизмерьте: выполните те же измерения и сравните.

Каждый шаг защищает от разного вида самообмана. Измерение сначала останавливает «починку» того, что не было настоящей проблемой. Письменная гипотеза мешает менять пять вещей одновременно и гадать, что сработало. Минимальные изменения снижают риск поломать поведение или добавить новые узкие места. Переизмерение ловит плацебо‑победы (например, ускорение из‑за тёплого кэша) и выявляет регрессии.

«Готово» — это не чувство. Это результат: целевая метрика двинулась в нужную сторону, и изменение не привело к явным регрессиям (ошибки, рост памяти, ухудшение p95 или замедление соседних эндпоинтов).

Понимание, когда остановиться, — часть процесса. Остановитесь, когда выигрыши выровняются, метрика уже достаточна для пользователей, или когда следующая идея требует крупных рефакторов ради малого эффекта. Работа над производительностью всегда имеет альтернативную стоимость; цикл помогает тратить время там, где он окупается.

Выберите метрику и зафиксируйте baseline

Если вы меряете пять вещей одновременно, вы не поймёте, что именно улучшилось. Выберите одну основную метрику для расследования и рассматривайте всё остальное как сигналы поддержки. Для пользовательских задач это часто latency. Для пакетной работы — throughput, время CPU, использование памяти или даже стоимость в облаке на запуск.

Будьте конкретны в сценарии. «API медленный» — слишком расплывчато. «POST /checkout с типичной корзиной из 3 товаров» — измеримо. Держите входы стабильными, чтобы числа имели смысл.

Запишите baseline и детали окружения до правки кода: размер датасета, тип машины, режим сборки, feature flags, конкуренция и прогрев. Этот baseline — ваш якорь. Без него любое изменение может выглядеть как прогресс.

Для latency опирайтесь на процентели, а не только на среднее. p50 показывает типичный опыт, а p95 и p99 — болезненный хвост, на который жалуются пользователи. Изменение, улучшающее p50, но ухудшающее p99, всё ещё может ощущаться медленнее.

Решите заранее, что считать «значимым», чтобы не праздновать шум:

  • Latency: улучшение p95 минимум на 10% (или фиксированный порог, например 50 мс)
  • Throughput: минимум +5% запросов в секунду при том же уровне ошибок
  • CPU или память: уменьшение, достаточное чтобы избежать масштабирования или краха
  • Стоимость: измеримое снижение на запуск или на 1000 запросов

Когда правила установлены, можно тестировать идеи, не двигая цель в процессе.

Собирайте доказательства с помощью профайлинга и простых метрик

Начните с самого простого надёжного сигнала. Одна тайм‑метка вокруг запроса может показать, есть ли реальная проблема и насколько она велика. Глубокий профайлинг оставьте на тот момент, когда нужно объяснить, почему всё медленно.

Хорошие доказательства обычно приходят из смешения источников:

  • App‑логи (длительность запросов, rate ошибок, самые медленные эндпоинты)
  • APM‑трейсы (где тратится время между сервисами)
  • Вывод профайлера или flame graph (горячие функции и стеки вызовов)
  • Статистика БД (медленные запросы, ожидания блокировок, hit rate кэша)
  • Метрики инфраструктуры (CPU, память, сеть, рестарты контейнеров)

Используйте простые метрики, когда вопрос «медленнее ли и на сколько?». Профайлинг — когда вопрос «куда уходит время?». Если p95 удвоился после деплоя, начните с таймингов и логов, чтобы подтвердить регрессию и определить границы. Если тайминги показывают, что большая часть задержки внутри кода приложения (а не в БД), CPU‑профайлер или flame graph укажут конкретную функцию.

Держите измерения безопасными. Собирайте то, что нужно для отладки, а не пользовательский контент. Предпочитайте агрегаты (длительности, счётчики, размеры) вместо сырых payload и по умолчанию редактируйте идентификаторы.

Шум — реальность, поэтому делайте несколько замеров и отмечайте выбросы. Прогоните один и тот же запрос 10–30 раз и фиксируйте медиану и p95, а не один лучший прогон.

Запишите точный рецепт теста, чтобы можно было повторить после изменений: окружение, датасет, эндпоинт, размер тела запроса, уровень конкуренции и способ сбора результатов.

Превратите доказательства в чёткую гипотезу

Plan the experiment first
Use Planning Mode to write the baseline, hypothesis, and re-test steps before coding.

Начните с симптома, который можно назвать: «p95 вырос с 220 ms до 900 ms в пиковую нагрузку», «CPU держится на 95% на двух ядрах» или «память растёт на 200 МБ в час». Расплывчатые симптомы вроде «кажется медленным» ведут к случайным изменениям.

Затем переведите измеренное в область подозрения. Flame graph может показать большую долю времени в JSON‑сериализации, трейсы — медленный путь вызовов, а статистика БД — один запрос, доминирующий во времени. Выберите наименьшую область, которая объясняет большую часть стоимости: функцию, один SQL‑запрос или один внешний вызов.

Хорошая гипотеза — одно предложение, проверяема и связана с предсказанием. Вы просите проверить идею, а не инструмент творчески сделать всё быстрее.

Простой шаблон гипотезы

Используйте формат:

  • Из‑за (доказательство), (подозреваемая часть) вызывает (симптом).
  • Если мы изменим (конкретное поведение), то (метрика) должна улучшиться на (примерно сколько).
  • Мы поймём, что это сработало, если (результат переизмерения).

Пример: "Because the profile shows 38% of CPU in SerializeResponse, allocating a new buffer per request is causing CPU spikes. If we reuse a buffer, p95 latency should drop by about 10-20% and CPU should fall by 15% under the same load." (пример оставлен на английском, чтобы сохранить имя функции и точность профиля).

Откройте альтернативы перед тем, как править код. Возможно, медленный участок — на самом деле внешняя зависимость, конкуренция за блокировки, изменение hit rate кэша или релиз, увеличивший размер payload.

Запишите 2–3 альтернативных объяснения, затем выберите то, которое лучше всего поддерживается доказательствами. Если изменения не сдвинули метрику, у вас уже будет следующая гипотеза.

Как использовать Claude Code, не скатываясь в догадки

Claude полезен в работе над производительностью, когда вы относитесь к нему как к аккуратному аналитику, а не к оракулу. Привязывайте каждое предложение к тому, что вы измерили, и убедитесь, что каждое утверждение можно опровергнуть.

Давайте ему реальные входные данные, а не расплывчатое описание. Вставьте небольшие, сфокусированные доказательства: сводку профиля, несколько строк лога вокруг медленного запроса, план запроса и конкретный путь в коде. Укажите числа «до» (p95, время CPU, время БД), чтобы он знал ваш baseline.

Попросите объяснить, что данные поддерживают, а что — нет. Затем форсируйте конкурирующие объяснения. Хороший промпт: «Дай 2–3 гипотезы и для каждой скажи, что её опровергнет.» Это мешает зациклиться на первой правдоподобной истории.

Перед правкой кода попросите наименьший эксперимент, проверяющий ведущую гипотезу. Делайте быстрые и обратимые проверки: один таймер вокруг функции, включить один флаг профилирования или выполнить EXPLAIN для запроса.

Если хотите строгую структуру вывода, запросите:

  • Что показывают доказательства (и степень уверенности)
  • 2–3 гипотезы с тестом на опровержение
  • Наименьшее изменение кода/конфигурации для проверки первой гипотезы
  • Точную метрику для переизмерения и ожидаемое направление

Если вывод не называет конкретную метрику, место и ожидаемый результат — вы снова гадали.

Делайте минимальные, обратимые изменения

Test DB changes safely
Iterate on Go + PostgreSQL queries and re-run the same scenario each time.

После того как появились доказательства и гипотеза, удержитесь от желания «почистить всё». Работу над производительностью легче доверять, когда изменение небольшое и его просто отменить.

Меняйте по одной вещи. Если вы подправили запрос, добавили кэш и отрефакторили цикл в одном коммите, вы не поймёте, что помогло (или навредило). Изменения в одной переменной делают следующее измерение значимым.

До правки кода запишите числовые ожидания. Пример: «p95 должен упасть с 420 ms до < 300 ms, и время БД должно упасть примерно на 100 ms.» Если результат не достигает цели, вы быстро поймёте, что гипотеза слабая или неполная.

Держите изменения обратимыми:

  • Предпочитайте небольшой diff, который легко откатить.
  • Поместите изменение за простым флагом, чтобы можно было быстро выключить.
  • Избегайте проходных рефакторов, меняющих имена, форматирование и логику одновременно.
  • Ограничьте область: один эндпоинт, один горячий путь, один дорогой вызов.
  • Добавьте короткую заметку в сообщении коммита с ожидаемыми before/after метриками.

«Минимальный» не значит «тривиальный». Это значит сфокусированный: кэшировать один дорогой результат функции, убрать одну повторяющуюся аллокацию в tight‑цикле или не выполнять лишнюю работу для запросов, которым она не нужна.

Добавьте лёгкие тайминги вокруг подозреваемого узкого места, чтобы увидеть, что сдвинулось. Одна отметка времени до и после вызова (в логе или как метрика) может подтвердить, попали ли вы в узкое место или просто переместили время в другое место.

Переизмерьте и решите, что дальше

После изменения выполните точно тот же сценарий, что и для baseline: те же входы, окружение и форму нагрузки. Если тест зависит от кэшей или прогрева, укажите это явно (например: «первый запуск холодный, следующие 5 — тёплые»). Иначе вы «найдёте» улучшение, которое оказалось везением.

Сравнивайте результаты по тем же метрикам и процентилям. Средние могут скрывать боль — следите за p95 и p99, а также за throughput и CPU. Сделайте достаточно повторов, чтобы понять стабильность чисел.

Прежде чем радоваться, проверьте регрессии, которые не видны в заголовке:

  • Корректность: ответы совпадают с ожидаемыми
  • Error rate: таймауты, 5xx, ретраи
  • Память: пик или устойчивый рост
  • Хвостовая задержка (p99): не ухудшилась ли она
  • Нагрузка на ресурсы: CPU/БД не взлетели

Затем решайте на основе доказательств, а не надежд. Если улучшение реально и регрессий нет — оставляйте. Если результаты смешанные или шумные — откатывайте и придумывайте новую гипотезу либо ещё сильнее изолируйте изменение.

Если вы работаете на платформе, такой как Koder.ai, создание снапшота до эксперимента может сделать откат одним шагом, что упрощает тестирование смелых идей.

Наконец, запишите, что вы узнали: baseline, изменение, новые числа и вывод. Эта короткая запись поможет не повторять те же тупики в следующий раз.

Частые ошибки, которые тратят время

Earn credits while you learn
Share what you measured and improved, and get credits for your Koder.ai content.

Работа над производительностью обычно идёт по наклонной, когда связь между тем, что вы измеряли, и тем, что вы изменили, теряется. Держите чистую цепочку доказательств, чтобы уверенно сказать, что именно улучшило ситуацию или ухудшило.

Частые промахи:

  • Починка не той цели: вы радуетесь улучшению медианы (p50), но хвост (p95/p99) всё ещё плох.
  • Изменение множества вещей сразу: рефакторы, кэш и правки запросов в одном коммите — вы не узнаете, что помогло.
  • Вера в один шумный запуск: локальный бенчмарк может скакать на 20% между прогоном и это не доказательство.
  • Трактовка одного профиля как всей правды: flame graph указывает на парсинг JSON, а в это время запросы накапливаются из‑за просадок БД.
  • Сравнение яблок с апельсинами: разные датасеты, feature flags, железо или уровни конкуренции, и выводы делаются всё равно.

Небольшой пример: эндпоинт кажется медленным, вы оптимизируете сериализатор, потому что он горячий в профиле. Затем тестируете с меньшим датасетом и всё кажется быстрее. В проде p99 ухудшается, потому что БД всё ещё узкое место, а изменение увеличило размер payload.

Если даёте Claude Code предложения по фиксам, держите его строго: просите 1–2 минимальных изменения, соответствующих уже собранным доказательствам, и требуйте плана переизмерения до принятия патча.

Короткий чек‑лист перед тем, как назвать «быстрее»

Обвинения в скорости разваливаются, когда тест нечёткий. Перед празднованием убедитесь, что можете объяснить, что измеряли, как измеряли и что изменили.

Начните с названия одной метрики и записи baseline. Включите детали, которые влияют на числа: тип машины, загрузка CPU, размер данных, режим сборки (debug vs release), feature flags, состояние кэша и конкуренция. Если вы не сможете воссоздать настройку завтра, у вас нет baseline.

Чек‑лист:

  • Метрика и baseline записаны с примечаниями об окружении (железо, конфиг, данные, холодный/тёплый кэш).
  • Шаги теста записаны и повторяемы.
  • Есть одна гипотеза с предсказанием (например, «если убрать N+1 запросы, p95 упадёт на ~30%»).
  • Вы сделали одно небольшое, обратимое изменение и задокументировали, что сдвинулось (файл, функция, запрос, настройка).
  • Вы переизмерили с несколькими прогоном и сравнили «как с как» (те же входы, та же нагрузка).

После того как числа улучшились, выполните быструю регрессионную проверку. Проверьте корректность (те же ответы), error rate и таймауты. Наблюдайте побочные эффекты вроде роста памяти, всплесков CPU, медленного старта или увеличения нагрузки на БД. Изменение, которое улучшает p95, но удваивает память, может быть плохой обмен.

FAQ

Какую первую метрику мне мерить, когда что‑то «чувствуется медленным»?

Начните с одной цифры, которая соответствует жалобе — обычно это p95 latency для конкретного эндпоинта и входных данных. Запишите базовую метрику в тех же условиях (размер данных, конкуренция, холодный/тёплый кэш), затем измените одну вещь и измерьте снова.

Если вы не можете воспроизвести базовое значение, вы ещё не измеряете — вы предполагаете.

Что мне нужно записать для baseline, чтобы он был полезен?

Хорошая базовая запись включает в себя:

  • Точный сценарий (эндпоинт, входы, уровень конкуренции)
  • Основную метрику (например p95 latency)
  • Примечания об окружении (машина/контейнер, режим сборки, feature flags)
  • Состояние кэша (холодный или тёплый) и шаги прогрева
  • Достаточно запусков, чтобы увидеть разброс (не один «лучший» прогон)

Запишите это до того, как будете править код, чтобы не двигать цель.

Почему все ориентируются на p95/p99, а не на среднюю задержку?

Процентели лучше отражают пользовательский опыт, чем среднее. p50 показывает типичный случай, но жалобы приходят из медленного хвоста — это p95/p99.

Если p50 улучшился, а p99 ухудшился, система может казаться медленнее, хотя среднее выглядит лучше.

Когда использовать профайлинг вместо простого измерения запроса?

Используйте простые тайминги/логи, когда вопрос «медленнее ли и на сколько?». Профайлинг нужен, когда вопрос «куда уходит время?».

Практический поток: подтвердите регрессию таймингами запросов, затем профилируйте, только если замедление реально и локализовано.

Как не потеряться, измеряя сразу слишком много показателей?

Выберите одну основную метрику, остальные рассматривайте как страховочные сигналы. Частая связка:

  • Основная: p95 latency (или throughput)
  • Страховки: error rate, p99, CPU, память, время БД

Это предотвращает ситуацию, когда вы «выигрываете» одну диаграмму и при этом тихо создаёте тайм‑ауты или рост памяти.

Как выглядит хорошая гипотеза в работе над производительностью?

Сформулируйте одно предложениe, привязанное к доказательству и предсказанию:

  • Из‑за (доказательство), (подозреваемая часть) вызывает (симптом).
  • Если мы изменим (конкретное поведение), то (метрика) должна улучшиться на (примерно сколько).

Если вы не можете назвать доказательство и ожидаемое изменение метрики, гипотеза не тестируемая.

Почему так важны минимальные, обратимые изменения?

Делайте изменения маленькими, сфокусированными и легко откатываемыми:

  • Меняйте по одной вещи в коммите
  • Ограничьте область одним эндпоинтом/горячим путём
  • Не смешивайте рефакторы с оптимизациями
  • Предпочитайте флаги, чтобы можно было быстро выключить

Маленькие диффы делают результаты измерений значимыми и снижают риск поломать поведение.

После изменения что проверить кроме «стало быстрее»?

Перезапустите точно тот же сценарий, что и при baseline: те же входы, окружение и нагрузка. Если тест зависит от кэша или прогрева, явно оговорите это (например: «первый запуск холодный, следующие 5 — тёплые»). Иначе вы «найдёте» улучшение, которое оказалось случайностью.

Сравнивайте те же процентели и метрики. Средние могут скрывать проблему — смотрите p95 и p99, throughput и CPU. Сделайте достаточно повторов, чтобы понять, устаканились ли числа.

Перед празднованием проверьте регрессии, которые не видны в заголовках:

  • Корректность: ответы совпадают с ожидаемыми
  • Error rate: таймауты, 5xx, ретраи
  • Память: пик или устойчивый рост
  • Хвостовая задержка: ухудшение p99
  • Нагрузка на ресурсы: всплески CPU/БД

Если улучшение реальное и регрессий нет — внедряйте. Если данные шумные или противоречивые — откатывайте и стройте новую гипотезу.

Как использовать Claude Code, не скатиться в «оптимизацию по ощущениям»?

Дайте Claude реальные входные данные, а не расплывчатое описание. Вставьте небольшое, сфокусированное доказательство: сводку профиля, несколько строк лога вокруг медленного запроса, план запроса, и конкретный путь в коде. Укажите «до» числа (p95, CPU, время БД), чтобы было с чем сравнивать.

Попросите объяснить, что данные поддерживают, а что — нет. Заставьте генерировать конкурирующие объяснения. Полезный промпт: «Дай 2–3 гипотезы и для каждой скажи, что её опровергнет.» Это защищает от фиксации на первой правдоподобной истории.

Перед изменением запросите наименьший эксперимент для проверки гипотезы: один таймер вокруг функции, включить флаг профилирования или выполнить EXPLAIN для запроса.

Если вывод не называет конкретную метрику, место и ожидаемый результат — вы снова гадали.

Похожие статьи