Книга: Программист-прагматик. Путь от подмастерья к мастеру

ППК и аварийное завершение работы программы

ППК и аварийное завершение работы программы

ППК прекрасно сочетается с принципом аварийного завершения работы программы (см. «Мертвые программы не лгут»). Предположим, что есть метод, вычисляющий квадратные корни (подобный классу DOUBLE в языке Eiffel). Этот метод требует наличия предусловия, которое ограничивает область действия положительными числами. Предусловие в языке Eiffel объявляется с помощью ключевого слова require, а постусловие – с помощью ключевого слова ensure, так можно записать:

Sqrt: DOUBLE is

-- Подпрограмма вычисления квадратного корня

require

  sqrt_arg_must_be_positive: Current >= 0;

--- ...

 --- здесь происходит вычисление квадратного корня

 --- ...

ensure

((Result*Result) – Current).abs <= epsilon*Current.abs;

-- Результат должен находиться в пределах погрешности

end;

Кто несет ответственность!

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

Рассмотрим программу, которая считывает с устройства ввода номер, извлекает из него квадратный корень (вызывая функцию sqrt) и выводит результат на печать. Функция sqrt имеет предусловие – ее аргумент не должен быть отрицательным числом. Если пользователь вводит отрицательное число, то именно вызывающая программа должна гарантировать, что это число не будет передано функции sqrt. Вызывающая программа может воспользоваться многими вариантами: она может завершить работу, выдать предупреждение и начать считывать другое число, она также может преобразовать число в положительное и добавить к результату, выданному функцией Sqrt, мнимую единицу. Какой бы вариант ни использовался, эта проблема определенно не связана с функцией sqrt.

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

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

Если вы передаете sqrt отрицательный параметр, рабочая среда Eiffel выводит на печать ошибку «sqrt_argjnust_be_positive» (аргумент функции sqrt должен быть положительным) наряду с трассировкой стека. Этот вариант реализован лучше, чем его аналогия в языках типа Java, С, и С++, где при передаче отрицательного числа в sqrt выдается специальное значение NaN (Not a Number – не число). Далее по ходу программы, когда вы попытаетесь произвести со значением NaN некие математические действия, результаты этого будут поистине удивительными.

Проблему намного проще найти и диагностировать «не сходя с места», при аварийном завершении работы программы.

Оглавление книги


Генерация: 1.116. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз