Loftschool школа онлайн обучения IT профессиям
Профессии
  • Веб-разработчик
  • Frontend разработчик
  • Backend разработчик
  • Full Stack разработчик
  • Интернет-маркетолог
  • Android-разработчик
  • UX/UI Дизайнер
Курсы
          • Основы вёрстки
          • Веб для начинающих
          • JavaScript
          • Vue.js
          • React.js
          • Node.js
          • PHP
          • Контекстная реклама
          • SMM
          • SEO для всех
          • Android: базовый
          • Android: продвинутый
          • UX/UI-дизайн: базовый
          • UX/UI-дизайн: PRO
          • Основы Python
          • Python: машинное обучение

        Скидка на курсы

        -25%

        с 20 по 31

        марта

        До конца акции:
        10
        Дней
        09
        Часов
        22
        Минут
        • Главная
        • Блог
        • Статьи
        • Баги, ворнинги и исключения: что это такое
        Полезный блог
        Статьи
        Опубликовано 30.01.2023 10:21

        Баги, ворнинги и исключения: что это такое

         

        Божья коровка на листе

         

        Оглавление:

          1. Как «жучок» попал в разработку
          2. Разновидности сбоев
          3. Ворнинг
          4. Исключение
          5. От чего зависит забагованность кода
          6. Инструменты для локализации
          7. Как найти и устранить

        Откуда взялось слово bug

        Существует множество историй о происхождении термина bug и о том, как он стал применяться в программировании. Самая реалистичная и популярная версия следующая: американский ученый Грейс Мюррей Хоппер обнаружила, что компьютер Harvard Mark II выдает неправильные ответы. Когда она более внимательно осмотрела машину, пытаясь найти проблему – была найдена раздавленная моль, которая попала между контактами электромеханического реле. Насекомое не давало реле полностью замкнуться; таким образом и появился первый компьютерный bug. Хоппер извлекла мотылька пинцетом и записала его в операторский журнал с комментарием: «Найден первый реальный bug». Хоппер же впервые письменно использовала термин «дебаггинг» по отношению к программированию машин.

        Так выглядел первый компьютерный bug

        Так выглядел первый компьютерный bug

        Другие версии о происхождении жаргонизма bug – не так реалистичны. Возможно, истинную этимологию этого слова мы так и не узнаем никогда.

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

        Разновидности ошибок

        Попробуем классифицировать все сбои в коде на четыре большие категории: лексические, синтаксические, ошибки времени выполнения и логические.

        Лексические ошибки

        Возникает всякий раз, когда программа содержит слово или символ, которых нет в словаре конкретного языка программирования (Python, например) или которые были ранее связаны с определенным значением. 

        Пример ошибки лексемы в C++

        #include <iostream>
        using namespace std;
        
        int main() {
        
        	printf("Я пошел гулять");$
        	return 0;
        }

        Появление недопустимых символов 

        В качестве аналогии предположим, что мы находимся на улице Ленина в городе Реутов и заблудившийся автомобилист спрашивает у нас: «Как мне добраться до мавзолея в Москве?». Если мы ответим: «Просто поверните напоаво, затем вафвдите из города, после дойёдете 666меровl и попадете на трассу М*00$» –  мы совершим несколько лексических ошибок. Автомобилист не сможет следовать нашим инструкциям, потому что он просто не сможет расшифровать некоторые слова, из которых составлены инструкции. Точно так же интерпретатор Python должен распознать в программе каждую лексему (идентификатор, оператор, разделитель, литерал или комментарий). Иначе выполнить код просто не получится.

        Синтаксические ошибки

        Допустим интерпретатор Python распознал каждую лексему (они также называются токенами) в коде, но программа при этом все равно может не запуститься. Например – потому, что она содержит синтаксическую ошибку. Синтаксические сбои возникают всякий раз, когда разработчик задействует неправильную грамматику или пунктуацию (не соответствующую правилам синтаксиса языка программирования). 

        Пример ошибки синтаксиса в Python

        print('Привет, это я)

        Забыли хоть один символ? Все, программа уже не запустится.

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

        Итак, если программа содержит какие-либо нераспознанные лексемы или синтаксические ошибки, то интерпретатор обнаружит их и сообщит об этом.

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

        Все вышеуказанные ошибки называются статическими, потому что интерпретатор обнаруживает их, пока мы набираем и отлаживаем программу, до ее запуска на выполнение. Ошибки, возникающие уже во время работы программы, называются динамическими (или ошибками runtime / времени выполнения). 

        Исправлять статические ошибки гораздо проще.

        Ошибки времени выполнения

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

        Пример ошибки выполнения в С++

        // C++ программа для иллюстрирования
        // SIGFPE-сбой
          
        #include <iostream>
        using namespace std;
          
        // Driver Code
        int main()
        {
          
            int a = 5;
          
            // Division by Zero
            cout << a / 0;
            return 0;
        }

        Возвращаясь к нашему автомобилисту, пытающемуся добраться из Реутова в Москву, мы можем сказать ему: «Продолжайте ехать 150 километров». Но если он ехал на запад и будет интерпретировать наши инструкции буквально, то он сможет проехать всего несколько километров, прежде чем достигнет Москвы. В этот момент наш автомобилист остановится (надеемся) и поймет, что не смог выполнить наши инструкции так, как они были даны. Этот пример иллюстрирует сбой выполнения.

        Логические ошибки

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

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

        Пример логической ошибки

        int average(int a, int b)
        {
            return a + b / 2;     /* правильная запись (a + b) / 2 */
        }

        Забыли об иерархии операторов

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

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

        Что такое ворнинг

        Ворнинг (от английского warning) – это не ошибка, а только предупреждение. Такие предупреждения выводятся компилятором, когда существуют формальная вероятность возникновения сбоя. 

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

         

        В большинстве случаев необходимо активировать функцию treat warnings as errors – в таком случае компилятор будет помечать все найденные воринги в качестве сбоев и вы не сможете работать дальше, пока их не исправите.

        Пример treat warnings as errors в SciLexer Property Pages

        Пример treat warnings as errors в SciLexer Property Pages

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

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

        Важно: можно и нужно отключать ворнинги для сторонних библиотек.

         

        Пример ворнинга

        Создать ворнинг в Python так же просто, как создать пользовательское исключение:

        Ворнинг выделен красным

        Ворнинг выделен красным

        Что такое исключение

        Исключение (exception) в программировании – это особая ситуация, возникающая во время выполнения программы и являющаяся неожиданной или аномальной. Например, к появлению исключения приводит попытка открыть несуществующий файл или прочитать файл со сбойного носителя.

        Разработчик должен предвидеть возможность возникновения исключений и правильно обрабатывать их в коде, при этом выполнение программы должно ветвиться, чтобы избежать фатального сбоя. Этот аспект программирования известен как обработка исключений.

        Виды исключений

        Исключения можно отнести к одному из двух типов: предопределенные и определенные.

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

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

        Пример исключения

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

        public static void Main ()
        {
           int numerator, denominator;
           try
           {
               int quotient = numerator/denominator;
           }
               catch (DivideByZeroException e)
               {
                   System.out.println("Divide By Zero Exception Occurred!");
               }
        }

         

        Объект исключения всегда создается методом, в котором возникает сбой, и затем передается системе выполнения. Этот процесс называется выбросом исключения. Объект содержит сведения о сбое, его типе и так далее.

        От чего зависит количество ошибок

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

        Ошибка – это не плохо. Она лишь означает, что вы пытаетесь сделать что-то сложнее, чем обычным.  И это еще не работает, как задумано. Но ошибка ни в коем случае не означает, что вы должны прекратить попытки.

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

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

        Вот лишь некоторые компоненты, от которых зависит количество сбоев в итоговом коде:

        • Используемые библиотеки.
        • Используемые компиляторы.
        • Используемые фреймворки.
        • Особенности операционной системы.

        Что касается самих сбоев, то чаще всего они относятся к:

        • Дизайну программы.
        • Тестированию.
        • Управлению потоками.
        • UI.
        • Сбою системы обработки.
        • GIT.
        • Граничным условиям.
        • Нагрузке.
        • Вычислениями.
        • Обработке данных.
        • Интерпретации данных.

        На самом деле, существуют целые инженерные профессии, построенные на поиске и исправлении сбоев в коде. Например, инженер по тестированию создает автоматизированные тесты для обнаружения ошибок в программном обеспечении и проверки его соответствия стандартам компании.

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

        Google, Amazon и Microsoft поощряют пользователей искать ошибки и сообщать об их обнаружении.

         

        Почему же эти гиганты платят за найденные проблемы? Почему крупная технологическая компания хочет, чтобы пользователи пытались взломать её программное обеспечение? Ответ: поиск проблем –- один из лучших способов улучшить код своего продукта. 

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

        Два инструмента для устранения ошибок

        Для снижения забагованности кода используют множество инструментов. Самые востребованные – дебаггинг и сплиты.

        Отладка

        Отладка или debugging – это деятельность по поиску и устранению ошибок в программе. Дебаггинг происходит сразу после обнаружения сбоев в тестах. Разработчик, тестирующий программу, всегда пытается найти bug для исправления. 

        Без инструментов отладки код будет бесполезным. Ведь зачем выкатывать код в релиз, если он забагован? 

         

        Отладка – это обязательный шаг на ранних этапах разработки программы. 

        Ещё один инструмент локализации багов и других сбоев – модульное тестирование.

        Модульное тестирование

        Модульное тестирование (юнит-тестирование) делает процесс отлавливания багов более гибким. Когда вы добавляете все новые и новые функции в продукт, иногда возникает необходимость изменить старый дизайн и код. Однако менять уже протестированный код – рискованно и дорого. Если же есть модульные тесты – можно с уверенностью приступать к рефакторингу.

        Модульное тестирование идет рука об руку с agile-программированием всех видов (в них такое тестирование уже предусмотрено). И разработчику становится легче вносить изменения

         

        Другими словами, модульные тесты способствуют безопасному рефакторингу кода.

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

        Процесс отладки. Юнит-тестирование помогает упростить процесс отладки. Если тест не сработал, то отлаживать нужно только последние изменения, внесенные в код.

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

        Как найти и избежать ошибку

        Вот пошаговая инструкция, как найти bug в коде и устранить его:

        1. Зарегистрировать bug в трекере. Это необходимо, чтобы не потерять условия появления сбоя и при необходимости воспроизвести его позже.
        2. Погуглите сообщение о возникшей ошибке. Большая часть сообщений уже разобрана в интернете, поэтому достаточно поискать по описанию.
        3. Идентифицируйте конкретную строчку, где появляется bug. В некоторых случаях, такой подход позволит обнаружить источник или природу сбоя. Например, нередко программа «падает» из-за некорректных данных. И отладчик позволит поэтапно проанализировать трассировку стека и обнаружить источник сбоя.
        4. Определите вид или класс ошибки. Это могут быть самые разнообразные сценарии, от неправильных состояний до переполнения буфера.
        5. Используйте технику исключений. Отключайте блоки до тех пор, пока баг не будет устранён. Либо можно закрывать отдельные методы при помощи фреймворка для модульного тестирования. Такое изолирование нужно делать до тех пор, пока сбой не будет устранен.
        6. Делайте более тщательное логирование и проверяйте каждую запись в логах.
        7. Попробуйте подключиться к другой сети.
        8. Попробуйте сменить компьютер, который используется для запуска программы. Другими словами, необходимо максимально исключить влияние и аппаратной платформы и программной.
        9. Анализируйте совпадения. Вы должны найти какие-либо общие моменты, которые предшествуют появлению сбоя. Может быть – это определённое время суток, определенная сеть, определённая уровень загруженности оперативной памяти.

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

        Остались вопросы?
        Укажите ваши данные, и мы вам перезвоним

          Поделись публикацией

          Категории

          • Все записи блога
            • Трудоустройство
              • Истории выпускников LoftSchool
              • Полезные советы
            • Полезные ссылки
              • Книги
              • Инструменты
            • Новости школы
              • Команда LoftSchool
              • Информация о курсах
            • Статьи
              • Архив материалов
                • DevNews
                • DevShow
                • Loftnews
                • Loftschool
                • Loftvlog
                • Интервью
                • Видеоуроки
              • © 2012 - 2023 LOFT

                Школа онлайн образования

              • © 2012 - 2023 LOFT

                Школа онлайн образования

                • +7 (800) 600 09 54
                • +7 (812) 339 22 01
                • [email protected]
                УчастникSkolkovo
              • Полезная рассылка

                Подпишись, чтобы быть в курсе наших новостей, акций и скидок.

              • Полезное
                • Карта курсов
                • B2B
                • Работодателям
                • Партнерская программа
                • Вакансии
                • Стать автором
                • Подарочные сертификаты
                • Вебинары
                • Блог
                • FAQ
              • Информация
                • О нас
                • Отзывы
                • Способы оплаты
                • Контакты
                • Публичная оферта портала
                • Политика конфиденциальности
                Безопасная передача данных