|
|
|
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?fid=16&msg=34513934&tid=1346065]: |
0ms |
get settings: |
10ms |
get forum list: |
15ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
167ms |
get topic data: |
10ms |
get forum data: |
2ms |
get page messages: |
48ms |
get tp. blocked users: |
1ms |
| others: | 246ms |
| total: | 507ms |

| 0 / 0 |
