Следует ли всегда включать проверку границ? Вот что говорит по этому поводу Тони Хоар:
В нашем компиляторе каждое вхождение каждого индекса в каждый массив проверялось во всех случаях в период выполнения. Через много лет мы спросили наших клиентов, не стоит ли ввести в интересах эффективности параметр компиляции, позволяющий отключать эту проверку. Единогласно они убеждали нас не делать этого, - они уже хорошо знали, как часто встречается эта ошибка и к каким ужасным последствиям она может приводить. Со страхом и ужасом я заметил, что даже сегодня проектировщики языков и пользователи не выучили этот урок. В любой уважающей себя ветви инженерии непринятие предосторожностей такого рода считались бы нарушением закона. |
Этот комментарий применим не только к массивам, но и ко всем предусловиям в целом. Если действительно "ошибки задания индекса часто встречаются в работающих системах", то это должно быть истинно и для других нарушений предусловий.
Кто-то может занимать менее экстремальную позицию. Прежде всего, это компании, поставляющие ПО, в котором ошибки предусловий, "часто встречающиеся в работающей системе", связаны и с низким качеством самой системы, не решаемые мониторингом утверждений. Мониторинг фиксирует следствия - неисправности (fault), но не причины - ошибки и дефекты. Это правда, что мониторинг полезен конечным пользователям даже в системе низкого качества. Лучше часто получать сообщения об ошибках, чем получать неверные результаты. Есть один неприятный эффект, возникающий у разработчиков, поставляющих системы с некоторым уровнем мониторинга утверждений. У них может возникнуть, даже неосознанная, беззаботная позиция по отношению к корректности. Нестрашно, что есть ошибки в поставляемом ПО - пользователи их обнаружат в процессе мониторинга, и мы исправим их в очередной версии. Так не стоит ли остановить отладку прямо сейчас и начать поставку системы?
Трудно дать абсолютный ответ на вопрос "следует ли оставлять включенным некоторый уровень мониторинга?". Без знания потери производительности на мониторинг утверждений на него не ответить. Если добавление мониторинга увеличивает время работы системы в 10 раз, то немногие поддержат точку зрения Хоара, кроме тех, кто занимается критически важными приложениями, где за ошибки приходится дорого платить. Если потери производительности на мониторинг составляют два процента, то немногие решатся отключить мониторинг. На практике, конечно, потери находятся где-то посредине.
Но, между прочим, каковы они? Ясно, что многое зависит от того, что делает ПО, и как много в нем утверждений, но можно сообщить некоторые эмпирические наблюдения. По опыту ISE стоимость мониторинга предусловий (параметр по умолчанию, включающий, конечно, и проверку границ массивов) составляет 50%. Что самое удивительное, - 75% этой стоимости не связано с проверкой предусловий, а идет на поддержку трассировки вызовов, чтобы при нарушении предусловия можно было точно сказать, кто нарушил и где. Это может быть названо Парадоксом Проверки Предусловия: проверка предусловия сама по себе недорого стоит, но, чтобы получить ее, нужно заплатить за дополнительные услуги. Что касается постусловий и инвариантов, то штраф может достигать от 100% до 200%.
Кому-то может показаться, что привнесение производительности в это обсуждение, означает компромисс с корректностью, что нарушает основной принцип, высказанный еще в начале этой книги:
Как бы ни были необходимы компромиссы между факторами качества, один из факторов стоит в стороне от остальных - корректность. Нет никакого оправдания тому, что корректность подвергается опасности ради других факторов, таких как эффективность. Если программный продукт не выполняет свою функцию, все остальное не имеет смысла. |
Рассмотрение производительности, когда мы решаем, оставить ли мониторинг или нет, не является нарушением этого принципа. Вопрос не в том, приносить ли корректность в жертву эффективности, - нужно решить, что делать с некорректной системой, при разработке которой мы, очевидно, не приложили достаточных усилий, чтобы сделать ее корректной.
В действительности, эффективность - часть корректности. Рассмотрим метеорологическую систему, требующей 12 часов работы для выработки прогноза на следующие сутки. Система тщательно оптимизирована, в частности исключены все проверки, в том числе выход индекса за границы и другие подобные неисправности. Она тщательно разрабатывалась и тестировалась. Теперь, предположим, что добавление проверок периода исполнения вдвое увеличит время ее работы. Будет ли включена проверка, - нет!
Давайте не остановимся на этом, а зададим действительно трудный вопрос. Предположим, что 12 часов уходит на работу системы с включенными проверками, Хотелось ли бы вам удалить их, чтобы получить прогноз за 6 часов, а не за 12, или тратить те же 12 часов, но перейти к более сложному алгоритму, дающему лучший прогноз? Я думаю, что если предлагается "возможность выключить проверки в интересах эффективности производственной системы", почти каждый ответит "да".
В конечном итоге, выбор уровня мониторинга в производственных системах не так прост, как предполагает Хоаровское правило. Следует соблюдать несколько точных и строгих правил.
[x]. Помните, программная система должна быть сделана надежной до того, как она начнет свою производственную жизнь. Ключом является применение методов, обеспечивающих надежность, описанных в литературе по программной инженерии, включая методы данной лекции и всей этой книги.
[x]. Если вы являетесь менеджером проекта, никогда не позволяйте своим разработчикам предполагать, что в производственной версии проверки будут включены. Заставьте каждого исходить из того, - все проверки могут быть выключены. Это особенно важно для больших систем, в природе которых устрашающие последствия ошибок.
[x]. Убедитесь, что в процессе разработки системы проверка утверждений всегда включена, по меньшей мере, на уровне предусловий.
[x]. Выполняйте интенсивное тестирование со всеми включенными проверками. Включайте также все проверки при каждом найденном жучке и устранении его последствий.
[x]. Для стандартной производственной версии решите, выберите ли версию без проверок или защищенную версию. Напомню о трех факторах, рассмотренных в самом начале этого раздела, которые следует учитывать при принятии решения.
[x]. Если вы решите выбрать версию без проверок в качестве стандарта, то включите в поставку и версию с проверками, по меньшей мере, предусловий. В случае, если система у пользователей начнет вести себя непредсказуемым способом, вопреки ожиданиям, вы сможете попросить пользователей перейти на защищенную версию, что поможет быстро отыскать неисправности системы.
Такой способ использования мониторинга утверждений обеспечивает замечательную помощь в быстрой прополке всех сорняков - ошибок, сумевших выстоять в процессе систематического конструирования программной системы.
Обсуждение
Механизм утверждений, представленный в этой лекции, привносит несколько тонких проблем, подлежащих исследованию.
Нужен ли мониторинг в период выполнения?
Действительно, нужно ли проверять утверждения в период выполнения? После того, как мы были в состоянии, используя утверждения, дать теоретическое определение корректности класса: каждая процедура создания должна гарантировать инвариант, и тело каждой процедуры, запущенной в состоянии, удовлетворяющем инварианту и предусловию, сохраняет в заключительном состоянии инвариант и гарантирует выполнение постусловия. Теперь мы должны выполнить математическую проверку m+n соответствующих условий (для m процедур создания и n экспортируемых процедур), и тогда долой мониторинг в период выполнения.