define('DISALLOW_FILE_EDIT', true); define('DISALLOW_FILE_MODS', true); Обзор методов отладки программного обеспечения

Обзор методов отладки программного обеспечения

Время от времени на форумах «пролетает» вопрос: «Какие методы отладки вы использовали?». Этот пост — мой ответ.

Отладка — это комплексный процесс по выявлению и исправлению дефектов в программном обеспечении.  Сами же дефекты, обычно, обнаруживается в процессе тестирования ПО.

(Прим. Часто под термином «отладка» подразумевают «тестирование» + «непосредственно отладка». В данном посте эти термины я буду разделять.)

Отладка состоит из следующих этапов:

  1. воспроизведение дефекта (любым из доступных способов);
  2. анализ дефекта (поиск причины возникновения дефекта — root-cause);
  3. дизайн исправления дефекта (и возможно ревью, если есть альтернативы);
  4. кодирование исправления дефекта (и какие-либо активности связанные с кодированием);
  5. валидация исправления;
  6. интеграция исправления в кодовую базу или целевую систему;
  7. дополнительные валидации после интеграции (если необходимости).

Пункты 1 и 2 — самые длительные этапы. Они могут объединяться, например, если сложность отладки именно в воспроизведение проблемы и  имеется достаточно assert-ов в коде, то тогда после воспроизведение дефекта root-cause будет автоматически выявлен за счёт детального сообщения об ошибке в assert-е. Но бывает и по-другому, когда дефект воспроизводится легко, но root-cause абсолютно не ясен.

Если root-cause дефекта найден, то разработать исправление не составляет большого труда (конечно, в зависимости от требований к качеству ПО). Поэтому с этапами 1 и 2 в большинстве случаев ассоциируется термин «отладка». Более того, отладка — это рекурсивный процесс. На  любом этапе отладки могут возникнуть новые дефекты, которые придётся отлаживать. Например, какая-то часть исправления в коде работает не так как ожидается и соответственно придётся отлаживать эту часть в изоляции и снова основное время уходит на пункты 1 и 2 и т.д. Таким образом,  под методами отладки дефектов я понимаю методики и подходы выполнения пунктов 1 и 2. (Прим. Другие пункты тоже достаточно важны, но они не входят в скоуп данного поста.)

Намерено не даю никакие ссылки на инструментальные средства, чтобы не делать рекламы. Методы предотвращения дефектов (защитное программирование, инспекции кода и т.п.) вне скоупа данного поста. Хотя, assert-ы как часть методики защитного программирования могут считаться отдельным вполне полезным методом отладки ПО. Также существуют различные методики рассуждений при поиске root-cause-а, но они тоже вне скоупа ;).

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

  1. Запуск программы из под отладчика (софтварного, железячного или удалённого дебагера) с пошаговой отладкой, просмотром состояний (переменных, стека, памяти, регистров, тредов и т.п.) в требуемых точках исполнения программы.
  2. Логирования кода — вывод в файл (или консоль и т.п.) входных, выходных аргументов функций, промежуточных состояний (переменных, стека, памяти, передаваемых или получаемых каким-либо образом данных и т.п.) в процессе исполнения программы. Детальный лог является историческим описанием исполнения программы. При сложностях с воспроизведением сценария дефекта, логирование становится основной методикой отладки.
  3. Анализ кода без исполнения программы — поиск причин возникновения дефекта с помощью анализа исходного кода программы, проблемного контента, конфигурации, состояния базы данных и т.п.
  4. Анализ поведения системы или её части (в т.ч. в более простых use-case-ах) — изолирование проблемы, путём упрощения сценария (используя ручное или автоматическое тестирование). Аксиома звучит так: чем проще сценарий, тем проще отладить проблему. Если найти более простой сценарий, то отладка может упроститься.
  5. Unit тестирование — выполнение автоматических unit test-ов в основном изолировано (т.е. в более простых сценариях) для функций (модулей, компонентов и т.п.), и таким образом автоматическое выявление проблемных участков кода. Unit тестирование в каком-то смысле одна из разновидностей отладки путём «анализа поведения системы».
  6. Прототипирование — проверка функций (модулей, библиотек, и т.п.) в изоляции с помощью небольших примеров кода (прототипов). Прототип легче отлаживать, чем целевую систему. Если проблема воспроизводиться с помощью прототипа, отладка упрощается. Unit тестирование в этом смысле более эффективный метод отладки, поскольку unit test-ы выполняются автоматически и «накапливаются» для будущего реюза, а прототипы редко становятся частью системы.
  7. Отладка с помощью memory-dump-ов или crash-дампов (применимо в основном для анализа паник) — разновидность логирования кода, только здесь логируется не просто некая структура памяти, а целиком вся память процесса и состояния регистров, когда возникает exception. По такому дампу памяти, имея дебажные символы, можно «раскрутить» состояние программы (стеков, очередей, переменных и т.п.), в котором она находилась во время паники. Достаточно много существует инструментальных средств для выполнения этой операции.
  8. Отладка с помощью перехватов (hook-ов, spy-ев) — в основном используется в случаях утечки ресурсов, разновидность логирования кода. Основная идея перехват и логирование вызова функций выделения и освобождения ресурса, а также анализ состояния ресурсов (например, памяти) в требуемый момент времени или в нужной точке исполнения программы.
  9. Профилирование кода (если необходима оптимизация производительности) — разновидность логирования кода, хотя часто выполняется с использованием специализированных инструментальных средств (профилировщиков). Этот метод отладки позволяет получить профиль исполнения программы — сколько и какая функция, строчка кода, модуль, и т.п. отнимают процессорного времени, и таким образом найти узкие места.
  10. Выполнения программы (или её части) в другой среде (операционной системе, эмуляторе, симуляторе) — основная идея в том, что если нет инструментальных средств на целевой платформе, то можно спортировать код на другую платформу, где они есть. Также можно изначально писать кросс-платформенный код системы или какой-то её части, и таким образом, при необходимости практически без портирования отлаживать код на другой платформе.
  11. Отладка методом RPC (remote procedure call)  — применимо в основном для встроенного программирования. Суть метода в возможности вызвать любую функцию (модуль и т.п.) передавая аргументы и получая результаты исполнения удалённо с одного хоста на другом вместо того, чтобы тратить время на компиляцию или обновление софта на удалённом хосте (или железке). Существуют множество готовых фреймворков (правда в основном платных), которые инструментируют код и позволяют вызывать любые функции кода через USB или IP соединения.
  12. Отладка путём анализа документации, дизайна, требований или ограничений модулей (программных или аппаратных) — применимо в основном для сложных и крупных проектов. Основная идея понять по имеющейся документации допустимо ли поведение, происходящее в дефекте. Например, поддерживается ли сложная комбинация одновременно работающих фич. Если  поведение не поддерживается, то необходимо просто программно закрыть use-case, вместо того, чтобы пытаться глубоко анализировать код или пытаться найти root-cause в third-party компонентах.
  13. Отладка трансляцией кода — сложный алгоритм пишется или прототипируется на одном языке программирования (возможно медленном или интерпретируемом) с наличием всех доступных инструментальных средств (дебагера и т.п.), а потом исходный код отлаженного алгоритма транслируется в ручную или автоматически в другой язык программирования (целевой системы), для которого отсутствуют необходимые инструментальный средства. При таком подходе отладится можно на практически любом удобном для себя языке программирования, а потом заново странслировать программу на целевой язык программирования. Возможны и другие варианты, например,  дисассемблерование с целью более низкоуровневого понимания, что происходит при выполнении программы. Т.е. анализируется некий промежуточный вариант кода, который в некоторых ситуациях легче отладить или понять.
  14. Отладка разработкой интерпретатора — это не только метод отладки, но и паттерн проектирования. Этот метод используется, когда модуль требует частых изменений (из-за плавающих требований или поддержки большого количества фич, железок и т.п.), а время построения приложения очень большое. Для ускорения процесса и гибкости пишется небольшой интерпретатор кода с наличием управляющих конструкций if, циклов, goto. При наличии такого интерпретатора разработчик сравнительно не сложно создаёт скрипты, которые  можно быстрее исправить и отладить. Как упрощённый вариант такого способа отладки, например, использование дебажных флагов в коде, которые конфигурируют код и позволяют проверить разные варианты исполнения кода сделав лишь один build.

Существуют также неправильные методы отладки. Они обобщаются следующим pattern-ами:

  1. занимают слишком много времени;
  2. root-cause не обнаружен или никого не волнует в чём был root-cause;
  3. исправление ухудшает качество ПО, несмотря на то, что оригинальный дефект исправлен.

Однако, это тема для отдельных обсуждений.

это «unit тестирование»
Запись опубликована в рубрике Программирование, Философия программирования с тэгами , , . Создать закладку наpermalink. Оставить комментарийили trackback:Trackback URL.

Один комментарий

  1. Mehin
    Опубликован 25.04.2011 в 7:12 пп | Прямая ссылка

    спасиб вам)

Оставить комментарий

Ваш e-mail никогда не будет опубликован или передан третьим лицам. Обязательные поля отмечены *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>