Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером
О, нет, ошибки! И как с ними справляться
—
Введение в программирование
Видео может быть заблокировано из-за расширений браузера. В статье вы найдете решение этой проблемы.
Ключевой момент: ошибки программирования можно разделить на три типа: синтаксические ошибки, ошибки во время выполнения и логические ошибки.
Методы (пути) снижение ошибок в программировании
- использование тестиования
- использование более простых решений
- использование систем с наименьшим числом составлящих
- использование ранее использованных и проверенных компонентов
- использование более квалифицрованных специалистов
Начните с просмотра видео, чтобы познакомиться с принципами эффективной отладки и избежать распространенных ошибок.
Также загляните в наш Твиттер. В одном треде мы разобрали несколько примеров, когда вроде бы рабочий код не проходит тесты на Хекслете. Сам тред можно найти здесь.
Примеры в этой статье написаны на языке JavaScript, но принципы одинаковы для любого языка.
Привет, Вы узнаете про виды ошибок программного обеспечения, Разберем основные ее виды и особенности использования. Еще будет много подробных примеров и описаний. Для того чтобы лучше понимать что такое
виды ошибок программного обеспечения, принципы отладки , настоятельно рекомендую прочитать все из категории Качество и тестирование программного обеспечения. Quality Assurance..
Ошибки оформления (синтаксиса и линтера)
—
Основы JavaScript
Если программа на JavaScript написана синтаксически некорректно, то интерпретатор выводит на экран соответствующее сообщение, а также указание на файл и строчку в нем, где, по его мнению, произошла ошибка. Синтаксическая ошибка возникает в том случае, когда код был записан с нарушением грамматических правил. В человеческих языках грамматика важна, но текст с ошибками чаще всего можно понять и прочитать. В программировании все строго. Любое мельчайшее нарушение, и программа даже не запустится. Примером может быть забытая ;, неправильно расставленные скобки и другие детали.
Вот пример кода с синтаксической ошибкой:
Если запустить код выше, то мы увидим следующее сообщение: SyntaxError: missing ) after argument list, а также указание на строку и файл, где возникла эта ошибка. Подобные синтаксические ошибки в JavaScript относятся к разряду SyntaxError.
С одной стороны, ошибки SyntaxError — самые простые, потому что они связаны исключительно с грамматическими правилами написания кода, а не с самим смыслом кода. Их легко исправить: нужно лишь найти нарушение в записи.
С другой стороны, интерпретатор не всегда может четко указать на это нарушение. Поэтому бывает, что забытую скобку нужно поставить не туда, куда указывает сообщение об ошибке.
SyntaxError — это ошибка, которая легко может ввести в ступор начинающего программиста. Стоит забыть одну запятую или не там поставить кавычку и Python наотрез откажется запускать программу. Что ещё хуже, по выводу в консоль сложно сообразить в чём дело. Выглядят сообщения страшно и непонятно. Что с этим делать — не ясно. Вот неполный список того, что можно встретить:
- SyntaxError: invalid syntax
- SyntaxError: EOL while scanning string literal
- SyntaxError: unexpected EOF while parsing
Эта статья о том, как справиться с синтаксической ошибкой SyntaxError. Дочитайте её до конца и получите безотказный простой алгоритм действий, что поможет вам в трудную минуту — ваш спасательный круг.
Работать будем с программой, которая выводит на экран список учеников. Её код выглядит немного громоздко и, возможно, непривычно. Если не всё написанное вам понятно, то не отчаивайтесь, чтению статьи это не помешает.
students
first_name last_name students
label
first_name first_name
last_name last_name
label
Ожидается примерно такой результат в консоли:
Имя ученика: Егор Кузьмин
Имя ученика: Денис Давыдов
Но запуск программы приводит к совсем другому результату. Скрипт сломан:
File «script.py», line 9
last_name = last_name
^
SyntaxError: invalid syntax
Ошибки в программе бывают разные и каждой нужен свой особый подход. Первым делом внимательно посмотрите на вывод программы в консоль. На последней строчке написано SyntaxError: invalid syntax. Если эти слова вам не знакомы, то обратитесь за переводом к Яндекс.Переводчику:
SyntaxError: недопустимый синтаксис
SyntaxError: неверный синтаксис
Первое слово SyntaxError Яндекс не понял. Помогите ему и разделите слова пробелом:
Syntax Error: invalid syntax
Синтаксическая ошибка: неверный синтаксис
Методы отладки
- — Использование отладочной печати в тексте программы — произвольно и в большом количестве.Получать информацию о выполнении каждого оператора тоже небезынтересно. Но здесь мы снова сталкиваемся со слишком большими объемами информации. Кроме того, мы здорово захламляем программу добавочными операторами, получая малочитабельный текст, да еще рискуем внести десяток новых ошибок.
- — Использование автоматических средств отладки — трассировки с отслеживанием промежуточных значений переменых.Пожалуй, это самый распространенный способ отладки. Не нужно только забывать, что это только один из способов, и применять всегда и везде только его — часто невыгодно.
Сложности возникают, когда приходится отслеживать слишком большие структуры данных или огромное их число. Еще проблематичнее трассировать проект, где выполнение каждой подпрограммы приводит к вызову пары десятков других. Но для небольших программ трассировки вполне достаточно.
С точки зрения «правильного» программирования силовые методы плохи тем, что не поощряют анализ задачи.
Суммируя свойства силовых методов, получаем практические советы:
— использовать трассировку и отслеживание значений переменных для небольших проектов, отдельных подпрограмм;
— использовать отладочную печать в небольших количества и «по делу»;
— оставить дамп памяти на самый крайний случай.
Метод индукции — анализ программы от частного к общему.
Просматриваем симптомы ошибки и определяем данные, которые имеют к ней хоть какое-то отношение. Затем, используя тесты, исключаем маловероятные гипотезы, пока не остается одна, которую мы пытаемся уточнить и доказать.
Метод дедукции — от общего к частному.
Выдвигаем гипотезу, которая может объяснить ошибку, пусть и не полностью. Затем при помощи тестов эта гипотеза проверяется и доказывается.
Обратное движение по алгоритму.
Отладка начинается там, где впервые встретился неправильный результат. Затем работа программы прослеживается (мысленно или при помощи тестов) в обратном порядке, пока не будет обнаружено место возможной ошибки.
Метод тестирования.
Давайте рассмотрим процесс локализации ошибки на конкретном примере. Пусть дана небольшая программа, которая выдает значение максимального из трех введенных пользователем чисел.
Обе выделенные ошибки можно обнаружить невооруженным глазом: первая явно допущена по невнимательности, вторая — из-за того, что скопированную строку не исправили.
Тестовые наборы данных должны учитывать все варианты решения, поэтому выберем следующие наборы чисел:
Данные Ожидаемый результат
a=10; b=-4; c=1 max=a=10
a=-2; b=8; c=4 max=b=8
a=90; b=0; c=90.4 max=c=90.4
В результате выполнения программы мы, однако, получим следующие результаты:
Для a=10; b=-4; c=1:
Наибольшим оказалось первое число 10.00
Наибольшим оказалось третье число 0.00
Вывод во втором и третьем случаях явно неверен. Будем разбираться.
Локализация ошибок
Локализация — это нахождение места ошибки в программе.
В процессе поиска ошибки мы обычно выполняем одни и те же действия:
- прогоняем программу и получаем результаты;
- сверяем результаты с эталонными и анализируем несоответствие;
- выявляем наличие ошибки, выдвигаем гипотезу о ее характере и месте в программе;
- проверяем текст программы, исправляем ошибку, если мы нашли ее правильно.
Способы обнаружения ошибки:
- Аналитический — имея достаточное представление о структуре программы, просматриваем ее текст вручную, без прогона.
- Экспериментальный — прогоняем программу, используя отладочную печать и средства трассировки, и анализируем результаты ее работы.
Оба способа по-своему удобны и обычно используются совместно.
- ошибки в приложениях , bugs , баг репорт , bug report ,
- Фича
- GIGO
- Патч
- тестирование
- цикломатическая сложность
- баг репорт
- качество программного обеспечения
К сожалению, в одной статье не просто дать все знания про виды ошибок программного обеспечения. Но я — старался.
Если ты проявишь интерес к раскрытию подробностей,я обязательно напишу продолжение! Надеюсь, что теперь ты понял что такое виды ошибок программного обеспечения, принципы отладки
и для чего все это нужно, а если не понял, или есть замечания,
то нестесняся пиши или спрашивай в комментариях, с удовольствием отвечу. Для того чтобы глубже понять настоятельно рекомендую изучить всю информацию из категории
Качество и тестирование программного обеспечения. Quality Assurance.
Разбейте выражение на инструкции
В прошлых шагах вы узнали что сломан этот фрагмент кода:
label
first_name first_name
last_name last_name
Разберите его на инструкции:
- получить у строки метод format
- вызвать функцию с двумя аргументами
- результат присвоить переменной label
Так выделил бы инструкции программист, но вот Python сделать так не смог и сломался. Пора выяснить на какой инструкции нашла коса на камень.
Теперь ваша задача переписать код так, чтобы в каждой строке программы исполнялось не более одной инструкции из списка выше. Так вы сможете тестировать их по отдельности и облегчите себе задачу. Так выглядит отделение инструкции по созданию строки:
# 1. создать строку
template
label template
first_name first_name
last_name last_name
Сразу запустите код, проверьте что ошибка осталась на прежнему месте. Приступайте ко второй инструкции:
# 1. создать строку
template
# 2. получить у строки метод
template
label
first_name first_name
last_name last_name
Снова запустите код. Ошибка появится внутри format. Под сомнением остались две инструкции:
- вызвать функцию с двумя аргументами
- результат присвоить переменной label
Скорее всего, Python не распознал вызов функции. Проверьте это, избавьтесь от последней инструкции — от создания переменной label:
# 1. создать строку
template
# 2. получить у строки метод
template
# 3. вызвать функцию
first_name first_name
last_name last_name
Запустите код. Ошибка снова там же — внутри format. Выходит, код вызова функции написан с ошибкой, Python не смог его превратить в инструкцию.
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты.
Ошибки линтера
Теперь, когда мы уже научились писать простые программы, можно немного поговорить о том, как их писать.
Код программы следует оформлять определенным образом, чтобы он был достаточно понятным и простым в поддержке. Специальные наборы правил — стандарты — описывают различные аспекты написания кода. Таких стандартов несколько, самые известные в JavaScript: AirBnb, Standard, Google. В уроках мы будем придерживаться AirBnb.
В любом языке программирования существуют утилиты — так называемые линтеры. Они проверяют код на соответствие стандартам. В JavaScript это eslint.
Взгляните на пример из предыдущего урока:
Линтер будет «ругаться» на нарушение сразу нескольких правил:
В прошлом уроке мы сами признали, что такое обилие цифр и символов запутывает, и решили добавить скобки исключительно для удобства чтения:
Этот вариант уже не нарушает правил, и линтер будет «молчать».
Рассмотрим еще один пример:
Есть ли здесь нарушение стандарта?
К сожалению, да. На этот раз операции * и / находятся в одном выражении без разделения скобками. Вы можете решить эту проблему, добавив дополнительные скобки. Но в какой-то момент количество скобок может быть уже настолько большим, что код снова станет неудобным и непонятным. В этот момент разумнее будет разделить выражение на отдельные части. Мы научимся это делать в следующих уроках.
no-mixed-operators — лишь одно из большого количества правил. Другие правила описывают отступы, названия создаваемых сущностей, скобки, математические операции, длину строк и множество иных аспектов. Каждое отдельное правило кажется довольно мелким, не очень важным. Но вместе они составляют основу хорошего кода.
На Хекслете линтер начинает проверять код и сообщать о нарушениях после оформления подписки.
Дополнительные материалы
Проверьте синтаксис вызова функции
Теперь вы знаете что проблема в коде, вызывающем функцию. Можно помедитировать еще немного над кодом программы, пройтись по нему зорким взглядом еще разок в надежде на лучшее. А можно поискать в сети примеры кода для сравнения.
Запросите у Яндекса статьи по фразе “Python синтаксис функции”, а в них поищите код, похожий на вызов format и сравните. Вот одна из первых статей в поисковой выдаче:
Уверен, теперь вы нашли ошибку. Победа!
Синтаксические ошибки
Ошибки, которые обнаруживает компилятор, называют синтаксическими ошибками или ошибками компиляции. Синтаксические ошибки являются результатом ошибок в конструкции кода, таких как неправильное написание ключевого слова, пропуск необходимого знака пунктуации или использование открывающей фигурной скобки без соответствующей закрывающей фигурной скобки. Эти ошибки обычно легко обнаружить, поскольку компилятор говорит вам, где они находятся и что стало их причиной. Пример программы с синтаксической ошибкой:
Попытка компиляции приведённого кода:
Будет сообщено о четырёх ошибках, но в действительности программа содержит две ошибки:
- Во второй строке отсутствует ключевое слово void перед main
- Строка Welcome to Java должна быть закрыта закрывающей кавычкой в третьей строчке программы
Поскольку одна ошибка часто будет приводить к показу множества ошибок компиляции в разных строках, хорошей практикой является исправление ошибок начиная с верхней строки и постепенно двигаясь вниз. Исправление ошибок, которые ранее возникли в программе, может также исправить дополнительные ошибки, которые произошли позже.
Совет: если вы не знаете, как исправить ошибку, внимательно сравните вашу программу, символ за символом с похожими примерами в тексте. На начальном этапе обучения вы, вероятно, будете проводить много времени исправляя ошибки синтаксиса. Скоро вы будете знакомы с синтаксисом Java и сможете быстро исправлять синтаксические ошибки.
Ошибки во время выполнения
Ошибки во время выполнения – это ошибки, которые приводят к ненормальному обрывы работы программы. Они возникают во время работы программы, если среда обнаруживает операцию, которую невозможно выполнить. Обычно ошибки ввода становятся причинами ошибок во время выполнения. Ошибки ввода возникают, когда программа ожидает от пользователя ввода значения, но пользователь вводит величину, которую программа не может обработать. Например, программа ожидает получение числа, но вместо этого пользователь вводит строку, это приводит к ошибкам в программе, связанным с типами данных.
Другой пример ошибок во время выполнения – это деление на ноль. Это происходит, когда в целочисленном деление делитель равен нулю. Пример программы, которая вызовет ошибку во время выполнения:
Тесты
Код на Хекслете проверяется с помощью автоматических тестов. Обычно они написаны на том же языке, на котором написан сам код. Общий принцип работы такого вида тестирования довольно прост. Тестируемая программа загружается в память и вызывается с разными параметрами, а тесты следят за тем, чтобы ее поведение соответствовало ожидаемому.
Когда код не проходит тесты, то обычно говорят что тесты упали. В этот момент начинается самое интересное. Необходимо понять, где и почему возникла ошибка. И вывод тестов в этом процессе играет ключевую роль, это главный помощник и проводник. Но необходим опыт, чтобы начать делать правильные выводы из того, что пишут тесты.
В первую очередь нужно классифицировать проблему. Ошибки в тестах можно грубо разделить на две категории:
- ошибки, которые выдает компилятор или интерпретатор: синтаксическая ошибка, ошибка типизации
- ошибочные утверждения.
Тестирование
Тестирование — это выполнение программы для набора проверочных входных значений и сравнение полученных результатов с ожидаемыми.
Цель тестирования — проверка и доказательство правильности работы программы. В противном случае — выявление того, что в ней есть ошибки. Тестирование само не показывает местонахождение ошибки и не указывает на ее причины.
Принципы тестирования.
1) Тест — просчитанный вручную пример выполнения программы от исходных данных до ожидаемых результатов расчета. Эти результаты считаются эталонными.
Полномаршрутным будет такое тестирование, при котором каждый линейный участок программы будет пройден хотя бы при выполнении одного теста.
2) При прогоне программы по тестовым начальным данным, полученные результаты нужно сверить с эталонными и проанализировать разницу, если она есть.
3) При разработке тестов нужно учитывать не только правильные, но и неверные исходные данные.
4) Мы должны проверить программу на нежелательные побочные эффекты при задании некоторых исходных данных (деление на ноль, попытка считывания из несуществующего файла и т.д.).
5) Тестирование нужно планировать: заранее выбрать, что мы контролируем и как это сделать лучше. Обычно тесты планируются на этапе алгоритмизации или выбора численного метода решения. Причем, составляя тесты, мы предполагаем, что ошибки в программе есть.
6) Чем больше ошибок в коде мы уже нашли, тем больше вероятность, что мы обнаружим еще не найденные.
Хорошим называют тест, который с большой вероятностью должен обнаруживать ошибки, а удачным — тот, который их обнаружил.
Стратегии тестирования
1) Тестирование программы как «черного ящика».
Мы знаем только о том, что делает программа, но даже не задумываемся о ее внутренней структуре. Задаем набор входных данных, получаем результаты, сверяем с эталонными.
При этом обнаружить все ошибки мы можем только если составили тесты для всех возможных наборов данных. Естественно, это противоречит экономическим принципам, да и просто достаточно глупо.
«Черным ящиком» удобно тестировать небольшие подпрограммы.
2) Тестирование программы как «белого ящика».
Здесь перед составлением теста мы изучаем логику программы, ее внутреннюю структуру. Тестирование будет считаться удачным, если проверяет программу по всем направлениям. Однако, как мы уже говорили, это требует огромного количества тестов.
На практике мы, как всегда, совместно используем оба принципа.
3) Тестирование программ модульной структуры.
Мы снова возвращаемся к вопросу о структурном программировании. Если вы помните, программы строятся из модулей не в последнюю очередь для того, чтобы их легко было отлаживать и тестировать. Действительно, структурированную программу мы будем тестировать частями. При этом нам нужно:
строить набор тестов;
комбинировать модули для тестирования.
Такое комбинирование может строиться двумя способами:
Пошаговое тестирование — тестируем каждый модуль, присоединяя его к уже оттестированным. При этом можем соединять части программы сверху вниз (нисходящий способ) или снизу вверх (восходящий).
Монолитное тестирование — каждый модуль тестируется отдельно, а затем из них формируется готовая рабочая программа и тестируется уже целиком.
Чтобы протестировать отдельный модуль, нужен модуль-драйвер (всегда один) и модул и-заглушки (этих может быть несколько).
Модуль-драйвер содержит фиксированные исходные данные. Он вызывает тестируемый модуль и отображает (а возможно, и анализирует) результаты.
Модуль-заглушка нужен, если в тестируемом модуле есть вызовы других. Вместо этого вызова управление передается модулю-заглушке, и уже он имитирует необходимые действия.
К сожалению, мы опять сталкиваемся с тем, что драйверы и заглушки сами могут оказаться источником ошибок. Поэтому создаваться они должны с большой осторожностью.
Метод дедукции
Неверные результаты в нашем случае могут получиться из-за ошибки в:
- — вводе данных;
- — расчетном блоке;
- — собственно выводе.
Для доказательства мы можем пользоваться отладочной печатью, трассировкой или просто набором тестов. В любом случае мы выявляем одну ошибку в расчете и одну в выводе.
Метод индукции
Судя по результатам, ошибка возникает, когда максимальное число — второе или третье (если максимальное — первое, то определяется оно правильно, для доказательства можно програть еще два-три теста).
Просматриваем все, относящееся к переменным b и с. Со вводом никаких проблем не замечено, а что касается вывода — то мы быстро натыкаемся на замену b на с. Исправляем.
Утверждения
Утверждение — это специальная функция, которая вызывает ваш код с определенными параметрами и проверяет, что он возвращает ожидаемый результат. Например:
Самое важное: если тесты упали на утверждении, это означает, что ваш код как минимум отработал, но его результат не соответствует ожидаемому. Причем часто бывает так, что часть утверждений проходит проверку, то есть код возвращает правильный результат, а часть — нет, обычно в пограничных случаях. В конечном итоге падение теста на утверждении говорит о том, что в коде логическая ошибка.
Ниже — пример вывода упавшего теста. То, насколько вывод подробный, зависит от вида утверждения и возможностей тестовой среды.
Вывод можно разделить на две части:
Принципы отладки
Принципы локализации ошибок:
- Большинство ошибок обнаруживается вообще без запуска программы — просто внимательным просматриванием текста.
- Если отладка зашла в тупик и обнаружить ошибку не удается, лучше отложить программу. Когда глаз «замылен», эффективность работы упорно стремится к нулю.
- Чрезвычайно удобные вспомогательные средства — это отладочные механизмы среды разработки: трассировка, промежуточный контроль значений. Можно использовать даже дамп памяти, но такие радикальные действия нужны крайне редко.
- Экспериментирования типа «а что будет, если изменить плюс на минус» — нужно избегать всеми силами. Обычно это не дает результатов, а только больше запутывает процесс отладки, да еще и добавляет новые ошибки.
Принципы исправления ошибок еще больше похожи на законы Мерфи:
- Там, где найдена одна ошибка, возможно, есть и другие.
- Вероятность, что ошибка найдена правильно, никогда не равна ста процентам.
- Наша задача — найти саму ошибку, а не ее симптом.
Это утверждение хочется пояснить. Если программа упорно выдает результат 0,1 вместо эталонного нуля, простым округлением вопрос не решить. Если результат получается отрицательным вместо эталонного положительного, бесполезно брать его по модулю — мы получим вместо решения задачи ерунду с подгонкой.
Исправляя одну ошибку, очень легко внести в программу еще парочку. «Наведенные» ошибки — настоящий бич отладки.
Исправление ошибок зачастую вынуждает нас возвращаться на этап составления программы. Это неприятно, но порой неизбежно.
Конечно, в реальной работе мы не расписываем так занудно каждый шаг, не прибегаем исключительно к одной методике, да и вообще частенько не задумываемся, каким образом искать ляпы. Теперь, когда мы разобрались со всеми подходами, каждый волен выбрать те из них, которые кажутся самыми удобными.
Обратное движение по алгоритму
Зная, что ошибка возникает при выводе результатов, рассматриваем код, начиная с операторов вывода. Сразу же находим лишнюю b в операторе writeln.
Трассировка и промежуточная наблюдение за переменными
Добавляем промежуточную печать или наблюдение за переменными:
- — вывод a, b, c после ввода (проверяем, правильно ли получили данные)
- — вывод значения каждого из условий (проверяем, правильно ли записали условия)
Листинг программы существенно увеличился и стал вот таким:
В принципе, еще при наборе у нас неплохой шанс отловить ошибку в условии: подобные кусочки кода обычно не перебиваются, а копируются, и если дать себе труд слегка при этом задуматься, ошибку найти легко.
Но давайте считать, что глаз «замылен» совершенно, и найти ошибку не удалось.
Вывод для второго случая получается следующим:
Со вводом все в порядке . Об этом говорит сайт https://intellect.icu . Впрочем, в этом сомнений и так было немного. А вот что касается второй группы операторов печати, то картина вышла интересная: в результате выводится верное число (8.00), но неправильное слово («третье», а не «второе»).
Вероятно, проблемы в выводе результатов. Тщательно проверяем текст и обнаруживаем, что действительно в последнем случае выводится не c, а b. Однако к решению текущей проблемы это не относится: исправив ошибку, мы получаем для чисел -2.0, 8.0, 4.0 следующий результат.
Наибольшим оказалось третье число 4.00
Теперь ошибка локализована до расчетного блока и, после некоторых усилий, мы ее находим и исправляем.
Транскрипт урока
У вас вечеринка, а закуска кончилась, вы просите подругу что-нибудь купить.
— Эй, можешь сходить в магазин и купить какой-нибудь еды?
— Что именно?
— Ну, типа чипсы или что-нибудь такое. У нас всё закончилось.
— Сколько упаковок чипсов взять?
И у вас уже начинает немного вскипать мозг:
— А какие чипсы?
Десять минут спустя она возвращается с пустыми руками и говорит «у них не было таких чипсов в пакетах среднего размера».
О «программистах» есть определённые стереотипы и то, что они могут быть слишком конкретными и чересчур дотошными — один из них. Многие думают, что такие люди хорошо разбираются в математике или что-то подобное.
В реальности всё намного сложнее. Не существует всего двух типов людей, спектр типов личности буквально бесконечен. И для некоторых людей программирование немного более органично, потому что компьютеры абсолютно конкретные и абсурдно однозначные. Это совершенно не значит, что если вы считаете, что у вас «нематематический склад ума», вы не сможете стать хорошим разработчиком. Это значит только, что вам нужно научиться лучше распознавать и понимать, как именно работают компьютеры.
Такой способ поведения компьютеров ведёт ко множеству ошибок. Если вы наберёте console,log — console запятая log, вместо console точка log, JavaScript скажет «Понятия не имею, что ты имел в виду».
Вы будете делать ошибки и ваши программы будут содержать ошибки. Жизнь — она такая. Любой программист делает ошибки и это не имеет особого значения. Значение имеет только то, как вы потом с ними справляетесь. Исправление ошибок — важный навык. Это делает программирование непохожим на другие типы работ: ошибки неизбежны, вы не можете от них полностью застраховаться, а исправление ошибок — часть вашей работы.
Ошибка вроде «запятая вместо точки» это тип, который проще всего заметить и исправить. Это «синтаксическая ошибка», потому что неверный символ, как запятая в этом случае, нарушает синтаксические правила языка.
Когда вы запускаете код с такой ошибкой, интерпретатор JavaScript — та штука, которая исполняет JavaScript-программы — пожалуется: SyntaxError и укажет вам на то место, где по его мнению есть проблема.
Вот, например, это определение функции и в конце — лишняя скобка. Её там быть не должно и это ломает всю программу, поэтому JavaScript жалуется: «SyntaxError:» Unexpected token (символ))». Эта скобка unexpected — неожиданная.
Синтаксическая ошибка — это как если кто-то бредит вслух. Никто вокруг ничего не понимает.
Следующий тип ошибки подобен синтаксической, но в этом случае вы нарушаете не законы синтаксиса языка, а как бы законы синтаксиса собственного кода. В прошлый раз мы создали функцию abs, которая возвращала абсолютное значение числа.
Если вы вызовете ads вместо abs, интерпретатор JavaScript пожалуется: ReferenceError: ads is not defined. Вы использовали, как вам кажется, существующее название, но на самом деле такого названия нет.
Несколько строк, которые следуют после указания ошибки, могут смутить и оттолкнуть вас, но они тут только для пользы. Это stack trace — последовательность вызовов функций, которая привела к ошибке. Когда вы запускаете свою программу, даже крошечную, она становится частью чего-то более крупного — сложной системой JavaScript-кода, который приводится в действие, чтобы оживить вашу программу. Тут видно, что проблема была в моём файле. Следующая строка — это место, откуда был вызван мой код, третья строка — откуда была вызвана вторая и в таком духе можно продолжать дальше. Это как отслеживать шаги в обратном направлении — проблема есть, и мы можем возвращаться по одному шагу назад и смотреть, не нашлась ли ошибка.
Мы допускаем, что вся внутренняя система исправно работает, поэтому ошибка в нашем коде. Когда одна из ваших функций вызывает другую, вы увидите эту последовательность вызовов в стектрейсе.
ReferenceError может случиться с другими константами: например, если ваш код содержит 10 * pi, а pi не существует, потому что вы не создавали константу с точно таким названием, вы получите ReferenceError.
ReferenceError — это как называть кого-то чужим именем.
Следующий тип ошибки — когда вы путаете одну вещь с другой. Взгляните на этот код:
Сначала мы создали константу. Помните, что это как давать чему-то название: в нашем случае — числу 12 даётся название length. В следующей строке мы вызываем функцию length и передаём ей аргумент — число 54. Но подождите! length — это не функция! Это всего лишь число. Числа — это не функции, не ящики, которые производят какие-то действия. И JavaScript пожалуется именно на это:
Это Ошибка типизации: тип объекта, который вы использовали, неверный. Интерпретатор JavaScript не скажет чем что-то является, но точно скажет чем оно не является. length — это не функция.
Ошибка типизации — это как просить кошку постирать бельё. Возможно, вы хотели попросить об этом вашего друга.
Все эти ошибки — syntax error, reference error и type error — возникают из-за использования неправильных слов. И все они предельно очевидные: вы видите сообщение об ошибке и достаточно хорошо понимаете в чём проблема. Обычно сразу понятно, как их исправить:
- Синтаксическая ошибка? Заменить, удалить или добавить символы. Часто проблема в скобках и кавычках: открытые скобки и открытые кавычки должны быть закрыты.
- Reference error? Проверить, существует ли тот объект, на который вы ссылаетесь. Возможно, вы использовали неправильное название или забыли создать его.
- Ошибка типизации? Убедиться, что вы используете объекты верно. Часто проблема — простая путаница: вы создали и числовую константу и функцию, а потом пытаетесь вызвать число. Наверное, вы хотели вызвать функцию.
Последний тип ошибки, о котором мы сегодня поговорим — самый злой: Логическая ошибка. Допустим, мы пишем функцию, которая конвертирует градусы по фаренгейту (F) в градусы по цельсию (C). Чтобы сконвертировать температуру по одной шкале в другую, нужно вычесть 32 и умножить на 5/9. Например (50°F — 32) x 5/9 = 10°C.
Выглядит нормально? Давайте запустим эту функцию, сконвертируем 50 градусов и выведем на экран:
И у нас получилось 32.22222222222222. Не 10. Что произошло? JavaScript не пожаловался, когда код запустился, никаких ошибок не выскакивало. Компьютер не знает, что нам нужно, поэтому он производит вычисление, как мы его и просили. Но такое вычисление ошибочно — допустили ошибку мы. Нам нужно вначале вычесть 32, а потом умножить это на 5/9. Но мы не использовали скобки, поэтому 32 вначале умножилось на 5/9, а затем результат был отнят от температуры в фаренгейтах.
Это Логическая ошибка. Мы не нарушили никаких правил, мы просто сделали что-то не то. Наш пример был простым: мы написали функцию, запустили её и увидели неверный результат. Но представьте, что функция — это только маленькая частица крупной системы. Приложение для формирования бюджета в огромной организации отправляет отчёт в главную бухгалтерию, что в следующем месяце для оплаты счёта за электричество требуются дополнительные $300 000. Организуется экстренное собрание, увольняют людей, генеральный директор снова уходит в запой. Что случилось?
Иногда обнаружить проблему может оказаться трудной задачей: система кондиционирования ожидает, что январская температура будет 32 градуса по цельсию, вместо 10, потому что кто-то забыл использовать скобки в функции.
Борьба с логическими ошибками — это целиком ваша ответственность. И временами — тяжёлая работа, но в конце приходит сильное облегчение и удовлетворение: а-ааа, так вот в чём была проблема!
Теперь ваша очередь делать ошибки! Выполните тест и упражнение, чтобы ощутить боль.
Синтаксические ошибки зачастую выявляют уже на этапе трансляции. К сожалению, многие ошибки других видов транслятор выявить не в силах, т.к. ему не известен задуманный или требуемый результат работы программы. Отсутствие сообщений транслятора о наличии синтаксических ошибок является необходимым условием правильности программы, но не может свидетельствовать о том, что она даст правильный результат.
Примеры синтаксических ошибок :
- отсутствие знака пунктуации;
- несоответствие количества открывающих и закрывающих скобок;
- неправильно сформированный оператор;
- неправильная запись имени переменной;
- ошибка в написании служебных слов;
- отсутствие условия окончания цикла;
- отсутствие описания массивов и т.п.
Логические ошибки
Логические ошибки происходят, когда программа неправильно выполняет то, для чего она была создана. Ошибки этого рода возникают по многим различным причинам. Допустим, вы написали программу, которая конвертирует 35 градусов Цельсия в градусы Фаренгейта следующим образом:
Вы получите 67 градусов по Фаренгейту, что является неверным. Должно быть 95.0. В Java целочисленное деление показывает только часть – дробная часть отсекается, по этой причине в Java 9 / 5 это 1. Для получения правильного результата, нужно использовать 9.0 / 5, что даст результат 1.8.
Обычно ошибки синтаксиса легко обнаружить и легко исправить, поскольку компилятор даёт указания откуда пришла ошибка и что не так. Ошибки во время выполнения не трудны для поиска, поскольку причина и место для этих ошибок также показывается в консоли во время прерывания программы. Поиск логических ошибок, в свою очередь, очень сложный. В последующих главах вы обучитесь техникам трассировки программ и поиска логических ошибок.
Советы отладчику
1) Проверяйте тщательнее: ошибка скорее всего находится не в том месте, в котором кажется.
2) Часто оказывается легче выделить те места программы, ошибок в которых нет, а затем уже искать в остальных.
3) Тщательнее следить за объявлениями констант, типов и переменных, входными данными.
4) При последовательной разработке приходится особенно аккуратно писать драйверы и заглушки — они сами могут быть источником ошибок.
5) Анализировать код, начиная с самых простых вариантов. Чаще всего встречаются ошибки:
— значения входных аргументов принимаются не в том порядке,
— переменная не проинициализирована,
— при повторном прохождении модуля, перемен ная повторно не инициализируется,
— вместо предполагаемого полного копирования структуры данных, копируется только верхний уровень (например, вместо создания новой динамической переменной и присваивания ей нужного значения, адрес тупо копируется из уже существующей переменной),
— скобки в сложном выражении расставлены неправильно.
6) При упорной длительной отладке глаз «замыливается». Хороший прием — обратиться за помощью к другому лицу, чтобы не повторять ошибочных рассуждений. Правда, частенько остается проблемой убедить это другое лицо помочь вам.
7) Ошибка, скорее всего окажется вашей и будет находиться в тексте программы. Гораздо реже она оказывается:
- в компиляторе,
- операционной системе,
- аппаратной части,
- электропроводке в здании и т.д.
Но если вы совершенно уверены, что в программе ошибок нет, просмотрите стандартные модули, к которым она обращается, выясните, не менялась ли версия среды разработки, в конце концов, просто перегрузите компьютер — некоторые проблемы (особенно в DOS-средах, запускаемых из-под Windows) возникают из-за некорректной работы с памятью.
8) Убедитесь, что исходный текст программы соответствует скомпилированному объектному коду (текст может быть изменен, а запускаемый модуль, который вы тестируете — скомпилирован еще из старого варианта).
9) Навязчивый поиск одной ошибки почти всегда непродуктивен. Не получается — отложите задачу, возьмитесь за написание следующего модуля, на худой конец займитесь документированием.
10) Старайтесь не жалеть времени, чтобы уясненить причину ошибки. Это поможет вам:
исправить программу,
обнаружить другие ошибки того же типа,
не делать их в дальнейшем.
11) Если вы уже знаете симптомы ошибки, иногда полезно не исправлять ее сразу, а на фоне известного поведения программы поискать другие ляпы.
12) Самые труднообнаруживаемые ошибки — наведенные, то есть те, что были внесены в код при исправлении других.
Классификация ошибок
Ошибки в программах могут допускаться от самого начального этапа составления алгоритма решения задачи до окончательного оформления программы. Разновидностей ошибок достаточно много. Рассмотрим некоторые группы ошибок и соответствующие примеры:
Если вы удручены тем, что насажали в текст программы глупых ошибок — не расстраивайтесь. Ошибки вообще не бывают умными, хотя и могут относиться к самым разным частям кода:
- — ошибки обращения к данным,
- — ошибки описания данных,
- — ошибки вычислений,
- — ошибки при сравнении,
- — ошибки в передаче управления,
- — ошибки ввода-вывода,
- — ошибки интерфейса,
- и т д
Классификация ошибок по этапу обработки программы
рис Классификация ошибок этапа выполнения по возможным причинам
Проверь себя
- Что такое синтаксические ошибки (ошибки компилятора), ошибки во время работы и логические ошибки?
- Приведите примеры синтаксических ошибок, ошибок во время выполнения и логических ошибок?
- Если вы забыли написать закрывающую кавычку для строки, какого рода ошибка возникнет?
- Если ваша программа должна считать целое число, но пользователь ввёл строку, возникнет ли ошибка во время работы программы? Если да, то какого рода это ошибка?
- Предположим вы пишите программу для вычисления периметра прямоугольника, но по ошибке написали программу, которая вычисляет площадь прямоугольника. Какого рода эта ошибка?
- Выявите и исправьте ошибки в следующем коде:
Ошибки, которые не обнаруживает транслятор
В случае правильного написания операторов в программе может присутствовать большое количество ошибок, которые транслятор не может обнаружить. Рассмотрим примеры таких ошибок:
Логические ошибки: после проверки заданного условия неправильно указана ветвь алгоритма; неполный перечень возможных условий при решении задачи; один или более блоков алгоритма в программе пропущен.
Ошибки в циклах: неправильно указано начало цикла; неправильно указаны условия окончания цикла; неправильно указано количество повторений цикла; использование бесконечного цикла.
Ошибки ввода-вывода; ошибки при работе с данными: неправильно задан тип данных; организовано считывание меньшего или большего объема данных, чем нужно; неправильно отредактированы данные.
Ошибки в использовании переменных: используются переменных, для которых не указаны начальные значения; ошибочно указана одна переменная вместо другой. Ошибки при работе с массивами: пропущено предварительное обнуление массивов; неправильное описание массивов; индексы массивов следуют в ошибочном порядке.
ошибки безопасности, умышленные и не умышленные уязвимости в системе, открытость к отказам в обслуживании. несанкционированном доступе. екхолы
Ошибки в арифметических операциях: неправильное использование типа переменной (например, для сохранения результата деления используется целочисленная переменная); неправильно определен порядок действий; выполняется деление на нуль; при расчете выполняется попытка извлечения квадратного корня из отрицательного числа; не учитываются значащие разряды числа.
ошибки в архитектуре приложения пприводящие к увеличени технического долга
Проектирование тестов
Тесты просчитываются вручную, значит, они должны быть достаточно просты для этого.
Тесты должны проверять каждую ветку алгоритма. По возможности, конечно. Так что количество и сложность тестов зависит от сложности программы.
Тесты составляются до кодирования и отладки: во время разработки алгоритма или даже составления математической модели.
Обычно для экономии времени сначала пропускают более простые тесты, а затем более сложные.
Давайте рассмотрим задачу: нужно проверить, попадает ли введенное число в заданный пользователем диапазон.
program Example;
(******************************************************
* Задача: проверить, попадает ли введенное число в *
* заданный пользователем диапазон *
******************************************************)
Как видите, программа очень мала, а тестов для проверки всех ветвей ее алгоритма, требуется довольно много.
Распространённые ошибки
Пропуск закрывающей фигурной скобки, пропуск точки с запятой, пропуск кавычки для строки и неправильное написание имён – всё это самые распространённые ошибки для новых программистов.
Частые ошибки 1: Пропущенные фигурные скобки
Фигурные скобки используются для обозначения в программе блоков. Каждой открывающей фигурной скобке должна соответствовать закрывающая фигурная скобка. Распространённая ошибка – это пропуск закрывающей фигурной скобки. Чтобы избежать эту ошибки, печатайте закрывающую фигурную скобку всякий раз, когда печатаете открывающую фигурную скобку как показано в следующем примере:
Если вы используете IDE такую как NetBeans и Eclipse, то IDE автоматически вставит закрывающую фигурную скобку каждой введённой вами открывающей фигурной скобки.
Частые ошибки 2: Пропуск точки с запятой
Каждая инструкция заканчивается ограничителем инструкции (;). Часто новые программисты забывают поместить ограничитель инструкции для последней инструкции в блоке как это показано в следующем примере:
Частые ошибки 3: Пропуск кавычки
Строки должны помещаться в кавычки. Часто начинающие программисты забывают поместить кавычку в конце строки как показано в следующем примере:
Если вы используете IDE, такую как NetBeans и Eclipse, то IDE автоматически вставит закрывающую кавычку каждый раз, когда вы ввели открывающую кавычку.
Частые ошибки 4: Неправильное написание имён
Java чувствительная к регистру. Неправильное написание имён – частая ошибка для новых программистов. Например, пишут слово main как Main, а вместо String пишут string. Пример:
Средства отладки
Помимо методик, хорошо бы иметь представление о средствах, которые помогают нам выявлять ошибки. Это:
1) Аварийная печать — вывод сообщений о ненормальном завершении отдельных блоков и всей программы в целом.
2) Печать в узлах программы — вывод промежуточных значений параметров в местах, выбранных программистом. Обычно, это критичные участки алгоритма (например, значение, от которого зависит дальнейший ход выполнения) или составные части сложных формул (отдельно просчитать и вывести числитель и знаменатель большой дроби).
3) Непосредственное слежение:
- — арифметическое (за тем, чему равны, когда и как изменяются выбранные переменные),
- — логическое (когда и как выполняется выбранная последовательность операторов),
- — контроль выхода индексов за допустимые пределы,
- — отслеживание обращений к переменным,
- — отслеживание обращений к подпрограммам,
- — проверка значений индексов элементов массивов и т.д.
Нынешние среды разработки часто предлагают нам реагировать на возникающую проблему в диалоговом режиме. При этом можно:
- — просмотреть текущие значения переменных, состояние памяти, участок алгоритма, где произошел сбой;
- — прервать выполнение программы;
- — внести в программу изменения и повторно запустить ее (в компиляторных средах для этого потребуется перекомпилировать код, в интерпретаторных выполнение можно продолжить прямо с измененного оператора).
Рис Пример отладки приложения
Теория. Синтаксические ошибки
Программирование — это не магия, а Python — не волшебный шар. Он не умеет предсказывать будущее, у него нет доступа к секретным знаниями, это просто автомат, это программа. Узнайте как она работает, как ищет ошибки в коде, и тогда легко найдете эффективный способ отладки. Вся необходимая теория собрана в этом разделе, дочитайте до конца.
SyntaxError — это синтаксическая ошибка. Она случается очень рано, еще до того, как Python запустит программу. Вот что делает компьютер, когда вы запускаете скрипт командой python script.py:
- запускает программу python
- python считывает текст из файла script.py
- python превращает текст программы в инструкции
- python исполняет инструкции
Синтаксическая ошибка SyntaxError возникает на четвёртом этапе в момент, когда Python разбирает текст программы на понятные ему компоненты. Сложные выражения в коде он разбирает на простейшие инструкции. Вот пример кода и инструкции для него:
- создать строку ‘Евгений’
- создать словарь
- в словарь добавить ключ ‘name’ со значением ‘Евгений’
- присвоить результат переменной person
SyntaxError случается когда Python не смог разбить сложный код на простые инструкции. Зная это, вы можете вручную разбить код на инструкции, чтобы затем проверить каждую из них по отдельности. Ошибка прячется в одной из инструкций.
Дополнение к уроку
Самый действенный способ понять, как работает участок кода —
это расписать его выполнение на бумажке, как если бы вы были компьютером (медленным и немного голодным).
Метод утенка
Метод утёнка — психологический метод решения задачи, делегирующий её мысленному помощнику. Метод описан в книге «Программист-прагматик».
Тестируемый ставит на рабочем столе игрушечного утёнка
(или представляет его мысленно; на самом деле уточка — это условно, предмет может быть любым), и когда у него возникает вопрос, на который трудно ответить, то он задаёт его игрушке, как живому человеку, словно она действительно может ответить.
Считается, что правильная формулировка вопроса содержит как минимум половину ответа, а также это дает толчок мыслям, направляя их в нужное русло.
Метод также используется при отладке. Если определённая часть программы не работает, программист пытается объяснить утёнку, что делает каждая строка программы, и в процессе этого сам находит ошибку.
Предупреждения компилятора и интерпретатора
Самый простой тип ошибок. Такая ошибка говорит о том, что вы ошиблись в синтаксисе. Забыли запятую, скобку и тому подобные вещи. Такие ошибки легко находить и исправлять. Синтаксическая ошибка сопровождается текстом, по которому можно загуглить возможные причины.
Другие ошибки
Большой класс ошибок, которые могут возникать в процессе разработки. В выводе компилятора или интерпретатора всегда присутствует сообщение об ошибке, которое очень важно понять. Проще всего сделать, загуглив текст ошибки. Рекомендуем наш гайд Как искать техническую информацию.
Также ошибки содержат вывод backtrace, по которому можно найти то место, в котором возникла ошибка и попробовать его проанализировать.
Многие из этих ошибок легко исправить с помощью отладочной печати (см. урок Отладочная печать).
Найдите поломанное выражение
Этот шаг сэкономит вам кучу сил. Найдите в программе сломанный участок кода. Его вам предстоит разобрать на отдельные инструкции. Посмотрите на вывод программы в консоль:
Вторая строчка сообщает: File «script.py», line 9 — ошибка в файле script.py на девятой строчке. Но эта строка является частью более сложного выражения, посмотрите на него целиком:
«Девман» — авторская методика обучения программированию. Готовим к работе крутых программистов на Python. Станьте программистом, пройдите продвинутый курс Python.
Отладка программы
Отладка, как мы уже говорили, бывает двух видов:
Синтаксическая отладка. Синтаксические ошибки выявляет компилятор, поэтому исправлять их достаточно легко.
Семантическая (смысловая) отладка. Ее время наступает тогда, когда синтаксических ошибок не осталось, но результаты программа выдает неверные. Здесь компилятор сам ничего выявить не сможет, хотя в среде программирования обычно существуют вспомогательные средства отладки, о которых мы еще поговорим.
Отладка — это процесс локализации и исправления ошибок в программе.
Как бы тщательно мы ни писали, отладка почти всегда занимает больше времени, чем программирование.
Выводы
4 типа ошибок:
- Syntax error. Неверное использование языка. Часто лишние или недостающие скобки или кавычки. Что делать? Заменить, удалить или добавить символы. Часто проблема в скобках или кавычках: открытые скобки должны быть закрыты, открытые кавычки должны быть закрыты.
- Reference error. Использование несуществующего названия. Что делать? Проверить, существует ли то, на что вы ссылаетесь. Возможно вы использовали ошибочное название или забыли его создать.
- Type error. Использование неверного типа, например попытка вызвать константу числа, как функцию. Что делать? Убедиться, что всё используется верно. Часто проблема в простой путанице: вы создали численную константу и функциональную константу, а потом пытаетесь вызвать число. Вероятно вы собирались вызвать функцию.
- Logic error. (Логическая ошибка) Ваш код выполняет не то, что требуется, но программа запускается и не выдаёт ошибок трёх перечисленных выше типов. Сломана логика. Что делать? Проверить свой код, убедиться, что он выполняет то, что должен.