|
|
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
Правильно-ли я понимаю, что предусловия каждого метода следует проверять обычным if, и в случае несовпадения выбрасывать exception, а постусловия метода и инвариант класса assert'ом ? А также, верно-ли то, что exception'ы для предусловий следует использовать вместо assert потому, что-бы иметь возможность при использовании этого метода перехватить это исключение и попытаться восстановить работу программы ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.05.2007, 12:21 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
Попробуйте привести мысли в порядок и сказать то же самое еще раз. Отдельно буду весьма признателен за объяснение, чем EAssertionFailed так уж принципиально отличается от других exception-ов. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.05.2007, 14:04 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
Имеем следующий метод: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. Т.е. меня теперь интересует, где использовать assert, а где exception. Или это типа вообще без разницы ? softwarer Отдельно буду весьма признателен за объяснение, чем EAssertionFailed так уж принципиально отличается от других exception-ов. по-видимому чем-то отличается, раз не является потомком Exception и не ловиться даже всеядным фильтром catch() На мой взгляд, Assert гораздо удобнее и нагляднее (в том числе и для предусловия), чем дурацкий If, но в документации настойчиво советуют использовать именно ArgumentOutOfRangeException, да и в .NET для поимки необработанного исключения применяется делегат Application.ThreadException, который не обращает никакого внимания на Assert Failed, пропуская к пользователю уродливое окно :( ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.05.2007, 16:17 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
heyТ.е. меня теперь интересует, где использовать assert, а где exception. Или это типа вообще без разницы ? Принципиальной разницы нет. Есть некоторое соглашение, общепринятое понимание "что есть assertion и зачем и как оно используется". hey softwarer Отдельно буду весьма признателен за объяснение, чем EAssertionFailed так уж принципиально отличается от других exception-ов. по-видимому чем-то отличается, раз не является потомком Exception и не ловиться даже всеядным фильтром catch() Ну это у кого как. У меня, например, Код: plaintext 1. 2. 3. 4. 5. 6. 7. heyНа мой взгляд, Assert гораздо удобнее и нагляднее (в том числе и для предусловия), чем дурацкий If, но в документации настойчиво советуют использовать именно ArgumentOutOfRangeException, Хм. А кто мешает Вам обойтись без дурацкого if? Кто мешает написать что-нибудь типа Код: plaintext 1. 2. 3. 4. 5. heyда и в .NET для поимки необработанного исключения применяется делегат Application.ThreadException, который не обращает никакого внимания на Assert Failed, пропуская к пользователю уродливое окно :( Вообще-то пользователю обычно дают версию без assert-ов. Еще раз: разница между ними - в предназначении. Exception означает, что ситуация не позволяет выполнить запрошенную операцию, и чаще всего это является "внешней" по отношению к исполняемому коду ошибкой - то ли вызвали с неправильными параметрами, то ли организовали неправильный контекст, то ли еще что-нибудь в этом духе. Assert - это ситуация "внутренней ошибки", "ошибки программирования где-то рядом, в этом самом классе или модуле". Обработать ее, исправить в рантайме как правило невозможно, в некоторых случаях - пересоздав и заново инициализировав объект. Такие проверки принято щедро разбросать по коду и не собирать в release версию. По сути assertion - это миниатюрный юнит-тест. Решение, какая ошибка внешняя, а какая внутренняя - вообще говоря, неформально, зависит от того, что Вы считаете модулем. Скажем, для стандартных коллекций "неправильный индекс" - никак не может быть assertion-ом, это в 99.99% случаев ошибка вызывающего. В то же время если у Вас в классе есть inner class коллекции - в нем тот же самый неправильный индекс запросто может быть именно внутренней ошибкой, assertion-ом. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.05.2007, 16:48 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. Глядя на этот исходник абсолютно невозможно сделать выводы о том, какие и где следует толкать исключения. Только исходя из внутренней политики разработок и рассматривая этот модуль в совокупности с другими модулями (контейнерами) можно декларировать требования. Вообще подобные вещи обсуждаются с другими разработчиками-участниками проекта. Тесты утверждений можно ставить щедрой рукой в подозрительных местах, не забывая про возможность видеть результат их работы. Тоесть разрабатываемая "система" должна предусматривать наблюдение за ассертами. В противном случае - они не нужны. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.05.2007, 17:53 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
softwarer ... спасибо понятно, по большому счету я так и думал - предусловия - exception, постусловия и инварианты - assert. Просто меня сбивает с толку такое разделение, ведь оба они занимаются одним делом - проверкой правильности поведения программы, и не так уж важно с точки зрения всего приложения, вызвана ошибка неверным поведением вызывающего модуля (ведь он просто нарушил контракт - зная, что нужны положительные х, использовал отрицательные, это кстати можно (и нужно) было-бы проверить, перед вызовом), либо неверным поведением внутри модуля, приведшим к неверным результатам. Ну а то, что нельзя перехватить Assert (по крайней мере я пока не знаю, как это сделать в .NET) и показать пользователю нормальное окно с извинениями - это вообще никуда не годиться (может я хочу оставить такие проверки в релизе - если они не отьедают непозволительно большое количество ресурсов, то вообще-то так как раз и рекомендуется поступать), а если такой способ и есть - все равно имхо разделение на exception и assert какое-то исскуственное mayton Глядя на этот исходник абсолютно невозможно сделать выводы о том, какие и где следует толкать исключения ну раз любой открытый метод обязан проверять аргументы на входе, то почему-же не ясно ? или имеете ввиду, что там вместо exception вполне может оказаться assert ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.05.2007, 18:32 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
hey по большому счету я так и думал - предусловия - exception, постусловия и инварианты - assert. Я этого не говорил. hey Просто меня сбивает с толку такое разделение, ведь оба они занимаются одним делом - проверкой правильности поведения программы, и не так уж важно с точки зрения всего приложения, Пока Вы смотрите с точки зрения всего приложения - неважно. Грань, которую мы обсуждаем, действительно тонкая и нечеткая. По большому счету, между любыми исключительными ситуациями, выглядящими для конечного пользователя как internal error, нет особой разницы. Мало того, те же самые проверки предусловий время от времени хочется убрать ради эффективности. Однако, есть определенная практика. Срабатывание assert-а означает ошибку внутри модуля; получив assert, я автоматом говорю: "Вася, смотри, твой код глюкнул". А получив исключение, я первым делом смотрю, а правильно ли я Васин код вызвал. heyНу а то, что нельзя перехватить Assert (по крайней мере я пока не знаю, как это сделать в .NET) Думаю, ковырнуть Debug.Listeners. Ну или погуглить :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.05.2007, 18:48 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
softwarer Я этого не говорил значит, я что-то не так понял. Из ваших слов "то ли вызвали с неправильными параметрами, то ли организовали неправильный контекст" я понял, что это про предусловия (а кто, если не они ? Неверные параметры и контекст - самые что ни на есть предусловия), а "ошибки программирования где-то рядом, в этом самом классе или модуле" это и есть постусловие + инвариант + проверки по ходу работы чего-нибудь еще. softwarer Однако, есть определенная практика. Срабатывание assert-а означает ошибку внутри модуля; получив assert, я автоматом говорю: "Вася, смотри, твой код глюкнул". А получив исключение, я первым делом смотрю, а правильно ли я Васин код вызвал. а что собственно помешает мне указать на Васю в случае исключения ? Неужели и в самом деле это все просто практика программирования ? Мне казалось, что имеются более веские причины разделять эти понятия. Вот например если при запросе к БД оборвалась связь - это безусловно исключение, а вот вызов с неправильными параметрами - это нарушение правил работы (ошибка программиста) с модулем. Зачем тут исключение ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.05.2007, 19:52 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
Обычно утверждениями удобно документировать допушения кода. Те. например: Код: plaintext 1. 2. 3. 4. Но т.к. операции с соединением (т.б. по сети) относятся к внешним факторам (т.е. не зависят от качества ПО), то ошибки соединения надо обрабатывать отдельно, например: Код: plaintext 1. 2. 3. 4. 5. 6. 7. В таком случает даже убрав assert'ы из релиза всё равно будет обработка. А на стадии разработки покажет неверные допушения, и код который нужно изменить. Posted via ActualForum NNTP Server 1.4 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.05.2007, 10:22 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
heyНу а то, что нельзя перехватить Assert (по крайней мере я пока не знаю, как это сделать в .NET) и показать пользователю нормальное окно с извинениями - это вообще никуда не годиться (может я хочу оставить такие проверки в релизе - если они не отьедают непозволительно большое количество ресурсов, то вообще-то так как раз и рекомендуется поступать), а если такой способ и есть - все равно имхо разделение на exception и assert какое-то исскуственное Насколько я понимаю, Assert нужен только на этапе отладки, когда вы строите Release версию, все методы классов Debug и Debugger игнорируются, что позволяет повысить производительность приложения. Так что не стоит пытаться перехватить и обработать Assert. Если вам это нужно, используйте Exception. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.05.2007, 10:32 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
heyИз ваших слов Я назвал яркие типовые случаи, действительно ложащиеся на Ваш взгляд, но не имел в виду ограничиваться только ими, наоборот, хотел сфокусироваться на другом критерии деления, внешнее/внутреннее. heyа что собственно помешает мне указать на Васю в случае исключения ? То, что Вася обидится, если Вы начнете валить все на него раньше, чем проверите отсутствие бревна у себя. heyНеужели и в самом деле это все просто практика программирования ? Безусловно. Я даже больше скажу - и исключения, и assert-ы выросли целиком из практики, никто их специально не придумывал. Просто, когда таких механизмов не было на уровне языка, приходилось писать более или менее уродливый код, реализующий то же доступными средствами. Разумеется, любой механизм можно применить и "не совсем по назначению", бывают случаи, когда это оказывается удобно. Но тем не менее, когда такой вот возникший механизм уже отработан, концептуально вылизан и приспособлен для решения своих задач, чем дальше от них его применяешь - тем более все похоже на ковыряние в правом ухе левой ногой. heyМне казалось, что имеются более веские причины разделять эти понятия. Вот например если при запросе к БД оборвалась связь - это безусловно исключение, а вот вызов с неправильными параметрами - это нарушение правил работы (ошибка программиста) с модулем. Зачем тут исключение ? Хм. Понимаете ли в чем дело, граница - гибкая, ее можно провести там и так, как Вам удобно (с естественными оговорками на командную работу итп). Поэтому та экстремальная позиция, которую занимаете Вы, не является неправильной, можно и так, и каких-то стопроцентных недостатков в ней не назовешь, вопрос в довольно нечетком удобстве. Cкажем, "вызов с неправильными параметрами вроде как ошибка программиста". А что делать, если: 1. Читаем параметры из конфигурационного файла 2. Класс, который читает файл, нафиг не должен знать про смысл этих параметров, его задача - читать файл и запихивать прочитанное в объект, который и будет разбираться со смыслом 3. В случае неверного параметра нужно ругаться, причем не просто так, а "параметр такой-то в файле таком-то не отвечает таким-то требованиям" ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.05.2007, 11:12 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
Anton. Насколько я понимаю, Assert нужен только на этапе отладки, когда вы строите Release версию, все методы классов Debug и Debugger игнорируются, что позволяет повысить производительность приложения. Так что не стоит пытаться перехватить и обработать Assert. Если вам это нужно, используйте Exception. Во-первых, почитав документацию, сегодня я уже нашел, как ловить Assert'ы в .NET (как и говорил softwarer, нужно копаться в Listener'aх - правда немного неудобно сделано, создать своего потомка от этого класса и переопределить метод Fail(), а имеющийся по умолчанию Listener удалить из коллекции). Во-вторых, Trace'ы не отключаются (по умолчанию) в релизе, так что обрабатывать Trace.Assert'ы все равно надо. В-третих, если тестирование показывает, что снижение производительности от проверок не является значительным, то их отключение - очень странный поступок. softwarer То, что Вася обидится, если Вы начнете валить все на него раньше, чем проверите отсутствие бревна у себя. а причем тут исключение ? Какая разница, что возникло на экране - исключение или assert, ведь смотреть-то надо на его текст, а там будет все написано, кто из нас дурак softwarer Но тем не менее, когда такой вот возникший механизм уже отработан, концептуально вылизан и приспособлен для решения своих задач, чем дальше от них его применяешь - тем более все похоже на ковыряние в правом ухе левой ногой. все-таки не совсем понятно, почему проверка предусловий Exception'ами называется отходом от решения задач приспособленным способом и ковырянием в носу через задницу softwarer вопрос в довольно нечетком удобстве. а также не понятно, почему Exception там удобнее. Как я написал под первой цитатой - все равно надо смотреть на текст сообщения, кроме того, ведь не каждое-же исключение будет являться вашим бревном - обрыв связи с сервером БД уж точно не ваша ошибка softwarer Cкажем, "вызов с неправильными параметрами вроде как ошибка программиста". А что делать, если: 1. Читаем параметры из конфигурационного файла 2. Класс, который читает файл, нафиг не должен знать про смысл этих параметров, его задача - читать файл и запихивать прочитанное в объект, который и будет разбираться со смыслом 3. В случае неверного параметра нужно ругаться, причем не просто так, а "параметр такой-то в файле таком-то не отвечает таким-то требованиям" ? вроде-как это-же один из шаблонов проектирования, когда для чтения пользовательского ввода или файлов применяется фильтр, который разбирается с тем, что прочитал, и либо ругается, либо что-то пытается с этим сделать, после чего подает на вход модулю нормальные данные, удовлетворяющие его (модуля) предусловия. Так что "нафиг не должен знать про смысл этих параметров" - неправильно :) Также не совсем понял, почему вы обозвали позицию "нарушения предусловий, постусловий, инварианта - assert(), а проблемы невозможности выполнения задачи (обрыв связи, не найден файл итп) - исключения" - экстремальной. Мне как раз кажется очень логичной и интуитивно понятной идея размешения Assert'ов там, где возможны ошибки программирования (а неправильный ввод - это именно ошибка: раз уж определили такой контракт с классом, так будьте добры его выполнять), а проблемы, возникающие по вине посторонних лиц, такие как невозможность выделить память - в Еxception'ы. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.05.2007, 16:21 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
hey а неправильный ввод - это именно ошибка следует читать как "а не правильный параметр (не удовлетворяющий заданному контрактом предусловию), поданный на вход модуля - это именно ошибка" ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.05.2007, 16:26 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
heyа причем тут исключение ? Какая разница, что возникло на экране - исключение или assert, ведь смотреть-то надо на его текст, а там будет все написано, кто из нас дурак Можно, конечно, и так. Как я уже говорил, это вопрос исключительно принятой практики. heyвсе-таки не совсем понятно, почему проверка предусловий Exception'ами называется отходом от решения задач приспособленным способом и ковырянием в носу через задницу Exception-ами или Assert-ами? heyа также не понятно, почему Exception там удобнее. Может быть удобнее. Один из примеров я привел выше. heyвроде-как это-же один из шаблонов проектирования, когда для чтения пользовательского ввода или файлов применяется фильтр, который разбирается с тем, что прочитал, и либо ругается, либо что-то пытается с этим сделать, после чего подает на вход модулю нормальные данные, удовлетворяющие его (модуля) предусловия. Так что "нафиг не должен знать про смысл этих параметров" - неправильно :) Ну если "инкапсуляция" это "неправильно", то в задницу такой шаблон проектирования :) При всей правильности мысли о шаблонах проектирования мне крайне не нравится не так уж редко мелькающая мысль о том, что они могут заменить мозги. Это не так; думать и действовать исходя из этого - все равно что полагать, что автомобиль может заменить водителя. Вы в данном случае ответили поспешно. Можно выделить фильтр, можно не выделять - это отдельный вопрос. В любом случае у нас есть три взаимодействующих объекта: инициатор, ридер и фильтр-либо-целевой-объект, каждый из которых обладает определенными уникальными знаниями, и итогом их работы должно стать выданное инициатором окно типа "ошибка в конфигурационном файле, строка такая-то, параметр такой-то, ошибка состоит в том-то". Для этого использовать Exception во-первых удобно, во-вторых, естественно, несмотря на то, что ошибка вроде бы подходит под Ваше "вызван не с теми параметрами". heyТакже не совсем понял, почему вы обозвали позицию "нарушения предусловий, постусловий, инварианта - assert(), а проблемы невозможности выполнения задачи (обрыв связи, не найден файл итп) - исключения" - экстремальной. Экстремум - это предел, край. Позиция экстремальна, потому что в ней граница между assert-ом и exception-ом задвинута так далеко от некоего "среднего", как только можно; по сути, Вы предлагаете, иметь в программе 99% assert-ов и 1% exception-ов. heyМне как раз кажется очень логичной и интуитивно понятной идея размешения Assert'ов там, где возможны ошибки программирования (а неправильный ввод - это именно ошибка: раз уж определили такой контракт с классом, так будьте добры его выполнять), а проблемы, возникающие по вине посторонних лиц, такие как невозможность выделить память - в Еxception'ы. Эту логику постоянно пытаются реализовать тем или иным образом, например, в дотнете разделили исключения на SystemException и ApplicationException. Но в итоге каждый раз оказывается, что не все так однозначно. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.05.2007, 16:52 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
softwarer Exception-ами или Assert-ами? Exception-ами softwarer Ну если "инкапсуляция" это "неправильно", то в задницу такой шаблон проектирования :) Раз-уж такой шаблон есть и широко используется, то по всей вероятности с инкапсуляцией там все в порядке :) softwarer При всей правильности мысли о шаблонах проектирования мне крайне не нравится не так уж редко мелькающая мысль о том, что они могут заменить мозги. Это не так; думать и действовать исходя из этого - все равно что полагать, что автомобиль может заменить водителя. возможно будете смеяться, но такие автомобили уже есть, я их сам видел по телевизору - они ездят по специальным трассам, где находяться некие метки, на которые ориентируется автопилот автомобиля. Я к примеру нахожу вполне вероятным, что в старости меня будет возить автомобиль, примерно такой-же как возил Шварценеггера в "Вспомнить все" ;) А если по теме - то шаблоны не заменяют мозги, а позволяют избавить их от ненужной работы там, где уже все давно продумано и доказано. Если есть типовая задача - то и решать ее надо типовым способом, а применить мозги тут нужно только в плане анализа - насколько эта задача подпадает под шаблон. softwarer Вы в данном случае ответили поспешно. Можно выделить фильтр, можно не выделять - это отдельный вопрос. В любом случае у нас есть три взаимодействующих объекта: инициатор, ридер и фильтр-либо-целевой-объект, каждый из которых обладает определенными уникальными знаниями, и итогом их работы должно стать выданное инициатором окно типа "ошибка в конфигурационном файле, строка такая-то, параметр такой-то, ошибка состоит в том-то". Для этого использовать Exception во-первых удобно, во-вторых, естественно, несмотря на то, что ошибка вроде бы подходит под Ваше "вызван не с теми параметрами". Давайте-ка более аккуратно: исключение это по определению ситуация, наступление которой мы предполагаем маловероятным, но все-же предвидеть обязаны. Под это определение попадает обрыв связи и отсутствие необходимой памяти. В этой ситуации метод обязан доложить об невозможности выполнения своего контракта "наверх" и умыть руки, потому-что обычно он не в состоянии решить эту проблему (восстановить связь например). Под это определение не попадает нарушение предусловий, потому-что в протестированной системе теоретически это невозможно, и мы не обязаны этого предвидеть. Хотя на практике конечно лучше оставить там на охране Assert и в случае ошибки например вообще прервать выполнение приложения. При чтении файла или пользовательского ввода можно говорить о том, что вероятность поступления неверной информации настолько велика (по сути, поступление верных данных более маловероятно, чем неверных , что мы должны всегда ее проверять (тщательно), и уже поэтому это не должно быть Exception. Я могу согласиться тем не менее, что иногда Exception может оказаться тут "удобным", но насколько это будет "естественно" - не уверен. По-сути, вы просто распихали обязанности верификатора по двум ни в чем не повинным объектам - ридеру файла (или пользовательскому окну) и объекту бизнес логики. Мне не кажется, что они будут вам за это очень благодарны. Теперь ридер или окно (а окон кстати может быть много) должно мало того, что знать об этом объекте, так и еще и брать на себя обязанности по отлову исключения и выводу ошибки на экран. А объект бизнес логики должен теперь проверять и выбрасывать исключения (что хотя конечно мало отличается от Assert, который все равно там должен быть, но вот если потом вы решите при считывании неверного параметра не ругаться сразу, а попытаться конвертировать его в более правильный (напр. "Yes" в "Y"), ваш метод CalculateSales(int items) рискует превратиться в что-нибуть типа Verify_Items_Parameter_And_Correct_It_If_Possible_And_Then_Calculate_Sales_Otherwise_Raise_Exception(int items)) softwarer Позиция экстремальна, потому что в ней граница между assert-ом и exception-ом задвинута так далеко от некоего "среднего", как только можно; по сути, Вы предлагаете, иметь в программе 99% assert-ов и 1% exception-ов. если моя программа и в самом деле не зависит от внешних поставшиков данных типа БД, линий связи и прочей ненадежной среды, то не вижу причин не иметь там максимум 1% Exception'ов, разве это экстрим ? Я и сам часто люблю говорить о "золотой середине", но все-таки зачем насильно уравнивать вещи без надобности ? softwarer Эту логику постоянно пытаются реализовать тем или иным образом, например, в дотнете разделили исключения на SystemException и ApplicationException. Но в итоге каждый раз оказывается, что не все так однозначно. Рихтер уже успел поругать эту идею :) Тем не менее это не сильно касается проблем разделения Assert и Exception ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.05.2007, 21:32 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
heyРаз-уж такой шаблон есть и широко используется, Кто Вам сказал, что он есть и тем более широко используется? heyто по всей вероятности с инкапсуляцией там все в порядке :) Может все-таки лучше полагаться на то, что видим, а не на "по всей вероятности"? heyвозможно будете смеяться, но такие автомобили уже есть, Не знаю, будете ли Вы смеяться, но подумайте над тем, что я сказал, еще раз. "Автомобиль, который может заменить водителя" - совсем не то же самое, что и "автомобиль, который ездит на автопилоте". heyа применить мозги тут нужно только в плане анализа - насколько эта задача подпадает под шаблон. К сожалению, именно на этом этапе делается неимоверное количество ошибок. heyДавайте-ка более аккуратно: исключение это по определению ситуация, наступление которой мы предполагаем маловероятным, но все-же предвидеть обязаны. ...... Под это определение не попадает нарушение предусловий, потому-что в протестированной системе теоретически это невозможно, и мы не обязаны этого предвидеть. Ну, в том, что касается изречения "в протестированной системе теоретически не может быть ошибок", оно более чем достойно быть увековеченным. Определение довольно спорное, но я бы отметил, что Вы уперлись в то, о чем я говорил в самом первом письме: в то, что Вы считаете модулем. Если Вы считаете модулем приложение в целом, такое рассуждение могло бы быть верным. Если же Вы считаете модулем, например, класс коллекции (усугубляя - класс коллекции, который Вы разработали как компонент на продажу), ситуация вызова с неверным аргументом - как раз "маловероятно, но все же предвидеть обязаны". heyХотя на практике конечно лучше оставить там на охране Assert и в случае ошибки например вообще прервать выполнение приложения. Это, пардон, выдающаяся глупость. Признаться, меня вообще шокирует привычка современных программ падать по любому поводу, но как только Вы побудете в шкуре пользователя, который полчаса набивал данные только для того, чтобы программа упала там, где эти данные вполне можно было спасти (ну хотя бы нажать "сохранить в файл" вместо "сохранить в базу")..... heyПри чтении файла или пользовательского ввода можно говорить о том, что вероятность поступления неверной информации настолько велика (по сути, поступление верных данных более маловероятно, чем неверных , что мы должны всегда ее проверять (тщательно), и уже поэтому это не должно быть Exception. Странное рассуждение. По сути, Вы говорите "то маловероятное, что мы должны предвидеть, это exception, а то более вероятное, что мы должны предвидеть, это уже не exception". С удовольствием покритикую теорию "где именно проходит граница, отделяющая маловероятное от более вероятного". heyПо-сути, вы просто распихали обязанности верификатора по двум ни в чем не повинным объектам - ридеру файла (или пользовательскому окну) и объекту бизнес логики. Простите, Вы сказали какую-то чушь. Во-первых, я наоборот, избавил ридер от обязанностей верификатора. Я свел работу ридера к предельно простому и надежному алгоритму - прочитать данные (то, что он умеет) и передать их в интерфейс потребителя (и его уже не волнует, что это за потребитель, что он понимает, что не понимает). Потребителем может выступить верификатор - который после проверки передаст их в объект бизнес-логики. Может выступить сам объект бизнес-логики. Может выступить например объект отладочной печати - что бы то ни было, ридеру на это наплевать. Это и есть та независимость объектов, которая позволяет строить гибкие и надежные приложения - и сравните это с Вашим предложением, где ридер должен не только знать про существование некоего "верификатора", не только обрабатывать возможность его отсутствия (скажем - нафиг верификатор, если мы подаем данные в модуль печати), но и самое главное - уметь найти верификатор, подходящий к установленному типу объекта-получателя. Для этого есть свои шаблоны, но в целом это безусловно лишняя, вредная связь. Во-вторых, объект бизнес-логики в данном случае - единственный, кто знает, что ему на самом деле нужно. Рассмотрим простой случай: объект дорабатывается, в него добавляется новое свойство. При верификации в сеттере свойства все оказывается очень просто - добавили это свойство и все, все работает, новая строка из конфигурационного файла транзитом через ридер попадает куда нужно и верифицируется. Вы предлагаете добавлять это свойство в два места - собственно в класс бизнес-логики и в класс-верификатор. Это уже ненадежно, уже тонкое место. Более того, Вы обязываете любого, кто работает с классом бизнес-логики, не забывать пользоваться верификатором. Чтение конфиг-файла - хорошо, но в соседнем проекте такого файла может не быть, а тот же самый объект будет инициализироваться в коде. Что это значит? Это значит, что кто-то будет обязан, как последний идиот, писать что-нибудь типа Код: plaintext 1. 2. 3. Замечательный код, идеально подходит в помойку. heyМне не кажется, что они будут вам за это очень благодарны. Теперь ридер или окно (а окон кстати может быть много) должно мало того, что знать об этом объекте, так и еще и брать на себя обязанности по отлову исключения и выводу ошибки на экран. И снова не так. Обязанность ридера - добавить свою информацию к исключению, если оно будет. То есть: если при инициализации объекта происходит исключение, добавить к нему информацию о файле, свойстве и значении (ну и может быть строке файла). Отлов исключений в каждом окне поотдельности - малопонятный мне идиотизм, к сожалению, используемый по умолчанию для программ на java и .net. Впрочем, и там, и там, вполне можно сделать нормально. heyА объект бизнес логики должен теперь проверять и выбрасывать исключения (что хотя конечно мало отличается от Assert, который все равно там должен быть, Он должен это делать в любом случае - иначе он обяжен программиста в каждом месте использования класса явно вызывать верификатор, что антитехнологично. heyно вот если потом вы решите при считывании неверного параметра не ругаться сразу, а попытаться конвертировать его в более правильный (напр. "Yes" в "Y"), ваш метод CalculateSales(int items) рискует превратиться в что-нибуть типа Verify_Items_Parameter_And_Correct_It_If_Possible_And_Then_Calculate_Sales_Otherwise_Raise_Exception(int items)) Звучит неубедительно. Впрочем, я предпочту обратить этот аргумент против Вас: представьте себе, во что превратится Ваш верификатор в этом же случае. Либо ему придется проверять Verify_Items_Parameter_Eigther_Correct_Or_Can_Be_Corrected, а бизнес-объекту затем делать что-нибудь типа If_Parameter_Not_Correct_But_Can_Be_Corrected_Then_Correct_And_Process_Else_Simply_Process, либо, что более идеологично в Вашей модели, Вам придется придумать еще и третий вспомогательный класс - корректор. То есть - обратите внимание - из-за изменения требований к объекту бизнес-логики Вам придется править класс ридера. И это - лучшая иллюстрация "вредной связи". heyразве это экстрим ? Если показатель задвинут на край допустимого диапазона, его значение безусловно экстремально. Не очень понимаю Вашей нервной реакции. heyРихтер уже успел поругать эту идею :) Тем не менее это не сильно касается проблем разделения Assert и Exception Это практически оно и есть. Почти все SystemException-ы - это то, что Вы хотите обрабатывать assert-ами. Не полностью, но почти (особенно учитывая, что AgumentException - это 95% всех ошибок этого класса). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 03.05.2007, 22:39 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
softwarer Ну, в том, что касается изречения "в протестированной системе теоретически не может быть ошибок", оно более чем достойно быть увековеченным. Слово “теоретически” здесь у меня применено в смысле “по большому счету”. В обыденной жизни я его всегда применяю только в этом смысле, и не учел того, что в форуме это кого-нибудь может сбить с толку. softwarer Определение довольно спорное, но я бы отметил, что Вы уперлись в то, о чем я говорил в самом первом письме: в то, что Вы считаете модулем. Если Вы считаете модулем приложение в целом, такое рассуждение могло бы быть верным. Если же Вы считаете модулем, например, класс коллекции (усугубляя - класс коллекции, который Вы разработали как компонент на продажу), ситуация вызова с неверным аргументом - как раз "маловероятно, но все же предвидеть обязаны". Это упирается и в мой первый пост. Я прекрасно вижу, что все поставляемые библиотеки выбрасывают исключения при неверных входных параметрах, и этот подход рекомендуется при разработках библиотек повторного использования. Мне этот подход не кажется правильным и это является причиной появления в этом форуме моего вопроса. Пока-что в ваших объяснениях я увидел только смутное очертания утверждения “просто так везде принято”. Почему так принято, я не понял. softwarer Это, пардон, выдающаяся глупость. Признаться, меня вообще шокирует привычка современных программ падать по любому поводу, но как только Вы побудете в шкуре пользователя, который полчаса набивал данные только для того, чтобы программа упала там, где эти данные вполне можно было спасти (ну хотя бы нажать "сохранить в файл" вместо "сохранить в базу")..... Softwarer, я-бы попросил вас не делать необоснованных и нелепых выводов, да еще и публиковать их в бесцеремонной форме. Вы там слово “например” что-ли не заметили ? И с чего вы взяли, что “прерывание выполнения приложения” тождественно равно “немедленно убить процесс” ? И с какими-это из современных программ вы работаете, если все они падают от малейшего дунавения ветра, уничтожая вашу бесценную информацию ? Современные офисные пакеты пытаются восстановить данные, даже будучи вырубленными Reset’ом. Я-уж молчу про “"сохранить в файл" вместо "сохранить в базу"”. Невозможность сохранения в БД как раз и поднимает исключение (а не Assert, о чем я написал наверно уже раз 15), подразумевая таким образом возможность для приложения не только не падать, но и нормально продолжать работу. softwarer Странное рассуждение. По сути, Вы говорите "то маловероятное, что мы должны предвидеть, это exception, а то более вероятное, что мы должны предвидеть, это уже не exception". С удовольствием покритикую теорию "где именно проходит граница, отделяющая маловероятное от более вероятного". Вы не поняли, о чем я говорил. Exception – это “маловероятное, но обязательное к проверке”. Даже если программа полностью корректна, то ошибка соединения обязана быть предусмотрена. Assert – это нарушение контракта или нормального течения работы метода. Это является ошибкой программирования и при обнаружении обязано быть исправленным. Кроме того, в прошлом посте я не сделал ударения (и вы благополучно это пропустили) на том важном атрибуте исключения, как неспособность метода, где оно возникло, справиться с ним. Именно поэтому он возбуждает исключение, которое передается вызывающему методу, а уж тот решает, что с ним делать – обработать или подняв уровень абстракции передать еще выше. А при получении неверного параметра имхо все гораздо проще – к выполнению тела программы вообще нельзя приступать, налицо ошибка программирования. Которую исправлять нужно, а не играться с уровнями абстракции … softwarer Во-первых, я наоборот, избавил ридер от обязанностей верификатора. Я свел работу ридера к предельно простому и надежному алгоритму - прочитать данные (то, что он умеет) и передать их в интерфейс потребителя (и его уже не волнует, что это за потребитель, что он понимает, что не понимает). Потребителем может выступить верификатор - который после проверки передаст их в объект бизнес-логики. Может выступить сам объект бизнес-логики. Может выступить например объект отладочной печати - что бы то ни было, ридеру на это наплевать. Это и есть та независимость объектов, которая позволяет строить гибкие и надежные приложения - и сравните это с Вашим предложением, где ридер должен не только знать про существование некоего "верификатора", не только обрабатывать возможность его отсутствия (скажем - нафиг верификатор, если мы подаем данные в модуль печати), но и самое главное - уметь найти верификатор, подходящий к установленному типу объекта-получателя. Для этого есть свои шаблоны, но в целом это безусловно лишняя, вредная связь. Объясните мне пожалуйста разницу между вашим верификатором, и моим. А то простите я не понял, почему ридер->верификатор->объект в моем случае хуже чем ридер->верификатор->объект в вашем. softwarer Во-вторых, объект бизнес-логики в данном случае - единственный, кто знает, что ему на самом деле нужно. Рассмотрим простой случай: объект дорабатывается, в него добавляется новое свойство. При верификации в сеттере свойства все оказывается очень просто - добавили это свойство и все, все работает, новая строка из конфигурационного файла транзитом через ридер попадает куда нужно и верифицируется. Вы предлагаете добавлять это свойство в два места - собственно в класс бизнес-логики и в класс-верификатор При изменении интерфейса класса это безусловно влияет на взаимодействующие с ним классы. softwarer Более того, Вы обязываете любого, кто работает с классом бизнес-логики, не забывать пользоваться верификатором Не знаю, какой верификатор вы имеете в виду, но уж точно не мой. Любой другой объект ну ни как не обязан пользоваться фильтром, а может напрямую вызывать этот объект. Вы явно говорите про что-то другое, иначе как объяснить появление метода If_Parameter_Not_Correct_But_Can_Be_Corrected_Then_Correct_And_Process_Else_Simply_Process, которым дескать обязан обладать мой объект бизнес-логики ;) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 04.05.2007, 21:40 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
heyСлово “теоретически” здесь у меня применено в смысле “по большому счету”. Если так, это вышибает почву из-под Вашего "не обязаны предвидеть". Как только мы признаем наличие "малого счета", придется признать и "либо обязаны предвидеть, либо приложение будет некачественным". heyЭто упирается и в мой первый пост. Я прекрасно вижу, что все поставляемые библиотеки выбрасывают исключения при неверных входных параметрах, и этот подход рекомендуется при разработках библиотек повторного использования. Мне этот подход не кажется правильным А что же им делать? Они не обладают информацией о контексте, которая позволила бы им принять иное решение. Скажем, just for example, Вы - автор библиотеки - не можете полагаться на то, что кому-нибудь из Ваших пользователей не взбредет в голову написать нечто типа Код: plaintext 1. 2. 3. 4. 5. heyПока-что в ваших объяснениях я увидел только смутное очертания утверждения “просто так везде принято”. Почему так принято, я не понял. Хм. Мне кажется, Вам мешает то, что Вы считаете Exception и Assert принципиально разными вещами. В действительности - достаточно давно придумали использовать подкласс исключений, называемых Assert, для решения определенной задачи. Вам кажется , что этот класс был бы более удобен для решения несколько иного класса задач (будем считать, более широкого). Это вопрос всего лишь понимания слов. Если Вам (и вашей команде) будет так удобнее - да наздоровье, берлинской стены здесь никто не возводит. Вдобавок, есть ощущение, что это кажется обусловлено отсутствием для исключений синтаксиса а-ля assert, того, который я Вам предложил добавить самому. heySoftwarer, я-бы попросил вас не делать необоснованных и нелепых выводов, да еще и публиковать их в бесцеремонной форме. Вы там слово “например” что-ли не заметили ? Приведенный Вами пример меня и шокировал. heyИ с чего вы взяли, что “прерывание выполнения приложения” тождественно равно “немедленно убить процесс” ? Да какая вообще разница, сколь тождественно? Какого хрена "прерывать выполнение" приложения, которое запросто может работать? Допустим, у приложения в силу неведомых причин выпадает assert на функции пятого уровня значимости - например, отражении в статусбаре времени выполнения текущей операции. И что по-Вашему, этого достаточно, чтобы при любой попытке выполнения операции "прерывать выполнение приложения"? Типичный пример эскалации мухи в слона. Технология программирования призвана решать строго обратную задачу - задачу устойчивости. Главное, что программа может делать со своими ошибками - минимизировать их последствия. И самочинно "прерывать выполнение приложения" можно в одном-единственном случае - при наличии уверенности, что "продолжение выполнения" еще более усугубит ситуацию. heyИ с какими-это из современных программ вы работаете, если все они падают от малейшего дунавения ветра, уничтожая вашу бесценную информацию ? В последний раз этим отличилась Visual Studio 2005. heyНевозможность сохранения в БД как раз и поднимает исключение (а не Assert, о чем я написал наверно уже раз 15), Я недостаточно четко проговорит этот момент, но и Вы, если не затруднит, пытайтесь таки понять сказанное, а не "первую неправильную версию, которая пришла Вам в голову". Я не сказал, что все происходит "из-за невозможности сохранения в БД". А имел в виду примерно следующую ситуацию - выпадает Assert во время сохранения в БД. Выпадает на чем угодно, например на том же неправильном доступе к коллекции. Понятно, что в этом случае невозможно сохранить в БД - продолжать операцию после такого нарушения невозможно. Но это не значит, что программу нужно немедленно вырубить, как предложили Вы. В такой ситуации программа может продолжить работу, например, велика вероятность того, что кнопка "сохранить в файл" таки сработает. heyВы не поняли, о чем я говорил. Exception – это “маловероятное, но обязательное к проверке”. Даже если программа полностью корректна, то ошибка соединения обязана быть предусмотрена. Assert – это нарушение контракта или нормального течения работы метода. Боюсь, это Вы не поняли того, что я сказал. Потому что кроме процитированной трактовки exception-а Вы сказали, что "при чтении файла или пользовательского ввода вероятность ошибки столь велика, что это уже не exception". Вот я и спрашиваю - что же это тогда, и как Вы собираетесь проводить границу между "маловероятным" и "более чем маловероятным". heyКроме того, в прошлом посте я не сделал ударения (и вы благополучно это пропустили) на том важном атрибуте исключения, как неспособность метода, где оно возникло, справиться с ним. Этот атрибут является общим для почти любой ошибочной ситуации, я бы сказал, для всех, которые мы обсуждали. Поэтому действительно не вижу причин специально его выделять. heyИменно поэтому он возбуждает исключение, которое передается вызывающему методу, а уж тот решает, что с ним делать – обработать или подняв уровень абстракции передать еще выше. А при получении неверного параметра имхо все гораздо проще – к выполнению тела программы вообще нельзя приступать, налицо ошибка программирования. Которую исправлять нужно, а не играться с уровнями абстракции … У меня такое ощущение, что Вы уже слегка забыли, о чем мы говорим. Я наталкиваю Вас на тот момент, что "получение неверного параметра - ошибка программирования", и в то же время, параметр может быть зашит не константой в приложении, а так или иначе приходить из внешних источников (конфигурационный файл - самый простой пример), и в этом случае это уже не "ошибка программирования", а "ситуация, при которой нужно выдать пользователю вменяемую диагностику, что именно не устраивает, дабы он мог откорректировать этот внешний источник либо иначе решить проблему без какой-либо модификации программы". Различить эти ситуации на уровне программирования бизнес-объекта невозможно. Базовый принцип модульности - объект не должен зависеть от того, кто его вызывает. Соответственно, автор бизнес-объекта не может сказать "ну это ошибка программирования, assert-ная ситуация". heyОбъясните мне пожалуйста разницу между вашим верификатором, и моим. А то простите я не понял, почему ридер->верификатор->объект в моем случае хуже чем ридер->верификатор->объект в вашем. Вопрос, похоже, свидетельствует о некоем непонимании между нами. Давайте сделаем откат и попробуем потщательнее. Итак, изначально я говорил о некоторой системе инициатор->ридер->какой-то-объект. В ней постулировалось следующее: 1. Ридер читает некий файл, в корректности информации в котором мы не уверены, и передает все прочитанное объекту. 2. В случае, если объект не в состоянии принять данные, пользователь должен получить информацию, сочетающую сообщение из объекта (что за ошибка) и информацию из ридера (что за файл). Выдать соответствующее сообщение - по идее, функция инициатора (или чего-то за инициатором). Я привел это как пример взаимодействия, при котором исключение является прямым, удобным и естественным механизмом, которое позволит объекту и ридеру передать информацию об ошибке инициатору. Таким образом я попытался обосновать то, что объект должен выкидывать исключение при ошибке во входных параметрах, поступающих от ридера. Вы сказали, что для этого следует применить паттерн с верификатором. Не знаю, какой именно паттерн Вы имели в виду, принципиально есть две схемы подключения: Код: plaintext и Код: plaintext 1. 2. 3. Не так важно, какая именно схема будет выбрана, важно на самом деле следующее: либо объект бизнес-логики виден снаружи, доступен непосредственно, либо верификатор полностью закрывает его собой. Первый вариант неудачен, что я обосновываю различными приведенными примерами. Если так, значит любой, кто знает об объекте, должен также постоянно помнить о том, что работать надо не напрямую, а через верификатор (или еще хуже - половина действий напрямую, половина с использованием верификатора). Второй же вариант - как раз та схема, с которой мы начали. Практически получается следующее: Код: plaintext 1. 2. 3. 4. 5. В этом случае, выделять ли верификатор, как именно его использовать - внутреннее дело "некоего объекта", ни ридер, ни кто-то другой об этом не знает и не думает. Именно эту схему я полагаю правильной и пытаюсь обосновать. heyНе знаю, какой верификатор вы имеете в виду, но уж точно не мой. Любой другой объект ну ни как не обязан пользоваться фильтром, а может напрямую вызывать этот объект. :(( То есть Вы полагаете нормальным взаимодействие, при которой кто-то может напрямую вызвать не защищенный проверками объект? Давайте еще раз. Сконструируем предельно простой случай: объект с одним свойством. Я предлагаю примерно следующее решение (которое, как Вы говорите, рекомендуется в литературе): Код: plaintext 1. 2. 3. 4. 5. (прошу прощения за возможные синтаксические ошибки, не особо владею C#. Вы говорите о том, что надо выделить верификатор. Учитывая возможность вызова напрямую, которую Вы упомянули, я вижу три варианта: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. Что касается этих вариантов: 1. Просто ненадежен. При прямом обращении класс легко ломается, и это никак не контролируется. 2. Одни и те же проверки приходится делать в двух местах. Классическое копирование кода, со всеми его недостатками. 3. В принципе нормально, но становится непонятно - а нафига нужен этот верификатор. Кому будет хуже, если проверку запихать напрямую в сеттер? heyВы явно говорите про что-то другое, иначе как объяснить появление метода If_Parameter_Not_Correct_But_Can_Be_Corrected_Then_Correct_And_Process_Else_Simply_Process, которым дескать обязан обладать мой объект бизнес-логики ;) Хм. Похоже, с этой аналогией мы совсем перестали понимать друг друга. Предлагаю не выяснять, что мы хотели сказать этими жуткими методами, выше уже все сказано. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 04.05.2007, 23:32 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
softwarer Если так, это вышибает почву из-под Вашего "не обязаны предвидеть". Как только мы признаем наличие "малого счета", придется признать и "либо обязаны предвидеть, либо приложение будет некачественным". На мой взгляд, есть важная разница между ошибкой доступа к серверу, потому-что он недоступен, и ошибкой в методе, потому-что его хреново тестировали. Предвидеть обязаны в обоих случаях: В первом) выбросить исключение, а вызывающий объект должен уметь поймать это исключение. Т.е. вызывающий объект как-бы говорит: выполняй метод, но если сервер отключен, то скажи мне об этом, а я дальше разберусь. Во втором) выбросить Assert. Выбрасывать исключение нелогично, и уж тем более нелогично программировать вызывающий объект на отлов этого исключения. Прямо смешно, если вызывающий объект говорит: выполняй метод, а если я тебе вдруг вместо положительного числа дал отрицательное, то скажи мне, а я дальше разберусь 8-). softwarer Хм. Мне кажется, Вам мешает то, что Вы считаете Exception и Assert принципиально разными вещами не принципиально разными, но разными. Выбрасывание исключения подразумевает, что его кто-то будет ловить. Assert такого не подразумевает. Имхо разница на лицо. softwarer Приведенный Вами пример меня и шокировал. Вы легкошокируемый человек. Правда все равно не понимаю, что именно там шокирующего, тем более что вы и сами не отрицаете возможность прервать программу в определенных случаях. softwarer Да какая вообще разница, сколь тождественно? Какого хрена "прерывать выполнение" приложения, которое запросто может работать? Допустим, у приложения в силу неведомых причин выпадает assert на функции пятого уровня значимости - например, отражении в статусбаре времени выполнения текущей операции. И что по-Вашему, этого достаточно, чтобы при любой попытке выполнения операции "прерывать выполнение приложения"? Типичный пример эскалации мухи в слона. Технология программирования призвана решать строго обратную задачу - задачу устойчивости. Главное, что программа может делать со своими ошибками - минимизировать их последствия. И самочинно "прерывать выполнение приложения" можно в одном-единственном случае - при наличии уверенности, что "продолжение выполнения" еще более усугубит ситуацию Если вы уверены, что программа в состоянии продолжать работу, так запишите ошибку в лог-файл, и работайте себе дальше, я-же не против :) softwarer Боюсь, это Вы не поняли того, что я сказал. Потому что кроме процитированной трактовки exception-а Вы сказали, что "при чтении файла или пользовательского ввода вероятность ошибки столь велика, что это уже не exception". Вот я и спрашиваю - что же это тогда, и как Вы собираетесь проводить границу между "маловероятным" и "более чем маловероятным". Дело вовсе не в том, где пролегает эта граница, а том, что вызывает ошибку, и соответственно в разных путях ее преодоления. softwarer Я наталкиваю Вас на тот момент, что "получение неверного параметра - ошибка программирования", и в то же время, параметр может быть зашит не константой в приложении, а так или иначе приходить из внешних источников (конфигурационный файл - самый простой пример), и в этом случае это уже не "ошибка программирования", а "ситуация, при которой нужно выдать пользователю вменяемую диагностику, что именно не устраивает, дабы он мог откорректировать этот внешний источник либо иначе решить проблему без какой-либо модификации программы". Различить эти ситуации на уровне программирования бизнес-объекта невозможно. Базовый принцип модульности - объект не должен зависеть от того, кто его вызывает. Соответственно, автор бизнес-объекта не может сказать "ну это ошибка программирования, assert-ная ситуация". Вот если с этой ситуацией разбирается непосредственно бизнес-объект (без встроенного верификатора), то действительно невозможно. Поэтому это и является работой верификатора, который должен сначала изучить поступаемые из файла данные, а уж затем решить, что с ними делать - посылать в объект или выводить ругательное окно пользователю. softwarer Итак, изначально я говорил о некоторой системе инициатор->ридер->какой-то-объект. В ней постулировалось следующее: ... Понятно. Фактически вы используете исключение как способ сказать инициатору, что в файле находиться недопустимый параметр. Что-ж, позвольте тогда спросить, почему вы не хотите для этой цели использовать сообщения ? Зачем использовать исключение, что-бы просто сказать что-то другому объекту ? В моей версии существует бизнес-объект (второй вариант указанный вами): Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. Предполагается получать параметр myValue как из файла, так и из другого объекта. При чтении из файла, используется верификатор. При получении неверного параметра он отсылает соответствующее сообщение классу, ответственному за отображение ошибки, либо в простейшем случае вообще сам это сообщение выводит на экран. Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. При получении из другого объекта, никакого верификатора не нужно, потому-что вызывающий объект обязан быть в курсе ограничений интерфейса объекта BusinessObject. Да, здесь есть нехороший недостаток - создание еще одной сущности и дублирование проверок. Не желая быть снова обвиненным вами в эктремизме скажу, что вероятно в некоторых случаях исключения действительно будут лучше. Но, все-таки давайте посмотрим с другой точки зрения. Во-первых, проверки могут оказаться тяжеловесными. Тогда в моей версии я просто отключу Assert в бизнес объекте и проверки будут производиться только для вызовов на основе чтения из конфиг-файла. Во-вторых, получение из конфиг-файла отрицательного значения вовсе не обязательно должно заканчиваться сообщением пользователю. Возможно достаточно просто свести это значение к ближайшему допустимому (например к единице). В тоже время, получение отрицательного значения из другого объекта свидетельствует об ошибке и как-то должно обработаться. Или к примеру, при получении отрицательного значения поле BusinessObject.MyValue вообще не надо трогать, а оставить то значение, которое оно имеет на текущий момент. Имхо, лучше всю всю эту логику вынести за пределы BusinessObject, так как она его по-сути не касается. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 06.05.2007, 18:02 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
heyНа мой взгляд, есть важная разница между ошибкой доступа к серверу, потому-что он недоступен, и ошибкой в методе, потому-что его хреново тестировали. Где-то это различие важно, где-то не важно. heyВо втором) выбросить Assert. Выбрасывать исключение нелогично, и уж тем более нелогично программировать вызывающий объект на отлов этого исключения. Только потому, что Вы не ощущаете следующий простой принцип: "Программа должна работать". Представьте себе любой сервер, любой сервис, скажем тривиальную рассылку клиентам поздравлений с днем рождения. Вполне может быть, что при отправке почты на домен, just say, myname.org, в силу любой возможной особенности сендер падает с assert-ом. Так вот: это совершенно не значит, что несколько десятков, сотен или тысяч других клиентов должны на неопределенный срок остаться без поздравлений. Напротив, по какой бы причине отправка не упала, эта ситуация должна быть корректно обработана (допустим - отметить недоставленное сообщение в БД, отправить сообщение об ошибке админам, нормально обрабатывать другие сообщения, периодически пытаться перепослать это). heyВыбрасывание исключения подразумевает, что его кто-то будет ловить. Совершенно не обязательно - если под "кто-то" не имеется в виду "хандлер самого верхнего уровня, вся функция которого - вывести сообщение об ошибке и не дать программе молча упасть". Ну а такой хандлер ловит и ассерты (точнее, должен ловить - иное будет махровым непрофессионализмом). heyВы легкошокируемый человек. Да нет, вообще говоря. Это вопрос исключительно точки зрения - типа как один человек говорит "всю жизнь курю - никто еще так не реагировал", а другой - "первый раз встречаю человека, прикуривающего на пороховом складе". heyЕсли вы уверены, что программа в состоянии продолжать работу, так запишите ошибку в лог-файл, и работайте себе дальше, я-же не против :) А вот для этого и надо ловить assert-ы. Точнее будет сказать так: и вот именно в этом месте нет никакой разницы между assert-ом и "исключением в Вашем понимании". hey softwarerВот я и спрашиваю - что же это тогда, и как Вы собираетесь проводить границу между "маловероятным" и "более чем маловероятным". Дело вовсе не в том, где пролегает эта граница, а том, что вызывает ошибку, и соответственно в разных путях ее преодоления. Ошибку в обоих случаях вызывает непредсказуемая внешняя среда - в одном случае, например, админ, который потушил сервер БД, в другом случае тот же админ, который сделал опечатку в конфиг-файле. В чем разница? Итак, где пролегает граница? heyВот если с этой ситуацией разбирается непосредственно бизнес-объект (без встроенного верификатора), то действительно невозможно. Поэтому это и является работой верификатора, Во-первых, откуда Вы взяли "без встроенного верификатора"? Я ни про что такое не говорил. heyкоторый должен сначала изучить поступаемые из файла данные, а уж затем решить, что с ними делать - посылать в объект или выводить ругательное окно пользователю. Во-вторых, "выводить ругательное окно" - совершенно не функция верификатора. Он в этом некомпетентен. Дело верификатора - высказать претензии, а кто и как их обработает - вопрос вызывающему объекту. heyПонятно. Фактически вы используете исключение как способ сказать инициатору, что в файле находиться недопустимый параметр. Нет, не так. Я использую исключение как способ сказать инициатору, что операция "чтение конфигурационного файла" закончилась неудачей. При этом я хочу передать в исключении дополнительную диагностическую информацию. Кто и как будет ее использовать - в общем-то, бизнес-объекту без разницы; скажем, инициатор может использовать ее для того, чтобы открыть в редакторе нужный конфигурационный файл, поставить курсор в место ошибки и сказать админу: исправляй. heyЧто-ж, позвольте тогда спросить, почему вы не хотите для этой цели использовать сообщения ? Зачем использовать исключение, что-бы просто сказать что-то другому объекту ? Хм. Знаете, есть такой принцип: "если что-то выглядит как утка, плавает как утка и крякает как утка, то это утка". Так вот: если мне нужно некоторое "сообщение", которое, во-первых, прервет текущую последовательность исполнения программы, во-вторых, доставит информацию не известному заранее "инициатору", проскочив транзитом через тех вызывающих, которые не хотят это сообщение получить - то это "сообщение" называется "исключение", и пытаться использовать в этом месте что-то другое - мягко говоря, нетехнологично. heyВ моей версии существует бизнес-объект (второй вариант указанный вами): ok. По поводу аргументов "против" мы согласны, осталось выяснить, что хорошего мы получим, за что Вы предлагаете платить такую цену. heyВо-первых, проверки могут оказаться тяжеловесными. Тогда в моей версии я просто отключу Assert в бизнес объекте и проверки будут производиться только для вызовов на основе чтения из конфиг-файла. Я согласен с поставленной задачей, но не с решением и предполагаемыми из него выводами. Во-первых, тут нет никакой разницы между assert и exception (надеюсь, Вы в курсе, как реализовано "отключу assert". Ну а во-вторых, верификатор здесь - менее удачное решение, нежели "флаг в бизнес-объекте, включающий или отключающий проверки". Почему менее удачное: 1. Флаг не требует дублирования кода. В частности, не может возникнуть ситуация "в бизнес-объект добавили некоторую проверку, а продублировать ее в верификатор забыли". 2. Флаг можно сделать включенным по умолчанию - и его потребуется явно отключать там, где программист сочтет это безопасным. Наоборот, в Вашей схеме проверки окажутся "по умолчанию отключены", и программист должен будет специально позаботиться - использовать верификатор - для того, чтобы эти проверки включить. heyВо-вторых, получение из конфиг-файла отрицательного значения вовсе не обязательно должно заканчиваться сообщением пользователю. Возможно достаточно просто свести это значение к ближайшему допустимому (например к единице). В тоже время, получение отрицательного значения из другого объекта свидетельствует об ошибке и как-то должно обработаться. Крайне спорное рассуждение, я бы даже сказал, идеологически ложное. По сути Вы говорите следующее: объект должен вести себя по-разному в зависимости от того, кто его вызвал. Это нарушает базовый принцип модульности. Разумеется, подобная постановка задачи возможна, но зависит они никак не от того, идут ли данные из файла или откуда-нибудь еще. Наиболее естественно в такой ситуации сделать два метода, SetValue и SetCorrectedValue, и в каждом месте вызывать тот из них, который соответствует требованиям задачи. heyИмхо, лучше всю всю эту логику вынести за пределы BusinessObject, так как она его по-сути не касается. Я бы сказал, остальных она касается еще меньше. Автор BusinessObject вполне может, если захочет, вынести это в некий отдельный внутренний класс (не в смысле inner, а в смысле internal), и таким образом отделить "суть бизнес-объекта" от "вспомогательного кода". Он может дать некий дополнительный интерфейс для управления этими проверками, включения-выключения коррекции итп, если это нужно. Однако, признаться, удобства двух публичных классов - бизнес-объекта и верификатора - я пока не прочувствовал. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 06.05.2007, 22:37 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
У вас очень длиные посты, сорри я их не осилил. Хочу свои мысли привести по поводу assert-ов в java, думаю в .net ситуация должна быть аналогичная. Проверять предуслувия через assert не есть правильно. У метода есть контракт и этот контракт должен быть постоянным. Assert`ы можно отключать в runtime и отключив ваш код перестает выполнять свой контракт. "Мусор на входе, мусор на выходе" - это плохой стиль программировния. простой пример вы проверяете в setter методе что аргумент не null. Код: plaintext 1. 2. 3. Если проверяка будет реализована через assert, то при отключенных assert`ах этот код выполниться (без каких либо проблем) и переведет вашу систему в некорректное состояние. И потом далее при первом обращении вы получите NullPointerException, а когда получите это еще большой вопрос. Так что если вы пишите библиотеку не только для себя, то так проверять входные параметры не следует. Пример как мне кажется правильного использования assert`ов. Вы пишите код для нахождения обратной матрицы, ну и assert что исходная * результат = единичная матрица. (т.е. просто проверка инвариантов). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.05.2007, 09:35 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
vas0Проверять предуслувия через assert не есть правильно. У метода есть контракт и этот контракт должен быть постоянным. Assert`ы можно отключать в runtime и отключив ваш код перестает выполнять свой контракт. "Мусор на входе, мусор на выходе" - это плохой стиль программировния. Я во многом согласен с Вами, однако, отмечу пару моментов. Во-первых, хотя лично я полагаю, что хороший код - тот, который корректно работает в любых условиях (и если угодно, имеет соответствующий контракт), не так уж редка и другая точка зрения; в частности, если пороетесь в архивах форума, обнаружите, что моя ругань на java имеет одной из причин именно обилие решений, нарушающих этот принцип. Я не хочу сказать, что точка зрения "вызывайте меня только так, иначе получите кирдык" правильна, но она достаточно распространена. Ну а наиболее важный момент заключается в том, что подобные проверки нередко стоит отключать из-за соображений эффективности. Если приложение хорошо оттестировано, элиминация ряда проверок из release build вполне разумна. Скажем, если посмотреть на Ваш пример - в общем-то не так важно, вылетит ли из метода assert violation или null pointer exception, обрабатывать их нужно одинаково. Согласен, null pointer несколько хуже - может проявиться в другом месте, испортить состояние объекта итп - но разница тут уже количественная, имеет смысл считать, стоит ли игра свеч. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.05.2007, 10:39 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
В принципе согласен со softwarer'ом. Просто мне кажется слишком длинные объяснения запутывают исходное определение. Если подходить с точки зрения практики (сделаем лишь бы работало) Изначально assert и другие исключения ничем не отличаются - они просто говорят, что что-то не так мол разбирайся. Разница только в том, что assert'ы можно легко отключать. Соответсвенно их не стоит ставить туда, где проверка нужна в любом случае. Если подходить с точки зрения теории (сделаем как надо) То assert используется только в "незашищенных" участках, для регистрации некоректного поведения в процессе разработки, а также для документирования допущений кода. Данные факторы весомы особенно когда проект изменчив (либо предполагается его продолжительная поддержка) либо когда над одним проектом работают несколько разработкиков. Возможно в такой среде нужно будет выделить несколько уровней защищенности. Дополнительно возможно разработчик решит считать небезопасным код коллег, хотя всё это может относится к сугобо внутренней закрытой реализации. Если отключение assert'ов не предполагается, то разницы между ними и "обычными" исключениями - разве только в синтаксисе (что легко решаемо). Но опять таки всегда проверять всё не эфективно. А как известно одна из главных проблем программирования - преждевременная оптимизация. Posted via ActualForum NNTP Server 1.4 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.05.2007, 12:13 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
softwarer Только потому, что Вы не ощущаете следующий простой принцип: "Программа должна работать". Представьте себе любой сервер, любой сервис, скажем тривиальную рассылку клиентам поздравлений с днем рождения. Вполне может быть, что при отправке почты на домен, just say, myname.org, в силу любой возможной особенности сендер падает с assert-ом. Так вот: это совершенно не значит, что несколько десятков, сотен или тысяч других клиентов должны на неопределенный срок остаться без поздравлений. Напротив, по какой бы причине отправка не упала, эта ситуация должна быть корректно обработана (допустим - отметить недоставленное сообщение в БД, отправить сообщение об ошибке админам, нормально обрабатывать другие сообщения, периодически пытаться перепослать это). а почему вы исходите из того, что при выпавшем Assert приложение придется закрыть ? Вовсе не обязательно. Есть разные виды assert'а, например в .NET в классе Trace есть метод WriteLineIf(), который можно заставить просто записать ошибку в ваш лог-файл. Собственно даже сам метод Fail() можно переопределить так, что он будет только записывать информацию в лог и все. softwarer Совершенно не обязательно - если под "кто-то" не имеется в виду "хандлер самого верхнего уровня, вся функция которого - вывести сообщение об ошибке и не дать программе молча упасть". Ну а такой хандлер ловит и ассерты (точнее, должен ловить - иное будет махровым непрофессионализмом). exception поднимается из метода, где появился и до тех пор, пока кем-нибудь не обработается, хотя-бы тем-же глобальным хуком на необработанные исключения в конечном приложении. Поэтому обработается в любом случае. А Assert кстати в том-же .NET надо ловить уже другим методом - листенером. softwarer А вот для этого и надо ловить assert-ы. Точнее будет сказать так: и вот именно в этом месте нет никакой разницы между assert-ом и "исключением в Вашем понимании". Кстати, а где конкретно вы собираетесь их ловить ? softwarer Ошибку в обоих случаях вызывает непредсказуемая внешняя среда - в одном случае, например, админ, который потушил сервер БД, в другом случае тот же админ, который сделал опечатку в конфиг-файле. В чем разница? Итак, где пролегает граница? Вообще, я могу с вами согласиться, что это очень спорная тема, прямо из разряда филосовских. Мое мнение об таких "границах" основывается просто на рекомендациях в литературе. Например Стив Макконнел призывает использовать исключения только для действительно исключительных ситуаций (правда толком не уточняет каких :) ), Э. Троелсон в "C# и платформа .NET" говорит о применении исключений только в непоправимых ситуациях, а когда есть возможность выхода из ситуации при помощи логики приложения - то исключения не нужны. На мой взгляд, пользовательский ввод не попадает под их разряд - это легко решается логикой приложения (у меня верификатором). А обрыв соединения или сбой сервера во-первых наступают действительно (много) реже пользовательских ошибок, да и обрабатывать простой логикой их уже сложнее. Но вообще я согласен, что эти рассуждения скорее исходят из моего зравого смысла, чем из каких-то точных обоснований, так что точно я вам эту границу не проложу :) softwarer Во-вторых, "выводить ругательное окно" - совершенно не функция верификатора. Он в этом некомпетентен. Дело верификатора - высказать претензии, а кто и как их обработает - вопрос вызывающему объекту. Пожалуйста. Пусть посылает сообщение (претензию) тому, кто будет заниматься выводом этого сообщения. softwarer Хм. Знаете, есть такой принцип: "если что-то выглядит как утка, плавает как утка и крякает как утка, то это утка". Так вот: если мне нужно некоторое "сообщение", которое, во-первых, прервет текущую последовательность исполнения программы, во-вторых, доставит информацию не известному заранее "инициатору", проскочив транзитом через тех вызывающих, которые не хотят это сообщение получить - то это "сообщение" называется "исключение", и пытаться использовать в этом месте что-то другое - мягко говоря, нетехнологично. А почему вы так уверены, что оно выглядит, плавает и крякает прямо как утка ? Любой объект, в том числе исключение, обладает набором свойств и ограничений целостности, которые в совокупности дают нечто, что мы рассматриваем как одно логическое целое. Т.е. мы не можем просто так присвоить аттрибут, который не будет согласовываться с абстракцией класса. Если взять за пример .NET, то в классе Exception вы сможете найти такой аттрибут как StackTrace, который определенно не нужен при передаче неверного параметра из файла. Вот у вашей утки уже и вырос волчий хвост. Можно также там найти ненужный в данном случае InnerException и пр., этак ваша утка скоро начнет покрываться шерстью и даже рычать. Зачам вам такой монстр в программе ? softwarer Я согласен с поставленной задачей, но не с решением и предполагаемыми из него выводами. Во-первых, тут нет никакой разницы между assert и exception (надеюсь, Вы в курсе, как реализовано "отключу assert". Ну а во-вторых, верификатор здесь - менее удачное решение, нежели "флаг в бизнес-объекте, включающий или отключающий проверки". Почему менее удачное: 1. Флаг не требует дублирования кода. В частности, не может возникнуть ситуация "в бизнес-объект добавили некоторую проверку, а продублировать ее в верификатор забыли". 2. Флаг можно сделать включенным по умолчанию - и его потребуется явно отключать там, где программист сочтет это безопасным. Наоборот, в Вашей схеме проверки окажутся "по умолчанию отключены", и программист должен будет специально позаботиться - использовать верификатор - для того, чтобы эти проверки включить. т.е. вы хотите заставить программиста в коде переключать этот флаг ? Имхо, перекомпиляция приложения в случае "больше не хочу проверок" - очень неудачная идея. Свой Trace я могу отключить, просто исправив параметр в .config файле сборки. Вам-же придется либо поставлять 2 exe-шника, либо сразу ставить вопрос ребром - работает только с проверками, либо только без них. softwarer Крайне спорное рассуждение, я бы даже сказал, идеологически ложное. По сути Вы говорите следующее: объект должен вести себя по-разному в зависимости от того, кто его вызвал. Это нарушает базовый принцип модульности. Разумеется, подобная постановка задачи возможна, но зависит они никак не от того, идут ли данные из файла или откуда-нибудь еще. Наиболее естественно в такой ситуации сделать два метода, SetValue и SetCorrectedValue, и в каждом месте вызывать тот из них, который соответствует требованиям задачи. Почему-же идеологически ложное ? Вот возьмем довольно простой пример - в свойствах монитора вашего компьютера вы сможете найти такой параметр как Частота обновления экрана. Там-же рядом стоит галка "Скрыть режимы, которые монитор не может использовать" (так как это может привести к неустойчивой работе и даже поломке). Теперь предположим, что у нас имеется метод SetFrequency(int frequency). Его задача предельно простая - установить требуемую частоту. При считывании данных из реестра (или уж откуда они там считываются) данные необходимо проверять на допустимость. Однако если имеется какая-то диагностическая утилита, то она должна иметь возможность поставить любую желаемую частоту. И что-же, вы теперь хотите наградить класс-владелец еще и методом SetCorrectedFrequency(), который будет запрашивать монитор на список допустимых частот ? А даже если и так, то что вы будете делать в случаях, когда возможны разные варианты получения корректной частоты ? Т.е. например в случае получения из реестра какой-нибудь ерунды, возможна как установка дефолтной частоты, так и получения последней выбранной кооректной частоты из текущего профиля компьютера. Не может такие веши решать класс, ответственный за настройку монитора. softwarer Я бы сказал, остальных она касается еще меньше. Автор BusinessObject вполне может, если захочет, вынести это в некий отдельный внутренний класс (не в смысле inner, а в смысле internal), и таким образом отделить "суть бизнес-объекта" от "вспомогательного кода". Он может дать некий дополнительный интерфейс для управления этими проверками, включения-выключения коррекции итп, если это нужно. хм, но стоит только перевести этот класс из internal в равноправные внешние классы, как он начнет крякать прямо как мой верификатор. Но ведь насколько я понимаю, вы обосновываете наличие проверок в самом методе, а не где-то еще в другом месте ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.05.2007, 18:04 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
heyа почему вы исходите из того, что при выпавшем Assert приложение придется закрыть ? Ничуть не исхожу, напротив, обосновываю, что оно не так. Если у нас "выпал assert", то есть ровно два варианта действий - либо "ловим", либо "не ловим". Вы сказали "нелогично программировать отлов" - вот я и привожу пример ситуации, в которой "программировать отлов вполне логично". Более того, я вполне осознанно толкаю пример, в котором между assert и exception нет практической разницы с точки зрения необходимой обработки, подчеркиваю, что ловить их в этом случае нужно совместно, одним и тем же куском кода. [font size=4]Однако[/font]. Похоже, я должен извиниться перед Вами, поскольку исходил из неверной посылки и думал о Debug.Assert много лучше, чем он заслуживает. Сейчас я добрался до вижуал студии и посмотрел, как он работает на самом деле, и могу только извиниться за то, что я предполагал по этому поводу раньше и говорил исходя из этого. Так, как он реализован в .NET, Assert, безусловно, совсем не то же самое, что и exception. Более того, это сомнительная хрень, которую без доработки недопустимо использовать в боевых программах (пояснение - release версии обязаны быть откомпилированы без этой... фичи). heyМое мнение об таких "границах" основывается просто на рекомендациях в литературе. Например Стив Макконнел призывает использовать исключения только для действительно исключительных ситуаций (правда толком не уточняет каких :) ), ..... Позволю себе прервать Вас. Мое мнение в данном случае выглядит так: если я, будь хоть трижды уверен в правильности некоего решения в некоторой ситуации, не могу назвать его четко видимых, объективных преимуществ, значит, вопрос тонкий, спорный, и категорические правила в этом случае неуместны; найдется близкая ситуация, в которой какая-нибудь деталь сделает лучшим другое решение. А следовательно, граница зыбка. heyЭ. Троелсон в "C# и платформа .NET" говорит о применении исключений только в непоправимых ситуациях, а когда есть возможность выхода из ситуации при помощи логики приложения - то исключения не нужны. Таких ситуаций нет и не может быть никогда. Просто потому, что когда-то не было исключений, а программы как-то жили и как-то с этими непоправимыми ситуациями справлялись :) Понимаете, хотя теория - важнейшая вещь, большой ошибкой является забывать о ее связи с практикой. В нашей науке теория - это обобщение опыта решения практических задач, и никак иначе. Исключения - это в первую и даже в единственную очередь способ более удачно написать следующий типовой фрагмент кода: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. Когда программистам надоело писать такой (не обязательно по форме, но по смыслу) код, тогда и появились software exceptions. heyда и обрабатывать простой логикой их уже сложнее. Но вообще я согласен, что эти рассуждения скорее исходят из моего зравого смысла, чем из каких-то точных обоснований, так что точно я вам эту границу не проложу :) Я, признаться, не очень понимаю, что Вы называете "обрабатывать логикой", но рад, что мы сошлись по вопросу опоры на здравый смысл. heyПожалуйста. Пусть посылает сообщение (претензию) тому, кто будет заниматься выводом этого сообщения. Уже ближе, но важно - не "выводом", а "обработкой". А кто у нас занимается обработкой такой ситуации? Я построил пример, в котором обработкой должен заниматься инициатор - поскольку ситуация "не прочитан конфигурационный файл" является его проблемой. heyА почему вы так уверены, что оно выглядит, плавает и крякает прямо как утка ? Думаю, правильно будет сказать так: он настолько не выглядит как кто-то другой, что небольшие расхождения во внешности с уткой незаметны. heyЕсли взять за пример .NET, то в классе Exception вы сможете найти такой аттрибут как StackTrace, который определенно не нужен при передаче неверного параметра из файла. Если взять за пример те примеры, что Вы приводили чуть раньше, то это атрибут точно так же не нужен при ситуации "не удалось установить соединение с БД". И точно так же не нужен ни в одной ситуации, которую Вы называете "точно нуждающимися в исключении". Я не хочу здесь уходить в глубокое обсуждение, предлагаю ограничиться констатацией факта, что если принять Вашу точку зрения, придется потребовать от Microsoft-а удаления этого атрибута из класса Exception, что в свою очередь вскроет тот факт, что Microsoft совершенно не "по-Вашему" построило свою модель исключений (ведь null pointer exception, или там array index out of range - это у Вас assert-ы, не exception-ы). Таким образом придется считать, что из вас двоих кто-то кардинально не понимает идеологии исключений :) Прошу прощения, продолжу когда приеду домой. Будет замечательно, если Вы дадите мне закончить прежде чем ответите, и ответите одним письмом на оба моих - иначе наша беседа рискует развалиться, уж слишком много моментов мы обсуждаем, если начнутся еще фрагментарные письма, запутаемся. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.05.2007, 19:59 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
heyМожно также там найти ненужный в данном случае InnerException Можно. А давайте посмотрим на что-нибудь стандартное, например System.ArgumentNullException. У него есть InnerException? Ему нужен InnerException или это торчащий хвост? hey softwarerНу а во-вторых, верификатор здесь - менее удачное решение, нежели "флаг в бизнес-объекте, включающий или отключающий проверки". т.е. вы хотите заставить программиста в коде переключать этот флаг ? Не совсем понял термин "заставить". Я хочу, чтобы проверки были включены до тех пор, пока программист явно и недвусмысленно не даст команду их отключить. Я не хочу, чтобы у одной бизнес-функции было два разных интерфейса, очень похожих внешне, но отличающихся внутренне, и не хочу, чтобы программист имел шанс по ошибке выбрать "не тот" интерфейс. heyИмхо, перекомпиляция приложения в случае "больше не хочу проверок" - очень неудачная идея. Свой Trace я могу отключить, просто исправив параметр в .config файле сборки. Вам-же придется либо поставлять 2 exe-шника, либо сразу ставить вопрос ребром - работает только с проверками, либо только без них. Простите, но я очень удивлен этим возражением. Вы так говорите, словно я не могу прочитать параметр и присвоить его значение переменной, а обязан буду перекомпилить приложение. Вы так говорите, словно Вы можете использовать ConditionalAttribute, а я - нет. Мало того, такое ощущение, что Вы успели забыть, о чем говорили раньше. Вы говорили по сути следующее: сделав публичный верификатор и публичный же класс без верификатора Вы даете возможность программисту выбрать, чем пользоваться в данном месте - вариантом с проверками или вариантом без них. Я показал, что флаг дает как минимум не меньшие возможности (реально большие - с флагом я могу включить проверки даже там, где изначально их не было, а Вы с conditional повторить этого не сможете). И теперь Вы вдруг откатываетесь к варианту Trace, глобальному для всего приложения, без всяких верификаторов. heyПочему-же идеологически ложное ? Я объяснил, почему. Потому что уже пятьдесят лет как существует принцип модульности, на нем основано в том числе ООП, а высказанное Вами желание нарушает этот принцип. heyВот возьмем довольно простой пример Простите, Ваш простой пример есть тавтология, "масло масляное" - Вы просто заменили чтение из файла чтением из реестра, и повторили совершенно необоснованное утверждение о том, что именно чтением из реестра обусловлена разная логика. Мало того, сказав .... heyПри считывании данных из реестра (или уж откуда они там считываются) данные необходимо проверять на допустимость. .... Вы фактически намекнули, что при вводе с клавиатуры такая проверка не требуется. А теперь - о том, как правильно спроектировать классы в этом примере. В этом примере должны существовать методы: Код: plaintext 1. 2. 3. 4. 5. Вот и все. И никаких мифических верификаторов, подключаемых по принципу "здесь играем, здесь не играем, а здесь рыбу заворачивали". heyА даже если и так, то что вы будете делать в случаях, когда возможны разные варианты получения корректной частоты ? Т.е. например в случае получения из реестра какой-нибудь ерунды, возможна как установка дефолтной частоты, так и получения последней выбранной кооректной частоты из текущего профиля компьютера. Не может такие веши решать класс, ответственный за настройку монитора . Really? А мне так кажется, именно "класс, отвественный за настройку монитора" и должен решать такие вещи. Точнее, взаимодействие должно выглядеть примерно так: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. heyхм, но стоит только перевести этот класс из internal в равноправные внешние классы, как он начнет крякать прямо как мой верификатор. Начал бы. Но именно этого не следует делать, по причинам, которые мы обсуждаем (дублирование кода и ненадежность при... спорных преимуществах). hey Но ведь насколько я понимаю, вы обосновываете наличие проверок в самом методе, а не где-то еще в другом месте ? Нет, ничуть. Я нигде такого не говорил, напротив. Я утверждал ровно одно: необходимость инкапсуляции. А именно: ридер выполняет свою задачу (читает данные) и засовывает их в предоставленный ему интерфейс, совершенно не интересуясь ни смыслом этих данных, ни получателем этих данных, ничем. Получатель, соответственно, выгребает данные из своего интерфейса, не интересуясь, от кого он их получил, и обрабатывает в соответствии с заложенными в него правилами. К этому процессу я выдвигаю определенные требования: в случае любой ошибки пользователь должен получить сообщение об этом вместе с информацией о контексте и принять решение из заданного списка (работать с конфигурацией по умолчанию - прервать работу). Обратите внимание на инкапсуляцию. Мне нафиг не интересно, как именно объект будет проверять свои параметры, это его внутреннее дело. Я написал такую спецификацию - и программисту так и скажу: да делай как хочешь, твое дело. Хочешь - делай internal class, хочешь - проверки в методах, хочешь - еще как-нибудь. Мне наплевать, что ты выберешь, до тех пор, пока твой код соответствует внешней спецификации и принятым требованиям к качеству. Вы же, пытаясь заглянуть под юбку, смотря в реализацию, как раз "идеологически" нарушаете инкапсуляцию - как раз то, что я говорил еще в первом письме на эту тему. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 08.05.2007, 00:25 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
softwarer ...думал о Debug.Assert много лучше, чем он заслуживает ... ... Более того, это сомнительная хрень, которую без доработки недопустимо использовать в боевых программах (пояснение - release версии обязаны быть откомпилированы без этой... фичи). Это вы заодно и его брате-близнице Trace.Assert() ? Просто Debug.Assert и так в релизной версии автоматически отключается. Ну и кроме того, такая резкая точка зрения заслуживает объяснения :) softwarer Мое мнение в данном случае выглядит так: если я, будь хоть трижды уверен в правильности некоего решения в некоторой ситуации, не могу назвать его четко видимых, объективных преимуществ, значит, вопрос тонкий, спорный, и категорические правила в этом случае неуместны вообще я не думаю, что уважаемые джентельмены, мною процитированные, утверждают это как категорическое правило, это скорее общее руководство, а не закон softwarer Таких ситуаций нет и не может быть никогда. Просто потому, что когда-то не было исключений, а программы как-то жили и как-то с этими непоправимыми ситуациями справлялись :) дык плохо-ведь справлялись, потому исключения и придумали :) softwarer Понимаете, хотя теория - важнейшая вещь, большой ошибкой является забывать о ее связи с практикой. В нашей науке теория - это обобщение опыта решения практических задач, и никак иначе идея конечно правильная, но вы интересно это сформулировали: "теория очень важна, но нельзя забывать о практике, ведь у нас теория - это обощение практики". Сложно знаете-ли потерять связь с практикой, если даже сама теория суть есть практика :)) softwarer Уже ближе, но важно - не "выводом", а "обработкой". А кто у нас занимается обработкой такой ситуации? Я построил пример, в котором обработкой должен заниматься инициатор - поскольку ситуация "не прочитан конфигурационный файл" является его проблемой. Ну. Так в чем проблема с message'ами - то ? Поймает message и обработает. softwarer Если взять за пример те примеры, что Вы приводили чуть раньше, то это атрибут точно так же не нужен при ситуации "не удалось установить соединение с БД". И точно так же не нужен ни в одной ситуации, которую Вы называете "точно нуждающимися в исключении". Я не хочу здесь уходить в глубокое обсуждение, предлагаю ограничиться констатацией факта, что если принять Вашу точку зрения, придется потребовать от Microsoft-а удаления этого атрибута из класса Exception, что в свою очередь вскроет тот факт, что Microsoft совершенно не "по-Вашему" построило свою модель исключений (ведь null pointer exception, или там array index out of range - это у Вас assert-ы, не exception-ы). Таким образом придется считать, что из вас двоих кто-то кардинально не понимает идеологии исключений :) Стоп-стоп-стоп :) Во-первых, если среди приведенных мною примеров нет такого, который требует StackTrace, это еще не значит, что идеологии полностью расходяться и этот аттрибут надо удалять. Возможна генерация исключения при правильных предусловиях и правильно выполняющемся методе, когда тем не менее на выходе нарушиться, например, инвариант класса, и нас будет интересовать StackTrace. В качестве такого примера можно привести, скажем, объект Автомобиль, у которого имеется метод Ускориться(int ускорение, int секунды), т.е. на вход могут поступить вполне законные параметры ускорения и промежутка времени, сколько надо ускоряться, и на выходе получить превышение допустимой скорости машины, с последующим выходом ее из строя. Во-вторых, библиотеки Microsoft при неверных предусловиях выбрасывают исключения, а не ассерты, и stackTrace там соответственно нужен. Однако несколько постов назад я уже писал, что мне это поведение не кажется правильным, и цель моего тут присутствия понять логику, стоящую за этим. Могу добавить, что я не считаю это кардинально неправильным , и в некоторых случаях допускаю, что это очень даже правильно, однако по большому счету такое поведение мне не нравиться, я не понимаю, зачем надо подавать неверные параметры в метод, а потом ловить его ругательства и что-то с ними делать. Гораздо более логично эти параметры сначала проверить на допустимость, а уж затем вызывать объект. softwarer Можно. А давайте посмотрим на что-нибудь стандартное, например System.ArgumentNullException. У него есть InnerException? Ему нужен InnerException или это торчащий хвост? торчащий хвост. Однако видите-ли в чем дело, его никто отрубать не будет, что-бы иерархию не усложнять. Но это не значит, что под этими знаменами вы можете легко пропихнуть свою утку, больше похожую на волка, аппелируя в том духе, что дескать "чего прикопались к морде, шерсти и клыкам ? Вон на свой иннер эксепшен посмотрите " ... softwarer Я хочу, чтобы проверки были включены до тех пор, пока программист явно и недвусмысленно не даст команду их отключить. Я не хочу, чтобы у одной бизнес-функции было два разных интерфейса, очень похожих внешне, но отличающихся внутренне, и не хочу, чтобы программист имел шанс по ошибке выбрать "не тот" интерфейс. мне не кажется убедительным аргумент, что программист может так запросто перепутать 2 разных класса, с разными названиями и методами. Если ваш программист настолько неадекватен, то он и флаг по ошибке забудет включить/выключить softwarer Простите, но я очень удивлен этим возражением. Вы так говорите, словно я не могу прочитать параметр и присвоить его значение переменной, а обязан буду перекомпилить приложение. Вы так говорите, словно Вы можете использовать ConditionalAttribute, а я - нет. хорошо, согласен, хотя вы попросту начинаете написание своей функциональности Trace, которая будет заниматься считкой и проверкой всех этих параметров, вместо использования уже готового решения softwarer реально большие - с флагом я могу включить проверки даже там, где изначально их не было тут не понял, как-это вы включите проверку, если ее там физически нету ? softwarer И теперь Вы вдруг откатываетесь к варианту Trace, глобальному для всего приложения, без всяких верификаторов. 8-) позвольте узнать, на каком основании вы это решили ? softwarer Потому что уже пятьдесят лет как существует принцип модульности, на нем основано в том числе ООП, а высказанное Вами желание нарушает этот принцип. чем именно ? softwarer Вы фактически намекнули, что при вводе с клавиатуры такая проверка не требуется. пардон, опять не понял, это где я так намекнул ? Меня иногда удивляют ваши ответы, мы уже столько много по этому поводу написали, что мне казалась кристально понятной моя идея - верификатор (aka фильтр данных), через который должны проходить все параметры, получаемые не из других методов, а снаружи - типа файла, реестра, ввода пользователем, голосового ввода и тп. При этом верификатор обязан подать на вход бизнес-объектов данные, согласованные с их контрактом, либо послать сообщение заинтересованным лицам о проблемах в параметрах, либо попытаться преобразовать их в допустимые по неким алгоритмам softwarer А теперь - о том, как правильно спроектировать классы в этом примере. В этом примере должны существовать методы: ... Вот и все. И никаких мифических верификаторов, подключаемых по принципу "здесь играем, здесь не играем, а здесь рыбу заворачивали". давайте-ка сначала поймем, правильно-ли я вас понял (а то кажется, что в алгоритме у вас там какая-то опечатка) Имеется класс Монитор, который знает свои допустимые частоты. Есть Видеокарта, которая обладает методом УстановитьЧастоту() Есть МенеджерМонитора, который занимается непосредственно вызовами этих методов. Т.е. когда МенеджерМонитора хочет инициализировать монитор, то он считывает нужную частоту из реестра. Сравнивает ее с допустимыми частотами, полученными от Монитора. Если все нормально, то отдает приказ видеокарте установить частоту. Если не все нормально, то по определенному алгоритму выбирает другую частоту и только затем отдает приказ видеокарте. Если все верно, то объясните, чем ваш МенеджерМонитора отличается от моего верификатора ? Видеокарта принимает приказ и бесприкословно его исполняет. Если данные из реестра негодные, то МенеджерМонитора (aka верификатор) меняет их (либо может на экране нарисовать ошибку о необходимости восстановления реестра) и корректные данные идут в видеокарту. Это в точности мой верификатор. А ваша Видеокарта - в точности мой бизнес-объект, который полностью доверяет входным данным, и не делает никаких проверок и исправлений самостоятельно, потому-что это не его забота. softwarer Вы же, пытаясь заглянуть под юбку, смотря в реализацию, как раз "идеологически" нарушаете инкапсуляцию - как раз то, что я говорил еще в первом письме на эту тему. также объясните мне, почему проверка на допустимость параметров контракту является нарушением инкапсуляции ? Осмелюсь сказать, что внешний интерфейс класса никак не относиться к реализации, и проверяя параметр на допустимость я ну никак не заглядываю в его внутренности. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 08.05.2007, 20:38 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
heyЭто вы заодно и его брате-близнице Trace.Assert() ? Наверное. Уже не помню, что я вчера гонял. Если они ведут себя по сути одинаково, то именно так. heyНу и кроме того, такая резкая точка зрения заслуживает объяснения :) А чего объяснять-то? Я сделал примерно следующий код: Код: plaintext 1. 2. 3. 4. и с глубоким восхищением лицезрел у себя на мониторе фразу Violated twice. Из этого следует однозначный вывод об экстремальном вреде такого вот assert-а в боевом коде. Потому что он: 1. Не защищает приложение от ошибок, всего лишь говорит "сейчас будет плохо". Если бы вместо второго Assert-а стоял код, которому бы от i <= 0 становилось реально плохо - приложению стало бы реально плохо. 2. Выбрасывает совершенно идиотское окно, категорически не удовлетворяющее потребностям пользователя (правда, возможно, это можно отчасти отконфигурить более мягкими средствами, нежели подмена листенера) В итоге я не вижу ситуации, в которой этот инструмент имеет серьезный смысл применять без серьезной доработки. По сути он сводится к моей старой привычке делать класс InternalWarnings - это просто коллекция сообщений, в которую приложение записывает список погрешностей, которые как-нибудь в будущем не мешало бы исправить (типичный пример сообщения - например "Нужно установить текст заголовка у окна A.B.C.D" heyвообще я не думаю, что уважаемые джентельмены, мною процитированные, утверждают это как категорическое правило, это скорее общее руководство, а не закон Ну так изначально Вы хотели максимальной однозначности, того, что я назвал экстремальной точкой зрения :) heyдык плохо-ведь справлялись, потому исключения и придумали :) Ну, исключения придумали не совсем для этого, но вопрос не в этом. Ситуация обратная - научились хорошо справляться с определенным классом задач, и затем эту практику решения обобщили в синтаксически и семантически удобный механизм. heyно вы интересно это сформулировали: "теория очень важна, но нельзя забывать о практике, ведь у нас теория - это обощение практики". Сложно знаете-ли потерять связь с практикой, если даже сама теория суть есть практика A.S. "суть" - это множественная форма глагола "есть". Сказать "суть есть" - это примерно то же самое, что сказать "они есть есть". Не "теория есть практика", а "теория есть обобщение практики". И потерять связь, к сожалению, очень и очень просто. Персонаж, который вроде как имеет знания, способен сказать умные слова о тех же паттернах, но категорически не способен эти знания применить, от взгляда на код которого уши дыбом встают - такой вот персонаж к сожалению не редкость. На этом форуме не так уж редко публикуется код, в котором общие, сверхстандартные фрагменты даже не выделены в подпрограммы - хотя, согласитесь, сейчас вряд ли найдется программист, который не слышал бы о соответствующем принципе. heyНу. Так в чем проблема с message'ами - то ? Поймает message и обработает. Проблема в том, что это плохо подходящий механизм, и его применение потребует лишних усилий. Во-первых, придется заложить тот же самый противный код с постоянным if WasError после каждого чиха. Во-вторых, message посылается либо конкретному адресату, либо каким-либо непрямым механизмом - подпиской, broadcast-ом итп. В первом случае отправитель должен знать, кому посылать - а следовательно как минимум получать такой дополнительный параметр, не говоря о других проблемах. Во втором случае вызывающие должны предпринять меры для того, чтобы в каждый момент времени сообщение обработал только один из них, и именно тот, который нужно. В общем, куча геморроя на пустом месте. heyВо-первых, если среди приведенных мною примеров нет такого, который требует StackTrace, это еще не значит, что идеологии полностью расходяться и этот аттрибут надо удалять. ..... Именно этим я и показываю слабость Вашего аргумента насчет торчащих хвостов. Ради экономии времени я позволю себе не вести Вас по всему пути рассуждений, а просто сформулирую итоговый факт: при отсутствии множественного наследования некоторая избыточность базовых классов часто оказывается лучшим решением, нежели возможные ей альтернативы. heyторчащий хвост. Однако видите-ли в чем дело, его никто отрубать не будет, что-бы иерархию не усложнять. Но это не значит, что под этими знаменами вы можете легко пропихнуть свою утку, больше похожую на волка, аппелируя в том духе, что дескать "чего прикопались к морде, шерсти и клыкам ? Вон на свой иннер эксепшен посмотрите " ... Я и не пропихиваю волка. Я пропихиваю утку, очень похожую на утку, а на Вашу фразу "что-то не похоже на утку, цвет перьев не тот" показываю, что из того, что Вы таки считаете уткой, вообще клыки торчат. Впрочем, сравнение похожести - вопрос философский. Для меня основа похожести - одинаковое поведение (требуемое мне и предоставляемое этим классом, включая его специфическую поддержку со стороны виртуальной машины). Если Вы предпочитаете другой критерий сравнения, вообще говоря нет оснований говорить, что один - правильный, другой - неправильный. Максимум, можно показать откровенную непрактичность какого-то варианта. heyВозможна генерация исключения при правильных предусловиях и правильно выполняющемся методе, когда тем не менее на выходе нарушиться, например, инвариант класса, и нас будет интересовать StackTrace. Возможна. По сути Вы сказали следующее: есть exception-ы, в который StackTrace нужен, есть exception-ы, в который StackTrace не нужен. Если так, это полностью дезавуирует сказанное Вами ранее "StackTrace не нужен - значит не exception". Вот и все, цель, которую я преследовал этим высказыванием, достигнута. heyВо-вторых, библиотеки Microsoft при неверных предусловиях выбрасывают исключения, а не ассерты, и stackTrace там соответственно нужен. А вот это уже просто логически ложное рассуждение, подмена понятий. Из первого факта никак не следует второе утверждение. Мало того, StackTrace там "не нужен", точнее, не нужен везде. Он нужен кое-где, а иметь его везде - удобнее, чем избирательно, вот и все. heyОднако несколько постов назад я уже писал, что мне это поведение не кажется правильным, и цель моего тут присутствия понять логику, стоящую за этим. С нововыявившимся поведением net-овского Assert других вариантов просто нет. Применение исключений в данном случае просто-напросто защищает приложение от разрушения, уменьшает цену допущенной ошибки. В качестве примера - давайте рассмотрим любой map, который не допускает null как значения ключа. Давайте представим, что кто-то вызывает map.Add (null, value). Что будет, если результатом будет ArgumentNullException? Да в общем ничего страшного: получили эту ошибку, программа осталась в работоспособном состоянии. В итоге получим ограниченный отказ - скажем, невозможность обработать файл A - но при этом возможность обработать файл B. А что будет, если будет применен Assert? Да в общем ничего хорошего: выполнение продолжится, внутренняя структура map-а разрушится, объект потеряет работоспособность. В лучшем случае это приведет к каскадным ошибкам где-нибудь дальше по ходу выполнения функции; в худшем - например, если это глобальный объект - приложение навернется нахрен. heyя не понимаю, зачем надо подавать неверные параметры в метод, а потом ловить его ругательства и что-то с ними делать. Гораздо более логично эти параметры сначала проверить на допустимость, а уж затем вызывать объект. По сути Вы снова повторяете мысль "гораздо логичнее не допускать ошибок, нежели защищаться от них". В общем-то да, логичнее. Проблема в том, что технологии, решающие задачу "не допускать ошибок" на сегодняшний день неконкурентноспособны по трудоемкости. heyмне не кажется убедительным аргумент, что программист может так запросто перепутать 2 разных класса, с разными названиями и методами. И снова Вы потрясающе неточны в изложении ситуации. Два разных класса с одинаковым основным предназначением, одинаковыми методами и разными деталями реализации, никак не видимыми в интерфейсе этого класса. Перепутать он может достаточно легко, если мы говорим не об учебных проектах на десять классов, а о реальной задаче. Одна из аксиом практического программирования звучит так: "Ни один человек не знает всю систему и все ее особенности на уровне, достаточном для того, чтобы сходу решать практические задачи ее развития сопровождения. А даже если знает - это временное счастье, которое рано или поздно закончится и на которое не следует полагаться". Из этого следует, что ряд программистов будут знать о существовании одного из этих классов и не знать о существовании другого. Вот и все - раз Вы знаете решение и оно единственно, Вы им и пользуетесь. heyЕсли ваш программист настолько неадекватен, Это, кстати, еще одна аксиома технологии - в более-менее больших командах ряд программистов неадекватен, и пример софтверных гигантов ее хорошо подтверждает. Из этого следует, что технология должна быть сколь возможно устойчива к неадекватности программистов. Этот вывод сделан давно и никем не оспаривается - подумайте хотя бы о том, что private/protected методы суть как раз защита от неадекватности; адекватным программистам хватило бы и строки "не вызывайте этот метод извне" в комментарии либо документации. heyто он и флаг по ошибке забудет включить/выключить Наконец-то до Вас дошло, уж извините. Именно поэтому я и хочу, чтобы по умолчанию проверка была включена и ее требовалось специально отключать; в этом случае программист если и забудет, то в безопасную сторону. У Вас же проверка по умолчанию отключена, чтобы ее включить, надо начать использовать другой класс - а следовательно, забывчивый программист становится обезьяной с гранатой. heyхорошо, согласен, хотя вы попросту начинаете написание своей функциональности Trace, которая будет заниматься считкой и проверкой всех этих параметров, вместо использования уже готового решения Исключительно потому, что Вы на ходу меняете требования. Вы поставили задачу - я показал, как ее решать. Стандартный Trace, кстати, эту задачу не решает. Тогда Вы поменяли условия "под стандартный Trace" и сказали: уж эту-то задачу не решит. Я показал, что решит, точно так же как решает стандартный Trace. И теперь Вы говорите "Но стандартный Trace решит эту задачу лучше" - то есть по сути совсем отказываетесь от той задачи, которую ставили в начале. Это, конечно, упрощенное изложение нашей беседы, но в обсуждаемом аспекте канва именно такова. Выглядит так, как будто Вы приняли как аксиому "нужно использовать Trace" и исходя из этого, подбираете аргументы. hey softwarer реально большие - с флагом я могу включить проверки даже там, где изначально их не было тут не понял, как-это вы включите проверку, если ее там физически нету ? И снова Вы неточно излагаете. Я сказал "включить", в смысле turn on. С флагами я могу вытворить то, что с любой техникой предкомпиляции, в том числе ConditionalAttribute, не получится. Скажем, при наличии в объекте соответствующего сервиса я могу повесить на этот флаг listener, который будет ловить попытки его сбросить и восстанавливать флаг обратно - и таким образом, если Вы написали код "без проверок", включить в нем проверки. Вы же с Вашей идеей отдельностоящего верификатора решить такую задачу сможете только коррекцией исходников. hey softwarer И теперь Вы вдруг откатываетесь к варианту Trace, глобальному для всего приложения, без всяких верификаторов. 8-) позвольте узнать, на каком основании вы это решили ? По Вашему изложению. Сначала Вы говорили о "бизнес-объект отдельно, верификатор отдельно, здесь играем, здесь не играем". А потом вдруг перешли на примеры с Trace, который включается и выключается при минимальной перекомпиляции, но целиком - "здесь играем, здесь не играем" уже не получится. hey softwarerПотому что уже пятьдесят лет как существует принцип модульности, на нем основано в том числе ООП, а высказанное Вами желание нарушает этот принцип. чем именно ? Нарушением независимости модуля. Желание "знать, кто меня вызвал, и действовать слегка по-разному в зависимости от этого" - классически неправильное в этом смысле. Впрочем, если Вас утешит, оно не такое уж редкое. Вы не представляете, какими словами мы крыли индусов из Oracle, когда в поисках ответа на вопрос "почему вот эта библиотека в составе Oracle Discoverer работает, а у нас - глючит" мы дизассемблировали ее и обнаружили в ряде мест условия вида "если работаем в Discoverer, то...." hey softwarer Вы фактически намекнули, что при вводе с клавиатуры такая проверка не требуется. пардон, опять не понял, это где я так намекнул ? Ну судите сами. Вы сказали Вот возьмем довольно простой пример - в свойствах монитора вашего компьютера вы сможете найти такой параметр как Частота обновления экрана. Там-же рядом стоит галка "Скрыть режимы, которые монитор не может использовать" (так как это может привести к неустойчивой работе и даже поломке). .... При считывании данных из реестра (или уж откуда они там считываются) данные необходимо проверять на допустимость. ..... Вместе получается: во втором случае данные надо проверять, в первом об этом не сказано, видимо, не надо. Попрошу обратить внимание: этот пример как раз довольно ярко показывает порочность идеи вынесенного верификатора. То ли Вы забыли упомянуть, то ли подразумевали что-то, мной не понятое, но факт в том, что если бы Вы дали мне именно это задание именно так, а я его выполнил на уровне честного кодера - результатом был бы кривой код. Не так важно, кто из нас виноват, важен результат взаимодействия двух не самых неадекватных разработчиков. heyМеня иногда удивляют ваши ответы, мы уже столько много по этому поводу написали, что мне казалась кристально понятной моя идея Тем не менее, если посмотреть выше, получается, что моя вина в том, что я не домыслил за Вас то, что Вы не сказали. Так вот, вспоминая то, чего я хочу: я хочу, чтобы в таких случаях по умолчанию проверка работала. Чтобы Вы, формулируя для меня ТЗ, называли не те частые случаи, когда проверка нужна, а те редкие случаи, когда ее стоит отключить. Чтобы я, ошибившись, сделал "лишнюю проверку" вместо "недостаточной проверки". То и иное пойдет на пользу качеству программы. heyдавайте-ка сначала поймем, правильно-ли я вас понял (а то кажется, что в алгоритме у вас там какая-то опечатка) Мне кажется, Вы в первую очередь неправильно поняли тот момент, что я не зря разделил ответ на две части, отвечающих каждая на свою квоту. Вы поставили маленькую и простую задачу - я показал, как стоит решать ее. Дальше Вы сказали следующее: "даже если так, вот другая задача" - и я показал, как решение будет нарастать в ту сторону. heyЕсть МенеджерМонитора, который занимается непосредственно вызовами этих методов. Пожалуй, правильнее было бы назвать класс МенеджерВидеосистемы. А еще правильнее - ЗагрузчикВидеосистемы. heyТ.е. когда МенеджерМонитора хочет инициализировать монитор, то он считывает нужную частоту из реестра. Сравнивает ее с допустимыми частотами, полученными от Монитора. Зачем дублировать код? Просто пихает ее в ВидеоКарта.УстановитьЧастоту. heyЕсли все верно, то объясните, чем ваш МенеджерМонитора отличается от моего верификатора ? Я действительно плохо нарисовал этот момент, попробую объяснить. МенеджерМонитора, который правильнее было бы назвать ЗагрузчикВидеосистемы, нарисован здесь как часть решения одной конкретной задачи - настройки оборудования при загрузке. Он берет на себя такие задачи как "слазить в реестр", "посмотреть в профиль", "посмотреть в данные последней удачной загрузки" и все прочее, что захочется именно в этом случае. Он не занимается проверкой данных на совместимость с монитором (кроме как реакцией на исключение) и используется в этом единственном месте. При изменении частоты монитора пользователем через интерфейс - он не используется. В этом случае будет сделано нечто типа Код: plaintext 1. 2. 3. 4. 5. Таким образом, надеюсь, ответ дан - МенеджерМонитора я позиционировал как инициатора, не как верификатор. Можно проиллюстрировать так: у меня два объекта, Менеджер (инициатор с функцией коррекции) и Монитор (исполнитель с функцией верификации). Вы предлагаете сделать третий объект, между ними, вынеся в него названные функции. Здесь я бы заодно подчеркнул еще одну проблему такого подхода: правила верификации неотрывны от исполнителя (каждое изменение исполнителя требует изменений в верификаторе), а вот корректор не то что отрывен, а так и даже может существовать в разных версиях внутри одной задачи. Так что если разделять, то уж не на три объекта, а на четыре. Кстати, обратите внимание на CheckBox.Checked - при использовании верификатора в этом месте пришлось бы писать нечто неуклюжее, типа Код: plaintext 1. 2. 3. - думаю, Вы согласитесь, что это плохой код - либо же делать метод типа Код: plaintext что и вовсе идиотизм. heyА ваша Видеокарта - в точности мой бизнес-объект, который полностью доверяет входным данным, и не делает никаких проверок и исправлений самостоятельно, потому-что это не его забота. Хм. А параметр ДажеЕслиНеПоддерживаетсяМонитором я, выходит, зря выделял? hey softwarer Вы же, пытаясь заглянуть под юбку, смотря в реализацию, как раз "идеологически" нарушаете инкапсуляцию - как раз то, что я говорил еще в первом письме на эту тему. также объясните мне, почему проверка на допустимость параметров контракту является нарушением инкапсуляции ? При чем тут? Я обратил внимание на тот факт, что Вы начали думать о том, как устроен внутри тот метод, который мы обсуждаем - то ли проверка "в нем самом", то ли "где-то еще". Вот именно это "думать, как устроен внутри" и есть нарушение инкапсуляции, самое что ни на есть натуральное. Модульного программиста должно интересовать только "как вызывать" и "что я получу в ответ". ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.05.2007, 00:34 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
softwarer и с глубоким восхищением лицезрел у себя на мониторе фразу Violated twice. Из этого следует однозначный вывод об экстремальном вреде такого вот assert-а в боевом коде. Потому что он: 1. Не защищает приложение от ошибок, всего лишь говорит "сейчас будет плохо". Если бы вместо второго Assert-а стоял код, которому бы от i <= 0 становилось реально плохо - приложению стало бы реально плохо. 2. Выбрасывает совершенно идиотское окно, категорически не удовлетворяющее потребностям пользователя (правда, возможно, это можно отчасти отконфигурить более мягкими средствами, нежели подмена листенера) Во-первых, при дефолтной обработке вас спрашивают, продолжать-ли работу или нет. Во-вторых, обработав assert вы можете получить то поведение (и окно), которое хотите. Поэтому мне непонятны подобные наезды softwarer Проблема в том, что это плохо подходящий механизм, и его применение потребует лишних усилий. Во-первых, придется заложить тот же самый противный код с постоянным if WasError после каждого чиха. Хм. Задача метода верификатора – проверить параметр и по результату проверки предпринять какие-то действия. Чего ради там появиться “противный код с постоянным if WasError после каждого чиха” ? softwarer Во втором случае вызывающие должны предпринять меры для того, чтобы в каждый момент времени сообщение обработал только один из них, и именно тот, который нужно Во первых, почему это вы вдруг ограничили возможность получения этого сообщения другими классами ? Если еще кто-то хочет узнать об этом событии, почему мы должны вставлять ему палки в колеса ? Ну а если вдруг у вас несколько разных объектов одновременно будут выдавать одинаковые окна предупреждения или делать еще какую-нибудь ерунду, так это пардон претензии предъявляйте к архитектуре, а не классу обработки данных из внешнего мира. Видимо вы отдали ее в разработку тому самому неадекватному программисту, способному спутать 2 разных класса :) softwarer Именно этим я и показываю слабость Вашего аргумента насчет торчащих хвостов Ну вообще-то это не такой уж и слабый аргумент. Да, если появляется лишний хвост, это еще не говорит о том, что утку нужно отправлять в кунтцкамеру. Однако вы должны насторожиться, направить в эту точку все локаторы и как следует прозондировать обстановку на местности. Лишний хвост – это один (из нескольких возможных) камней, которые могут перетянуть весы в сторону другого решения. Один он этого может не сможет. Зато в совокупности с другими - легко softwarer Возможна. По сути Вы сказали следующее: есть exception-ы, в который StackTrace нужен, есть exception-ы, в который StackTrace не нужен. Если так, это полностью дезавуирует сказанное Вами ранее "StackTrace не нужен - значит не exception". Вот и все, цель, которую я преследовал этим высказыванием, достигнута. … А вот это уже просто логически ложное рассуждение, подмена понятий. Из первого факта никак не следует второе утверждение. Мало того, StackTrace там "не нужен", точнее, не нужен везде. Он нужен кое-где, а иметь его везде - удобнее, чем избирательно, вот и все. Это уже не первый случай, когда вы самостоятельно домысливаете мои слова, делаете из них выводы и на основе этих выводов строите разоблачительную речь. Я в своих постах стараюсь не использовать превосходных степеней типа “всегда”, “без исключения” итп. Исключения есть всегда, и я полагал, что мне не нужно каждое предложение разбавлять словами “в большинстве случаев”, “практически” и им подобными. Конечно если вы настаиваете, я могу начать так делать, что безусловно увеличит размер постов в пару раз. softwarer С нововыявившимся поведением net-овского Assert других вариантов просто нет. Применение исключений в данном случае просто-напросто защищает приложение от разрушения, уменьшает цену допущенной ошибки. В качестве примера - давайте рассмотрим любой map, который не допускает null как значения ключа. Давайте представим, что кто-то вызывает map.Add (null, value). Что будет, если результатом будет ArgumentNullException? Да в общем ничего страшного: получили эту ошибку, программа осталась в работоспособном состоянии. В итоге получим ограниченный отказ - скажем, невозможность обработать файл A - но при этом возможность обработать файл B. А что будет, если будет применен Assert? Да в общем ничего хорошего: выполнение продолжится, внутренняя структура map-а разрушится, объект потеряет работоспособность. В лучшем случае это приведет к каскадным ошибкам где-нибудь дальше по ходу выполнения функции; в худшем - например, если это глобальный объект - приложение навернется нахрен. Вообще-то работа программы после ассерта полностью программируется вами, если хотите – выполнение продолжиться, не хотите – нет. Так что все зависит только от вас, если приложение нахрен навернется, то винить можете только себя :) Что-бы получить ошибку и оставить программу в рабочем состоянии, вам надо поставить на нее catch(ArgumentNullException). Если вы просто проверите аргумент перед вызовом, то тоже оставите программу в рабочем состоянии. В чем разница-то ? softwarer По сути Вы снова повторяете мысль "гораздо логичнее не допускать ошибок, нежели защищаться от них". В общем-то да, логичнее. Проблема в том, что технологии, решающие задачу "не допускать ошибок" на сегодняшний день неконкурентноспособны по трудоемкости. Вы наверно будете опять шокированы, но я, в обход непреодолимым трудностям, все-же смогу проверить аргумент на null и число на неотрицательность. А в тех случаях, когда это по определенным причинам проблематично, то выкинуть эксепшн. Например в вышеприведенном классе Автомобиль, когда мы не проверяем, не превысим-ли предельно допустимую скорость, а ускоряемся и ловим ошибку. softwarer И снова Вы потрясающе неточны в изложении ситуации. Два разных класса с одинаковым основным предназначением, одинаковыми методами и разными деталями реализации, никак не видимыми в интерфейсе этого класса. 8-) Т.е. бизнес-объект и фильтр, процеживающий данные вы называете классами “с одинаковым основным предназначением и одинаковыми методами” ? Однако. softwarer Это, кстати, еще одна аксиома технологии - в более-менее больших командах ряд программистов неадекватен, и пример софтверных гигантов ее хорошо подтверждает. Из этого следует, что технология должна быть сколь возможно устойчива к неадекватности программистов. Этот вывод сделан давно и никем не оспаривается - подумайте хотя бы о том, что private/protected методы суть как раз защита от неадекватности; адекватным программистам хватило бы и строки "не вызывайте этот метод извне" в комментарии либо документации Не спорю, возможно. А как это относиться к нашему обсуждению ? Если вы забыли, то проверки в бизнес-объекте никто и не отменял, там ассерты стоят. Они могут быть отключены в релизе при некоторых обстоятельствах, но при тестировании они там совершенно точно есть softwarer Наконец-то до Вас дошло, уж извините. Именно поэтому я и хочу, чтобы по умолчанию проверка была включена и ее требовалось специально отключать; в этом случае программист если и забудет, то в безопасную сторону. У Вас же проверка по умолчанию отключена, чтобы ее включить, надо начать использовать другой класс - а следовательно, забывчивый программист становится обезьяной с гранатой. Аналогично. Обезьяны с гранатами увидев ассерты идут лесом softwarer Исключительно потому, что Вы на ходу меняете требования. Вы поставили задачу - я показал, как ее решать. Стандартный Trace, кстати, эту задачу не решает. Тогда Вы поменяли условия "под стандартный Trace" и сказали: уж эту-то задачу не решит. Я показал, что решит, точно так же как решает стандартный Trace. И теперь Вы говорите "Но стандартный Trace решит эту задачу лучше" - то есть по сути совсем отказываетесь от той задачи, которую ставили в начале. Уж простите, ерунда. Задача как была в самом начале, так и осталась в неизменном виде. softwarer И снова Вы неточно излагаете. Я сказал "включить", в смысле turn on. С флагами я могу вытворить то, что с любой техникой предкомпиляции, в том числе ConditionalAttribute, не получится. Скажем, при наличии в объекте соответствующего сервиса я могу повесить на этот флаг listener, который будет ловить попытки его сбросить и восстанавливать флаг обратно - и таким образом, если Вы написали код "без проверок", включить в нем проверки. Вы же с Вашей идеей отдельностоящего верификатора решить такую задачу сможете только коррекцией исходников. А вот тут как раз вы начинаете добавлять к задаче доп. функциональность, которая изначала отсутствовала, но теперь вдруг стала необходимой, и по счастливому стечению обстоятельств она решается именно вашим методом ! softwarer Нарушением независимости модуля. Желание "знать, кто меня вызвал, и действовать слегка по-разному в зависимости от этого" - классически неправильное в этом смысле. Впрочем, если Вас утешит, оно не такое уж редкое. Вы не представляете, какими словами мы крыли индусов из Oracle, когда в поисках ответа на вопрос "почему вот эта библиотека в составе Oracle Discoverer работает, а у нас - глючит" мы дизассемблировали ее и обнаружили в ряде мест условия вида "если работаем в Discoverer, то...." Не понял сравнения. Никаких “если работаем через верификатор …” у меня нет. Бизнес-объект понятия о нем не имеет. softwarer Вместе получается: во втором случае данные надо проверять, в первом об этом не сказано, видимо, не надо. Попрошу обратить внимание: этот пример как раз довольно ярко показывает порочность идеи вынесенного верификатора. То ли Вы забыли упомянуть, то ли подразумевали что-то, мной не понятое, но факт в том, что если бы Вы дали мне именно это задание именно так, а я его выполнил на уровне честного кодера - результатом был бы кривой код. Не так важно, кто из нас виноват, важен результат взаимодействия двух не самых неадекватных разработчиков. Все-таки может будем различать обсуждения в форуме и тех. задание честным кодерам? Кстати обратите внимание, вы опять домыслили нечто на совершенно ровном месте. Пожалуйста, будьте аккуратнее. softwarer Я действительно плохо нарисовал этот момент, попробую объяснить. Так, значит ЗагрузчикВидеосистемы считывает данные из реестра, и неглядя пихает их в ВидеоКарту. Она получает список допустимых частот от Монитора, и в случае несовпадения выкидывает ексцепшн. Этот ексцепшн ловиться ЗагрузчикомВидеосистемы, который применяет какой-то алгоритм для коррекции частоты (взять дефолтную или из профиля компьютера). После чего засылает уже исправленную частоту в ВидеоКарту. Уже понятнее, но теперь непонятно, почему ЗагрузчикВидеосистемы сам не может проверить допустимость частоты. Кому будет хуже, если он сам прочитает допустимые частоты от Монитора (они-же все равно доступны всем) и применит алгоритм коррекции до того, как посылать их ВидеоКарте ? Имхо, куда логичнее. Ну и надеюсь вы понимаете, что в этом случае он все-таки превращается в верификатор softwarer Вы предлагаете сделать третий объект, между ними, вынеся в него названные функции. Здесь я бы заодно подчеркнул еще одну проблему такого подхода: правила верификации неотрывны от исполнителя (каждое изменение исполнителя требует изменений в верификаторе), а вот корректор не то что отрывен, а так и даже может существовать в разных версиях внутри одной задачи. Так что если разделять, то уж не на три объекта, а на четыре. Хм, нет, зачем третий объект, если все эти функции и так в ЗагрузчикеВидеосистемы ? Он сам верификатор. Кстати конкретно в этом случае при изменении допустимых частот Монитором коррекции для ЗагрузчикаВидеосистемы и не требуется, он-же не хранит их в себе, а получает от Монитора. [soft] При чем тут? Я обратил внимание на тот факт, что Вы начали думать о том, как устроен внутри тот метод, который мы обсуждаем - то ли проверка "в нем самом", то ли "где-то еще" [/] потому-что эта проверка может оказаться вне компетенции этого метода. При чем тут вообще инкапсуляция ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.05.2007, 18:36 |
|
||
|
Assert vs. Exception
|
|||
|---|---|---|---|
|
#18+
Дискуссия достаточно интересная, но стала уже через чур длинной. По-моему вы слишком увлеклись утками и перестали слушать друг-друга. Наверное, вы уже потеряли всякую надежду убедить друг-друга и работаете "на публику". Со мной могут не соласиться, но такие длинные посты "убивают" желание вчитываться и анализировать. Я думаю, что вам надо постараться не цепляться к словам, а постараться предельно коротко (на мой взгляд наиболее выразительный и лаконичный язык - программный код) сформулировать суть своей точки зрения. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.05.2007, 09:19 |
|
||
|
|

start [/forum/topic.php?all=1&fid=16&tid=1346065]: |
0ms |
get settings: |
6ms |
get forum list: |
15ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
173ms |
get topic data: |
10ms |
get forum data: |
2ms |
get page messages: |
63ms |
get tp. blocked users: |
2ms |
| others: | 213ms |
| total: | 490ms |

| 0 / 0 |
