Систематическая отладка
4-фазный поиск первопричины: понимайте ошибки до их исправления.
Метаданные навыка
| Источник | Встроенный (установлен по умолчанию) |
| Путь | skills/software-development/systematic-debugging |
| Версия | 1.1.0 |
| Автор | VibeOS (адаптировано из obra/superpowers) |
| Лицензия | MIT |
| Платформы | linux, macos, windows |
| Теги | debugging, troubleshooting, problem-solving, root-cause, investigation |
| Связанные навыки | test-driven-development, plan, subagent-driven-development |
Справочник: полный SKILL.md
Ниже приведено полное определение навыка, которое VibeOS загружает при его активации. Это те инструкции, которые видит агент, когда навык активен.
Систематическая отладка
Обзор
Случайные исправления тратят время и создают новые ошибки. Быстрые патчи маскируют глубинные проблемы.
Основной принцип: ВСЕГДА находите первопричину, прежде чем пытаться исправить. Устранение симптомов — это провал.
Нарушение буквы этого процесса — это нарушение духа отладки.
Железный закон
НИКАКИХ ИСПРАВЛЕНИЙ БЕЗ ПРЕДВАРИТЕЛЬНОГО ИССЛЕДОВАНИЯ ПЕРВОПРИЧИНЫ
Если вы не завершили Фазу 1, вы не можете предлагать исправления.
Правило цикла обратной связи
Цикл обратной связи — это и есть работа по отладке. Прежде чем читать код для построения теории, создайте или определите тесный цикл — команду, которая может покраснеть на точном симптоме пользователя и позеленеть, когда ошибка будет исправлена. Тесный цикл — это быстрый, детерминированный, выполняемый агентом и достаточно специфичный, чтобы поймать именно эту ошибку, а не просто «не падает».
Когда чистое воспроизведение затруднено, потратьте непропорционально много усилий на построение цикла. Угадывание без цикла, способного покраснеть, — это тот режим отказа, для предотвращения которого и существует этот навык.
Когда использовать
Используйте для ЛЮБОЙ технической проблемы:
- Ошибки в тестах
- Баги в продакшене
- Неожиданное поведение
- Проблемы с производительностью
- Ошибки сборки
- Проблемы интеграции
Используйте это ОСОБЕННО, когда:
- Не хватает времени (в чрезвычайных ситуациях велик соблазн угадывать)
- «Одно быстрое исправление» кажется очевидным
- Вы уже пробовали несколько исправлений
- Предыдущее исправление не сработало
- Вы не до конца понимаете проблему
Не пропускайте, когда:
- Проблема кажется простой (у простых ошибок тоже есть первопричины)
- Вы спешите (спешка гарантирует переделки)
- Кто-то хочет, чтобы это было исправлено СЕЙЧАС (системный подход быстрее, чем хаотичные попытки)
Четыре фазы
Вы ДОЛЖНЫ завершить каждую фазу, прежде чем переходить к следующей.
Фаза 1: Исследование первопричины
ПРЕЖДЕ чем пытаться что-либо ИСПРАВЛЯТЬ:
1. Внимательно читайте сообщения об ошибках
- Не пропускайте ошибки или предупреждения
- Часто они содержат точное решение
- Читайте стектрейсы полностью
- Обращайте внимание на номера строк, пути к файлам, коды ошибок
Действие: Используйте read_file для соответствующих исходных файлов. Используйте search_files для поиска строки ошибки в кодовой базе.
2. Постройте тесный цикл обратной связи
- Можете ли вы вызвать точный симптом пользователя одной командой?
- Терпит ли команда неудачу из-за этой ошибки и проходит только после её исправления?
- Достаточно ли она быстра для многократного запуска?
- Детерминирована ли она? Для плавающих ошибок — можете ли вы повысить частоту воспроизведения до уровня, пригодного для отладки?
- Если не воспроизводится → собирайте больше данных, не угадывайте.
Способы построения цикла — пробуйте примерно в таком порядке:
- Падающий тест на стыке, который достигает ошибки: модульный, интеграционный или сквозной.
- HTTP-скрипт / curl против запущенного dev-сервера.
- Вызов CLI с фикстурным вводом, сравнение stdout/stderr с ожидаемым выводом.
- Скрипт безголового браузера (Playwright/Puppeteer), проверяющий DOM, консоль или сеть.
- Воспроизведение захваченного трейса: HAR, тело запроса, лог событий, сообщение очереди или тело вебхука.
- Одноразовый харнас, загружающий наименьший полезный срез системы и вызывающий сбойный путь.
- Цикл свойств / фаззинг, когда ошибка проявляется как неверный вывод на широком пространстве входных данных.
- Харнас для бисекции, подходящий для
git bisect run, когда ошибка появилась между двумя известными состояниями. - Дифференциальный цикл, сравнивающий старую и новую версии, две конфигурации, двух провайдеров или два набора данных.
- Скрипт с участием человека только как крайняя мера: запрограммируйте шаги человека и захватите их результат, чтобы цикл оставался структурированным.
Уплотните цикл, как только он появится:
- Сделайте его быстрее: кешируйте настройку, сужайте область действия, пропускайте нерелевантную инициализацию.
- Сделайте сигнал более чётким: проверяйте точный симптом, а не общий успех.
- Сделайте его более детерминированным: фиксируйте время, инициализируйте генератор случайных чисел, изолируйте файловую систему, заморозьте сеть.
Для недетерминированных ошибок непосредственная цель — более высокая частота воспроизведения, а не совершенство. Запустите триггер 100 раз, распараллельте, добавьте нагрузку, сузьте временные окна или добавьте задержки. Плавающая ошибка с вероятностью 50% поддаётся отладке; с вероятностью 1% — обычно нет.
Действие: Используйте инструмент terminal для запуска тесного цикла:
# Запустить конкретный падающий тест
pytest tests/test_module.py::test_name -v
# Или запустить скрипт воспроизведения
python scripts/repro_bug.py
# Или запустить высокочастотное воспроизведение плавающей ошибки
for i in {1..100}; do pytest tests/test_flake.py::test_name -q || break; done
3. Проверьте недавние изменения
- Что изменилось, что могло вызвать это?
- Git diff, недавние коммиты
- Новые зависимости, изменения конфигурации
Действие:
# Недавние коммиты
git log --oneline -10
# Незакоммиченные изменения
git diff
# Изменения в конкретном файле
git log -p --follow src/problematic_file.py | head -100
4. Собирайте доказательства в многокомпонентных системах
КОГДА система состоит из нескольких компонентов (API → сервис → база данных, CI → сборка → развёртывание):
ПРЕЖДЕ чем предлагать исправления, добавьте диагностическую инструментовку:
Для КАЖДОЙ границы компонента:
- Логируйте, какие данные входят в компонент
- Логируйте, какие данные выходят из компонента
- Проверьте распространение окружения/конфигурации
- Проверьте состояние на каждом уровне
Запустите один раз, чтобы собрать доказательства, показывающие, ГДЕ происходит сбой. ЗАТЕМ проанализируйте доказательства, чтобы определить отказавший компонент. ЗАТЕМ исследуйте этот конкретный компонент.
5. Проследите поток данных
КОГДА ошибка находится глубоко в стеке вызовов:
- Откуда берётся неверное значение?
- Что вызвало эту функцию с неверным значением?
- Продолжайте трассировку вверх по потоку, пока не найдёте источник
- Исправляйте в источнике, а не в симптоме
Действие: Используйте search_files для трассировки ссылок:
# Найти, где вызывается функция
search_files("function_name(", path="src/", file_glob="*.py")
# Найти, где устанавливается переменная
search_files("variable_name\\s*=", path="src/", file_glob="*.py")
Контрольный список завершения Фазы 1
- Сообщения об ошибках полностью прочитаны и поняты
- Команда тесного цикла существует и была запущена хотя бы один раз
- Цикл способен покраснеть: он проверяет точный симптом пользователя, а не близкий сбой
- Цикл детерминирован, или плавающая ошибка имеет достаточно высокую частоту воспроизведения для отладки
- Недавние изменения идентифицированы и проверены
- Доказательства собраны (логи, состояние, поток данных)
- Проблема локализована в конкретном компоненте/коде
- Гипотезы о первопричине могут быть сформулированы и проверены
СТОП: Не переходите к Фазе 2, пока не поймёте, ПОЧЕМУ это происходит.
Фаза 2: Анализ паттернов
Найдите паттерн перед исправлением:
0. Минимизируйте воспроизведение
Как только цикл покраснел, сократите воспроизведение до наименьшего сценария, который всё ещё остаётся красным. Убирайте входные данные, вызывающие стороны, конфигурацию, данные и шаги по одному, перезапуская цикл после каждого сокращения. Оставляйте только то, что необходимо для сбоя.
Завершено, когда удаление любого оставшегося элемента делает цикл зелёным. Минимальное воспроизведение сужает пространство гипотез и часто становится самым чистым регрессионным тестом.
1. Найдите работающие примеры
- Найдите похожий работающий код в той же кодовой базе
- Что работает, что похоже на то, что сломано?
Действие: Используйте search_files для поиска сравнимых паттернов:
search_files("similar_pattern", path="src/", file_glob="*.py")
2. Сравните с эталонами
- Если реализуете паттерн, прочитайте эталонную реализацию ПОЛНОСТЬЮ
- Не просматривайте по диагонали — читайте каждую строку
- Полностью поймите паттерн перед применением
3. Определите различия
- Что отличается между работающим и сломанным?
- Перечислите каждое различие, каким бы малым оно ни было
- Не предполагайте, что «это не может иметь значения»
4. Поймите зависимости
- Какие другие компоненты нужны этому?
- Какие настройки, конфигурация, окружение?
- Какие предположения он делает?
Фаза 3: Гипотеза и тестирование
Научный метод:
1. Сформулируйте ранжированные опровергаемые гипотезы
- Сгенерируйте 3–5 правдоподобных гипотез, прежде чем тестировать какую-либо одну.
- Ранжируйте их по вероятности и дешевизне опровержения.
- Сформулируйте предсказание, которое делает каждая гипотеза: «Если X является причиной, то изменение или наблюдение Y должно привести к Z».
- Отбросьте или уточните любую гипотезу, которая не делает проверяемого предсказания.
Если пользователь присутствует, покажите ранжированный список перед тестированием. У него могут быть знания предметной области, которые мгновенно изменят ранжирование. Если пользователь недоступен, продолжайте с вашим ранжированием.
2. Тестируйте минимально
- Проверьте гипотезу с самым высоким рейтингом с помощью наименьшего возможного зонда.
- Изменяйте одну переменную за раз.
- Не исправляйте несколько вещей одновременно.
- Предпочитайте инспекцию отладчиком/REPL, когда это возможно; одна точка останова лучше десяти логов.
- Если добавляете логи, помечайте каждую временную строку уникальным префиксом, например
[DEBUG-a4f2], чтобы очистка была одним поиском.
3. Проверьте, прежде чем продолжать
- Сработало? → Фаза 4
- Не сработало? → Сформулируйте НОВУЮ гипотезу
- НЕ добавляйте больше исправлений поверх
4. Когда вы не знаете
- Скажите «Я не понимаю X»
- Не притворяйтесь, что знаете
- Попросите пользователя о помощи
- Исследуйте больше
Фаза 4: Реализация
Исправляйте первопричину, а не симптом:
1. Создайте падающий тестовый пример
- Максимально простое воспроизведение
- Автоматизированный тест, если возможно
- ДОЛЖЕН быть до исправления
- Используйте навык
test-driven-development
2. Реализуйте одно исправление
- Устраните выявленную первопричину
- ОДНО изменение за раз
- Никаких улучшений «пока я здесь»
- Никакого встроенного рефакторинга
3. Проверьте исправление
# Запустить конкретный регрессионный тест
pytest tests/test_module.py::test_regression -v
# Запустить полный набор — никаких регрессий
pytest tests/ -q
4. Если исправление не работает — Правило трёх
- СТОП.
- Посчитайте: сколько исправлений вы уже попробовали?
- Если < 3: Вернитесь к Фазе 1, проанализируйте заново с новой информацией
- Если ≥ 3: СТОП и поставьте под сомнение архитектуру (шаг 5 ниже)
- НЕ пытайтесь сделать Исправление №4 без обсуждения архитектуры
5. Если 3+ исправлений не сработали: Поставьте под сомнение архитектуру
Паттерн, указывающий на архитектурную проблему:
- Каждое исправление обнаруживает новое общее состояние/связь в другом месте
- Исправления требуют «масштабного рефакторинга» для реализации
- Каждое исправление создаёт новые симптомы в других местах
СТОП и поставьте под сомнение основы:
- Здоров ли этот паттерн в принципе?
- «Продолжаем ли мы его использовать просто по инерции»?
- Стоит ли рефакторить архитектуру вместо продолжения исправления симптомов?
Обсудите с пользователем, прежде чем пытаться сделать больше исправлений.
Это НЕ провальная гипотеза — это неправильная архитектура.
Красные флаги — СТОП и следуйте процессу
Если вы ловите себя на мысли:
- «Быстрое исправление сейчас, расследование потом»
- «Просто попробую изменить X и посмотрю, сработает ли»
- «Внесу несколько изменений, запущу тесты»
- «Пропущу тест, я проверю вручную»
- «Вероятно, это X, давайте это исправлю»
- «Я не совсем понимаю, но это может сработать»
- «Паттерн говорит X, но я адаптирую его иначе»
- «Вот основные проблемы: [перечисляет исправления без исследования]»
- Предлагать решения до трассировки потока данных
- «Ещё одна попытка исправления» (когда уже пробовали 2+)
- Каждое исправление обнаруживает новую проблему в другом месте
ВСЁ это означает: СТОП. Вернитесь к Фазе 1.
Если 3+ исправлений не сработали: Поставьте под сомнение архитектуру (Фаза 4, шаг 5).
Распространённые оправдания
| Оправдание | Реальность |
|---|---|
| «Проблема простая, процесс не нужен» | У простых проблем тоже есть первопричины. Для простых ошибок процесс быстр. |
| «Чрезвычайная ситуация, нет времени на процесс» | Систематическая отладка БЫСТРЕЕ, чем хаотичные догадки и проверки. |
| «Просто попробую это сначала, потом расследую» | Первое исправление задаёт паттерн. Делайте правильно с самого начала. |
| «Я напишу тест после подтверждения, что исправление работает» | Непроверенные исправления не держатся. Тест сначала доказывает это. |
| «Несколько исправлений сразу экономят время» | Нельзя изолировать, что сработало. Вызывает новые ошибки. |
| «Эталон слишком длинный, я адаптирую паттерн» | Частичное понимание гарантирует ошибки. Прочитайте его полностью. |
| «Я вижу проблему, давайте её исправлю» | Видеть симптомы ≠ понимать первопричину. |
| «Ещё одна попытка исправления» (после 2+ неудач) | 3+ неудачи = архитектурная проблема. Поставьте под сомнение паттерн, не исправляйте снова. |
Краткий справочник
| Фаза | Ключевые действия | Критерии успеха |
|---|---|---|
| 1. Первопричина | Читать ошибки, воспроизводить, проверять изменения, собирать доказательства, трассировать поток данных | Понять ЧТО и ПОЧЕМУ |
| 2. Паттерн | Найти работающие примеры, сравнить, определить различия | Знать, что отличается |
| 3. Гипотеза | Сформулировать теорию, тестировать минимально, одна переменная за раз | Подтверждённая или новая гипотеза |
| 4. Реализация | Создать регрессионный тест, исправить первопричину, проверить | Ошибка устранена, все тесты проходят |
Интеграция с VibeOS
Инструменты расследования
Используйте эти инструменты VibeOS во время Фазы 1:
search_files— Найти строки ошибок, трассировать вызовы функций, находить паттерныread_file— Читать исходный код с номерами строк для точного анализаterminal— Запускать тесты, проверять историю git, воспроизводить ошибкиweb_search/web_extract— Исследовать сообщения об ошибках, документацию библиотек
С помощью delegate_task
Для сложной многокомпонентной отладки отправляйте подчинённых агентов для расследования:
delegate_task(
goal="Выяснить, почему [конкретный тест/поведение] падает",
context="""
Следуйте навыку систематической отладки:
1. Внимательно прочитайте сообщение об ошибке
2. Воспроизведите проблему
3. Проследите поток данных, чтобы найти первопричину
4. Сообщите результаты — НЕ исправляйте пока
Ошибка: [вставьте полную ошибку]
Файл: [путь к падающему коду]
Команда теста: [точная команда]
""",
toolsets=['terminal', 'file']
)
С помощью test-driven-development
При исправлении ошибок:
- Напишите тест, который воспроизводит ошибку (RED)
- Отлаживайте систематически, чтобы найти первопричину
- Исправьте первопричину (GREEN)
- Тест доказывает исправление и предотвращает регрессию
Реальное влияние
Из сессий отладки:
- Систематический подход: 15-30 минут на исправление
- Подход случайных исправлений: 2-3 часа хаотичных попыток
- Процент успешных исправлений с первой попытки: 95% против 40%
- Новые ошибки: почти ноль против частых
Никаких сокращений. Никаких догадок. Системный подход всегда побеждает.