Файл: Руководство по стилю программирования и конструированию по.pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 30.11.2023
Просмотров: 833
Скачиваний: 2
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
СОДЕРЖАНИЕ
ГЛАВА 23 Отладка
531
поведение ошибки. Затем, тщательно изменяя тест и наблюдая за поведением программы в контролируемых условиях, вы можете диагностировать проблему.
Если в вашей организации есть независимая группа тестирования, упрощение тестов иногда можно поручить ей, но в большинстве случаев это ваша работа.
Для упрощения теста также следует использовать научный метод. Допустим, вы определили 10 факторов, комбинация которых приводит к ошибке. Сформулируйте гипотезу о том, какие факторы нерелевантны для возникновения ошибки. Измените эти факторы и выполните тест еще раз. Если ошибка никуда не исчезает, вы може- те упростить тест, исключив эти факторы. Затем вы можете попробовать сделать тест еще проще. Если ошибка больше не возникает, значит, вы опровергли кон- кретную гипотезу и получили дополнительные сведения о проблеме. Возможно,
другие изменения все еще будут приводить к ошибке, но теперь вы хотя бы знаете одно конкретное изменение, после внесения которого ошибка исчезает.
В нашем случае при первом запуске программы запись
Many-Loop, Mavis выводится в списке после
Modula, Mildred. Однако при втором запуске записи выводятся в правильном порядке:
Formatting, Fred Freeform $5,877
Global, Gary $1,666
Many-Loop, Mavis $8,889
Modula, Mildred $10,788
Statement, Sue Switch $4,000
Whileloop, Wendy $7,860
После ввода записи
Fruit-Loop, Frita, которая появляется в неверной позиции, вы вспоминаете, что запись
Modula, Mildred также была введена непосредственно перед отображением некорректного списка. Что необычно в этих случаях, так это то,
что записи были введены по отдельности. Как правило, данные вводятся сразу для нескольких сотрудников.
Итак, можно предположить, что проблема как-то связана с вводом одной новой записи. Если это так, то при следующем запуске программы запись
Fruit-Loop, Frita
должна занять правильное место. Ну-ка, проверим:
Formatting, Fred Freeform $5,877
Fruit-Loop, Frita $5,771
Global, Gary $1,666
Many-Loop, Mavis $8,889
Modula, Mildred $10,788
Statement, Sue Switch $4,000
Whileloop, Wendy $7,860
Правильная сортировка списка соответствует выдвинутой гипотезе. И все же для ее окончательного подтверждения следует добавить несколько новых записей по одной за раз и посмотреть, выводятся ли они в неверном порядке при первом запуске программы и изменяется ли их порядок при втором.
532
ЧАСТЬ V Усовершенствование кода
Определение источника ошибки
Определение источника ошибки также призывает к использованию научного метода. Так, вы могли бы заподозрить, что дефект является результатом конкрет- ной проблемы, такой как ошибка занижения или завышения на 1. Для проверки этой гипотезы вы могли бы присвоить параметру, который предположительно вызывает проблему, значение, равное граничному условию, а также два значения,
отличающихся от граничного условия на 1.
В нашем примере причиной проблемы может быть занижение или завышение на
1 при добавлении одной новой записи, но не двух или более. Однако изучение кода не приводит к нахождению очевидной ошибки занижения или завышения на 1. Тогда вы обращаетесь к плану Б и добавляете в БД одну новую запись, чтобы увидеть, вызовет ли это проблему. Вы добавляете запись
Hardcase, Henry и пред- полагаете, что она займет неправильное место. При запуске программы выводит- ся:
Formatting, Fred Freeform $5,877
Fruit-Loop, Frita $5,771
Global, Gary $1,666
Hardcase, Henry $493
Many-Loop, Mavis $8,889
Modula, Mildred $10,788
Statement, Sue Switch $4,000
Whileloop, Wendy $7,860
Список отсортирован правильно, а значит, первая гипотеза ошибочна. Добавле- ние одного нового сотрудника не является причиной проблемы. Проблема имеет или более сложную, или совсем другую природу.
При более внимательном изучении выходных данных теста можно заметить, что только записи
Fruit-Loop, Frita и Many-Loop, Mavis включают дефисы. Сразу же после ввода запись
Fruit-Loop занимала неверное положение, но с записью Many-Loop
все было в порядке, ведь так? Хотя распечатки результатов самого первого запус- ка программы у вас нет, вы помните, что вас смутило место записи
Modula, Mildred,
но она располагалась по соседству с
Many-Loop. Возможно, ошибочным было положение записи
Many-Loop, а не Modula.
Вы выдвигаете новую гипотезу: причина проблемы связана с фамилиями, содер- жащими дефисы, а не с фамилиями, которые вводятся по одной.
Но как это объясняет тот факт, что проблема возникает только при вводе записи?
Вы изучаете код и замечаете, что в программе используются два разных метода сортировки: один вызывается при вводе записи, а второй — при ее сохранении.
Более тщательный анализ первого метода показывает, что он и не должен сорти- ровать список полностью. Вставляя новую запись, он лишь приблизительно определяет ее положение для ускорения сортировки, которую выполняет второй метод. Так что проблема в том, что данные печатаются до их сортировки. Фами- лии, содержащие дефисы, располагаются в неправильном порядке из-за того, что метод примерной сортировки не обрабатывает подобные тонкости. Теперь вы можете выдвинуть еще более точную гипотезу: фамилии, содержащие знаки пун- ктуации, правильно сортируются только во время сохранения.
ГЛАВА 23 Отладка
533
Далее вы подтверждаете эту гипотезу при помощи дополнительных тестов.
Советы по поиску причин дефектов
После стабилизации ошибки и уточнения вызывающих ее условий поиск ее может быть как тривиальным, так и трудным: это зависит от того, насколько хорошо на- писан код. Если найти причину дефекта не удается, возможно, это обусловлено низким качеством кода. Каким бы неприятным ни был такой вывод, ничего не по- делаешь: это правда. В подобной ситуации вам помогут следующие советы.
Формулируя гипотезу, используйте все имеющиеся данные Выдвигая ги- потезу об источнике дефекта, постарайтесь учесть как можно больше данных.
В нашем примере вы могли бы обратить внимание на неверное место записи
Fruit-
Loop, Frita и предположить, что неверно сортируются все фамилии, начинающи- еся на букву «F». Гипотеза неудачна: она не объясняет неправильное место записи
Modula, Mildred и правильную сортировку записей при втором запуске програм- мы. Если данные не соответствуют гипотезе, не игнорируйте их — подумайте,
почему они ей не соответствуют, и сформулируйте новую гипотезу.
Вторая наша гипотеза, согласно которой причина проблемы связана с фамилия- ми, содержащими дефисы, а не с вводом фамилий по одной, также первоначаль- но не объясняла правильную сортировку фамилий при повторном выполнении программы. Однако она привела нас к более точной гипотезе, оказавшейся вер- ной. Если первая гипотеза не объясняет все данные, ничего страшного — улуч- шайте ее, пока не достигнете этой цели.
Детализируйте тесты, приводящие к ошибке Если вы не можете найти ис- точник ошибки, попробуйте уточнить уже имеющиеся тесты. Возможно, измене- ние какого-нибудь из параметров в более широком диапазоне или концентрация на одном из параметров позволит сдвинуть отладку с мертвой точки.
Проверяйте код при помощи блочных тестов Как пра- вило, в небольших фрагментах кода дефекты искать легче,
чем в крупных интегрированных программах. Используй- те для изолированного тестирования фрагментов кода блоч- ные тесты.
Используйте разные инструменты На рынке имеются многочисленные ин- струменты, облегчающие отладку: интерактивные отладчики, строгие компиляторы,
инструменты проверки памяти, утилиты проверки синтаксиса и т. д. Правильный инструмент способен сделать трудную работу простой. Мне вспоминается случай,
когда одна неуловимая ошибка заставляла одну часть программы перезаписывать память другой части. Традиционные методики отладки не помогли в поисках ошибки: программист не мог определить, какой именно фрагмент перезаписы- вал память. Тогда он установил точку прерывания на конкретный адрес памяти.
Когда программа выполнила запись по этому адресу, отладчик прервал ее выпол- нение, и виновный код был обнаружен.
Это пример проблемы, которую трудно диагностировать аналитически, но довольно легко с помощью правильного инструмента.
Воспроизведите ошибку несколькими способами Иногда полезную инфор- мацию можно получить, выполнив тест, похожий на тесты, приводящие к ошиб-
Перекрестная ссылка Среды блочного тестирования упоми- наются в подразделе «Встраи- вайте блочные тесты в среду тестирования» раздела 22.4.
534
ЧАСТЬ V Усовершенствование кода ке, но не идентичный им. Можете рассматривать этот подход как триангулирова- ние дефекта. Воспроизведя дефект несколькими способами, вы точнее определи- те его источник.
Воспроизведение ошибки разными способами помогает диагностировать причину ошибки (рис. 23-1). Как только вы решили, что причина дефекта ясна, выполните тест, который сам не должен вызывать ошибку, но напоминает тесты, приводя- щие к ошибке. Если ошибка при этом все же возникает, значит, вы еще не полно- стью поняли проблему. Причиной ошибки часто становится комбинация факто- ров, поэтому попытка диагностировать проблему при помощи только одного те- ста часто не приводит к обнаружению корня проблемы.
Рис. 23-1. Чтобы точно определить причину ошибки, попробуйте воспроизвести
ошибку разными способами
Генерируйте больше данных для формулирования большего числа гипотез
Выберите тесты, отличающиеся от тестов, результаты которых уже известны.
Выполните их, чтобы получить дополнительные данные и использовать их для выдвижения дополнительных гипотез.
Используйте результаты отрицательных тестов Предположим, что вы выдвинули гипотезу и запустили тест с целью ее подтверждения. Допустим далее,
что тест опроверг гипотезу, так что причина ошибки все еще неизвестна. И все же вы узнали нечто полезное: одно из ваших предположений о причинах дефек- та ошибочно. Это сужает область поиска и уменьшает число оставшихся гипотез.
Используйте «мозговой штурм» для построения нескольких гипотез Не останавливайтесь на первой пришедшей в голову гипотезе, а попробуйте выдви- нуть несколько гипотез. Не анализируйте их сразу — просто придумайте за не- сколько минут максимальное число гипотез. Затем рассмотрите их по очереди и подумайте о тестах, которые могут их доказать или опровергнуть. Это упражне- ние помогает сдвинуть отладку с мертвой точки, обусловленной слишком силь- ной концентрацией на одной линии рассуждения.
Составьте список подходов, которые стоит попробовать Иногда про- граммисты не могут найти ошибку по той причине, что слишком долго следова- ли по пути, ведущему в тупик. Составьте список подходов, которые стоит попро- бовать, и, если один из них не работает, переходите к следующему.
1 ... 61 62 63 64 65 66 67 68 ... 104
ГЛАВА 23 Отладка
535
Сократите подозрительную область кода Вместо тестирования всей про- граммы, всего класса или метода протестируйте сначала меньший фрагмент кода.
Используйте для нахождения ошибочного фрагмента команды печати, запись информации в журнал или трассировку.
Есть и более эффективный способ сужения подозрительной области кода: систе- матически удаляйте части программы и смотрите, возникает ли ошибка. Если ошибка исчезла, ищите ее в удаленной части. Если ошибка по-прежнему возни- кает, дефектный код все еще присутствует в программе.
Вместо удаления случайных фрагментов руководствуйтесь принципом «разделяй и властвуй». Используйте алгоритм двоичного поиска. Попробуйте удалить в пер- вый раз примерно половину кода. Определите половину, содержащую дефект, и разделите ее. Снова определите дефектную половину и снова разделите ее попо- лам. Продолжайте, пока дефект не будет найден.
Если программа содержит много небольших методов, можете убирать фрагменты кода, просто комментируя вызовы методов. В противном случае можете блокиро- вать фрагменты кода при помощи комментариев или директив препроцессора.
Работая с отладчиком, удалять фрагменты кода не обязательно. Вместо этого можно задать точки прерывания. Если отладчик позволяет пропускать вызовы методов,
попробуйте найти дефектный код, пропуская выполнение определенных методов и наблюдая, исчезает ли после этого ошибка. Этот процесс во многом похож на действительное удаление фрагментов программы.
С подозрением относитесь к классам и методам, ко-
торые содержали дефекты ранее Классы, которые бы- ли дефектными раньше, более подвержены ошибкам. Новые дефекты чаще обнаруживаются в классах, с которыми и раньше были связаны проблемы, а не в классах, которые были безошибочными. Проанализируйте подверженные ошибкам классы и методы еще раз.
Проверьте код, который был изменен недавно Если у вас появилась новая непростая ошибка, она скорее всего содержится в фрагменте, который был изме- нен недавно. Ее источником может быть как абсолютно новый код, так и изме- ненный старый. Если вы не можете найти дефект, запустите старую версию про- граммы и проверьте, возникает ли ошибка. Если нет, ошибка содержится в новом коде или объясняется взаимодействием с новым кодом. Изучите различия между старой и новой версиями. Посмотрите в журнале системы управления версиями,