|
Термин защитное программирование характеризует такой стиль написания программ, при котором появляющиеся ошибки легко обнаруживаются и идентифицируются программистом. Необходимость защитного программирования диктуется тем, что имеющиеся в подавляющем большинстве программ ошибки далеко не всегда сказываются явным образом на их работе и могут в течение многих месяцев оставаться необнаруженными.
Встраивание отладочных средств в программу есть не что иное, как защитное программирование. Средства отладки, предусматриваемые в исходной программе, называют стопорами ошибок. Их назначение — сохранить "улики", позволяющие идентифицировать ошибку путем указания ее местоположения. Такой подход отличается от традиционного, при котором вначале устанавливается факт явной ошибки, а затем делается попытка проследить за процессом ее возникновения в обратном порядке. Последнее, однако, затрудняется тем, что обычно ошибка не оставляет в самой программе никаких следов. Поэтому для обнаружения ее местоположения приходится выполнять по нескольку отладочных прогонов.
Существует несколько причин, по которым программисты не пользуются защитным программированием.
Первая из них— это излишняя самоуверенность. Отладочные операторы не предусматриваются в программе лишь потому, что мы переоцениваем собственные шансы работать без серьезных ошибок. Бывает, что даже длительный практический опыт затруднений и неудач не помогает избавиться от этого неверного убеждения.
Вторая причина кроется в излишней доверчивости по отношению к другим программистам. Она проявляется в том, что, если достаточно опытный программист убеждает нас в совершенстве своей подпрограммы, нам в голову не приходит мысль о проверке этого утверждения, даже если в прошлом работа программиста не была столь уж безукоризненной.
Третьей причиной пренебрежения защитным программированием является неверное предположение, будто оно приводит к излишне большому расходу памяти и замедлению работы программы. На самом же деле наиболее существенное обстоятельство, замедляющее работу программы, — это невозможность заставить ее нормально функционировать.
Первые два случая связаны с обычным заблуждением, но даже если конкретная программа и работает без ошибок, средства отладки все же необходимы для того, чтобы быть уверенным в этом.
Нельзя полагаться и на полную достоверность информации. Ошибки оператора, неверные форматы данных, изменения в программе, вносимые в последнюю минуту, ошибки перфорирования и другие подобные огрехи — все это приводит к возрастанию трудностей обработки данных. Однако не следует впадать и в другую крайность, полагая, что если кто-то дает входные данные для вашей программы, то причина ее плохой работы заключается именно в них. Ведь если ваша программа или подпрограмма принимает неверные данные к обработке, а затем выходит из строя или, что еще хуже, до конца обрабатывает неверные данные, вина за это ложится только на вас как на программиста. В случае же когда подпрограмма, составленная вами, принимает информацию, содержащую ошибки, и передает ее какой-либо другой подпрограмме" очевидно, что ваше детище не способно распознавать неверные данные, и поэтому вы — соучастник ошибки. Ведь вполне возможно, что именно ваша подпрограмма является в программе наиболее подходящим местом для выявления конкретной ошибки.
Сомнительна и справедливость утверждения относительно неэффективности применения защитного программирования. Дело в том, что незначительное число избыточных операторов, вводимых в программу для предотвращения или обнаружения ошибок, не должно приводить к большому дополнительному расходу машинного времени на выполнение программы в рабочем режиме. Наоборот, такие операторы наверняка сэкономят ваше собственное и машинное время на этапе отладки. А если уж окажется необходимым исключить из программы все стопоры ошибок по соображениям увеличения эффективности использования машинных ресурсов, это легко сделать и позже.
Стопоры ошибок проще всего вводить в программу на стадии ее написания. Всякое откладывание этой работы до момента появления ошибок может привести к забыванию существенных деталей и неверной организации контроля за ошибками. Кроме того, слишком позднее введение отладочных средств в программу связано с ее повторным компилированием, что в свою очередь требует времени.
В большинстве стандартных подпрограмм, поставляемых изготовителями ЭВМ, входные параметры подвергаются обязательному контролю. Так, например, подпрограммы извлечения квадратного корня и взятия логарифма проверяют, имеет ли аргумент положительное значение. Подобным же образом осуществляется контроль за тем, чтобы значения чисел, участвующих в вычислениях, не превышали максимально допустимых. И такие проверки выполняются в каждом цикле работы подпрограммы, причем считается, что они оправданны. Следовательно, у программиста нет никаких оснований поступать иначе в собственных подпрограммах, тем более, что их параметры обычно тоже подчиняются определенным ограничениям.
Существует несколько принципов защитного программирования:
1. Общее недоверие. В соответствии с этим принципом для каждого модуля должно предполагаться, что входные данные могут оказаться неверными и подлежат проверке.
2. Немедленное обнаружение. Этот принцип гласит, что лучше всего выявлять ошибку возможно раньше, поскольку при этом упрощается задача установления ее первопричины.
3. Изолирование ошибок. Согласно этому принципу, ошибки в одной из частей программы изолируются посредством так называемых брандмауэров, чтобы не допустить их губительного влияния на другие части.
Идеальной представляется такая ситуация, когда сообщения; печатаемые средствами отладки, могут использоваться для подтверждения того, что конкретный модуль получил предусмотренные входные данные, что в нем правильно выполнены все операции и что он обеспечил выдачу правильных результатов вызывавшей его программе. Соответствующие контрольные операторы должны быть независимыми в том смысле, что их исключение недолжно приводить к нарушению функционирования модуля.
Еще одним полезным средством отладки является счетчик, фиксирующий, как часто вызывалась та или иная подпрограмма и сколько раз выполнялся тот или иной цикл. Эта информация полезна для отладки, так как позволяет судить о близости процесса вычислений к завершению и указывает на те области программы, которые используются наиболее интенсивно и где оптимизация вычислительного процесса оправданна.
Можно предусмотреть в программе текущий контроль за поведением наиболее важных данных, например проверку нахождения переменных в допустимых пределах посредством сравнения их величин с максимальными и минимальными значениями. Такой конт--
роль носит название информационного фильтра. Кроме того, можно проводить сопоставление различных переменных в целях выявления ошибок вычислений. В некоторых старых операционных системах информационные фильтры применялись для анализа текущего состояния самих операционных систем; если при этом обнаруживалась ошибка, то печаталось сообщение: "Вызывайте системного программиста". К этому моменту автора подобного сообщения зачастую уже невозможно было найти, и поэтому никто не знал, что же следует предпринять. В настоящее время мы располагаем несомненно большими возможностями.
Теперь выясним, для чего и каким образом следует проверять ■Созданную программу:
1. Проверяйте тип данных. Контролируйте буквенные поля (поля имен), чтобы убедиться, что они не содержат цифровых данных. Проверяйте цифровые поля на отсутствие в них буквенных данных.
2. Делайте проверку области значений переменных, чтобы удостовериться, например, что положительные числа всегда положительны.
3. Выполняйте контроль правдоподобности значений переменных, которые не должны превышать некоторых констант или значений других переменных. Например, начисляемые налоги и удержания не должны быть больше суммы, по которой они определяются.
4. Контролируйте итоги вычислений путем введения всюду, где это возможно, перекрестных итогов, контрольных сумм и счетчиков числа обрабатываемых элементов информации.
5. Используйте автоматические проверки, такие, как контроль за переполнением, потерей значимости и метками файлов.
6. Проверяйте длину элементов информации, если она задана, например код почтового индекса.
7. Контролируйте закрепленные признаки, под которыми понимаются обязательные элементы полей или записей данных. Например, если определенный тип записей должен всегда содержать в колонках 73—75 код MST, необходимо этот факт проверять.
8. Выполняйте проверку контрольных разрядов. Так как некоторые элементы данных могут иметь дополнительные контрольные цифры, существует возможность проверки правильности этой информации. Такой код называется избыточным.
Защитное программирование, разумеется, приводит к созданию избыточной программы подобно тому, как использование контроля по четности вносит избыточность в работу аппаратных средств. Необходимо помнить вместе с тем, что ошибка, которую вы стремитесь обнаружить или появление которой стараетесь предотвратить, в дальнейшем потребует меньшего внимания. Сотрудники вычислительных центров любят ссылаться на поговорку: "Мякину заложишь — мякину получишь", которую можно назвать принципом МЗМП. Хорошая программа—это та, которая обнаруживает "заложенную мякину", не допуская ее появления на выходе.
Контролируйте правдоподобность вводимых данных.
⇐4.23. Обнаружение ошибок || Оглавление || 4.25. Утверждения⇒
|