Какой процесс вы обычно используете при попытке отладить проблему / проблему / ошибку с вашим программным обеспечением? [закрыто]

15

Кажется, что большинство людей считают отладку искусством, а не наукой. Для тех, кто рассматривает это как науку, а не искусство - какой процесс (ы) вы обычно используете, когда сталкиваетесь с новой проблемой / ошибкой / проблемой?

blueberryfields
источник

Ответы:

13

В общих чертах, то, что я делаю, это:

  1. Попробуйте изолировать проблему. Подумайте, что изменилось, когда ошибка появилась впервые. Над чем ты работаешь? Какую часть кода вы меняли? 99% моих ошибок решаются таким образом. Обычно это что-то глупое.

  2. Если я угадаю, в чем проблема, внимательно посмотрите на код, который, кажется, является причиной. Прочитайте это. Прочитайте это вслух даже. Спросите себя: «Чего я пытаюсь достичь?». Для некоторых типов проблем: Может ли это иметь некоторые побочные эффекты или на него может повлиять код в каком-то другом месте, о котором я даже не думал?

  3. Попробуйте различными способами проанализировать, что идет не так, где и когда (см. Ниже).

  4. Если я до сих пор не имею понятия, я проверяю, есть ли такая же проблема в более старой версии моего источника, попробуйте найти, когда на моей временной шкале проблема появилась впервые. Для этого вам нужно работать с хорошей системой контроля версий, такой как git (в git есть функция bisect, предназначенная именно для такого рода отладки).

  5. Если до сих пор нет подсказки, сделайте перерыв .... это на самом деле часто помогает.

  6. Вернитесь к чертежной доске - рассмотрите, как ваша программа должна работать и имеет ли это смысл.

Это действительно зависит от типа проблемы, но если у меня есть общее представление о том, где может быть проблема, то:

  • Если я подозреваю, что проблема в некоторой части кода / недавнем изменении, я сначала пытаюсь удалить / закомментировать / изменить или что-то еще, чтобы ошибка исчезла, упростив код, а затем вернуть проблемный код и взять хорошо посмотри на это.

  • Запустите отладчик с точками останова (если вообще возможно) и посмотрите, как выглядят мои данные, пытаясь найти, когда они начинают плохо себя вести, чтобы лучше понять, где что-то идет не так.

sinelaw
источник
1
+1 за перерыв. Самые сложные проблемы только усугубляются, когда вы расстроены и за 6 часов отлаживаете их. Знание, когда сделать перерыв, является одним из самых полезных навыков отладки, которые я получил.
Брэд Гарднер
Потрясающий ответ. Я не могу сделать лучше.
EricBoersma
1
Очень похоже на мой подход, но вы забыли кое-что, когда просите коллег быстро взглянуть на них, и они сразу замечают орфографическую ошибку ...
ChrisAnnODell
1
Отличный ответ. Я просто хочу добавить, что унция профилактики стоит фунта лечения. Большая часть моего процесса отладки заключается в том, что, пока я занимаюсь кодированием, я делаю только небольшие, инкрементальные изменения и компилирую, тестирую и фиксирую локально между ними. Таким образом, если ошибка внезапно появляется, список вероятных подозреваемых очень мал и его легко увидеть с помощью bzr qdiffкоманды.
Карл Билефельдт
8

Я пытаюсь использовать разработку через тестирование ( TDD ). Я пишу тест, который повторяет ошибку, а затем пытаюсь пройти тест. Иногда сам процесс написания теста помогает найти ошибку.

Это удерживает меня от отладчика большую часть времени и предоставляет регрессионные тесты для предотвращения повторного появления ошибки.

Некоторые ссылки:

оборота TrueWill
источник
4
Я думаю, что этот ответ чрезвычайно неполный. Я не понимаю так много голосов.
Алекс
1
Он получает столько голосов, потому что включает в себя магическую аббревиатуру: TDD.
Бьярке Фрейнд-Хансен
@Alex - я добавил несколько ссылок. У "Найти ошибку, написать тест" есть пример. Я могу расширить это, но это действительно так просто.
TrueWill
7

Существует несколько определений слова «наука», но, похоже, вы имеете в виду то, что можно более точно назвать « научным методом ». Научный метод может быть обобщен как наблюдение за некоторыми явлениями (предположительно ошибка или неожиданное поведение программы), формулировка гипотезы или гипотезы для объяснения поведения и наиболее вероятные эксперименты, чтобы доказать это (написание теста, который надежно воспроизводит проблему).

Типы ошибок (явлений), которые могут возникнуть, практически бесконечны, а некоторые не обязательно требуют четко определенного процесса. Например, иногда вы наблюдаете ошибку и сразу узнаете, что ее вызвало, просто потому, что вы хорошо знакомы с кодом. В других случаях вы знаете, что при некотором вводе (действие, последовательность шагов и т. Д.) Получается неверный результат (сбой, неверный вывод и т. Д.). Для этих случаев это часто не требует большого "научного" мышления. Некоторая мысль может помочь уменьшить пространство поиска, но распространенный метод - просто пройтись по коду в отладчике и посмотреть, где все пошло не так.

Ситуации, которые я нахожу наиболее интересными и, возможно, достойными научного процесса, - это когда вам вручают какой-то конечный результат и просят объяснить, как это произошло. Очевидным примером этого является аварийный дамп. Вы можете загрузить аварийный дамп и наблюдать за состоянием системы, и ваша задача - объяснить, как она попала в это состояние. В аварийном дампе (или ядре) может отображаться исключительная ситуация, взаимоблокировка, внутренняя ошибка или некоторое «нежелательное» состояние, определенное пользователем (например, медлительность). В этих ситуациях я обычно выполняю следующие шаги:

  • Узкое наблюдение . Изучите информацию, непосредственно касающуюся конкретной проблемы, если применимо. Очевидными вещами здесь являются стек вызовов, локальные переменные, если вы их видите, строки кода, окружающие проблему. Этот тип исследования конкретного места не всегда применим. Например, изучение «медленной» системы может не иметь очевидного начального местоположения, подобного этому, но ситуация сбоя или внутренней ошибки, вероятно, будет иметь непосредственный и очевидный интерес. Одним конкретным шагом здесь может быть использование таких инструментов, как windbg (запустите! Анализ -v в загруженном аварийном дампе и посмотрите, что он говорит вам).

  • Широкое наблюдение : изучите другие части системы. Изучите состояние всех потоков в системе, просмотрите любую глобальную информацию (количество пользователей / операций / элементов, активных транзакций / процессов / виджетов и т. Д.), Информацию о системе (ОС) и т. Д. Если пользователь предоставил какие-либо внешние данные Подумайте о тех, с кем вы наблюдали. Например, если вам сказали, что проблема возникает каждый вторник во второй половине дня, спросите себя, что это может означать.

  • строить гипотезуЭто действительно забавная часть (и я не буду шутить о том, что это весело). Это часто требует большого логического мышления в обратном направлении. Может быть очень приятно думать о том, как система попала в текущее состояние. Я подозреваю, что это та часть, которую многие люди считают искусством. И я полагаю, что это может быть, если программист просто начинает случайным образом бросать вещи, чтобы увидеть, что прилипает. Но с опытом, это может быть довольно четко определенный процесс. Если вы мыслите очень логично на этом этапе, часто можно определить возможные наборы путей, которые привели к данному состоянию. Я знаю, что мы находимся в состоянии S5. Чтобы это произошло, должен был появиться S4a или S4b и, может быть, S3 до S4a и т. Д. Чаще всего этого не может быть несколько элементов, которые могут привести к данному состоянию. Иногда это может помочь записать на блокноте простую диаграмму потока или состояний или серию связанных со временем шагов. Фактические процессы здесь будут сильно различаться в зависимости от ситуации, но серьезное обдумывание (и повторное рассмотрение на предыдущих этапах) в настоящее время часто дают один или несколько правдоподобных ответов. Также обратите внимание, что чрезвычайно важной частью этого шага является устранение невозможного. Удаление невозможного может помочь обрезать пространство решения (помните, что сказал Шерлок Холмс о том, что осталось после того, как вы устранили невозможное). Также обратите внимание, что чрезвычайно важной частью этого шага является устранение невозможного. Удаление невозможного может помочь обрезать пространство решения (помните, что сказал Шерлок Холмс о том, что осталось после того, как вы устранили невозможное). Также обратите внимание, что чрезвычайно важной частью этого шага является устранение невозможного. Удаление невозможного может помочь обрезать пространство решения (помните, что сказал Шерлок Холмс о том, что осталось после того, как вы устранили невозможное).

  • Эксперимент . На этом этапе попытайтесь воспроизвести проблему, основываясь на гипотезах, полученных на предыдущем этапе. Если вы серьезно подумали на предыдущем шаге, это должно быть очень просто. Иногда я "обманываю" и изменяю кодовую базу, чтобы помочь в данном тесте. Например, недавно я расследовал аварию, которая, как я пришел к выводу, была связана с состоянием гонки. Чтобы проверить это, я просто помещаю Sleep (500) между парой строк кода, чтобы позволить другому потоку делать свои плохие вещи в «правильное» время. Я не знаю, допускается ли это в «реальной» науке, но это совершенно разумно в коде, которым вы владеете.

Если вам удастся воспроизвести его, скорее всего, вы почти закончили (все, что осталось, это простой шаг исправления ... но это на другой день). Обязательно проверьте новый тест в системе регрессионного тестирования. И я должен отметить, что я намеревался сделать это предыдущее заявление о том, что это просто быть насмешкой. Нахождение решения и его реализация могут потребовать большой работы. По моему мнению, исправление ошибки - это не часть процесса отладки, а скорее разработка. И если исправление вообще вовлечено, то это должно потребовать некоторого количества дизайна и обзора.

Марк Уилкинс
источник
Большинство ошибок, которые я видел, не были надежно воспроизводимыми, и для подмножества, которое было, большинство все еще требовало значительных отладочных работ после того, как они были воспроизведены, прежде чем можно было начать какую-либо работу по их исправлению. Даже если вместо того, чтобы сказать «преуспеть в воспроизведении», вы скажете «преуспеть в сужении модульного теста, который явно исправляет ошибку», я бы сказал, что отладочная работа еще не закончена. Для меня отладка заканчивается, когда у меня обоих есть исправление, которое, как я могу доказать, решает проблему, и у меня есть надежное доказательство того, что мое исправление - это то, что действительно исправляет вещи.
черничные
Я согласен, что это может быть довольно много работы, чтобы исправить это. Я действительно использовал сарказм в своих словах «простой шаг исправления», но это не очень хорошо видно по типу.
4

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

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

Кроме того, если вы знакомы с C / C ++, попробуйте запустить valgrind или очистить, чтобы изолировать проблемы, связанные с памятью.

Fanatic23
источник
2

Самая сложная часть отладки - это изоляция проблемы, особенно когда проблема скрыта под несколькими уровнями. В колледже я изучал музыкальную запись, и, как ни странно, был класс Studio Electronics, который непосредственно здесь применяется. Я собираюсь использовать отладку среды студии как иллюстрацию систематического процесса отладки.

  1. Проверьте свои счетчики. Используя тестовый сигнал при известном калиброванном напряжении, измеритель должен показывать «U» (единичное усиление). Перевод: Если ваши инструменты сломаны, вы не можете использовать их, чтобы выяснить, что еще не так.
  2. Проверьте каждую ступень компонента / усиления, работающую в обратном направлении от конца. При использовании того же тестового сигнала, который применяется к входу каскада, не должно быть никаких изменений на выходе каскада. Перевод: изолируя каждый объект от вывода в обратном направлении, мы укрепляем доверие к нашему коду, пока не найдем место, где он портит. Если вашим инструментам требуется несколько слоев, чтобы сообщить о проблеме, вы должны знать, что промежуточные слои не способствуют этому.

Отладка кода на самом деле не так уж отличается. Отладка намного проще, когда код вызывает исключение. Вы можете проследить назад от трассировки стека этого исключения и установить точки останова на ключевых позициях. Обычно сразу после установки переменной или в строке, которая вызывает метод, который выдает исключение. Вы можете обнаружить, что одно или несколько значений неверны. Если это не правильно (ноль, когда не должно быть, или значение выходит за пределы диапазона), то это процесс обнаружения, почему это не правильно. Точки останова в IDE эквивалентны электронным контрольным точкам (предназначенным для измерительного щупа для проверки цепи).

Теперь, после того, как я прошел через эту сложную часть выяснения, где моя настоящая проблема, я напишу несколько юнит-тестов, чтобы проверить это в будущем.

Берин Лорич
источник
2

Из-за неприятных ошибок, которые я изо всех сил стараюсь выследить поздно вечером, моя самая эффективная стратегия - встать и уйти на несколько минут. Обычно новые идеи о возможных источниках ошибок начинают поступать уже через 30 секунд.

сойка
источник
2

Для более практического подхода:

  1. Если ошибка связана с необработанным исключением - посмотрите трассировку стека. Нулевая ссылка, индекс за пределами границ и т. Д., А также ваши собственные определенные исключения являются наиболее распространенными, вы можете назначить эту ошибку для младшего разработчика, это, вероятно, легко и хороший учебный опыт.

  2. Если это происходит не на каждой машине, это, вероятно, форма проблемы гонки / многопоточности. Это очень весело, чтобы выследить, поставить вашего скучного старшего программиста на это. Много регистрации, хорошие знания и хорошие инструменты делают это.

  3. Еще один большой класс ошибок - это когда группе тестирования или клиенту (-ам) не нравится определенное поведение. Например, им не нравится, что вы решаете отображать идентификаторы пользователей или что при поиске вы не получаете автозаполнение. Это подлинные ошибки, подумайте о лучшем управлении продуктом и разработчиками с более широким обзором. Разработчику должно потребоваться относительно короткое время, чтобы «исправить» это, если он строит систему с учетом расширения.

  4. 80% всех других ошибок устраняются при наличии хороших систем регистрации и сбора достаточного количества информации для их устранения. Используйте встроенную трассировку с несколькими уровнями сложных систем журналирования, таких как Log4Net / Log4J

  5. Ошибки производительности - это отдельная категория, правило golder здесь «измеряй сначала, исправляй позже!», и вы будете удивлены, увидев, сколько разработчиков просто догадаются, где проблема, и сразу же решите ее, только чтобы увидеть позже просто на 3-4% уменьшение времени отклика.

Богдан Гаврил MSFT
источник
Если бы я мог +1 каждый из этих 5 индивидуально, я бы!
jmort253
1

У меня есть два подхода:

  1. Разделите данную проблему на более мелкие части, а затем покорите каждую меньшую часть, следуя Divide and Conquerпарадигме.
  2. Всякий раз, когда у меня возникают сомнения относительно каких-либо значений, я просто распечатываю значения переменных, чтобы увидеть, что именно входит и выходит из переменной.

Эти подходы помогли мне большую часть времени.

Рейчел
источник