Ох, уж эти ошибки! Их появление в коде ничего, кроме досады, не вызывает. Лично мне они точно портят настроение. Только представьте: вы создаете продукт, который согласно замыслу должен прекрасно работать, а он на ваших глазах просто разваливается. Что может быть обиднее! 

При этом не поймите меня неправильно: ошибки  —  это не конец света. В процессе отладки программы всегда можно научиться чему-то новому. В моей практике исправление сложных ошибок оборачивалось бесценным опытом. А то чувство, когда они исчезают по мановению пальцев, колдующих за клавиатурой,  —  разве с ним может что-то сравниться? В связи с этим на ум приходит известное высказывание.

“Если отладка  —  это процесс удаления ошибок ПО, то программирование, стало быть, является процессом их внесения”,  —  Эдсгер Вибе Дейкстра. 

Звучит довольно колко, но трудно не согласиться с тем, что большинство программ содержат ошибки. 

При написании кода сложно предугадать каждый сценарий. Поэтому программирование естественным образом сопряжено с ошибками. К сожалению, это слабое утешение при работе с ними, особенно если по их вине программа перестает функционировать. 

Однако в нашем распоряжении есть приемы и методы, благодаря которым отладка становится не таким уж болезненным процессом. В данной статье будут предложены 5 рекомендаций по ее оптимизации. Одни из них я позаимствовал из книги Дэвида Дж. Аганса “Debugging: The 9 Indispensable Rules for Finding Even the Most Elusive Software and Hardware Problems” (“Отладка: 9 незаменимых правил для обнаружения даже самых неуловимых программных и аппаратных ошибок”), а другие  —  из личного опыта. Приступим!

1. Воспроизводите поведение последовательно 

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

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

2. Определяйте проблемную область

Итак, у нас все готово для последовательного воспроизведения ошибки. На следующем этапе необходимо выявить участок кода, который ее вызывает. Именно здесь нужно углубиться и определить нужную область с точностью в 1–5 строк. С какого же участка начать? Исходя из базы кода и уровня владения ею, вы, возможно, сразу же определите отправную точку. 

Если же нет, то предлагаю несколько вспомогательных шагов. 

  1. Определите какие-нибудь строки, по которым можно выполнить поиск, например строковый литерал в UI или уникальное сообщение об ошибке. Произведите поиск выбранного выражения по всей базе кода. Таким образом вы получите представление об участке или области, требующей внимания. 
  2. Если вы работаете с одной базой кода совместно с коллегами по команде, то можно попросить их подсказать место поиска. Поверьте, ваша репутация не пострадает, но вот время вы точно сэкономите. 
  3. Определите точки останова и инструкции вывода. Это будет особенно эффективно, если вы уже ограничили зону поиска некоторой областью. Определите точки останова и разместите инструкции вывода в различных частях проверяемой области, чтобы получить снимки значений и состояний, помогающих определить местоположение ошибки. 

3. Изучайте окружение 

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

  • Почему он написан именно так?
  • Когда выполняется конкретная строка?
  • Почему данная переменная или функция необходимы в текущей реализации?

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

Еще один прием заключается в привязке временной шкалы на основе записей о совершенных действиях. Какие изменения были внесены с момента последнего выполнения кода? Изучите имеющуюся историю контроля версий. В этом случае вам отводится роль детектива, выясняющего причины произошедшего сбоя. А почему бы и не поучаствовать в подобной ролевой игре? Все, что помогает понять работу кода, оправдывает потраченное время. Данный этап решения проблемы требует хорошо развитых навыков логического мышления. 

4. Вносите одно изменение за раз 

Скорость и оперативность  —  полезные качества для программиста. Но при работе с ошибками приоритетной чертой становится обстоятельность. 

“Ошибки  —  дело тонкое”. 

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

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

5. Посмотрите на проблему по-новому  

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

Как говорил Альберт Эйнштейн: “Бессмысленно продолжать делать то же самое и ждать других результатов”. Поэтому выдержите паузу и свежим взглядом посмотрите на ошибку. Если вы работаете над одной и той же проблемой больше суток, то самое время сделать перерыв, а затем подойти к ее решению с новой точки зрения.  

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

Вот вы и узнали 5 рекомендаций по оптимизации отладки. На самом деле их намного больше, но именно эти я использую чаще всего. Рад был поделиться опытом, поскольку верю в пользу взаимообучения. Помогая друг другу в развитии профессиональных навыков, мы способствуем усилению всего сообщества программистов. 

Читайте также:

Читайте нас в Telegram, VK и Яндекс.Дзен


Перевод статьи Samuel Martins: 5 Essential Tips to Debug Any Piece of Code

Предыдущая статьяПочему теория графов круче, чем вы думали
Следующая статьяКак отслеживать события файловой системы в Python