Шрифт:
• ошибки, обнаруженные с помощью библиотеки (например, стандартной);
• ошибки, обнаруженные с помощью программы пользователя.
• Логические ошибки. Это ошибки, найденные программистом в поисках причины неправильных результатов.
Соблазнительно сказать, что задача программиста — устранить все ошибки. Разумеется, это было бы прекрасно, но часто этот идеал оказывается недостижимым. На самом деле для реальных программ трудно сказать, что подразумевается под выражением “все ошибки”. Например, если во время выполнения своей программы мы выдернем электрический шнур из розетки, то следует ли это рассматривать как ошибку и предусмотреть ее обработку? Во многих случаях совершенно очевидно, что ответ будет отрицательным, но в программе медицинского мониторинга или в программе, управляющей телефонными переключениями, это уже не так. В этих ситуациях пользователь вполне обоснованно может потребовать, чтобы система, частью которой является ваша программа, продолжала выполнять осмысленные действия, даже если исчезло энергопитание компьютера или космические лучи повредили его память. Основной вопрос заключается в следующем: должна ли программа сама обнаруживать ошибки?
1. Должна вычислять желаемые результаты при всех допустимых входных данных.
2. Должна выдавать осмысленные сообщения обо всех неправильных входных данных.
3. Не обязана обрабатывать ошибки аппаратного обеспечения.
4. Не обязана обрабатывать ошибки программного обеспечения.
5. Должна завершать работу после обнаружения ошибки.
Программы, для которых предположения 3–5 не выполняются, выходят за рамки рассмотрения нашей книги. В то же время предположения 1 и 2 являются частью основных профессиональных требований, а профессионализм — это именно то, к чему мы стремимся. Даже если мы не всегда соответствуем идеалу на 100%, он должен существовать.
При создании программы ошибки естественны и неизбежны. Вопрос лишь в том, как с ними справиться. По нашему мнению, при разработке серьезного программного обеспечения попытки обойти, найти и исправить ошибки занимают более 90% времени. Для программ, безопасность работы которых является первоочередной задачей, эти усилия займут еще больше времени. В маленьких программах легко избежать ошибок, но в больших вероятность ошибок возрастает.
• Организовать программное обеспечение так, чтобы минимизировать количество ошибок.
• Исключить большинство ошибок в ходе отладки и тестирования.
• Убедиться, что оставшиеся ошибки не серьезны.
Ни один из этих подходов сам по себе не позволяет полностью исключить ошибки, поэтому мы будем использовать все три.
При разработке надежных программ, т.е. программ, которые делают то, для чего предназначены при допустимом уровне ошибок, большую роль играет опыт. Пожалуйста, не забывайте, что в идеале программы всегда должны работать правильно. Разумеется, на практике мы можем лишь приблизиться к идеалу, но отказ от трудоемких попыток приблизиться к идеалу заслуживает безусловного осуждения.
5.2. Источники ошибок
• Плохая спецификация. Если мы слабо представляем себе, что должна делать программа, то вряд ли сможем адекватно проверить все ее “темные углы” и убедиться, что все варианты обрабатываются правильно (т.е. что при любом входном наборе данных мы получим либо правильный ответ, либо осмысленное сообщение об ошибке).
• Неполные программы. В ходе разработки неизбежно возникают варианты, которые мы не предусмотрели. Наша цель — убедиться, что все варианты обработаны правильно.
• Непредусмотренные аргументы. Функции принимают аргументы. Если функция принимает аргумент, который не был предусмотрен, то возникнет проблема, как, например, при вызове стандартной библиотечной функции извлечения корня из –1,2:
• Непредусмотренные входные данные. Обычно программы считывают данные (с клавиатуры, из файлов, из средств графического пользовательского интерфейса, из сетевых соединений и т.д.). Как правило, программы выдвигают к входным данным много требований, например, чтобы пользователь ввел число. А что, если пользователь введет не ожидаемое целое число, а строку “Отстань!”? Этот вид проблем обсуждается в разделах 5.6.3 и 10.6.
• Неожиданное состояние. Большинство программ хранит большое количество данных (“состояний”), предназначенных для разных частей системы. К их числу относятся списки адресов, каталоги телефонов и данные о температуре, записанные в объекты типа
• Логические ошибки. Эти ошибки приводят к тому, что программа просто делает не то, что от нее ожидается; мы должны найти и исправить эти ошибки. Примеры поиска таких ошибок приводятся в разделе 6.6 и 6.9.
Данный список имеет практическое применение. Мы можем использовать его для контроля качества программы. Ни одну программу нельзя считать законченной, пока не исследованы все потенциально возможные источники ошибок. Этот список целесообразно иметь в виду уже в самом начале проекта, поскольку очень маловероятно, что поиск и устранение ошибок в программе, запущенной на выполнение без предварительного анализа, не потребует серьезной переработки.
5.3. Ошибки во время компиляции