«Безошибочное программное обеспечение - это миф»!

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

import Math
a = Math.sqrt(2)
a = 1.4142…       //17 digits in all
a * a == 2
//False

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

Подумать только, что чаще всего эти ошибки возникают из-за очень небольшого количества синтаксических ошибок, таких как пропуск двоеточия («:») в конце объявления функции Python или логической. так же просто, как приравнять список к другому списку, когда нашим первоначальным намерением было просто сделать копию исходного списка, и в этом случае [:] было бы более предпочтительным, чем часто ошибочно используемый символ равенства (=).

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

Как исправить ошибки?

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

  1. Баги красятся в наших программах:

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

2. Порода ошибок

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

3. Цель отладки - устранить одну известную ошибку.

Это утверждение - только половина правды, более полная правда состоит в том, что цель отладки - убедиться, что у нас есть код без ошибок.

Отладка: рекомендации

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

Итак, что или как следует обрабатывать ошибки? Я бы сказал, используйте инструменты!

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

  1. Операторы Print () в Python, операторы Console.log () в Javascript.
  2. Чтение

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

Итак, когда в следующий раз вы столкнетесь с ошибкой в ​​своем коде, вот что делать:

  1. Изучите текст программы.

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

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

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

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

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

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

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

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

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

def isPalindrome():
   input_list = []   //user inputs are stored in this list
   done = False      
   while not done:
       user_input = input('Please enter a value: ') //prompts user
       if user_input == '':
           done = True
       else:
           input_list.append(user_input)
   list_copy = input_list
   list_copy.reverse()
   isPalindrome = (input_list = list_copy)
   if isPalindrome:
      print(" This is a Palindrome")
   else:
      print("This is NOT a palindrome")

если для последовательных запросов мы вводим три значения, что делает наш input_list =[ 1, “a”, 1]

наш результат будет This is a Palindrome

конечно, опытные программисты возразят, и правильно, что это не самый эффективный способ решения проблемы палиндрома, ну для нашей цели это работает, или сработало?

Что ж, оказывается, что даже если наш код не выдает ошибок, если значения нашего input_list были [ 1, 2. 3]

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

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

def isPalindrome():
   input_list = []   //user inputs are stored in this list
   done = False      
   while not done:
       user_input = input('Please enter a value: ') //prompts user
       if user_input == '':
           done = True
       else:
           input_list.append(user_input)
   print(input_list)       //half point tool check
   list_copy = input_list
   list_copy.reverse()
   isPalindrome = (input_list = list_copy)
   print(input_list)  //output is [1,2,3]
   print(list_copy)   //output is [3,2,1]
   if isPalindrome:
      print(" This is a Palindrome")
   else:
      print("This is NOT a palindrome")

предположим, что мы ввели следующее, как в put 1, 2, 3, ожидается, что вывод этого среднего оператора печати будет [1,2,3], и это действительно то, что мы получаем. Это автоматически означает, что мы можем пренебречь всей верхней половиной всей кодовой базы, нашей ошибки здесь нет!

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

Но подождите секунду, это должно быть правильно, поскольку есть тест, который должен выдавать нам вывод «Не палиндром» после того, как тесты не удались? Что ж, логически мышление правильное, но его реализация была неправильной. Обратите внимание, что мы изначально намеревались создать копию input_list, а не приравнивать ее к новой переменной списка. Приравнивая его, условие теста в последующем блоке if всегда проходит как ИСТИНА и, следовательно, причина, по которой мы получаем утвердительный ответ «Это палиндром» даже для входных данных, которые, как знает ученик первого класса, не пройдут тест на палиндром.

Как же тогда исправить ошибку?

Мы просто исправляем оплошность реализации, создавая копию input_list и сохраняя ее в переменной list_copy следующим образом;

def isPalindrome():
   input_list = []   //user inputs are stored in this list
   done = False      
   while not done:
       user_input = input('Please enter a value: ') //prompts user
       if user_input == '':
           done = True
       else:
           input_list.append(user_input)
   list_copy = input_list[:]  // BUG FIXED
   list_copy.reverse()
   isPalindrome = (input_list = list_copy)
   if isPalindrome:
      print(" This is a Palindrome")
   else:
      print("This is NOT a palindrome")

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

Кстати, помните, когда я сказал в своих первых строках, что безошибочное программное обеспечение - это миф? , я был "технически" неправ!

Хорошо отлаженное программное обеспечение не содержит ошибок!