Главная страница
Навигация по странице:

  • Изучить программу, над которой работаете

  • Изучить собственные ошибки

  • Изучить качество своего кода с точки зрения кого-то, кому придется чи

  • Изучить используемые способы решения проблем

  • Изучить используемые способы исправления дефектов

  • Руководство Дьявола по отладке

  • Поиск дефектов, основанный на гадании

  • Тщательный анализ проблемы — пустая трата времени

  • Исправление ошибок самым очевидным образом

  • Перекрестная ссылка

  • ЧАСТЬ V

  • ГЛАВА 23

  • Формулируя гипотезу, используйте все имеющиеся данные

  • Детализируйте тесты, приводящие к ошибке

  • Проверяйте код при помощи блочных тестов

  • Используйте разные инструменты

  • Воспроизведите ошибку несколькими способами

  • Генерируйте больше данных для формулирования большего числа гипотез

  • Используйте результаты отрицательных тестов

  • Используйте «мозговой штурм» для построения нескольких гипотез

  • Составьте список подходов, которые стоит попробовать

  • Руководство по стилю программирования и конструированию по


    Скачать 7.6 Mb.
    НазваниеРуководство по стилю программирования и конструированию по
    Дата18.05.2023
    Размер7.6 Mb.
    Формат файлаpdf
    Имя файлаCode_Complete.pdf
    ТипРуководство
    #1139697
    страница65 из 104
    1   ...   61   62   63   64   65   66   67   68   ...   104
    ГЛАВА 23 Отладка
    527
    Однако люди несовершенны, и даже прекрасные программисты иногда допуска- ют промахи. В таких случаях ошибки предоставляют отличные возможности уз- нать много нового. Например, вы можете сделать все, что описано ниже.
    Изучить программу, над которой работаете Наличие дефекта указывает на то, что вы должны лучше изучить программу, потому что, если б вы уже отлич- но ее знали, в ней не было бы дефектов. Вы уже исправили бы их.
    Изучить собственные ошибки Все дефекты вашей про- граммы лежат на вашей совести. Не каждый день у вас по- является такая прекрасная возможность лучше узнать соб- ственные недостатки, и грех ее не использовать. Обнаружив ошибку, спросите себя, как и почему вы допустили ее. Как вы могли найти ее быстрее? Как ее можно было предотвра- тить? Содержит ли код другие подобные ошибки? Можно ли исправить их до того, как они приведут к проблемам?
    Изучить качество своего кода с точки зрения кого-то, кому придется чи-
    тать его Чтобы найти дефект, вы должны прочитать свой код. Это дает вам пре- красную возможность критически оценить его качество. Легко ли его читать? Как его можно улучшить? Используйте полученные знания для рефакторинга имею- щегося кода или для улучшения кода, который вы будете писать позднее.
    Изучить используемые способы решения проблем Чувствуете ли вы уверен- ность, обдумывая свой подход к отладке? Работает ли он? Быстро ли вы находите дефекты? Может, ваш подход к отладке неэффективен? Чувствуете ли вы тоску и огорчение? Не отлаживаете ли вы программу, опираясь на случайные предположе- ния? Нужно ли как-то улучшить процесс отладки? Если учесть объем времени, ухо- дящего на отладку во многих проектах, анализ вашего способа отладки определенно не будет пустой тратой времени. Трата некоторого времени на анализ и измене- ние процесса отладки может оказаться самым эффективным способом сокращения общего времени разработки программы.
    Изучить используемые способы исправления дефектов Кроме способа по- иска дефектов, вы можете изучить и свой способ их исправления. Вносите ли вы максимально простые исправления, используя операторы
    goto и частные случаи,
    устраняющие симптомы, но не проблему? Или вы вносите системные исправле- ния, точно определяя и устраняя причины проблем?
    Вышесказанное позволяет сделать вывод, что отладка обеспечивает программис- там крайне благоприятные возможности для самосовершенствования. Именно отладка является перекрестком всех дорог конструирования: удобочитаемости,
    качества проекта и кода и т. д. Именно на этапе отладки окупается создание хо- рошего кода, особенно если его качество редко заставляет прибегать к отладке.
    Неэффективный подход
    К сожалению, в вузах почти никогда не рассматриваются принципы отладки.
    Возможно, вы прослушали пару специальных лекций, но скорее всего на этом все и кончилось. Я никак не могу пожаловаться на качество полученного образова- ния, но и в моем случае рассмотрение отладки ограничилось советом «для нахож- дения дефектов включайте в код команды печати». Это неадекватный уровень. Если
    Дополнительные сведения Ме- тодики, помогающие узнать, ка- кие ошибки чаще всего допус- каете лично вы, рассматриваются в книге «A Discipline for Software
    Engineering» (Humphrey, 1995).

    528
    ЧАСТЬ V Усовершенствование кода образовательный опыт других программистов похож на мой, им приходится изоб- ретать концепции отладки заново. Какая трата времени и сил!
    Руководство Дьявола по отладке
    В свое время Данте отвел нижний круг ада самому Сатане.
    Но с тех пор кое-что изменилось, и сейчас Сатана охотно делит нижний круг с программистами, не умеющими эффек- тивно отлаживать программы. Он мучает программистов, за- ставляя их отлаживать программы с использованием попу- лярных принципов из следующего списка.
    Поиск дефектов, основанный на гадании Для нахож- дения дефекта разбросайте по программе случайным обра- зом команды печати и изучите выходные данные. Если при помощи команд пе- чати найти дефект не получается, попробуйте изменить тот или иной фрагмент
    — может, что и сработает. Не сохраняйте первоначальный вариант программы и не регистрируйте внесенные изменения. Если вы точно не знаете, что делает про- грамма, программирование становится более увлекательным. Запаситесь колой и леденцами, потому что вам придется провести перед монитором всю ночь.
    Тщательный анализ проблемы — пустая трата времени Скорее всего про- блема тривиальна, и ее не нужно полностью понимать, чтобы исправить. Доста- точно ее просто найти.
    Исправление ошибок самым очевидным образом Обычно можно просто устранить специфические симптомы проблемы, а не тратить время на внесение крупного амбициозного исправления, которое может затронуть всю программу.
    Вот прекрасный пример:
    x = Compute( y )
    if ( y = 17 )
    x = $25.15 — если y = 17, метод Compute() не работает; мы это исправляем
    Зачем анализировать метод
    Compute() в поисках причин непонятной проблемы со значением
    17, если можно просто написать частный случай в очевидном месте?
    Суеверная отладка
    Сатана выделил часть ада программистам, которые отлаживают программы, опи- раясь на суеверия. В каждой группе есть хоть один программист, бесконечно сра- жающийся с демоническими компьютерами, таинственными дефектами компи- лятора, скрытыми дефектами языка, которые проявляются только в полнолуние,
    плохими данными, утратой важных изменений, заколдованным текстовым редак- тором, который неправильно сохраняет программы… дополните этот список сами.
    Это и есть «суеверное программирование».
    Если написанная вами программа не работает, ошибка лежит на вашей совести.
    Компьютер и компилятор ни в чем не виноваты. Программа не делает каждый раз что-то иное. Она не писала сама себя — ее написали вы, так что не уходите от ответственности.
    Программисты не всегда ис- пользуют доступные данные для ограничения своих рассужде- ний. Они вносят в код неболь- шие и иррациональные исправ- ления и часто не отменяют не-
    корректные исправления.
    Айрис Весси (Iris Vessey)

    ГЛАВА 23 Отладка
    529
    Даже если ошибка поначалу кажется не вашей, в ваших интересах пола- гать, что справедливо обратное. Это предположение помогает в отладке.
    Ожидаемый дефект обнаружить в коде трудно; если вы полагаете, что ошибок в вашем коде нет, найти их еще труднее. Допуская вероятность того, что ошибка является вашей, вы будете вызывать большее доверие. Если вы утвержда- ете, что ошибся кто-то другой, ваши коллеги подумают, что вы тщательно прове- рили свой код. Предполагая, что виновником проблемы являетесь вы сами, вы сможете избежать неловких ситуаций, связанных с публичным признанием вины,
    которую вы первоначально отвергали.
    23.2. Поиск дефекта
    Отладка включает поиск дефекта и его исправление. Поиск дефекта и его пони- мание обычно составляют 90% работы.
    К счастью, существуют более эффективный подход к отладке, чем гадание, и, чтобы его применить, совсем не нужно заключать договор с Дьяволом. Отладка програм- мы, основанная на размышлении о проблеме, гораздо эффективнее и интереснее,
    чем отладка с использованием глаз тритона и помета летучей мыши.
    Допустим, вам нужно раскрыть тайну убийства. Что оказалось бы интереснее:
    обойти дома всех жителей района, проверяя их алиби, или найти несколько улик и, опираясь на них, установить убийцу? Большинство людей предпочло бы вто- рой вариант, поэтому вполне логично, что и у программистов большей популяр- ностью пользуется интеллектуальный подход к отладке. Лучшие программисты,
    отлаживающие программы в двадцать раз быстрее, чем их менее квалифициро- ванные коллеги, не гадают, как исправить дефекты. Они используют научный метод
    — основательный процесс анализа и доказательства.
    Научный метод отладки
    Классический научный метод включает следующие этапы.
    1. Сбор данных при помощи повторяющихся экспериментов.
    2. Формулирование гипотезы, объясняющей релевантные данные.
    3. Разработка эксперимента, призванного подтвердить или опровергнуть гипотезу.
    4. Подтверждение или опровержение гипотезы.
    5. Повторение процесса в случае надобности.
    Научный метод имеет много аналогов, используемых при отладке. Ниже описан эффективный метод поиска дефекта.
    1. Стабилизация ошибки.
    2. Определение источника ошибки.
    a. Сбор данных, приводящих к дефекту.
    b. Анализ собранных данных и формулирование гипотезы, объясняющей дефект.
    c. Определение способа подтверждения или опровержения гипотезы, осно- ванного или на тестировании программы, или на изучении кода.

    530
    ЧАСТЬ V Усовершенствование кода d. Подтверждение или опровержение гипотезы при помощи процедуры,
    определенной в п. 2(c).
    3. Исправление дефекта.
    4. Тестирование исправления.
    5. Поиск похожих ошибок.
    Первый этап этого процесса аналогичен первому этапу научного метода в том смысле, что оба они основаны на повторяемости. Диагностика дефекта облегча- ется, если его стабилизировать, т. е. обеспечить его надежное возникновение.
    Второй этап основан на этапах научного метода. Вы собираете тестовые данные,
    приводящие к проявлению дефекта, анализируете эти данные и формулируете гипотезу об источнике ошибки. Затем вы проектируете тест или инспекцию и оцениваете гипотезу, после чего празднуете успех (если гипотеза подтверждает- ся) или начинаете поиск источника ошибки сначала. Подтвердив гипотезу, вы исправляете дефект, тестируете исправление и ищете в коде похожие ошибки.
    Рассмотрим все эти этапы на примере. Допустим, вы столкнулись с несистемати- ческой ошибкой в программе, которая работает с базой данных о сотрудниках.
    Программа должна печатать список сотрудников в алфавитном порядке и суммы подоходного налога, вычитаемые из зарплаты каждого сотрудника, но при запус- ке программы выводится:
    Formatting, Fred Freeform $5,877
    Global, Gary $1,666
    Modula, Mildred $10,788
    Many-Loop, Mavis $8,889
    Statement, Sue Switch $4,000
    Whileloop, Wendy $7,860
    Как видите, список содержит ошибку: записи сотрудников
    Many-Loop, Mavis и
    Modula, Mildred выведены в неверном порядке.
    Стабилизация ошибки
    Если дефект проявляется не всегда, его почти невозможно диагностировать. Пе- ревод несистематического дефекта в разряд предсказуемых — один из самых слож- ных аспектов отладки.
    Непредсказуемые ошибки обычно связаны с инициализаци- ей, расчетом времени или зависшими указателями. Если сумма иногда вычисляется правильно, а иногда неправиль- но, это, вероятно, объясняется тем, что одна из переменных не инициализируется и просто получает в большинстве случаев нулевое значе- ние. Если вы столкнулись со странной непредсказуемой проблемой при работе с указателями, почти наверняка ее причина — неинициализированный указатель или использование указателя после освобождения соответствующей ему области памяти.
    Стабилизация ошибки обычно не ограничивается нахождением теста, приводя- щего к ошибке. Она предполагает упрощение теста до тех пор, пока не будет по- лучен самый простой тест, все еще приводящий к ошибке. Иначе говоря, тест следует сделать таким простым, чтобы изменение любого его аспекта изменяло
    Перекрестная ссылка О безо- пасном использовании указате- лей см. раздел 13.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


    написать администратору сайта