Сразу скажу, что сам я отказался от использования отладчика очень давно (точно уже не вспомнить, но вероятно где-то в 1997-1998 годах). Причиной этого стало понимание ужасающей неэффективности той технологии отладки, которая навязывается нам отладчиками общего назначения. Здесь я попробую кратко сформулировать основные свои соображения.
1. Само по себе наблюдение за выполнением программы было бы не очень полезным, если бы мы не могли наблюдать также и за теми изменениями, которые происходят в данных в результате выполнения нашей программы. Ясно, что все отладчики предоставляют такую возможность, но наши возможности по просмотру значений обычно ограничены относительно простыми типами данных. Почти бесполезна возможность просматривать значения полей сложного класса, если на данном этапе отладки сам этот класс работает вполне надежно и представляет некую сложную сущность, с которой работает отлаживаемый алгоритм (например, если алгоритм работает с изображением, то при его отладке возможность просмотра бинарного представления изображения почти бесполезна). Какой отладчик позволяет использовать предоставленные пользователем методы просмотра специфических для приложения данных и как реализовать такую возможность? Думаю, что это было бы весьма сложной задачей как для реализации в отладчике (например, через плагины), так и для поддержки со стороны пользователя (например путем написания соответствующих плагинов). В то же время, в большинстве случаев сама программа содержит достаточно полный набор средств для просмотра тех данных, с которыми она оперирует. Если с умом подойти к реализации вывода легко читаемых дампов всех основных внутренних структур данных, то программа сама становится идеальным отладчиком для самой себя. При этом появляется возможность получать и выводить дополнительную информацию о строении данных, которая нужна только для отладки и к которой обычный отладчик не может иметь доступа (например, выводить гистограммы яркостей для промежуточных изображений, существующих только в процессе обработки данных).
2. Сам по себе пошаговый проход по коду — весьма утомительное и неэффективное занятие. Отладчики предоставляют нам более или менее сложные средства для того, чтобы останавливать выполнение программы только в некоторых ее местах или при выполнении некоторых условий. Тем не менее, здесь мы снова сталкиваемся с отсутствием у отладчика контекста, который имеется у самой программы. Отладочный код, встроенный в программу, может выполнять некоторый нетривиальный анализ данных и по его результатам делать вывод о необходимости произвести отладочный вывод. Приложение обычно имеет все средства для анализа тех данных, с которыми оно работает, так что и их анализ для целей отладки оно может выполнить быстро и эффективно.
3. Если при решеннии некоторой проблемы мы прибегли к помощи отладчика, то в процессе отладки (сессия отладки) мы получаем довольно большое количество информации о внутренней структуре кода с точки зрения интересующей нас проблемы. За какими данными следует следить, какие условия следует проверять — все это является побочным продуктом сессии отладки, который при обычной технологии безвозвратно теряется по завершении сессии отладки. Если же весь отладочный код, проверяющий условия и выводящий логи и дампы данных, находится в коде программы, то он остается доступным и мы можем использовать его при появляении новых проблем. Интересно, что часто даже совершенно новые проблемы с кодом удается успешно решать, анализируя логи и дампы, код для которых писался в процессе решения совершенно других проблем.
Естественно, что подход, основанный на использовании отладочного кода, требует наличия удобного фреймворка, сокращающего усилия на отладку. Хотелось бы также иметь возможность создавать поименованные сессии отладки, генерирующие вывод, наиболее удобный для анализа некоторого конкретного аспекта поведения исследуемого кода. Уже много лет я двигаюсь в этом направлении, но совершенство все еще остается далекой целью. Тем не менее, отладка у меня сейчас занимает исчезающе малый процент рабочего времени, и этому я обязан отказу от использования отладчика общего назначения.
Таким образом, классический отладчик может быть удобен только для отладки низкоуровневых алгоритмов, работающих с более-менее простыми типами данных. Однако, в относительно большой системе все такие алгоритмы обычно давно написаны, отлажены, протестированы и спрятаны внутри библиотек и классов. Очень редко возникает необходимость писать и отлаживать такой низкоуровневый код и, даже если она и возникает, более эффективным оказывается метод «пристального взгляда». Окончательно получается, что у классического отладчика остается единственная достойная задача — дать возможность просмотреть стек вызовов в момент аварийного завершения программы. Для чего я его и использую. И вам желаю того же.
Update: Полезные ссылки:
Способы отладки приложений [
http://www.dtf.ru/articles/print.php?id=36376]
Способы отладки приложений: Протоколирование [
http://www.dtf.ru/articles/print.php?id=36547]
Способы отладки приложений: Отладка по крэш-дампам [
http://www.dtf.ru/articles/print.php?id=37058]
Integrated logging: printf debugging revisited [
http://www.cs.technion.ac.il/~gsasha/logger/]
Short introduction to log4j [
http://logging.apache.org/log4j/docs/manual.html]