Re[27]: Checked exceptions... зло или добро?
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.05 02:44
Оценка: 1 (1)
Здравствуйте, dshe, Вы писали:

D>В силу указанных ранее причин:

D>1. неочевидность (неявность) связей и взаимодействия (Павел Кузнецов: http://www.rsdn.ru/Forum/Message.aspx?mid=1284040&only=1
Автор: Павел Кузнецов
Дата: 20.07.05
)

D>2. в больших количествах исключения существенно подтормаживают скорость выполнения приложения (IT: http://www.rsdn.ru/Forum/Message.aspx?mid=1284093&only=1
Автор: IT
Дата: 21.07.05
)

D>3. сложности в отладке (IT: http://www.rsdn.ru/Forum/Message.aspx?mid=1284093&only=1
Автор: IT
Дата: 21.07.05
, alexeiz: http://www.rsdn.ru/Forum/Message.aspx?mid=1285986&only=1
Автор: alexeiz
Дата: 21.07.05
)


D>или есть еще другие?


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

Но в приципе любого из перечисленных пунктов достаточно чтобы не прменять исключения для ветвления основной логики программы.
... << RSDN@Home 1.2.0 alpha rev. 591>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[25]: Checked exceptions... зло или добро?
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.05 02:44
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Нет, тема обычно остается живая.


Дык удаляются обычно не все тымы целиком, а отдельные их подветки.
... << RSDN@Home 1.2.0 alpha rev. 591>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[26]: Checked exceptions... зло или добро?
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.05 02:44
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

Играть с тобой в горяче-холдно у меня желания нет. Время тратить на ответ по пунктам тоже. Больно много написано. Так что отвечу по существу.

Твою идею деления ошибок категорически не разделяю. В уонйк уонцнов ассер в типобезопасных средах мало чем отличается от ислючения.
Идею выпода в асадок по любому поводу тоже не разделяю.

Что касется фрэймворка... Остаюсь на своих позициях. Думаю, что натыкивание ассертов было вызвано все же надежной на тщательное (возможно автоматизированное) тестирование, большой альф- и бэта-цикл (в котором ассерты скорее всего вообще не убирались) и ра днругие заморочки. Но основной причинойконечно являлся минталитет программистов. Возможно он был схож с твоим. К этому выоду подталкивает и то, что C#-пная часть фрэймворка (которая намного больше по объему) в основном содержит именно генрацию исключений.

Кстати, примеры твои не совсем корректны. ExceptionUnwind это то самое исключение где генерация исключений является просто таки злом.

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

Другими словами ассрты сидят в глубоком ядре, а весь библиотечный код напичкан исключениями. Возможно это и разумно. Учитывая все те же факторы высокой степени отлаженности ядра, производительности и квалификации программистов писавших ядро можно считать объем внутренних ошибок минимальным. А отсуствие внутренних исключений позволяет лучше выявлять ошибки прикладных программистов. Вот только с твоей теорией это никак не вяжется.
... << RSDN@Home 1.2.0 alpha rev. 591>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[27]: Checked exceptions... зло или добро?
От: Павел Кузнецов  
Дата: 26.07.05 04:58
Оценка: 57 (8) +1
VladD2,

V> Твою идею деления ошибок категорически не разделяю. В уонйк уонцнов

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

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

Отсутствие "проходов по памяти" и т.п. здесь определяющего значения не имеет. Речь
идет о состоянии программы, о сохранении инвариантов и т.п. Т.е. при программировании
делаются некоторые предположения о том, что может, и что не может произойти.
Предположения могут быть как явными, так и неявными. В любом случае, они есть.
Эти предположения, относящиеся к состоянию программы или какой-то части ее данных
до исполнения некоторой функции называются предусловиями, после -- постусловиями.
Сохраняющиеся на протяжении выполнения всей программы (за исключением точно
оговоренных мест) -- инвариантами.

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

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

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


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

Вот пример конспекта по проектированию отказоустойчивых систем:
http://www.comp.lancs.ac.uk/computing/resources/IanS/Ian/Lectures/COURSES/CritSys/PDF-notes/Dep-Software-Dev.pdf

Несколько ключевых мест:

Fault tolerance actions

Fault detection The system must detect that a fault (an
incorrect system state) has occurred.
Damage assessment The parts of the system state affected by
the fault must be detected.
Fault recovery The system must restore its state to a known safe state.
Fault repair The system may be modified to prevent recurrence of the
fault. As many software faults are transitory, this is often unnecessary.


Damage assessment

• Analyse system state to judge the extent of corruption caused by a system failure
• Must assess what parts of the state space have been affected by the failure
• Generally based on ‘validity functions’ which can be applied to the state
elements to assess if their value is within an allowed range


Fault recovery

Forward recovery
• Apply repairs to a corrupted system state
Backward recovery
• Restore the system state to a known safe state
• Forward recovery is usually application specific — domain knowledge is
required to compute possible state corrections
• Backward error recovery is simpler. Details of a safe state are maintained
and this replaces the corrupted system


Recovery blocks

• Force a different algorithm to be used for each version so they reduce the
probability of common errors
• However, the design of the acceptance test is difficult as it must be
independent of the computation used
• There are problems with this approach for realtime systems because of
the sequential operation of the redundant versions


Fault minimisation

• Current methods of software engineering now allow for the production of
fault-free software.
Fault-free software means software which conforms to its specification.
It does NOT mean software which will always perform correctly as there
may be specification errors.
The cost of producing fault free software is very high. It is only cost-
effective in exceptional situations. May be cheaper to accept software faults


И т.п.

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

Вот чуть более подробная ссылка, если тебе, действительно, интересна эта тема:
http://www.ece.cmu.edu/~koopman/des_s99/contents.html

V> Что касется фрэймворка... Остаюсь на своих позициях. Думаю, что

V> натыкивание ассертов было вызвано все же надежной на тщательное
V> (возможно автоматизированное) тестирование, большой альф- и бэта-цикл (в
V> котором ассерты скорее всего вообще не убирались) и ра днругие
V> заморочки. Но основной причинойконечно являлся минталитет
V> программистов
. Возможно он был схож с твоим. К этому выоду
V> подталкивает и то, что C#-пная часть фрэймворка (которая намного больше
V> по объему) в основном содержит именно генрацию исключений.

Все проще. Те исключенительные ситуации, которые входят в спецификацию,
порождают исключения. Остальные причислены к ошибкам, и игнорируются, т.к.
с ними нечего больше делать. В самом деле, посмотри внимательнее на случаи,
диагностируемые с помощью assert. Как именно ты предложил бы восстанавливаться
в случае подобных ошибок? В этих случаях система находится в непредсказуемом
состоянии, а кода, диагностирующего нарушения состояния, и возвращающего все
"на родину" просто нет. Если бы, скажем, вызывающий код умел обрабатывать
какой-нибудь NullPointerException, выбрасываемый функцией, в данный момент
проверяющей предусловие с помощью _ASSERTE, то он вместо этого просто-напросто
не передал бы туда нулевой указатель. Все дела

А если допустить, что VM выбрасывала бы какое-нибудь InternalErrorException
пользователю, что именно мог бы сделать в ответ пользователь, если
он не может даже полагаться на свои данные, и корректность работы самых
базовых функций?

V> Кстати, примеры твои не совсем корректны. ExceptionUnwind это то самое

V> исключение где генерация исключений является просто таки злом.

Дык, я не выбирал примеры. Там можно, фактически, откуда угодно их дергать...

V> Другими словами ассрты сидят в глубоком ядре, а весь библиотечный код

V> напичкан исключениями.

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

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

V> квалификации программистов писавших ядро можно считать объем внутренних

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

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

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

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

Обычно подобные нарушения состояния вообще не диагностируются программой,
что мы и видели на примере VM .Net в release режиме.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[19]: Checked exceptions... зло или добро?
От: Andrei N.Sobchuck Украина www.smalltalk.ru
Дата: 26.07.05 09:53
Оценка:
Здравствуйте, Cyberax, Вы писали:

>> Если для обработки ситуаций непредусмотренных разработчиком, то от

>> использования проверяемых исключений один оверхед.

C>Как раз именно для ошибочных ситуаций, предусмотренных разработчиком.

C>Например, метод write в класса Socket вполне логично может кидать
C>ConnectionTerminatedException (наследник от IOException), и вполне
C>логично задекларировать это исключение в сигнатуре метода.

Я не о том разработчике. Я о разработчике, который пользователь библиотеки, а не её девелопер. Декларируя исключение ты принуждаеш пользователя реагировать. Всё, выбора нет. А может это исключение ему и не интересно.
... << RSDN@Home 1.1.4 stable rev. 510>>
Я ненавижу Hibernate
Автор: Andrei N.Sobchuck
Дата: 08.01.08
!
Re[26]: Checked exceptions... зло или добро?
От: Cyberax Марс  
Дата: 26.07.05 10:04
Оценка:
VladD2 wrote:

> C>Нет, тема обычно остается живая.

> Дык удаляются обычно не все тымы целиком, а отдельные их подветки.

Тогда мне должны приходить NNTP cancel'ы, которые нормально
обрабатываются. Так что все равно — недоработка.

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[20]: Checked exceptions... зло или добро?
От: Cyberax Марс  
Дата: 26.07.05 10:10
Оценка:
Andrei N.Sobchuck wrote:

> C>Как раз именно для ошибочных ситуаций, предусмотренных разработчиком.

> C>Например, метод write в класса Socket вполне логично может кидать
> C>ConnectionTerminatedException (наследник от IOException), и вполне
> C>логично задекларировать это исключение в сигнатуре метода.
> Я не о том разработчике. Я о разработчике, который пользователь
> библиотеки, а не её девелопер. Декларируя исключение ты принуждаеш
> пользователя реагировать. Всё, выбора нет.

Да, именно это и есть моя цель — заставить пользователя прореагировать
на возможность выброса исключений.

> А может это исключение ему и не интересно.


Пусть ставить try..catch или разрешает дальнейший проброс — в той же
IDEA это делается нажатием двух клавиш.

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[27]: Checked exceptions... зло или добро?
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.05 13:05
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Тогда мне должны приходить NNTP cancel'ы, которые нормально

C>обрабатываются. Так что все равно — недоработка.

Я незнаю как там должно быть в ННТП. Я говорю о том, что есть. ННТП пользуется сервисами сайта. Сам он думать не умеет. Если сайт скзал "низзя", значит низзя.
... << RSDN@Home 1.2.0 alpha rev. 591>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[28]: Checked exceptions... зло или добро?
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.05 13:05
Оценка: -5 :)
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>В случае же обнаружения состояния, из которого не известно, как

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

А, ну, ясно. Очередной пример ухода в споре в обсуждение глобальных филосовских проблем.

Понимаш ли в чем дело. Можно долго делать умное выражение лица... вдаваться в споры об наилучших способах создания супер-пупер-отказоустойчивых систем и т.п. А можно просто вспомнить, что 99% систем являются обычными.

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

Думаю, вопросы эти риторические. И если бы ты весто того, чтобы толкать свою теорию просто занялся бы Янусом или сайтом, то сам бы понял всю абсурдность своих слов.
... << RSDN@Home 1.2.0 alpha rev. 591>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[29]: Checked exceptions... зло или добро?
От: Павел Кузнецов  
Дата: 26.07.05 13:26
Оценка: 1 (1)
VladD2,

V> Далее нужно спросить у пользователя таких истем интересно ли им слушать программисткий булшит

V> про инварианты и прочие постусловия если в результате введенные им данные будут безвозвратно потеряны.

Вероятно, ему более интересно будет слушать программисткий булшит об управляемых "типобезопасных"
средах, о менталитете программистов и о прочем ни о чем... I rest my case.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[30]: Checked exceptions... зло или добро?
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.05 13:50
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Вероятно, ему более интересно будет слушать программисткий булшит об управляемых "типобезопасных"

ПК>средах, о менталитете программистов и о прочем ни о чем... I rest my case.

Ему приятнее будет видеть, что его данные не потеряны, а не слушать треп. Но я понимаю, что твои принципы выше этого.
... << RSDN@Home 1.2.0 alpha rev. 591>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[28]: Checked exceptions... зло или добро?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 26.07.05 15:31
Оценка: :)
Здравствуйте, Павел Кузнецов

Спасибо за интересные ссылки. Первый PDF файл посмотрел. Вот что сразу понравилось:

Fault tolerance means that the system can
continue in operation in spite of software failure

(это нужно прочитать любителям вызывать abort() при обнаружении нарушения контракта , шутка).

Не мог бы ты прояснить один момент:

ПК>В случае же обнаружения состояния, из которого не известно, как

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

Я вот не очень понимаю, почему мы можем определить наличие какого-то плохого состояния, но при этом мы не знаем, как из него выйти (т.е. как бы про такое состояние мы знаем, а вот как выйти, получается, нет)?
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[29]: Checked exceptions... зло или добро?
От: dshe  
Дата: 26.07.05 15:50
Оценка: +1 -1
Здравствуйте, eao197, Вы писали:

E>Здравствуйте, Павел Кузнецов


E>Не мог бы ты прояснить один момент:


ПК>>В случае же обнаружения состояния, из которого не известно, как

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

E>Я вот не очень понимаю, почему мы можем определить наличие какого-то плохого состояния, но при этом мы не знаем, как из него выйти (т.е. как бы про такое состояние мы знаем, а вот как выйти, получается, нет)?


Программист пишет код подразумевая при этом, что некоторые инварианты (предусловия, постусловия...) будут выполняться. Тем не менее, бывают, что они не выполняются. Это говорит, о том, что программист сделал ошибку. Написать код, который восстанавливается после ошибок программиста как правило бывает не проще, чем написать код без ошибок. В то же время, обнаружить ошибку (добавив в код дополнительные проверки), бывает гораздо проще.
--
Дмитро
Re[29]: Checked exceptions... зло или добро?
От: Павел Кузнецов  
Дата: 26.07.05 15:53
Оценка: 1 (1) -1
eao197,

e> Спасибо за интересные ссылки. Первый PDF файл посмотрел. Вот что сразу

e> понравилось:
e>

e> Fault tolerance means that the system can continue in operation in spite of software failure

e> (это нужно прочитать любителям вызывать abort() при обнаружении нарушения контракта , шутка).

Дык, я ж о чем и говорю: если пытаться писать систему, которая корректно
работает в присутствии отказов программных компонентов, то просто перестать вызывать
abort(), заменив это все на исключения, не достаточно: там работы намного больше.
А без этой работы можно напакостить очень много, пытаясь по умолчанию продолжать
исполнение после какого-нибудь NullReferenceException. Т.е. по умолчанию должно быть
завершение программы, а вот если известно, как восстанавливаться -- тогда уже можно
и восстановиться.

e> Не мог бы ты прояснить один момент:


ПК>> В случае же обнаружения состояния, из которого не известно,

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

e> Я вот не очень понимаю, почему мы можем определить наличие какого-то

e> плохого состояния, но при этом мы не знаем, как из него выйти (т.е. как
e> бы про такое состояние мы знаем, а вот как выйти, получается, нет)?

Например. Есть графический редактор. Скажем, Adobe Illustrator. Его данные
хранятся в виде сложной структуры (PDF). У него также есть некоторый валидатор,
который верифицирует корректность обрабатываемого файла. Если посреди работы
вдруг окажется, что корректность файла нарушена, далеко не факт, что в редакторе
присутствует код, который в состоянии проанализировать, как нужно исправить ситуацию.
Скажем, тег не закрыт, но где его закрывать -- программа не знает. В этом случае
вполне разумным может оказаться сообщить пользователю о том, что целостность файла
нарушена и полагаться на то, что есть средства, позволяющие восстановить работу
десятиминутной давности из autosave.

Если подобное нарушение, которое уже не так просто описать, но, полагаю, аналогия
должна быть вполне понятной, будет диагностировано во внутренних структурах программы,
а не в данных, ею обрабатываемых (или изолируемом контексте), то в этом случае
программа точно так же не будет знать, как же восстанавливаться, но точно так же
будет иметь возможность продиагностировать нарушение целостности.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[23]: Checked exceptions... зло или добро?
От: Denis_TST Россия www.transsys.ru
Дата: 26.07.05 21:41
Оценка:
Здравствуйте, dshe, Вы писали:

D>Здравствуйте, Павел Кузнецов, Вы писали:


D>Этот вариант является усовершенствованием варианта 2. При этом PatientNotFoundException считается ошибкой программирования, поскольку метод findPersonByName должен использоваться приблизительно таким образом:

D>
D>if(patientFinder.isPersonExist(name)) {
D>    Person person = findPersonByName(name);
D>    // . . .
D>}
D>

D> ...


варинт 4?

паттерн NullObject:

Если человек не найден , возвращатся экземпляр класса NullPerson (он может быть синглетоном) — он не содержит данных , и его методы ничего не делают

дальше :
 Person person = findPersonByName(name);
 if(!person.isNull())  // isNull есть у базового класса Person   
 {
        // . . .
 }

или так — тогда NullPerson должен реализовать INullObject
 if(!(person instance of INullObject)) {
        // . . .
 }
... << RSDN@Home 1.1.4 beta 6 rev. 433>>
Re[24]: Checked exceptions... зло или добро?
От: Павел Кузнецов  
Дата: 26.07.05 23:12
Оценка: +2
Denis_TST,

> Если человек не найден , возвращатся экземпляр класса NullPerson (он может быть синглетоном) — он не содержит данных , и его методы ничего не делают

> дальше :
>
>  Person person = findPersonByName(name);
>  if(!person.isNull())  // isNull есть у базового класса Person
>


Но человек может забыть о том, что ему нужно проверять person на Null. В этом-то и была исходная проблема.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[30]: Checked exceptions... зло или добро?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 27.07.05 04:47
Оценка: 1 (1) +2
Здравствуйте, Павел Кузнецов, Вы писали:

e>> Спасибо за интересные ссылки. Первый PDF файл посмотрел. Вот что сразу

e>> понравилось:
e>>

e>> Fault tolerance means that the system can continue in operation in spite of software failure

e>> (это нужно прочитать любителям вызывать abort() при обнаружении нарушения контракта , шутка).

ПК>Дык, я ж о чем и говорю: если пытаться писать систему, которая корректно

ПК>работает в присутствии отказов программных компонентов, то просто перестать вызывать
ПК>abort(), заменив это все на исключения, не достаточно: там работы намного больше.

+1
Мне думается, что здесь можно перефразировать Саттера, который говорил, что о безопасности кода по отношению к исключениям нужно заботится заранее, что нельзя просто добавить ее в уже существующий код. Аналогично и со сбоями -- нужно проектировать систему устойчивой к сбоям, ведь вряд ли получится просто адаптировать к сбоям уже существующую систему.

ПК>А без этой работы можно напакостить очень много, пытаясь по умолчанию продолжать

ПК>исполнение после какого-нибудь NullReferenceException. Т.е. по умолчанию должно быть
ПК>завершение программы, а вот если известно, как восстанавливаться -- тогда уже можно
ПК>и восстановиться.

Вот здесь, как мне кажется, в C++ попроще
В общем случае, платформенно переносимым способом, очень сложно перехватывать исключения о доступе по некорректному указателю. Если действовать в рамках стандарта C++ и не опускаться на уровень конкретной ОС, то перехватывать в C++ можно только то, что было в программе порождено. А не то, что по своему разумению выкинула VM.

ПК>Например. Есть графический редактор. Скажем, Adobe Illustrator. Его данные

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

ПК>Если подобное нарушение, которое уже не так просто описать, но, полагаю, аналогия

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

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

Но мне более симпатична другая, не менее очевидная вещь -- вместо того, чтобы пытаться исправить диагностированную ошибку лучше отвергнуть некорректные данные и вернуться в начальное состояние. Фактически, откатить транзакцию, как будто ничего и не было. Тот же Adobe Illustrator при обнаружении незакрытого тега должен очистить все уже выделенные ресурсы и вернуться в полностью корректное состояние, предшествовавшее попытке открытия файла.

Т.е., на мой взгляд, операции в приложении должны проектироваться как последовательности вложенных друг в друга транзакций. В самом простейшем случае сбой в какой-то N-ой транзакции приведет к откату всех (N-1) предшествующих транзакций и приложение вернется в начальное корректное состояние (т.е. восстановится в моем понимании). В более сложных случаях в каких-то узлах этой последовательности можно будет предусмотреть альтернативную цепочку исполнения при возникновении исключения. Например, у меня в ObjESSty при открытии БД ищется основной файл БД с определенным именем. Если он не найден -- это исключительная ситуация. Но в некотором месте есть возможность проверить -- может быть предыдущая сессия работы с БД завершилась неудачно, поэтому основной файл сейчас имеет другое имя. Если это так, то запускается другая цепочка минитранзакций. И если она доходит до конца, то вся операция открытия БД завершается успешно. Если же нет, то исключение отдается наружу. Но и там может быть предусмотрена альтернативная последовательность операций (например, может быть предпринята попытка восстановления БД из последней архивной копии).

Поэтому в моем представлении приложение состоит из большого количества уровней. При выполнении какой-либо операции управление передается сверху вниз. При этом каждый уровень может:
1) либо ожидать исключений чтобы предпринять попытку исправить ситуацию каким-либо иным образом (т.е. запустить другую последовательность транзакций);
2) либо ожидать исключений чтобы очистить свои ресурсы, восстановить свое начальное/конечное/специальное состояние и отдать исключение наружу (т.е. предоставлять базовую гарантию по отношению к исключениям);
3) либо ничего не ожидать и ничего не очищать (т.е. быть нейтральным по отношению к исключениям).

Имхо, наибольшую сложность представляют как раз 1-й и 3-й варианты. С первым вариантом все более-менее понятно. Там сложность проистекает именно из того, что альтернативные пути нужно предусматривать. А так же нужно четко понимать, при каких исключениях можно попробовать альтернативную цепочку транзакций, а при каких нет. Но что, если пойти по самому примитивному и оптимистичному пути -- расчитывать на то, что при порождении исключения нижележащие уровни приложения вернулись в какое-либо корректное состояние (т.е. обеспечили базовую гарантию)? Тогда, имхо, получается, что можно перехватить все исключения (может быть со специально оговоренными для приложения особенностями). Ведь все инициированные транзакции откатились, мы вернулись туда, откуда начали. Почему бы не попробовать еще раз? Вполне можно попробовать, если базовая гарантия действительно была обеспечена.

Самая плохая ситуация с 3-м вариантом. Если нижележащий уровень является нейтральным по отношению к исключениям и не обеспечивает базовую гарантию, то поймав где-то иключение, нельзя гарантировать, что мы находимся в исходной точке -- весьма вероятно, что какой-то мусор где-то остался. Тогда мы на самом деле оказываемся "out of known space." Отсюда получается, что уровни приложения (компоненты, модули и т.д.) должны обеспечивать базовую гарантию безопасности иключений. В противном случае самым простым выходом будет abort().

Думаю, что нужно специально подчеркнуть, что все сказанное относится к общему понятию "исключения", как к чему-то, что идет не так, там, где этого не предполагалось. А не к конкретно механизму исключений конкретного языка программирования (throw, try, catch). Здесь я с тобой согласен -- для информирования об исключительных ситуациях может использоваться как механизм исключений, как и обычные коды возврата.

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

Пока же можно затронуть пару вопросов, которые были подняты в данной теме.

Во-первых, нужно ли считать нарушение контракта (пред- и постусловий) настолько фатальной ошибкой, чтобы прерывать работу приложения? Или же воспринимать это как обычную внештатную ситуацию (тавтология, но в данном случае приемлимая)? Т.е., при программировании мы неизбежно оглядываемся на ряд факторов, с которыми нам не хотелось бы встречаться -- нехватка памяти, недостаточно места на диске, отсутствие доступа к нужному файлу, сбой диска при операции ввода/вывода, разрыв подключения к БД во время выполнения запроса и т.д. Против этих событий мы как-то пытаемся защитится (в зависимости от требований к надежности приложения). Так почему же не внести в эту категорию и нарушения контракта?

Здесь есть две точки зрения. Пессиместическая:
-- Капитан, в пятом отсеке вода!
-- Мать, мать, мать!!! Открыть кингстоны! Экипажу покинуть судно! А эта редиск..., этот нехороший человек, этот Василий Алибабаевич, говорил, что воды в пятом быть не может! И на испытаниях ее там никогда не бы.л..о...

Или оптимистическая:
-- Капитан, в пятом отсеке вода!
-- Ну и задрайте его нафиг! Машинное -- сбавить обороты. Радист -- доложить на базу об изменении сроков прибытия в порт. Старпом -- занесите описание проишествия в бортовой журнал. Передать всем -- будем идти вперед пока рубка над водой торчит!

(все персонажи являются вымышленными, любые совпадения с реальными лицами или событиями являются случайными )

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


Во-вторых, мне кажестся достаточно дикой идея вставлять в приложение специальные обработчики исключений, которые бы вступали в работу когда уже все плохо -- NullReferenceException валится один за одним, да и вообще последний вздох остался. И которые пытаются взять откуда-то остатки каких-то документов и как-то их сохранить, чтобы потом восстановится можно было. Мое мнение заключается в том, что восстанавливаемость должна разрабатываться изначально, наряду с безопасностью исключений. И проводится фиксация контрольных точек должна только тогда, когда приложение гарантированно находится в корректном состоянии. Яркие примеры тому -- write-ahead-log в СУБД, переодические autosave и bak-файлы в текстовых редакторах.

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




Замечу, что я не смог затронуть еще одну линию романа. До сих пор как бы подразумевалось, что когда нижележащий уровень обеспечивает базовую гарантию, то нет никаких side effects от прерванных исключением операций. Но на практике разные побочные эффекты возможны. Но здесь, имхо, на уровне прикладной логики нужно как-то страховаться от того, чтобы побочные эффекты прерванной транзакции не привели затем к пагубным последствиям.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[31]: Checked exceptions... зло или добро?
От: Павел Кузнецов  
Дата: 27.07.05 06:21
Оценка: 10 (5)
eao197,

e> Аналогично и со сбоями -- нужно проектировать систему устойчивой к

e> сбоям, ведь вряд ли получится просто адаптировать к сбоям уже
e> существующую систему.

+1

ПК>> Например. Есть графический редактор. Скажем, Adobe Illustrator. Его

ПК>> данные хранятся в виде сложной структуры (PDF). У него также есть
ПК>> некоторый валидатор, который верифицирует корректность обрабатываемого
ПК>> файла. Если посреди работы вдруг окажется, что корректность файла
ПК>> нарушена, далеко не факт, что в редакторе присутствует код, который в
ПК>> состоянии проанализировать, как нужно исправить ситуацию. <...>

e> Паша, ты привел хороший пример. Он достаточно точно иллюстрирует, на мой

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

e> Но мне более симпатична другая, не менее очевидная вещь -- вместо того,

e> чтобы пытаться исправить диагностированную ошибку лучше отвергнуть
e> некорректные данные и вернуться в начальное состояние. Фактически,
e> откатить транзакцию, как будто ничего и не было.

Различают два принципиальных способа восстановления после ошибок: forward
recovery и backward recovery. Ты их как раз здесь и противопоставил: первый
сводится к исправлению диагностированного невалидного состояния, второй --
к возврату в последнее известное валидное состояние. Каждый из них имеет
свои сильные и слабые стороны.

Forward recovery обычно сложнее в реализации, но потенциально более эффективен.
Основным недостатком является то, что forward recovery позволяет надежно
восстановиться только в случае заранее предусмотренных нарушений. Основным
достоинством является то, что в случае ошибки система может компенсировать ее
эффекты, и таки продолжить исполнение. Этот подход в силу сложности реализуется
намного реже, чем backward recovery.

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

e> Тот же Adobe Illustrator при обнаружении незакрытого тега должен очистить

e> все уже выделенные ресурсы и вернуться в полностью корректное состояние,
e> предшествовавшее попытке открытия файла.

Я выделил ключевые слова: "посреди работы". Негативный результат
запрограммированных проверок, очевидно, приведет к возврату в последнее
известное корректное состояние. Проблема лежит на шаг дальше: что если
проверки не обнаружили некорректную модификацию, и уже после того, как
состояние было изменено (т.е. transaction.commit), где-то в процессе
дальнейшей работы
было обнаружено нарушение внутреннего состояния?
Для чистой backward recovery, если не делаются checkpoints, такая ситуация
не подлежит исправлению. Да и в случае checkpoints гарантий, что ошибочное
состояние не было сохранено, нет никаких.

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

e> Т.е., на мой взгляд, операции в приложении должны проектироваться как

e> последовательности вложенных друг в друга транзакций. В самом простейшем
e> случае сбой в какой-то N-ой транзакции приведет к откату всех (N-1)
e> предшествующих транзакций и приложение вернется в начальное корректное
e> состояние (т.е. восстановится в моем понимании). В более сложных случаях
e> в каких-то узлах этой последовательности можно будет предусмотреть
e> альтернативную цепочку исполнения при возникновении исключения.

Это все здорово, но что будет, если невалидное состояние будет обнаружено
уже после того, как транзакции будут завершены успешно? Что делать в этом
случае, когда при "транзакционном" подходе обычно вся ставка на него, и процедур
для forward recovery, т.е. для исправления уже ошибочного состояния, обычно
не предусмотрено?

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

Однако если допустить, что проверки есть и по ходу "нормального" исполнения,
а не только в рамках транзакций, вопрос остается в силе: что предлагатся делать
в этом случае?

e> Самая плохая ситуация с 3-м вариантом. Если нижележащий уровень является

e> нейтральным по отношению к исключениям и не обеспечивает базовую
e> гарантию, то поймав где-то иключение, нельзя гарантировать, что мы
e> находимся в исходной точке -- весьма вероятно, что какой-то мусор где-то
e> остался. Тогда мы на самом деле оказываемся "out of known space." Отсюда
e> получается, что уровни приложения (компоненты, модули и т.д.) должны
e> обеспечивать базовую гарантию безопасности иключений. В противном случае
e> самым простым выходом будет abort().

Даже когда уровни в принципе обеспечивают всевозможные гарантии безопасности
относительно возникновения исключений, в них вполне могут присутствовать ошибки.
Вот об этом-то и идет речь: что делать в случае обнаружения подобной ошибки
после того, как все "должно было вернуться на свои места", но "не вернулось"?
По сути всевозможные гарантии безопасности относительно исключений суть спецификация,
и корректное их выполнение ошибками не является. А вот невыполнение одним из
компонент своих гарантий -- ошибка. Если возможно изолировать контекст исполнения
данного компонента -- хорошо, есть шансы на сравнительно легкое восстановление
корректности состояния посредством "убийства" данного контекста (закрытие сессии
отдельного пользователя на сервере), но это далеко не всегда так (например, сам
движок сервера, который "крутит" сессии, таким макаром не изолируется, т.к.
влияет на все сессии сразу).

e> Во-первых, нужно ли считать нарушение контракта (пред- и постусловий)

e> настолько фатальной ошибкой, чтобы прерывать работу приложения? Или же
e> воспринимать это как обычную внештатную ситуацию (тавтология, но в
e> данном случае приемлимая)?

Если в спецификации говорится, что, скажем, в случае нулевого аргумента данная
функция порождает исключение, то это уже вполне запланированная ситуация. Просто
предусловия функции расширили до включения варианта с нулевым аргументом.

e> Т.е., при программировании мы неизбежно оглядываемся на ряд факторов,

e> с которыми нам не хотелось бы встречаться -- нехватка памяти, недостаточно
e> места на диске, отсутствие доступа к нужному файлу, сбой диска при операции
e> ввода/вывода, разрыв подключения к БД во время выполнения запроса и т.д.
e> Против этих событий мы как-то пытаемся защитится (в зависимости от
e> требований к надежности приложения). Так почему же не внести в эту
e> категорию и нарушения контракта?

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

e> Здесь есть две точки зрения. Пессиместическая:

e> -- Капитан, в пятом отсеке вода!
e> -- Мать, мать, мать!!! Открыть кингстоны! Экипажу покинуть судно! А эта
e> редиск..., этот нехороший человек, этот Василий Алибабаевич, говорил,
e> что воды в пятом быть не может! И на испытаниях ее там никогда не
e> бы.л..о...

e> Или оптимистическая:

e> -- Капитан, в пятом отсеке вода!
e> -- Ну и задрайте его нафиг! Машинное -- сбавить обороты. Радист --
e> доложить на базу об изменении сроков прибытия в порт. Старпом --
e> занесите описание проишествия в бортовой журнал. Передать всем -- будем
e> идти вперед пока рубка над водой торчит!

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

Более близкой к ошибкам программирования/нарушению инвариантов в рамках
данной модели была бы другая аналогия:
-- Капитан, в пятом отсеке вода!
-- Ну и задрайте его нафиг!
-- Капитан!!! Люки Васька на металлолом сдал, задраивать нечем!!!

Теперь вопрос, что лучше (в рамках данной аналогии): чтоб (автоматизированный)
капитан продолжал отдавать команды, как будто пятый отсек задраивают,
или же чтобы он все-таки перешел к эвакуации судна, пытаясь спасти хотя бы
экипаж, если не судно?

e> Во-вторых, мне кажестся достаточно дикой идея вставлять в приложение

e> специальные обработчики исключений, которые бы вступали в работу когда
e> уже все плохо -- NullReferenceException валится один за одним, да и
e> вообще последний вздох остался. И которые пытаются взять откуда-то
e> остатки каких-то документов и как-то их сохранить, чтобы потом
e> восстановится можно было.

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

При этом достигаются еще и другие положительные моменты: пред-/постусловия
и инварианты становятся явно выраженными в коде в виде assertions, что в
будущем только помогает поддерживать программу.

e> Мое мнение заключается в том, что восстанавливаемость должна

e> разрабатываться изначально, наряду с безопасностью исключений.

С этим, имхо, глупо спорить. Я -- только за такие правильные действия.

e> И проводится фиксация контрольных точек должна только тогда, когда

e> приложение гарантированно находится в корректном состоянии.

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

e> При этом, если придерживаться нарисованной мной оптимистической картины

e> (когда каждый нижележащий уровень приложения обеспечивает базовую
e> гарантию исключений) такие гарантированно корректные точки в приложении
e> возможны даже при раскрутке вверх исключительной ситуации.

Это все описания работы системы, в которой нет критических ошибок: она честно
восстанавливается в случаях, предусмотренных разработчиками. Что эта система
делает в случаях, не предусмотренных?

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

Имхо, в таких случаях вызов abort() намного лучше, чем попытка
продолжения исполнения.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[32]: Checked exceptions... зло или добро?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 27.07.05 08:08
Оценка: +1
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Как уже говорилось, желание продолжать работу в таких случаях

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

ПК>Имхо, в таких случаях вызов abort() намного лучше, чем попытка

ПК>продолжения исполнения.

И все таки, давай возьмем реальную ситуацию. Предположим есть сервер приложений (уже релизный). В результате ошибки при каких то хитрых комбинациях данных внутри сервера эта ошибка вылазит. Какова должна быть, по твоему, правильная последовательность действий:
1) Выкинуть исключение клиенту, продолжить работу.
2) Выкинуть исключение клиенту, грохнуть клиентскую сессию.
3) Убить процесс сервера.
Дополнительные условия — все доступные данные для анализа сбрасываются в лог в любом случае. Сессии друг от друга, разумеется, изолированы. Никаких специальных действий по обнаружению и обработке этой конкретной ошибки в коде нет.
... << RSDN@Home 1.2.0 alpha rev. 596>>
AVK Blog
Re[32]: Checked exceptions... зло или добро?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 27.07.05 18:51
Оценка: 4 (1) +1
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Различают два принципиальных способа восстановления после ошибок: forward

ПК>recovery и backward recovery. Ты их как раз здесь и противопоставил: первый
ПК>сводится к исправлению диагностированного невалидного состояния, второй --
ПК>к возврату в последнее известное валидное состояние. Каждый из них имеет
ПК>свои сильные и слабые стороны.

ПК>Forward recovery обычно сложнее в реализации, но потенциально более эффективен.

ПК>Основным недостатком является то, что forward recovery позволяет надежно
ПК>восстановиться только в случае заранее предусмотренных нарушений. Основным
ПК>достоинством является то, что в случае ошибки система может компенсировать ее
ПК>эффекты, и таки продолжить исполнение. Этот подход в силу сложности реализуется
ПК>намного реже, чем backward recovery.

Лично у меня сложилось мнение, что forward recovery в большей степени относится к структуре обрабатываемых данных. Т.е. forward recovery вряд ли возможен, если в самих данных нет избыточности, за счет которой и обеспечивается восстановление сбойных данных.

e>> Тот же Adobe Illustrator при обнаружении незакрытого тега должен очистить

e>> все уже выделенные ресурсы и вернуться в полностью корректное состояние,
e>> предшествовавшее попытке открытия файла.

ПК>Я выделил ключевые слова: "посреди работы". Негативный результат

ПК>запрограммированных проверок, очевидно, приведет к возврату в последнее
ПК>известное корректное состояние. Проблема лежит на шаг дальше: что если
ПК>проверки не обнаружили некорректную модификацию, и уже после того, как
ПК>состояние было изменено (т.е. transaction.commit), где-то в процессе
ПК>дальнейшей работы
было обнаружено нарушение внутреннего состояния?

Мне кажется, что здесь затронуты два вопроса. Представим, что некая цепочка транзаций для выполнения действия A завершилась успешно. Затем началась другая цепочка транзакций для выполнения действия B и вот тут обнаружилась проблема, привнесенная в систему во время операции A (я полагаю, что ты именно это имел в виду). Имхо, первый вопрос состоит в том, что делать с операцией B? На мой взгляд -- откатывать. Второй вопрос состоит в том, каковы шансы столкнутся с последствиями операции A при очередной попытке выполнения операции B. Если результаты операции A где-то хранятся то мы получаем именно ту проблему с backward recovery, про которую ты говорил -- повторные входы в операцию B будут приводить к одному и тому же исходу -- откату операции B.

И мне кажется, что так и должно быть. Если в операции B не предусмотрены механизмы для forward recovery последствий ошибок в операции A, то все, что B может сделать -- это откатится, не запортив чего-то еще.

ПК>Для чистой backward recovery, если не делаются checkpoints, такая ситуация

ПК>не подлежит исправлению. Да и в случае checkpoints гарантий, что ошибочное
ПК>состояние не было сохранено, нет никаких.

Именно так.

ПК>Можно, конечно, спросить, почему же эти некорректные изменения не были обнаружены

ПК>до внесения модификаций?

Это риторический вопрос. Shit happens, что тут еще скажешь.

ПК>Это все здорово, но что будет, если невалидное состояние будет обнаружено

ПК>уже после того, как транзакции будут завершены успешно? Что делать в этом
ПК>случае, когда при "транзакционном" подходе обычно вся ставка на него, и процедур
ПК>для forward recovery, т.е. для исправления уже ошибочного состояния, обычно
ПК>не предусмотрено?

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

Но ключевой, с моей точки зрения, момент в том, что мы учимся справляться с проблемами уже после того, как эти поблемы обнаруживаются. А изначально сосредотачиваемся на том, чтобы максимально полно диагностировать "нормальность" ситуации и маскимально полно откатываться при обнаружении каких-то отклонений от нормы. Т.е. следуем правилам:
— проверяем все, что можем;
— ничего не портим, если не уверены в возможности отката;
— добавляем в систему решение обнаруженных проблем по мере их поступления.

Степень параноидальности первых двух пунктов зависит от характера задачи.

ПК>Обычно эта проблема "не стоит", т.к. при "транзакционном подходе" инварианты

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

ПК>Однако если допустить, что проверки есть и по ходу "нормального" исполнения,

ПК>а не только в рамках транзакций, вопрос остается в силе: что предлагатся делать
ПК>в этом случае?

Имхо, этот вопрос как бы предполагает, что есть какой-то один, универсальный ответ. Что-то типа поиска серебрянной пули.
Мне кажется, что в общем случае ответа на него нет. Я стою на оптимистических позициях и предполагаю, что даже если на N-ом уровне вложенности мы оказались в уже некорректном состоянии, то достаточно будет вернуться на M уровней вверх, чтобы выйти из него. А дальше уже задача разработчиков в том, чтобы определиться, почему так произошло. И внести в софт соответствующие исправления. Т.е. я возлагаю надежду на то, что откаты не позволят наломать лишних дров. И что лучше и проще решать обнаруженные проблемы, чем пытаться создать программу, которая изначально защищает от всего, что только может случится.

ПК>Если возможно изолировать контекст исполнения

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

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

e>> Во-первых, нужно ли считать нарушение контракта (пред- и постусловий)

e>> настолько фатальной ошибкой, чтобы прерывать работу приложения? Или же
e>> воспринимать это как обычную внештатную ситуацию (тавтология, но в
e>> данном случае приемлимая)?

ПК>Если в спецификации говорится, что, скажем, в случае нулевого аргумента данная

ПК>функция порождает исключение, то это уже вполне запланированная ситуация. Просто
ПК>предусловия функции расширили до включения варианта с нулевым аргументом.

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

e>> Т.е., при программировании мы неизбежно оглядываемся на ряд факторов,

e>> с которыми нам не хотелось бы встречаться -- нехватка памяти, недостаточно
e>> места на диске, отсутствие доступа к нужному файлу, сбой диска при операции
e>> ввода/вывода, разрыв подключения к БД во время выполнения запроса и т.д.
e>> Против этих событий мы как-то пытаемся защитится (в зависимости от
e>> требований к надежности приложения). Так почему же не внести в эту
e>> категорию и нарушения контракта?

ПК>Потому что действия по восстановлению могут быть совершенно различными.


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

ПК>Имхо, это несколько в другую сторону примеры: в конструкцию корабля заранее

ПК>внесены
специальные особенности, рассчитанные на затопление отдельных
ПК>отсеков. Т.е. затопление пятого отсека является ситуацией вполне просчитанной,
ПК>хотя и нежелательной.

Мне кажется, что как раз в ту сторону. По аналогии с кораблем, приложение так же должно быть сконструированно в предположении, что оно должно оставаться работоспособным даже при полной неработоспособности отдельных его компонентов. Может быть и звучит это дико, но на самом деле не так уж это и невозможно. Я сейчас как раз нахожусь в стадии переосмысления некоторых вещей. Еще года полтора назад я думал, что нормальным решением является сложный многопоточный комплекс, который решает сразу все задачи, которые перед ним стоят (благо наш агентно-ориентированный подход позволял легко это делать). Но сейчас я все больше и больше убеждаюсь, что более жизнеспособной схемой является разделение этого комплекса на ряд более простых процессов, взаимодействующих через IPC -- этакий спрут из процессов и сокетов/пайпов (благо наш агентно-ориентированный подход позволяет легко делать и это). В такой ситуации каждый процесс подобен отсеку корабля, который можно затопить (отключить).

ПК>Более близкой к ошибкам программирования/нарушению инвариантов в рамках

ПК>данной модели была бы другая аналогия:
ПК>-- Капитан, в пятом отсеке вода!
ПК>-- Ну и задрайте его нафиг!
ПК>-- Капитан!!! Люки Васька на металлолом сдал, задраивать нечем!!!

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

ПК>Теперь вопрос, что лучше (в рамках данной аналогии): чтоб (автоматизированный)

ПК>капитан продолжал отдавать команды, как будто пятый отсек задраивают,
ПК>или же чтобы он все-таки перешел к эвакуации судна, пытаясь спасти хотя бы
ПК>экипаж, если не судно?

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

e>> Во-вторых, мне кажестся достаточно дикой идея вставлять в приложение

e>> специальные обработчики исключений, которые бы вступали в работу когда
e>> уже все плохо -- NullReferenceException валится один за одним, да и
e>> вообще последний вздох остался. И которые пытаются взять откуда-то
e>> остатки каких-то документов и как-то их сохранить, чтобы потом
e>> восстановится можно было.

ПК>Да. Это одна из вполне принимаемых мною точек зрения: игнорировать нарушения

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

ПК>При этом достигаются еще и другие положительные моменты: пред-/постусловия

ПК>и инварианты становятся явно выраженными в коде в виде assertions, что в
ПК>будущем только помогает поддерживать программу.

+1

Но мне бы хотелось, чтобы эти варианты были не разрушающими. Т.е. модуль диагностировал нарушение, сделал сохранение информации о нем в dump/log, но все приложение не прервал.

e>> И проводится фиксация контрольных точек должна только тогда, когда

e>> приложение гарантированно находится в корректном состоянии.

ПК>А вот с этим уже сложнее: есть определенные пределы диагностики корректности

ПК>состояния по ходу внесения изменений, да и тривиальные ошибки никто не отменял.
ПК>Т.е. в случае, когда "гарантированно корректное состояние", действительно,
ПК>является корректным, вопросов нет. Вопросы возникают о том, что делать, когда,
ПК>вдруг, оказывается, что "гарантированно корректное состояние" корректным не
ПК>является...

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

ПК>Это все описания работы системы, в которой нет критических ошибок: она честно

ПК>восстанавливается в случаях, предусмотренных разработчиками. Что эта система
ПК>делает в случаях, не предусмотренных?

Паша, здесь я не очень понимаю, что имеется в виду под критическими ошибками. Если мы говорим о С++, то обращение к неверному указателю, которое повлекло за собой Access Violation -- это пример критической ошибки, которая (если нет хитрых системно-зависимых хаков) и приведет автоматом к abort(). Про managed среды сказать ничего не могу, т.к. с Java работал уже слишком давно, а на Ruby таких серьезных задач не решал. Исключения же в C++, которые произведены от std::exception, имхо, позволяют делать откат из сбойного модуля на более высокий уровень (в пределе это тот же main, тогда исключение и будет играть роль abort()).

ПК>Как уже говорилось, желание продолжать работу в таких случаях

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

ПК>Имхо, в таких случаях вызов abort() намного лучше, чем попытка

ПК>продолжения исполнения.

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

А вот что, если мы не можем позволить себе две реализации одного модуля по разным алгоритмам? Если можно сделать только одну реализацию? Простой вызов abort() может привести к тому, что если будет выявлена систематическая ошибка, то никакое дублирование или повторный запуск watch dog-ом не поможет -- каждая копия приложения будет падать в одном и том же месте с одним и тем же core dump-ом.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.