Debugging: Finding It Yourself
Практическое руководство по поиску ошибок без помощи других — как изолировать, проверить и действительно понять ваши баги.
Большинство начинающих относятся к багу как к стене. Они на неё наталкиваются, останавливаются и просят кого-то другого перелезть через неё. Привычка, которая действительно развивает навык, другая: вы учитесь рассматривать баг как вопрос с найдаемым ответом и ищете его прежде, чем спрашивать.
Читайте сообщение об ошибке как улику, а не как шум
Стек-трейсы постоянно пропускают, потому что они выглядят страшно. Но обычно они точно говорят вам, где и почему что-то сломалось. Если вы получите TypeError: 'NoneType' object is not subscriptable в Python, это не случайный набор символов — это означает, что переменная, которая должна содержать список или словарь, на самом деле None. Номер строки говорит вам, где это произошло. Ваша задача — проследить назад от этой строки и найти место, где значение должно было быть установлено, но не было.
Сделайте это перед поиском в интернете: сначала прочитайте последнюю строку трейсбека, потом двигайтесь вверх. Последняя строка обычно называет саму исключение. Строки выше показывают цепь вызовов, которая привела вас сюда.
Воспроизведите это намеренно
Если баг появляется только иногда, вы его ещё не понимаете. Перед тем как трогать код, попытайтесь сделать так, чтобы он происходил надёжно. Меняйте по одному входному значению за раз. Он падает на пустом списке, но не на полном? Он падает только при втором вызове функции, а не при первом? Баг, который вы можете воспроизвести по команде — это баг, который на 80% решён, потому что теперь вы можете проверить, сработало ли исправление, вместо того чтобы гадать.
Делите задачу пополам, потом ещё пополам
Двоичный поиск — это не только для отсортированных массивов — это самый быстрый способ найти неработающий код в длинной функции или конвейере. Закомментируйте или обойдите вторую половину вашей логики и проверьте, всё ли ещё воспроизводится баг в первой половине. Если да, проблема в первой половине. Если нет, то во второй. Повторите. Это работает для 200-строчного скрипта так же хорошо, как для многоэтапного конвейера данных, где вы проверяете выходные данные на каждом этапе с помощью print() или df.head().
Это лучше, чем случайно менять строки и перезапускать, что делает большинство людей под давлением, и это тратит намного больше времени, чем экономит.
Используйте отладчик вместо print(), когда print() перестаёт работать
print() хорошо работает в простых случаях, но когда вы отслеживаете состояние через несколько вызовов функций, настоящий отладчик экономит реальное время. В Python, поместите import pdb; pdb.set_trace() прямо перед подозрительной строкой, запустите скрипт и вы получите живую подсказку, где можно инспектировать переменные, пошагово двигаться по строкам с n и входить в вызовы функций с s. Встроенный отладчик VS Code делает то же самое с точками останова, которые вы нажимаете вместо ввода текста. В любом случае, цель одна: наблюдайте за реальным состоянием вашей программы вместо того чтобы гадать, какое оно, вероятно, есть.
Изолируйте это от остального вашего проекта
Если баг происходит внутри большой кодовой базы, не отлаживайте его внутри большой кодовой базы. Скопируйте релевантную функцию в свежий файл с поддельным, минимальным вводом, который вызывает ту же ошибку. Если баг исчезает, что-то в окружающем контексте — глобальная переменная, импорт, устаревшее состояние — это настоящая причина, и вы только что кое-что важное узнали. Если баг сохраняется в изоляции, теперь у вас есть маленький, shareable, testable случай, и вы намного ближе к реальному исправлению.
Проверяйте свои предположения против реальности, а не памяти
Огромная часть времени отладки уходит на неопровергаемые предположения:
Написано с помощью ИИ, проверено и опубликовано Михалом Пильхом (CISSP), Korra Studio.
Это одна заметка из базы знаний Korra Studio — платформа сочетает каждую тему с наставничеством один на один.
Начать бесплатноarrow_forward