Re[7]: –
От: Qbit86 Кипр
Дата: 12.08.10 13:25
Оценка: 45 (4) +3
Здравствуйте, 0K, Вы писали:

Q>>Предлагаю впредь не использовать термин «пользователь», а употреблять «конечный пользователь и «пользователь API».


0K>Давайте проще: разработчик, разработчик библиотеки и пользователь. Деньги откуда идут? От конечного пользователя. Нахрен вообще о программистах говорить?


Откровенная ерунда.

Q>>Библиотека даже не знает, будет ли конечным пользователем человек, или, скажем, сервис без пользовательского интерфейса.


0K>Собственно да. И что вы предлагаете вообще не делать понятных пользователю сообщений об ошибках в библиотеках?


В этой и соседних ветках я насчитал от тебя не менее пяти фраз (адресованных разным собеседникам) типа «т.е. вы предлагаете <и далее свои фантазии, желательно, легко опровергаемые>.» Раздражает. Например, было: «Т.е. вы предлагаете вернуться к кодам ошибок? (И ещё четыре вопросительных знака.)» То, что ты предлагаешь — оно и есть, только имеет тип не int, а string, и называется не код ошибки, а сообщение исключения.

Информация об ошибке передаётся:
1) В типе исключения. Позволяет сепарировать исключения в момент ловли.
2) В полях исключения. Позволяет восстанавливать контекст исключения, состояние возникновение ошибки.
3) В тексте сообщения. В случае usage exception'ов содержит указание, как изменить код, чтобы избежать выброс исключения; ориентировано на пользователя API. В случае runtime-исключения содержит сообщение о причинах исключения в меру своей осведомлённости; ориентировано на пользователя API или конечного пользователя. В подавляющем большинстве случаев это сообщение нельзя отображать в UI — в нём либо содержатся избыточные детали, либо, наоборот, отсутствует контекст. Например, стандартные коллекции не знают, что работают со списком пользовательских аккаунтов, их сообщения по простоте душевной оперируют терминами «элемент коллекции».

0K>Читайте внимательнее: библиотека не всегда знает ХУЖЕ вызывающего кода. Т.е. часто именно библиотека знает настоящие причины возникновения ошибки и может выдать пользователю нужную информацию.


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

Вот ты приводил пример, когда у тебя стописят разных ошибок, и все возвращаются через один класс EndUserFriendly-исключения, отличаясь только сообщениями. Отлично, ты просто выводишь месседж. А завтра начальник говорит тебе: а в случае, если тип ошибки «Номер +755щ2713141 имеет ниверный формат.», выдавать не сообщение с орфографической ошибкой, а окошко ввода нового номера. И у тебя начнётся ад. Тебе придётся сепарировать исключения по тексту сообщения. Да не просто равенством, а парсингом. Да учесть все возможные (как существующие, так и будущие) локализации. Это намного, намного хуже кодов ошибок! Ты проклянёшь автора библиотеки, который взял на себя смелость вместо пользователя API решать, что увидит конечный пользователь.

Q>>Рассмотрим стандартное исключение FileNotFoundException. Оно содержит ApiUserFriendly-сообщение «Could not find file 'temp_6B8FCD97.xml'.» плюс дополнительное поле ex.FileName, равное «temp_6B8FCD97.xml».

Q>>При трансляции конечному пользователю сообщение может превратиться в EndUserFriendly-сообщение, например, в такое: «Нет доступа к файлу с данными о днях рождения ваших друзей.»

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


Если нужно — легко. В классе FileNotFoundException содержится поле ex.FileName. Мне не важно, что в поле ex.Message содержится «Файл „filename.xml“ не найден». Я всегда смогу (и по умолчанию — буду) формировать своё сообщение, допустим, «Проверьте, пожалуйста, наличие файла {0}.»; и подставлю ex.FileName, а не выпарсенное между кавычками название файла.
Глаза у меня добрые, но рубашка — смирительная!
Re[9]: Исключения для пользователя и для программиста -- раз
От: Undying Россия  
Дата: 12.08.10 11:47
Оценка: 3 (1) +6
Здравствуйте, 0K, Вы писали:

0K>Здравсти! MSDN изредка почитывайте. Локализация сообщений об ошибках -- обязательное требование. Почему, по вашему, MS сами локализуют сообщения об ошибках в своей .Net платформе?


Потому что уроды. Найти информацию по англоязычному сообщению об ошибке в инете достаточно реально, а вот по русскому увы — вероятность на порядок-другой ниже. Соответственно правильный подход, это локализованное пользовательское сообщение об ошибке и нелокализованный текст собственно исключения, который показывается по кнопочке Advansed. Это удобно и для пользователя, и для программиста.
Re[3]: Исключения для пользователя и для программиста -- раз
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 12.08.10 08:53
Оценка: +5 :)
Здравствуйте, 0K, Вы писали:

0K>Здравствуйте, mrjeka, Вы писали:


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


0K>Нет. Исключения верхнего уровня в каждой конкретной библиотеке должны быть понятны пользователю.

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

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

Запомни, все исключения для программистов, что увидит пользователь не должно завязываться на исключения (или другой механизм репортинга ошибок).
Re[7]: Исключения для пользователя и для программиста -- раз
От: mrjeka Россия  
Дата: 12.08.10 09:34
Оценка: +4
Здравствуйте, 0K, Вы писали:

0K>А вот как узнать можно ли данное сообщение выводить пользователю? Является ли оно UserFriendly? Вот этого механизма и не хватает. Понимаете о чем речь? Ведь в сообщении могут быть очень полезные 0K>данные (имя файла, имя сетевой ошибки и пр.) а могут быть абсолютно не понятные пользователю контрактные данные (которые выводить ни в коем случае нельзя).


Не надо узнавать. Ответ ниже.

M>>Если уж библиотека должна выдавать читабельные эксепшены


0K>А кто должен выдавать? Вот вызываете вы метод для перевода денег со счета на банковскую карту. И он выдает исключение: превышен лимит операций. А вы что пользователю скажите? НЕ удалось перевести средства? И все? А причину он откуда может узнать? Может просто сетевая ошибка? А может его счет заблокирован по подозрению в мошенничестве? А может денег нет? Откуда бедному пользователю узнать, что именно превышен лимит операций?


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


0K>Ничего парсить не нужно, что за глупости. НЕ позорьтесь... сообщения парсить. По MSDN сообщения должны быть оформлены грамматически правиьлно и локализованы. Что вы парсить еще будете??


Про парсинг сообщений я ничего не говорил! Разбирать нужно сам exception!!! Вы получаете exception определенного типа. На основании этого можете построить свое сообщение. Бред писать локализацию к библиотеке. Локализация к приложению — ДА. Вы знаете заранее где и как будет использоваться библиотека?

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

0K>Вот только как узнать является ли исключение контрактным или предназначено для вывода пользователю -- этого механизма нет.


Да и не нужен этот механизм!!! Бросьте привычку выдавать пользователю e.Message. Если основная информация будет лежать в InnerException, что тогда???

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


0K>Зачем изменять, не понял?


Ну представьте, сообщение File 'имя файла' not found. Пользователь не рубит на английском. Тип исключения FileNotFoundException. Разумнее на основании типа полученного исключения в UI части обратиться к файлу локализации, достать нужное сообщение на нужном языке и выдать его пользователю.

M>>Я поэтому никогда не вывожу пользователю содержание исключения.

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

0K>Ну хорошо. Вот возникла ошибка при попытке перевести деньги со счета на банковскую карту. Вы что напишите? Не удалось перевести средства? Причин же может быть десятки! И это очень важно для пользователя.


Библиотека может передавать на клиента всю необходимую информацию об ошибке. Какие детали выводить пользователю решает программист.
Пусть тогда библиотека возвращает разные типы исключений.
Re[5]: Исключения для пользователя и для программиста -- раз
От: Qbit86 Кипр
Дата: 12.08.10 07:30
Оценка: 4 (2) +1
Здравствуйте, 0K.

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

0K>В том то и дело, что не всегда библиотека знает проблему хуже вызывающего кода (от вызывающего сокрыты детали). Вот при подключении к базе -- именно библиотека должна выдать UserFriendly-исключение.


ApiUserFriendly-исключение, а не EndUserFriendly. Библиотека не знает, что для конечного пользователя будет более friendly: текст на корейском, формат даты ISO-8601, упоминание смещения в файле, начиная с которого пошли некорректные данные, etc. Библиотека даже не знает, будет ли конечным пользователем человек, или, скажем, сервис без пользовательского интерфейса.

Кроме того, помимо текста сообщения в кастомном ApiUserFriendly-исключении могут хранится и другие данные, уточняющие причину исключения.

0K>В том то и дело, что не всегда библиотека знает проблему хуже вызывающего кода (от вызывающего сокрыты детали).


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

0K>По поводу вашего примера. Давайте более подробно.


Рассмотрим стандартное исключение FileNotFoundException. Оно содержит ApiUserFriendly-сообщение «Could not find file 'temp_6B8FCD97.xml'.» плюс дополнительное поле ex.FileName, равное «temp_6B8FCD97.xml».
При трансляции конечному пользователю сообщение может превратиться в EndUserFriendly-сообщение, например, в такое: «Нет доступа к файлу с данными о днях рождения ваших друзей.»
Глаза у меня добрые, но рубашка — смирительная!
Re[8]: Модератору
От: Qbit86 Кипр
Дата: 12.08.10 13:33
Оценка: 1 (1) +2
Реквестирую неудаление этой темы, несмотря на соответствующую пометку.
Глаза у меня добрые, но рубашка — смирительная!
Re[5]: Исключения для пользователя и для программиста -- раз
От: mrjeka Россия  
Дата: 12.08.10 08:00
Оценка: +3
Здравствуйте, 0K, Вы писали:

0K>Пользователь приложения использует и библиотеку. И в некоторых случаях именно библиотека должна выдвать UserFriendly-исключения.


Ну если уж у вас пользователи напрямую используют библиотеку, без какого либо UI-layer, тогда да. Этот вариант и нужен.

Я подразумевал стандартную архитектуру приложения.
UI работает с какой-либо библиотекой. Эта библиотека возвращает исключения в голом виде (как произошло так и возвращает).

Обработка в UI


try
{
Lib.GetData();
}
catch(Exception e)//Опустим пока подробности с типами исключений
{
  //Запись в лог
  Log.Write(e);
  //Вывод пользователю
  //Не факт, что e.Message содержит текст сообщения в читабельном виде... Мало ли, мож еще и перевести надо
  //Мало того, зачастую бывает что в e.Message вообще ничего разумного нет, а лежит в InnerException
  Console.WriteLine(GetFriendlyMessage(e));
}

private string GetFriendlyMessage(Exception e)
{
  //Делайте что хотите, как хотите, так и парсите этот эксепшн. Выдавайте какие угодно сообщения пользователю. 
}


0K>Или библиотека для работы с интерфейсами какого-нибудь финансового сервиса. 90% ошибок контрактные -- пользователю их ни в коем случае показывать нельзя. Но есть и UserFriendly -- исчерпан лимит операций, нет денег на счету и пр. Они понятны и нужны пользователю. Как программист, использующий вашу библиотеку узнает, что сообщение именно ЭТИХ исключений нужно отобразить пользователю?


Если уж библиотека должна выдавать читабельные эксепшены

Lib
....
try
{
  ...
}
catch(SqlException se)//не удалось подключиться 
{
  trow new SqlException("Не удалось подключиться к базе данных (можете распарсить текущий эксепшн и сформировать какое угодно сообщение)",se);
}
...


0K>Вы что не поняли? Речь не о системных исключениях. А о UserFriendly, которые содержат важный для пользователя Message.


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

M>>Пользователей за идиотов никто не считает. Сообщить — не значит выдать Exception в том виде, в котором он есть.


0K>Еще раз: контрактные исключения выдвать нельзя. UserFriendly нужно выдать, они содаржат важную информацию. Как вы отличаете исключения которые содержать важную для пользователю информацию от контрактных исключений?


Я поэтому никогда не вывожу пользователю содержание исключения.
Все содержание исключения пишется в лог или как-то обрабатывается. Для пользователя формируется сообщение относительно типа исключения.
Re[8]: Исключения для пользователя и для программиста -- раз
От: 0K Ниоткуда  
Дата: 12.08.10 09:59
Оценка: :)))
Здравствуйте, mrjeka, Вы писали:

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


Не одного типа, а наследуемые от одного типа. Естественно свои классы, но наследуемые от специального типа.

0K>>Ничего парсить не нужно, что за глупости. НЕ позорьтесь... сообщения парсить. По MSDN сообщения должны быть оформлены грамматически правиьлно и локализованы. Что вы парсить еще будете??


M>Бред писать локализацию к библиотеке. Локализация к приложению — ДА. Вы знаете заранее где и как будет использоваться библиотека?


Это не бред, а стандарт. .Net библиотеки и те локализованы.

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

M>Да и не нужен этот механизм!!! Бросьте привычку выдавать пользователю e.Message. Если основная информация будет лежать в InnerException, что тогда???


Тогда вывести Message от InnerException. А какие могут быть варианты? Как вы предлагает передавать сообщения из библиотеки в приложение?

M>Ну представьте, сообщение File 'имя файла' not found. Пользователь не рубит на английском. Тип исключения FileNotFoundException. Разумнее на основании типа полученного исключения в UI части обратиться к файлу локализации, достать нужное сообщение на нужном языке и выдать его пользователю.


Открою страшную тайну. Если пользователь не знает английского, у него будет русский (к примеру) Windows и русский .Net. В отличии от вас, MS локализуют все свои библиотеки. Сообщения об ошибках там на русском языке.

0K>>Ну хорошо. Вот возникла ошибка при попытке перевести деньги со счета на банковскую карту. Вы что напишите? Не удалось перевести средства? Причин же может быть десятки! И это очень важно для пользователя.


M>Библиотека может передавать на клиента всю необходимую информацию об ошибке. Какие детали выводить пользователю решает программист.


Как раз таки может и должна. Вы думаете почему существует ТРЕБОВАНИЕ ЛОКАЛИЗОВАТЬ СООБЩЕНИЯ ОБ ОШИБКАХ???

M>Пусть тогда библиотека возвращает разные типы исключений.


Вы хоть представляете какую вы сейчас ерунду спороли? Вы знаете сколько может быть вариантов почему деньги со счета на карту перевести не удалось? Около сотни. И вы будете создавать и обрабатывать все 100 типов исключений Атхнитесь!!!

Прочтите MSDN и локализуйте свои библиотеки. Это не рекомендация -- это ТРЕБОВАНИЕ!!!
Re[11]: Резюме
От: Qbit86 Кипр
Дата: 23.08.10 11:51
Оценка: 17 (2)
Здравствуйте, 0K.

http://bik-top.livejournal.com/49233.html
Глаза у меня добрые, но рубашка — смирительная!
Re[2]: Исключения для пользователя и для программиста -- раз
От: Qbit86 Кипр
Дата: 12.08.10 06:39
Оценка: 8 (2)
Здравствуйте, SE, Вы писали:

SE>Насколько помню, для случаев нарушения целостности классов рекомендуется наследоваться от InvalidOperationException, для случаев нарушения работы программы (это именно случай, когда нужно сообщить об ошибке) от ApplicationException.

SE>Что не так?

От ApplicationException не рекомендуется наследоваться: «Do derive custom exceptions from the T:System.Exception class rather than the T:System.ApplicationException class.» http://msdn.microsoft.com/en-us/library/ms229007.aspx
Глаза у меня добрые, но рубашка — смирительная!
Re[4]: О глобальном перехвате исключений
От: Qbit86 Кипр
Дата: 12.08.10 14:05
Оценка: 5 (2)
Здравствуйте, Mystic, Вы писали:

Q>>Пришло тебе в глобальный обработчик исключение типа System.InvalidOperationException с сообщением «Sequence contains no elements». Давай, преобразуй исключение в понятное сообщение.


M>Внутренняя ошибка программы, опишите выполненные вами действия и отправьте отчет разработчикам. И кнопка "Отправить отчет"


Мне больше по нраву другой вариант. Перехватываю исключение не в глобальном обработчике, а как только оно поднимается до уровня, где хватает данных о контексте. Тогда я сформирую сообщение «К этому отделу не приписан ни один сотрудник.», проброшу свой тип исключения, определяемый в моей бизнес-логике, а presentation layer доблестно отобразит понятное пользователю сообщение. Все рады, довольны, багрепорты разработчику не шлют, профит!
Глаза у меня добрые, но рубашка — смирительная!
Исключения для пользователя и для программиста -- разница
От: 0K Ниоткуда  
Дата: 12.08.10 06:27
Оценка: 1 (1) -1
В продолжение темы об исключениях (см. тег).

90% Exception'ов генерируются для программиста. Для пользователя они не информативны. Они служат для реализации контрактов и инвариантов (к примеру, проверка аргументов функции на null).

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

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

А то каков смысл выдвавать сообщение пользователю: ArgumentNullException parameter = value?

Вот вам практический пример глупости от Microsoft: http://rsdn.ru/Forum/Info/FAQ.rsdn.forum.xslt.aspx
Автор: nzeemin
Дата: 18.11.05
Exception Details: System.ArgumentException: Unsupported language. Это же исключение нарушения контракта. Его нужно было обрамить в CompilerException и написать пояснение: не удалось скомпилировать aspx-страницу, т.к. указан неподдерживаемый язык. А то поди догадайся.

14.08.10 00:03: Перенесено модератором из '.NET' — TK
exception
Re[7]: Исключения для пользователя и для программиста -- раз
От: mrjeka Россия  
Дата: 12.08.10 09:05
Оценка: 1 (1) +1
Здравствуйте, 0K, Вы писали:


Q>>ApiUserFriendly-исключение, а не EndUserFriendly. Библиотека не знает, что для конечного пользователя будет более friendly: текст на корейском, формат даты ISO-8601, упоминание смещения в файле, начиная с которого пошли некорректные данные, etc.


0K>Это исключение должно быть локализовано, Естественно. Если не локализовано -- другой разговор -- нужно дописать файл локализации к библиотеке.


И интересно получается, вы будете писать файлы локализации на всех языках? Ведь не известно, где и как будет использоваться библиотека.
Более привычное решение — локализация к UI.
Re[2]: Исключения для пользователя и для программиста -- раз
От: Qbit86 Кипр
Дата: 12.08.10 12:49
Оценка: 1 (1) +1
Здравствуйте, Mystic, Вы писали:

M>Хм... а что, нет единого обработчика всех исключений, вроде как Application.OnException в Delphi? Там, в одном месте, собственно говоря, и должна выполняться вся работа по преобразованию исключений в понятные сообщения.


Пришло тебе в глобальный обработчик исключение типа System.InvalidOperationException с сообщением «Sequence contains no elements». Давай, преобразуй исключение в понятное сообщение.
Глаза у меня добрые, но рубашка — смирительная!
Re[10]: Дополнение
От: mrjeka Россия  
Дата: 12.08.10 10:43
Оценка: +2
Вы не можете понять одно.

Сценарий

UI -> Lib1 -> Lib2(ваша библиотека).

Т.е. ситуация, когда с вашей библиотекой работает другая библиотека. Вот эту другую библиотеку совсем не интересуют FriendlyMessage. Её больше интересует искомое происхождение ошибки. Какое выдать сообщение на верх решается не в вашей библиотеке. И вместо того, чтобы получать сводную информацию в одном поле, для это библиотеки было бы куда удобнее иметь всю инфу об ошибке, разбитую по полям.
Re[12]: –
От: samius Япония http://sams-tricks.blogspot.com
Дата: 13.08.10 03:39
Оценка: +2
Здравствуйте, midcyber, Вы писали:

M>Я вообще не понимаю, что ты спрашиваешь. Какой еще лимит операций?

M>Если исключение ожидаемо, нафига его делать исключением изначально?
M>Проверяй условие completedOperations <= limit

С такой логикой далеко не уедешь. Ситуации с отсутствием файла, недопустимым индексом, и т.п. вполне ожидаемы. Нафига было городить исключения?
Re[18]: –
От: samius Япония http://sams-tricks.blogspot.com
Дата: 13.08.10 05:14
Оценка: +2
Здравствуйте, midcyber, Вы писали:

M>Здравствуйте, samius, Вы писали:


S>>Этот вариант мне ближе тем, что сообщение для пользователя берется не из исключения. Но плох тем что

S>>
M>Зачем try/catch в данном случае? Пусть приложение падает, если программист забыл вызвать CanComplete


Даже если программист не забыл вызвать CanComplete, со времени успешной проверки до времени выполнения операции может многое что измениться в системе. Проверка не блокирует записи в БД на изменение! Проверка тут вообще может говорить лишь о прогнозе выполнения операции, потому как если даже она закончилась неудачно, то через пол секунды наступит завтра и счетчики операций будут обнулены.
Re[9]: Исключения для пользователя и для программиста -- раз
От: Mamut Швеция http://dmitriid.com
Дата: 17.08.10 11:24
Оценка: +2
G>>Каким образом в глубине приложения можно сформировать информацию для пользователя? Если ругнуться что AccountBalance отрицательный, то это пользователю ничего не даст, такого поля может и не быть на форме.

0K>А кто еще, как ни библиотека, знает все тонкости процесса? Именно библиотека и должна сформировать корректное исключение.


Откуда библиотека, открывающая файл, знает, что это — не просто файл, а файл с днями рождениями пользователя? Ниоткуда. Это знает прикладной код, который использует библиотеку, и который на FileNotFundException сможет сформировать необходимое сообщение пользователю.

Откуда библиотека, парсящая XML, знает, что это за XML и в каком контексте он используется? Ниоткуда. Это знает прикладной код, который использует библиотеку, и который на InvalidXmlException сможет сформировать необходимое сообщение пользователю.

и т.п.


G>>Отлично, и кто будет формировать UserFriendlyException ?


0K>Библиотека, которая напрямую работает с сервисом/базой данных и пр. Или вы предлагаете номера ошибок передавать, а уже в пользовательском интерфейсе сделать сопоставление: номер ошибки — текст????


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


dmitriid.comGitHubLinkedIn
Re[12]: Дополнение
От: Mamut Швеция http://dmitriid.com
Дата: 17.08.10 11:38
Оценка: +2
0K>Смотрите какая парадигма:

0K>1. Есть ошибки, возникающие из-за некорректных данных, введенных пользователем (здесь стараемся не генерировать исключений, сразу проверяем).

0K>2. Есть ошибки нарушения сценария пользователем. Здесь без генерации Exception's не обойтись, но они не являются чем-то непредсказуемым. Их нет смысла заносить в лог. Они не нужны программисту (зачем программисту знать, что в Васи исчерпан лимит операций по счету?).

0K>Вот эти 2 типа ошибок не нужно логировать. Они известны и предсказуемы. Их не нужно исправлять. Они не для программиста а для пользователя.


Неверно. Что первое, что второе могут быть попытками взломать систему, поэтому их надо заносить в лог и обрабатывать соответственно.


dmitriid.comGitHubLinkedIn
Re: Исключения для пользователя и для программиста -- разниц
От: Qbit86 Кипр
Дата: 12.08.10 06:36
Оценка: +1
Здравствуйте, 0K, Вы писали:

0K>90% Exception'ов генерируются для программиста. Для пользователя они не информативны.


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

0K>Но некоторые Exception'ы содержат текст для пользователя: этот текст будет ему понятен и полезен.


И этот текст, в частности, должен быть локализован (переведён в ресурсах).

0K>Почему их (эти 2 категории исключений) никак не отличают?


Почему не отличают — некоторые отличают :)
Глаза у меня добрые, но рубашка — смирительная!
Re[3]: Исключения для пользователя и для программиста -- раз
От: SE Украина  
Дата: 12.08.10 06:45
Оценка: :)
Здравствуйте, Qbit86, Вы писали:

Q>Здравствуйте, SE, Вы писали:


SE>>Насколько помню, для случаев нарушения целостности классов рекомендуется наследоваться от InvalidOperationException, для случаев нарушения работы программы (это именно случай, когда нужно сообщить об ошибке) от ApplicationException.

SE>>Что не так?

Q>От ApplicationException не рекомендуется наследоваться: «Do derive custom exceptions from the T:System.Exception class rather than the T:System.ApplicationException class.» http://msdn.microsoft.com/en-us/library/ms229007.aspx


Ух, ты. Я отстал от жизни. Видно, читал рекомнедации еще когда, цитирую оотуда же:

It was originally thought that custom exceptions should derive from the ApplicationException class;


А оно вон как повернулось
Re[9]: Исключения для пользователя и для программиста -- раз
От: mrjeka Россия  
Дата: 12.08.10 10:25
Оценка: +1
Здравствуйте, 0K, Вы писали:

0K>Это не бред, а стандарт. .Net библиотеки и те локализованы.


Да, если вы заметили, что они ориентированы на разработчиков, а не на пользователей.
Такое сообщение как "Null reference exception" все равно пользователю ни о чем не скажет.

0K>Вы когда продаете библиотеку -- знаете кому продаете? Деньги вам когда платят говорят на каких языках должна быть локализация? В случае чего -- сами локализуют.


Библиотеку можно продать другой софтверной компании. А кому она будет её поставлять, это уже её дела.

M>>Да и не нужен этот механизм!!! Бросьте привычку выдавать пользователю e.Message. Если основная информация будет лежать в InnerException, что тогда???


0K>Тогда вывести Message от InnerException. А какие могут быть варианты? Как вы предлагает передавать сообщения из библиотеки в приложение?


Я уже вам говорил, создайте кастомный класс, заполните поля нужной информацией.

M>>Ну представьте, сообщение File 'имя файла' not found. Пользователь не рубит на английском. Тип исключения FileNotFoundException. Разумнее на основании типа полученного исключения в UI части обратиться к файлу локализации, достать нужное сообщение на нужном языке и выдать его пользователю.


0K>Открою страшную тайну. Если пользователь не знает английского, у него будет русский (к примеру) Windows и русский .Net. В отличии от вас, MS локализуют все свои библиотеки. Сообщения об ошибках там на русском языке.


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

0K>>>Ну хорошо. Вот возникла ошибка при попытке перевести деньги со счета на банковскую карту. Вы что напишите? Не удалось перевести средства? Причин же может быть десятки! И это очень важно для пользователя.


M>>Библиотека может передавать на клиента всю необходимую информацию об ошибке. Какие детали выводить пользователю решает программист.


0K>Как раз таки может и должна. Вы думаете почему существует ТРЕБОВАНИЕ ЛОКАЛИЗОВАТЬ СООБЩЕНИЯ ОБ ОШИБКАХ???


Объясняю на пальцах. Используются 2 сторонние библиотеки разных производителей. У одних ошибка "Файл {0} не найден", у других "Не найден файл".
Какой толк от такой локализации в библиотеках??? Или вы не взирая ни на что, будете выдавать сообщения так, как они заложены в библиотеках?

M>>Пусть тогда библиотека возвращает разные типы исключений.


0K>Вы хоть представляете какую вы сейчас ерунду спороли? Вы знаете сколько может быть вариантов почему деньги со счета на карту перевести не удалось? Около сотни. И вы будете создавать и обрабатывать все 100 типов исключений Атхнитесь!!!


Если вы не можете сами догадаться, то помогу. Помимо того, что можно разбивать исключения на типы, можно еще ввести коды ошибок. И можете не создавать сотни типов исключений.
Re[13]: Исключения для пользователя и для программиста -- ра
От: mrjeka Россия  
Дата: 12.08.10 12:04
Оценка: +1
Здравствуйте, 0K, Вы писали:

0K>Здравствуйте, mrjeka, Вы писали:


M>>И я твержу уже сколько. Не надо полагаться на сообщение исключения!!! формируйте своё на основании типа и другой информации исключения. Вам никто не гарантирует, что в e.Message сторонней библиотеки, даже как бы предназначенной для показа пользователю будет лежать то, что вам нужно.


0K>Автор библиотеки это должен гарантировать. И такие исключения нужно наследовать от специального системного класса.


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

0K>Зачем делать двойную работу??? Почему каждый пользователь библиотеки должен расшифровывать тысячи вариантов ошибок?


ситуация простая. Приведу пример.


        public class Lib2
         {
             void Foo()
             {
                 int val1;
                 int val2;
                 int val3;

                 try
                 {
                     val1 = Lib1.GetVal1();
                 }
                 catch (DivideByZeroException ex)
                 {
                     //какая-то обработка ошибки
                     ...
                     val2 = Lib1.GetVal2();
                 }
                 catch (ArgumentException aex)
                 {
                     //какая-то обработка ошибки
                     ...
                     val3 = Lib1.GetVal3();
                 }
                 catch(CustomException ce)
                 {
                     //В зависимости от кода ошибки сделать какие либо действия
                     if(ce.ErrorType == ErrorType.One) 
                     //....
                     else if(ce.ErrorType == ErrorType.Two)
                     //....
                 }
                 catch(SqlException se)
                 {
                     //Не удалось получить данные с определенного сервера
                     if(se.Server == "ServerName") 
                     //Получаем данные с другого сервера
                     else if(se.Server == "ServerName1")
                     //Поднимаем исключение наверх
                 }
             }
         }

И так можно разворачивать сценарий как угодно. И разработчику библиотеки невозможно предсказать, как и в каких сценариях будет использоваться его библиотека.
На разные типы ошибок могут быть разные сценарии.
Разработчик использует вашу библиотеку. Зачем ему FriendlyMessage? У него по бизнес-логике должно формироваться другое сообщение или другие сценарии.


0K>>>При локализации вы меняете язык. Можете кое-чего добавить. А что вам еще нужно?

M>>Ну тогда вам нужно будет менять все во всех файлах ресурсов. 10 библиотек с ресурсами, полезете во все 10 библиотек.

0K>А разве локализацию сделать не на порядок проще, чем вручную расшифровать исключения по кодам ошибок? Локализация -- это дешевая работа, даже программистом не нужно быть. Переводчик нужен всего-лишь.


M>>Не проще ли на уровне приложения создать 1 файл ресурсов, который бы на одинаковые типы ошибок выдавал одинаковые сообщения?


0K>Нет, не проще. Это работа программиста и стоит дороже. Переводчик сделает все качественнее, быстрее и дешевле.


Правильно. И тот, кто заказывает библиотеки, не будет 10 раз платить за локализацию 10-ти библиотек, а создаст 1 файл локализации своими средствами.
И в дальнейшем при смене языка придется нанимать переводчика для перевода 1-го файла ресурсов вместо 10-ти.

0K>Зачем каждый дожен расшифровывать коды ошибок библиотеки, если можно один раз в самой библиотеке создать файл ресурсов с корректными сообщениями об ошибках? Зачем делать дурную работу?


Да потому что на каждый тип/код ошибки может быть свой сценарий работы приложения. Задумайтесь об этом.
Re[3]: Исключения для пользователя и для программиста -- раз
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 12.08.10 14:00
Оценка: :)
Здравствуйте, Qbit86, Вы писали:

Q>Пришло тебе в глобальный обработчик исключение типа System.InvalidOperationException с сообщением «Sequence contains no elements». Давай, преобразуй исключение в понятное сообщение.


Внутренняя ошибка программы, опишите выполненные вами действия и отправьте отчет разработчикам. И кнопка "Отправить отчет"
Re[9]: —
От: Qbit86 Кипр
Дата: 12.08.10 14:27
Оценка: +1
Здравствуйте, 0K, Вы писали:

Q>>3) В тексте сообщения. В случае usage exception'ов содержит указание, как изменить код, чтобы избежать выброс исключения;


0K>Да поймите же вы! Не нужно менять код для этого исключения! Оно ожидаемо. Нет ошибки в коде. Сколько можно повторять???


Хорошо-хорошо, значит, имеем дело с runtime-исключением. Ошибки в коде нет, спокойно.

0K>Не нужно его логировать. Не нужно о нем знать разработчику и беспокоить его лишний раз этим исключением. Оно только для пользователя!


Логи бывают:
1) Для конечных пользователей и администраторов, чтобы они могли отследить активность приложения в своё отсутствие.
2) Для разработчиков, чтобы помочь им в выявлять ошибки в коде.
3) Ещё разные типы логов, которые я не упомянул.

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

0K>Кроме того, UserFriendly может содержать и Enum с типом. Об этом я выше писал...

0K>Ничто не мешает добавить Enum с типом. Выше я писал об этом.

OMFG, enum с типом — это что такое? RTTI на коленке, закат солнца вручную?

Q>>Вот ты приводил пример, когда у тебя стописят разных ошибок, и все возвращаются через один класс EndUserFriendly-исключения, отличаясь только сообщениями. Отлично, ты просто выводишь месседж. А завтра начальник говорит тебе: а в случае, если тип ошибки «Номер +755щ2713141 имеет ниверный формат.», выдавать не сообщение с орфографической ошибкой, а окошко ввода нового номера.


0K>Здесь просто. Данные, которые вводит пользователь обрабатываем сразу. Исключения не генерируются.


Хорошо, пусть это будут исключения, не связанные с вводом. Мои рассуждения относительно твоего примера с 500 однотипных EndUserFriendly-исключений с разными сообщениями остаются в силе. Даже если ты добавишь туда Enum — ты же не запихнёшь в него контекст (например, номер счёта «91922»).

Q>>Если нужно — легко. В классе FileNotFoundException содержится поле ex.FileName. Мне не важно, что в поле ex.Message содержится «Файл „filename.xml“ не найден». Я всегда смогу (и по умолчанию — буду) формировать своё сообщение, допустим, «Проверьте, пожалуйста, наличие файла {0}.»; и подставлю ex.FileName, а не выпарсенное между кавычками название файла.


0K>А нахрена? Вы знаете, что вы допустили ошибку сейчас? В данном случае слово пожалуйста не уместно и пользователь будет чувствовать себя неловко.


Это не важно, можешь мысленно это слово опустить. Придирки к словам же.

0K>Оставьте все как есть, там все хорошо без ваших стараний сделано.


Без «моих стараний» пользователь так и не узнает, что filename.xml содержит даты рождения его друзей (если это необходимо). Иными словами, в сообщении отсутствует семантика. Библиотека не знает, в каком окружении будет применяться: к файлу с датами рождения или с телефонными номерами. Об этом знает прикладной код пользователя библиотеки. Именно он в подавляющем большинстве и должен формировать «end-user friendly» сообщения. Может опять же засунуть в своё BL-исключение, чтобы потом отобразить в PL, возможно, ещё раз декорировав.
Глаза у меня добрые, но рубашка — смирительная!
Re[11]: Исключения для пользователя и для программиста -- ра
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.08.10 18:38
Оценка: +1
Здравствуйте, 0K, Вы писали:


0K>Не считайте пользователей идиотами. Они прекрасно поймут текст ошибки в 80% случаев он им будет полезен.

Это какая-то очень странная библиотека. Фактически, она заранее знает, какого вида UI будет ею пользоваться. В частности, она почему-то в курсе, что есть пользователь, который выполняет операцию, и которому могут быть интересны подробности.

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

В ситуации, когда очень-очень хочется что-то сказать пользователю, а нельзя, применяют не исключения, а всё же коды ошибок.
То есть выбрасывают что-то типа BusinessRuleException, у которого есть список обнаруженных проблем — с кодами (чтобы пользователь мог погуглить) и текстами. Важность этого исключения не настолько велика, чтобы вносить его ажно во фреймворк — вполне хватит одного на библиотеку. Ведь клиенту библиотеки не нужно реализовывать разную обработку этих ситуаций — значит и классы никакие не нужны.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: Исключения для пользователя и для программиста -- раз
От: 0K Ниоткуда  
Дата: 17.08.10 09:30
Оценка: -1
Здравствуйте, mrTwister, Вы писали:

T>Если эта ситуации ожидаема, то она будет описана в SRS в виде отдельных use-case'в со своей собственной логикой. Реализовывать эту логику через обработчики исключений — это называется использование исключений не по назначению. Таким образом, мы строим логику на исключениях, делая код более запутанным.


Читайте выше как опозорился midcyber с таким же мнением. Вот что изменило его мнение и привело к полному позору:

Даже если программист не забыл вызвать CanComplete, со времени успешной проверки до времени выполнения операции может многое что измениться в системе. Проверка не блокирует записи в БД на изменение! Проверка тут вообще может говорить лишь о прогнозе выполнения операции, потому как если даже она закончилась неудачно, то через пол секунды наступит завтра и счетчики операций будут обнулены.


(с) samius

0K>>А вы знаете что по стандарту все исключения должны быть сериализуемыми?

T>Ссылку можно?

MSDN.microsoft.com Запустите FxCop с несериализуемым, там будет конкретная ссылка.
Re[21]: –
От: midcyber
Дата: 17.08.10 09:54
Оценка: :)
Здравствуйте, 0K, Вы писали:

0K>Здравствуйте, midcyber, Вы писали:


M>>Ну тогда мой вариант вообще жить не может, всю логику надо строить на исключениях. Учту на будущее.


0K>Ну слава Богу! Хоть до одного дошло. Если бы я говорил -- то ради упрямства бы не принял.


Я так и думал, что реально вопрос ты не задавал, просто ждал пока кто-то с тобой согласится =)
Re: Исключения для пользователя и для программиста -- разниц
От: SE Украина  
Дата: 12.08.10 06:37
Оценка:
Здравствуйте, 0K, Вы писали:

0K>В продолжение темы об исключениях (см. тег).


0K>90% Exception'ов генерируются для программиста. Для пользователя они не информативны. Они служат для реализации контрактов и инвариантов (к примеру, проверка аргументов функции на null).


0K>Почему их (эти 2 категории исключений) никак не отличают? Сделали бы стандарт: все исключения, содержащие информацию полезную для пользователя наследовать от UserFriendlyException. А остальные инсключения -- контрактные -- не должны показываться пользователю.


Насколько помню, для случаев нарушения целостности классов рекомендуется наследоваться от InvalidOperationException, для случаев нарушения работы программы (это именно случай, когда нужно сообщить об ошибке) от ApplicationException.
Что не так?
Re: Исключения для пользователя и для программиста -- разниц
От: mrjeka Россия  
Дата: 12.08.10 06:37
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Но некоторые Exception'ы содержат текст для пользователя: этот текст будет ему понятен и полезен. Как правило такие исключения генерируются ближе к выходу из конкретной библиотеки (т.е. на самом верхнем уровне) и они обрамляют все исключения контрактов (перехватывают контрактные исключения, т.к. нет смысла в ArgumentNullException выше самой библиотеки).


И в этом случае пользователем является разработчик.

0K>Почему их (эти 2 категории исключений) никак не отличают? Сделали бы стандарт: все исключения, содержащие информацию полезную для пользователя наследовать от UserFriendlyException. А остальные инсключения -- контрактные -- не должны показываться пользователю.


0K>А то каков смысл выдвавать сообщение пользователю: ArgumentNullException parameter = value?


0K>Вот вам практический пример глупости от Microsoft: http://rsdn.ru/Forum/Info/FAQ.rsdn.forum.xslt.aspx
Автор: nzeemin
Дата: 18.11.05
Exception Details: System.ArgumentException: Unsupported language. Это же исключение нарушения контракта. Его нужно было обрамить в CompilerException и написать пояснение: не удалось скомпилировать aspx-страницу, т.к. указан неподдерживаемый язык. А то поди догадайся.


Как правило, все исключения поднимаются для разработчиков. Разработчик должен позаботится о том, чтобы пользователь увидел нормальное исключение, а не непонятную, для его мозга, информацию.
Вы можете вообще не выдавать пользователю никаких исключений, а писать свой текст на своё усмотрение, либо вообще придумать своё поведение приложения.
Re[2]: Исключения для пользователя и для программиста -- раз
От: 0K Ниоткуда  
Дата: 12.08.10 06:40
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>Практически верно. Но ты смешиваешь в кучу исключения и сообщения исключений. Пользователю может отображаться не тот текст, который пришёл в исключении.


Сообщения есть для пользователей а есть для программистов. И типы исключений, соответственно, должны быть разными.

Q>В исключении приходит, скажем, «Нет ни одного элемента в таблице Accounts», пользователю транслируем: «Нет ни одного пользователя».


И как вы это будете делать? String.Replace?

Q>И этот текст, в частности, должен быть локализован (переведён в ресурсах).


Ага.

0K>>Почему их (эти 2 категории исключений) никак не отличают?


Q>Почему не отличают — некоторые отличают


Я имею в виду, что нужно наследовать от разных базовых классов. Должна быть структура и порядок.
Re[2]: Исключения для пользователя и для программиста -- раз
От: 0K Ниоткуда  
Дата: 12.08.10 06:43
Оценка:
Здравствуйте, SE, Вы писали:

SE>Насколько помню, для случаев нарушения целостности классов рекомендуется наследоваться от InvalidOperationException


Это инвариантное исключение. Для программиста.

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


От ApplicationException ранее рекомендовали наследовать ВСЕ новые типы исключений (не системные). А теперь как?

SE>Что не так?


Должен быть базовый тип для UserFriendly исключений. Тест таких исключений 100% должен быть понятен пользователю. Иначе откуда я знаю выводить ли текст отловленного исключения пользователю или нет?
Re[3]: Исключения для пользователя и для программиста -- раз
От: Qbit86 Кипр
Дата: 12.08.10 06:47
Оценка:
Здравствуйте, 0K, Вы писали:

Q>>В исключении приходит, скажем, «Нет ни одного элемента в таблице Accounts», пользователю транслируем: «Нет ни одного пользователя».


0K>И как вы это будете делать? String.Replace?


Нет. Библиотека не знает, с какими сущностями она работает, поэтому она выдаёт «обобщённые» сообщения, типа «Sequence contains no elements». Пользователю (разработчику-пользователю библиотеки) в момент вызова известен контекст, скажем, что работа происходит с залогинеными пользователями, а не просто с «элементами коллекции».

0K>Я имею в виду, что нужно наследовать от разных базовых классов. Должна быть структура и порядок.


В C++ иерархия стандартных исключений, AFAIR, была более упорядочена.
Глаза у меня добрые, но рубашка — смирительная!
Re[2]: Исключения для пользователя и для программиста -- раз
От: 0K Ниоткуда  
Дата: 12.08.10 06:47
Оценка:
Здравствуйте, mrjeka, Вы писали:

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


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

Если заранее не предусмотреть такие UserFriendly-исключения -- программист никак не сможет из ArgumentNull или еще чего сделать понятные пользователю.

M>Вы можете вообще не выдавать пользователю никаких исключений, а писать свой текст на своё усмотрение, либо вообще придумать своё поведение приложения.


Ага. И кто потом захочет использовать ваши программы? Не считайте пользователей за идиотов. Если возникла проблема с базой -- сообщите, они разбрутся. Если не доступен сервис -- выведите ошибку 403 или 500 -- 80% пользователей знают что это за ошибка или найдут в google.
Re[3]: Исключения для пользователя и для программиста -- раз
От: SE Украина  
Дата: 12.08.10 06:51
Оценка:
Здравствуйте, 0K, Вы писали:

SE>>Что не так?


0K>Должен быть базовый тип для UserFriendly исключений. Тест таких исключений 100% должен быть понятен пользователю. Иначе откуда я знаю выводить ли текст отловленного исключения пользователю или нет?


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

Необернутые исключения в таком случе, получается не были мной обработаны корректно и считаются мной такими, которые нарушили целостность, и программа должна быть закрыта с неким почти бесполезным комментарием "Все, капец, приплыли, произошло неведомое, извините".
Re[4]: Исключения для пользователя и для программиста -- раз
От: 0K Ниоткуда  
Дата: 12.08.10 06:55
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>Нет. Библиотека не знает, с какими сущностями она работает, поэтому она выдаёт «обобщённые» сообщения, типа «Sequence contains no elements». Пользователю (разработчику-пользователю библиотеки) в момент вызова известен контекст, скажем, что работа происходит с залогинеными пользователями, а не просто с «элементами коллекции».


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

По поводу вашего примера. Давайте более подробно.
Re[4]: Исключения для пользователя и для программиста -- раз
От: 0K Ниоткуда  
Дата: 12.08.10 06:58
Оценка:
Здравствуйте, SE, Вы писали:

SE>Ну, вот я обычно при разработке программы и создаю свой базовый класс исключений, в который оборачиваются пойманые исключение перед показом пользователю. Разумеется с внятным объяснением ошибки.


Правильный подход. Но это должно быть не на лично уровне, а на уровне соглашений.

А когда вы вызываете другие библиотеки откуда вы знаете какие исключения являются UserFriendly?

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


Вот не нужно спешить закрывать программу. Что вы для атомных электростанций или для больницы софт пишите?
Re[3]: Исключения для пользователя и для программиста -- раз
От: mrjeka Россия  
Дата: 12.08.10 07:11
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Нет. Исключения верхнего уровня в каждой конкретной библиотеке должны быть понятны пользователю. К примеру, если в библиотеке для работы с базой данных не возникло исключение -- оно должно быть понятно пользователю: он должен понять в чем проблема и почему не удалось подключиться к базе.


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

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


0K>Если заранее не предусмотреть такие UserFriendly-исключения -- программист никак не сможет из ArgumentNull или еще чего сделать понятные пользователю.


Если речь идет о том, какое сообщение выдавать конечному пользователю, то никто вам не мешает сделать что-то вроде


try
{
   //do something
}
catch(OutOfMemoryException e)
{
   Console.WriteLine("Friendly message");
   //throw new CustomException("Это уже на ваше воображение, как хотите так и фантазируйте");
   //throw; пинаем исключение наверх (я так делаю в библиотеках)
}




0K>Ага. И кто потом захочет использовать ваши программы? Не считайте пользователей за идиотов. Если возникла проблема с базой -- сообщите, они разбрутся.


Пользователей за идиотов никто не считает. Сообщить — не значит выдать Exception в том виде, в котором он есть.

0K>Если не доступен сервис -- выведите ошибку 403 или 500 -- 80% пользователей знают что это за ошибка или найдут в google.


значит ваш круг общения состоит из 80% программистов или по крайней мере продвинутых пользователей.
Re[4]: Исключения для пользователя и для программиста -- раз
От: 0K Ниоткуда  
Дата: 12.08.10 07:33
Оценка:
Здравствуйте, mrjeka, Вы писали:

M>Уточните, кого вы подразумеваете под пользователем?


Конечного пользователя. Тот, ради которого все и делаем.

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

M>Пользователь приложения — это человек, который к программированию не имеет ни какого отношения.

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

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


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

Или библиотека для работы с интерфейсами какого-нибудь финансового сервиса. 90% ошибок контрактные -- пользователю их ни в коем случае показывать нельзя. Но есть и UserFriendly -- исчерпан лимит операций, нет денег на счету и пр. Они понятны и нужны пользователю. Как программист, использующий вашу библиотеку узнает, что сообщение именно ЭТИХ исключений нужно отобразить пользователю?

M>
M>try
M>{
M>   //do something
M>}
M>catch(OutOfMemoryException e)
M>{
M>   Console.WriteLine("Friendly message");
M>   //throw new CustomException("Это уже на ваше воображение, как хотите так и фантазируйте");
M>   //throw; пинаем исключение наверх (я так делаю в библиотеках)
M>}
M>


Вы что не поняли? Речь не о системных исключениях. А о UserFriendly, которые содержат важный для пользователя Message.

M>Пользователей за идиотов никто не считает. Сообщить — не значит выдать Exception в том виде, в котором он есть.


Еще раз: контрактные исключения выдвать нельзя. UserFriendly нужно выдать, они содаржат важную информацию. Как вы отличаете исключения которые содержать важную для пользователю информацию от контрактных исключений?

M>значит ваш круг общения состоит из 80% программистов или по крайней мере продвинутых пользователей.


Вовсе нет. Вы недооцениваете людей. Намного понятее для 80% пользователей "не удалось подключиться к сервису ya.ru, проверьте подключение к интернету", чем "ошибка соединения".
Re[3]: Исключения для пользователя и для программиста -- раз
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 12.08.10 08:49
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Здравствуйте, Qbit86, Вы писали:


Q>>Практически верно. Но ты смешиваешь в кучу исключения и сообщения исключений. Пользователю может отображаться не тот текст, который пришёл в исключении.


0K>Сообщения есть для пользователей а есть для программистов. И типы исключений, соответственно, должны быть разными.


Кому должны?

Сообщения для программистов лучше вообще не перехватывать, поэтому какой у него тип — значения не имеет.

Для пользовательских исключений все равно будут перехватываться конкретные типы исключений.
Re[6]: Исключения для пользователя и для программиста -- раз
От: 0K Ниоткуда  
Дата: 12.08.10 08:54
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>Предлагаю впредь не использовать термин «пользователь», а употреблять «конечный пользователь и «пользователь API».


Давайте проще: разработчик, разработчик библиотеки и пользователь. Деньги откуда идут? От конечного пользователя. Нахрен вообще о программистах говорить?

Q>ApiUserFriendly-исключение, а не EndUserFriendly. Библиотека не знает, что для конечного пользователя будет более friendly: текст на корейском, формат даты ISO-8601, упоминание смещения в файле, начиная с которого пошли некорректные данные, etc.


Это исключение должно быть локализовано, Естественно. Если не локализовано -- другой разговор -- нужно дописать файл локализации к библиотеке.

Q>Библиотека даже не знает, будет ли конечным пользователем человек, или, скажем, сервис без пользовательского интерфейса.


Собственно да. И что вы предлагаете вообще не делать понятных пользователю сообщений об ошибках в библиотеках?

0K>>В том то и дело, что не всегда библиотека знает проблему хуже вызывающего кода (от вызывающего сокрыты детали).


Q>Если библиотека скрывает детали, то это на совести автора библиотеки, он счёл это нужным, таков контракт библиотеки.


Читайте внимательнее: библиотека не всегда знает ХУЖЕ вызывающего кода. Т.е. часто именно библиотека знает настоящие причины возникновения ошибки и может выдать пользователю нужную информацию.

Q>Рассмотрим стандартное исключение FileNotFoundException. Оно содержит ApiUserFriendly-сообщение «Could not find file 'temp_6B8FCD97.xml'.» плюс дополнительное поле ex.FileName, равное «temp_6B8FCD97.xml».

Q>При трансляции конечному пользователю сообщение может превратиться в EndUserFriendly-сообщение, например, в такое: «Нет доступа к файлу с данными о днях рождения ваших друзей.»

Простите, слишком узко смотрите. Программа зачастую не знает что пользователь хранит в файле. Нужно выдать конкретное имя файла, с которым проблема. Как вы это сделаете?
Re[6]: Исключения для пользователя и для программиста -- раз
От: 0K Ниоткуда  
Дата: 12.08.10 09:03
Оценка:
Здравствуйте, mrjeka, Вы писали:

M>Ну если уж у вас пользователи напрямую используют библиотеку, без какого либо UI-layer, тогда да. Этот вариант и нужен.


Не напрямую, конечно.

M>Обработка в UI



M>
M>try
M>{
M>Lib.GetData();
M>}
M>catch(Exception e)//Опустим пока подробности с типами исключений
M>{
M>  //Запись в лог
M>  Log.Write(e);
M>  //Вывод пользователю
M>  //Не факт, что e.Message содержит текст сообщения в читабельном виде... Мало ли, мож еще и перевести надо
M>  //Мало того, зачастую бывает что в e.Message вообще ничего разумного нет, а лежит в InnerException
M>  Console.WriteLine(GetFriendlyMessage(e));
M>}

M>private string GetFriendlyMessage(Exception e)
M>{
M>  //Делайте что хотите, как хотите, так и парсите этот эксепшн. Выдавайте какие угодно сообщения пользователю. 
M>}
M>


Вот! Теперь, похоже, вы поняли проблему. Вы же сами написали "Не факт, что e.Message содержит текст сообщения в читабельном виде... Мало ли, мож еще и перевести надо". Нужно перевести или нет -- зависит от локализации библиотеки. Если нет локализации -- добавить ее (это обязательно!).

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

M>Если уж библиотека должна выдавать читабельные эксепшены


А кто должен выдавать? Вот вызываете вы метод для перевода денег со счета на банковскую карту. И он выдает исключение: превышен лимит операций. А вы что пользователю скажите? НЕ удалось перевести средства? И все? А причину он откуда может узнать? Может просто сетевая ошибка? А может его счет заблокирован по подозрению в мошенничестве? А может денег нет? Откуда бедному пользователю узнать, что именно превышен лимит операций?

M>Lib

M>
M>....
M>try
M>{
M>  ...
M>}
M>catch(SqlException se)//не удалось подключиться 
M>{
M>  trow new SqlException("Не удалось подключиться к базе данных (можете распарсить текущий эксепшн и сформировать какое угодно сообщение)",se);
M>}
M>...
M>


Ничего парсить не нужно, что за глупости. НЕ позорьтесь... сообщения парсить. По MSDN сообщения должны быть оформлены грамматически правиьлно и локализованы. Что вы парсить еще будете??

Вот только как узнать является ли исключение контрактным или предназначено для вывода пользователю -- этого механизма нет.

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


Зачем изменять, не понял?

M>Я поэтому никогда не вывожу пользователю содержание исключения.

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

Ну хорошо. Вот возникла ошибка при попытке перевести деньги со счета на банковскую карту. Вы что напишите? Не удалось перевести средства? Причин же может быть десятки! И это очень важно для пользователя.
Re[4]: Исключения для пользователя и для программиста -- раз
От: 0K Ниоткуда  
Дата: 12.08.10 09:08
Оценка:
Здравствуйте, gandjustas, Вы писали:

0K>>Сообщения есть для пользователей а есть для программистов. И типы исключений, соответственно, должны быть разными.


G>Кому должны?


Не кому, а почему. Без этого невозможна структуризация.

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


Какие именно конкретные типы? Как вы узнаете какое сообщение содержит текст для пользователя, а какое является контрактным и содержит текст для программиста?
Re[4]: Исключения для пользователя и для программиста -- раз
От: 0K Ниоткуда  
Дата: 12.08.10 09:18
Оценка:
Здравствуйте, gandjustas, Вы писали:

0K>>Нет. Исключения верхнего уровня в каждой конкретной библиотеке должны быть понятны пользователю.

G>Кому должны? Если в программе вываливается исключение со стактрейсом, то пользователь приходит в ужас даже несмотря на буковки сообщений. А без стактрейса исключения смысла собственно не имеют, можно и обычными сообщениями обойтись.

Еще раз повторяю: пользователю нужно отобразить только Message UserFriendlyException. Не любого Exceptin, а именно UserFriendly. Как его отличить -- в этом то и вопрос. Механизма нет, хотя должен быть.

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

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

Простите, а каким образом вы предлагаете передавать сообщения об ошбках пользователю?

На конкретном примере. Библиотека для работы с финансовой системой. Метод для перевода средств со счета на карту. Клиент вызывает этот метод -- происходит ошибка. В Message -- детальное описание причины ошибки (причин может быть несколько десятков). Вы выведете это сообщение пользователю, или вы будете out-параметр добавлять в метод и описание ошибки в него записывать?
Re[8]: Исключения для пользователя и для программиста -- раз
От: 0K Ниоткуда  
Дата: 12.08.10 09:21
Оценка:
Здравствуйте, mrjeka, Вы писали:

M>И интересно получается, вы будете писать файлы локализации на всех языках? Ведь не известно, где и как будет использоваться библиотека.

M>Более привычное решение — локализация к UI.

Здравсти! MSDN изредка почитывайте. Локализация сообщений об ошибках -- обязательное требование. Почему, по вашему, MS сами локализуют сообщения об ошибках в своей .Net платформе? Локализовать может и тот, кто будет использовать вашу библиотеку. Для этого перекомпиляция не нужна, есть специальная тулуза в SDK.

Локализация -- это не больно. Открываете файл ресурсов и быстренько переводите все UserFriendly-сообщения об ошибках.
Re[5]: Исключения для пользователя и для программиста -- раз
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 12.08.10 09:42
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Здравствуйте, gandjustas, Вы писали:


0K>>>Сообщения есть для пользователей а есть для программистов. И типы исключений, соответственно, должны быть разными.


G>>Кому должны?


0K>Не кому, а почему. Без этого невозможна структуризация.


А зачем и кому нужна структуризация?

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


0K>Какие именно конкретные типы? Как вы узнаете какое сообщение содержит текст для пользователя, а какое является контрактным и содержит текст для программиста?


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

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

Твое желание поиметь общий базовый класс для каких-то исключений породит только то что будут писать

try
{
//code
}
catch(SomeBaseException e)
{
}


вместо

try
{
//code
}
catch(Exception e)
{
}


Ведь за последнее можно линейкой по пальцам (а иногда и сапогом по роже) получить, а на первое не ругнется FxCop.

Далее, даже если ты перехватываешь SomeBaseException, что ты с ним сделаешь?
MessageBox(e.ToString()) — пользователь также испугается и убежит
MessageBox(e.Message) — теряется важный stacktrace
MessageBox(e.Message); Log(e.ToString()) — нету разницы с обычным exception.
Re[5]: Исключения для пользователя и для программиста -- раз
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 12.08.10 09:49
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Здравствуйте, gandjustas, Вы писали:


0K>>>Нет. Исключения верхнего уровня в каждой конкретной библиотеке должны быть понятны пользователю.

G>>Кому должны? Если в программе вываливается исключение со стактрейсом, то пользователь приходит в ужас даже несмотря на буковки сообщений. А без стактрейса исключения смысла собственно не имеют, можно и обычными сообщениями обойтись.

0K>Еще раз повторяю: пользователю нужно отобразить только Message UserFriendlyException. Не любого Exceptin, а именно UserFriendly. Как его отличить -- в этом то и вопрос.

А смысл? Потерять stacktrace? И зачем пользователю отображать текст exception, ему нужно отображать инструкцию как ошибку исправить.

0K>Механизма нет, хотя должен быть.

Никому не должен, это ты сам придумал.

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

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

0K>Простите, а каким образом вы предлагаете передавать сообщения об ошбках пользователю?

Поля валидации\summary, окна сообщений, репорты на почту.

0K>На конкретном примере. Библиотека для работы с финансовой системой. Метод для перевода средств со счета на карту. Клиент вызывает этот метод -- происходит ошибка. В Message -- детальное описание причины ошибки (причин может быть несколько десятков).

Откуда оно там взялось? Код бизнес-слоя формирует? А если этот же код из сервиса вызываться будет? Удаленному приложению уйдет ошибка с текстом вроде "В поле2 сумма должна быть больше, чем в поле1"?

Обычно user-friendly сообщения формирует слой PL (там ему и место), а если текст формируется в PL, то заворачивать его в исключение и не надо.
Re[6]: Исключения для пользователя и для программиста -- раз
От: 0K Ниоткуда  
Дата: 12.08.10 10:11
Оценка:
Здравствуйте, gandjustas, Вы писали:

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


Вот с этого места подробнее. Какие именно типы исключений перехватываются? Как вы их выделяете?

G>Для того чтобы облегчить жизнь другим программистам некоторые программисты в своем коде создают так называемые business exceptions, которые не только сообщают о какой-либо ошибке, но и предоставляют много деталей для её исправления (например ошибки валидации, если репортинг идет через исключения). И программист на верхнем уровне может эти данные получить и отобразить красиво пользователю, а может даже исправить автоматически. Программист должен знать конкретных тип выбрасываемого исключения чтобы его так обрабатывать.


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

G>Твое желание поиметь общий базовый класс для каких-то исключений породит только то что будут писать


Не для каких-то, а содержащих ИНФОРМАЦИЮ ДЛЯ ПОЛЬЗОВАТЕЛЯ!!!

G>
G>try
G>{
G>//code
G>}
G>catch(SomeBaseException e)
G>{
G>}
G>


Не так будут писать. Будут писать вот как

// Верхний уровень
try
{
   //Вызов сторонней библиотеки
}
catch(UserFriendlyException e)
{
   MessageBox.Show(this, e.Message.....);
}


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

G>
G>try
G>{
G>//code
G>}
G>catch(Exception e)
G>{
G>}
G>


G>Ведь за последнее можно линейкой по пальцам (а иногда и сапогом по роже) получить, а на первое не ругнется FxCop.


Правильно. Потому-что не понятно почему это сообщение возникло. А UserFriendlyException возникает специально для того, чтобы его отобразили пользователю. Оно ожидаемо и понятно. Его не нужно бояться. Оно предсказуемо!

G>Далее, даже если ты перехватываешь SomeBaseException, что ты с ним сделаешь?

G>MessageBox(e.ToString()) — пользователь также испугается и убежит

Нет. Нужен только Message.

G>MessageBox(e.Message) — теряется важный stacktrace


Да, именно так. Никакой stacktrace вам не нужен. Если в сообщении ясно сказано: превышен лимит операций по счету 1111. Что еще вам нужно? Какой стек? Вы только лог захламлять будете. Это ожидаемое и предсказуемое сообщение.

G>MessageBox(e.Message); Log(e.ToString()) — нету разницы с обычным exception.


Ничего в лог заносить не нужно. В лог заносят то, что нужно исправить разработчику. Здесь разработчику исправлять ничего не нужно -- это исключение не нарушает логику работы программы и не является признаком ошибки в программе (в отличии от контрактных исключений).
Re[7]: Исключения для пользователя и для программиста -- раз
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 12.08.10 10:22
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Здравствуйте, gandjustas, Вы писали:


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


0K>Вот с этого места подробнее. Какие именно типы исключений перехватываются? Как вы их выделяете?

Самый частый пример — валидация, хотя её лучше не exception_ами делать.

G>>Твое желание поиметь общий базовый класс для каких-то исключений породит только то что будут писать


0K>Не для каких-то, а содержащих ИНФОРМАЦИЮ ДЛЯ ПОЛЬЗОВАТЕЛЯ!!!

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

0K>Будут писать вот как


0K>
0K>// Верхний уровень
0K>try
0K>{
0K>   //Вызов сторонней библиотеки
0K>}
0K>catch(UserFriendlyException e)
0K>{
0K>   MessageBox.Show(this, e.Message.....);
0K>}
0K>

Отлично, и кто будет формировать UserFriendlyException ?
Re[6]: Исключения для пользователя и для программиста -- раз
От: 0K Ниоткуда  
Дата: 12.08.10 10:22
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>А смысл? Потерять stacktrace? И зачем пользователю отображать текст exception, ему нужно отображать инструкцию как ошибку исправить.


А накой вам stacktrace предсказуемого исключения? Если у пользователя исчерпан лимит операций по счету -- накой вам stacktrace? Вы что будете действительно разбирать такие вот ошибки от 10 тыс. пользователей использующих программу?

В лог пишем только то, что является нарушением контрактов и инвариантов (ошибка в коде). А эти исключения не ошибка в коде -- они абсолютно предсказуемая ошибка в бизнес-процессе -- исчерпан лимит. Зачем программисту знать, что у какого-то пользователя исчерпан лимит по счету?

0K>>Механизма нет, хотя должен быть.

G>Никому не должен, это ты сам придумал.

Я не зря придумал. Возможно скоро MS это поймут и введут.

0K>>Простите, а каким образом вы предлагаете передавать сообщения об ошбках пользователю?

G>Поля валидации\summary, окна сообщений, репорты на почту.

Накой вам инфа на почту о том, что у пользователя исчерпан лимит по счету? Скажите пожалуйста? Что вы здесь будете исправлять?

0K>>На конкретном примере. Библиотека для работы с финансовой системой. Метод для перевода средств со счета на карту. Клиент вызывает этот метод -- происходит ошибка. В Message -- детальное описание причины ошибки (причин может быть несколько десятков).


G>Откуда оно там взялось? Код бизнес-слоя формирует? А если этот же код из сервиса вызываться будет? Удаленному приложению уйдет ошибка с текстом вроде "В поле2 сумма должна быть больше, чем в поле1"?


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

По поводу ошибки в текстовом виде. Я бы предложил в теле исключения сделать Enum и расшифровку. Enum будет представлять состояние. А расшифровка в ресурсах библиотеки (с локализацией).

G>Обычно user-friendly сообщения формирует слой PL (там ему и место), а если текст формируется в PL, то заворачивать его в исключение и не надо.


Библиотека работает с финансовым сервисом. Сервис вообще не на .Net написан. Он возвращает описание ошибки в текстовом виде. Что ваша библиотека, строку будет возвращать? Или сообщение со специальным Message?
Re[8]: Исключения для пользователя и для программиста -- раз
От: 0K Ниоткуда  
Дата: 12.08.10 10:26
Оценка:
Здравствуйте, gandjustas, Вы писали:

0K>>Вот с этого места подробнее. Какие именно типы исключений перехватываются? Как вы их выделяете?

G>Самый частый пример — валидация, хотя её лучше не exception_ами делать.

Подробнее. Вы проверяете данные, которые вернул сервис. Там текст ошибки. Вы что с ним делать будете?

0K>>Не для каких-то, а содержащих ИНФОРМАЦИЮ ДЛЯ ПОЛЬЗОВАТЕЛЯ!!!

G>Каким образом в глубине приложения можно сформировать информацию для пользователя? Если ругнуться что AccountBalance отрицательный, то это пользователю ничего не даст, такого поля может и не быть на форме.

А кто еще, как ни библиотека, знает все тонкости процесса? Именно библиотека и должна сформировать корректное исключение.

G>Отлично, и кто будет формировать UserFriendlyException ?


Библиотека, которая напрямую работает с сервисом/базой данных и пр. Или вы предлагаете номера ошибок передавать, а уже в пользовательском интерфейсе сделать сопоставление: номер ошибки — текст????
Re[10]: Исключения для пользователя и для программиста -- ра
От: 0K Ниоткуда  
Дата: 12.08.10 10:36
Оценка:
Здравствуйте, mrjeka, Вы писали:

M>Да, если вы заметили, что они ориентированы на разработчиков, а не на пользователей.

M>Такое сообщение как "Null reference exception" все равно пользователю ни о чем не скажет.

Не все типы исключений там для разработчиков. Далеко не все.

Контрактные и инвариантные -- для разработчиков. Некоторые более конкретные -- для обычных пользователей.

M>Библиотеку можно продать другой софтверной компании. А кому она будет её поставлять, это уже её дела.


В чем проблема локализовать?

M>Я уже вам говорил, создайте кастомный класс, заполните поля нужной информацией.


Это не решает проблемы. Откуда я знаю какие типы исключений в сторонней библиотеке предназначены для вывода Message пользователю?

M>>>Ну представьте, сообщение File 'имя файла' not found. Пользователь не рубит на английском. Тип исключения FileNotFoundException. Разумнее на основании типа полученного исключения в UI части обратиться к файлу локализации, достать нужное сообщение на нужном языке и выдать его пользователю.


0K>>Открою страшную тайну. Если пользователь не знает английского, у него будет русский (к примеру) Windows и русский .Net. В отличии от вас, MS локализуют все свои библиотеки. Сообщения об ошибках там на русском языке.


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


В чем проблема добавить -- там правильная пунктуация, в конце предложения точка.

M>Объясняю на пальцах. Используются 2 сторонние библиотеки разных производителей. У одних ошибка "Файл {0} не найден", у других "Не найден файл".

M>Какой толк от такой локализации в библиотеках??? Или вы не взирая ни на что, будете выдавать сообщения так, как они заложены в библиотеках?

При локализации вы меняете язык. Можете кое-чего добавить. А что вам еще нужно?

0K>>Вы хоть представляете какую вы сейчас ерунду спороли? Вы знаете сколько может быть вариантов почему деньги со счета на карту перевести не удалось? Около сотни. И вы будете создавать и обрабатывать все 100 типов исключений Атхнитесь!!!


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


Ага. Т.е. вы предлагаете вернуться к парадигме C++ и использовать коды ошибок?

А если нет кодов ошибок? Сервис выдает вам текст исключения и все тут.
Re[11]: Дополнение
От: 0K Ниоткуда  
Дата: 12.08.10 10:50
Оценка:
Здравствуйте, mrjeka, Вы писали:

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


Смотрите какая парадигма:

1. Есть ошибки, возникающие из-за некорректных данных, введенных пользователем (здесь стараемся не генерировать исключений, сразу проверяем).
2. Есть ошибки нарушения сценария пользователем. Здесь без генерации Exception's не обойтись, но они не являются чем-то непредсказуемым. Их нет смысла заносить в лог. Они не нужны программисту (зачем программисту знать, что в Васи исчерпан лимит операций по счету?).

Вот эти 2 типа ошибок не нужно логировать. Они известны и предсказуемы. Их не нужно исправлять. Они не для программиста а для пользователя.

3. Есть ошибки кода (кривой код, нарушение контрактов и инвариантов). Это нужно знать программисту.
4. Ошибочные данные от сервиса (нужно знать программисту).
5. Аппаратные ошибки (ошибки системы).

И естественно, ошибки и описания ошибок, возникающих при работе с финансовой системой, должна генерировать библиотека. А не ваш код. Ваш код должен лишь знать, что ошибки определенного типа предназначены для пользователя!!!
Re[7]: Исключения для пользователя и для программиста -- раз
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 12.08.10 10:50
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Здравствуйте, gandjustas, Вы писали:


G>>А смысл? Потерять stacktrace? И зачем пользователю отображать текст exception, ему нужно отображать инструкцию как ошибку исправить.


0K>А накой вам stacktrace предсказуемого исключения? Если у пользователя исчерпан лимит операций по счету -- накой вам stacktrace? Вы что будете действительно разбирать такие вот ошибки от 10 тыс. пользователей использующих программу?

0K>В лог пишем только то, что является нарушением контрактов и инвариантов (ошибка в коде). А эти исключения не ошибка в коде -- они абсолютно предсказуемая ошибка в бизнес-процессе -- исчерпан лимит. Зачем программисту знать, что у какого-то пользователя исчерпан лимит по счету?
Наверное затем что он программу пишет

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

0K>>>Механизма нет, хотя должен быть.

G>>Никому не должен, это ты сам придумал.
0K>Я не зря придумал. Возможно скоро MS это поймут и введут.

Ты правда считаешь себя умнее программистов в MS?


0K>>>На конкретном примере. Библиотека для работы с финансовой системой. Метод для перевода средств со счета на карту. Клиент вызывает этот метод -- происходит ошибка. В Message -- детальное описание причины ошибки (причин может быть несколько десятков).


G>>Откуда оно там взялось? Код бизнес-слоя формирует? А если этот же код из сервиса вызываться будет? Удаленному приложению уйдет ошибка с текстом вроде "В поле2 сумма должна быть больше, чем в поле1"?

0K>А вы знаете что по стандарту все исключения должны быть сериализуемыми? И именно для того, чтобы можно было передавать удаленно.
И что? Если там простой текст мне на клиенте это никак не поможет.

0K>По поводу ошибки в текстовом виде. Я бы предложил в теле исключения сделать Enum и расшифровку. Enum будет представлять состояние. А расшифровка в ресурсах библиотеки (с локализацией).

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


G>>Обычно user-friendly сообщения формирует слой PL (там ему и место), а если текст формируется в PL, то заворачивать его в исключение и не надо.


0K>Библиотека работает с финансовым сервисом. Сервис вообще не на .Net написан. Он возвращает описание ошибки в текстовом виде. Что ваша библиотека, строку будет возвращать? Или сообщение со специальным Message?

Ну если кто-то профакапил архитектуру до меня, то уже ниче сделать не смогу. Но мы тут обсуждаем как самому не профакапить.
Re[11]: Исключения для пользователя и для программиста -- ра
От: mrjeka Россия  
Дата: 12.08.10 10:55
Оценка:
Здравствуйте, 0K, Вы писали:

M>>Я уже вам говорил, создайте кастомный класс, заполните поля нужной информацией.


0K>Это не решает проблемы. Откуда я знаю какие типы исключений в сторонней библиотеке предназначены для вывода Message пользователю?


И я твержу уже сколько. Не надо полагаться на сообщение исключения!!! формируйте своё на основании типа и другой информации исключения. Вам никто не гарантирует, что в e.Message сторонней библиотеки, даже как бы предназначенной для показа пользователю будет лежать то, что вам нужно.

M>>Объясняю на пальцах. Используются 2 сторонние библиотеки разных производителей. У одних ошибка "Файл {0} не найден", у других "Не найден файл".

M>>Какой толк от такой локализации в библиотеках??? Или вы не взирая ни на что, будете выдавать сообщения так, как они заложены в библиотеках?

0K>При локализации вы меняете язык. Можете кое-чего добавить. А что вам еще нужно?

Ну тогда вам нужно будет менять все во всех файлах ресурсов. 10 библиотек с ресурсами, полезете во все 10 библиотек.
Не проще ли на уровне приложения создать 1 файл ресурсов, который бы на одинаковые типы ошибок выдавал одинаковые сообщения?

0K>>>Вы хоть представляете какую вы сейчас ерунду спороли? Вы знаете сколько может быть вариантов почему деньги со счета на карту перевести не удалось? Около сотни. И вы будете создавать и обрабатывать все 100 типов исключений Атхнитесь!!!


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


0K>Ага. Т.е. вы предлагаете вернуться к парадигме C++ и использовать коды ошибок?


ну такие коды как 503, 404 используются и никто от этого не умер.

0K>А если нет кодов ошибок? Сервис выдает вам текст исключения и все тут.


А если в теле сообщения исключения матом кроют????
Re[9]: Исключения для пользователя и для программиста -- раз
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 12.08.10 10:57
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Здравствуйте, gandjustas, Вы писали:


0K>>>Вот с этого места подробнее. Какие именно типы исключений перехватываются? Как вы их выделяете?

G>>Самый частый пример — валидация, хотя её лучше не exception_ами делать.

0K>Подробнее. Вы проверяете данные, которые вернул сервис. Там текст ошибки. Вы что с ним делать будете?


Найду автора сервиса и дам по роже


0K>>>Не для каких-то, а содержащих ИНФОРМАЦИЮ ДЛЯ ПОЛЬЗОВАТЕЛЯ!!!

G>>Каким образом в глубине приложения можно сформировать информацию для пользователя? Если ругнуться что AccountBalance отрицательный, то это пользователю ничего не даст, такого поля может и не быть на форме.

0K>А кто еще, как ни библиотека, знает все тонкости процесса? Именно библиотека и должна сформировать корректное исключение.

Именно и библиотека не знает, потому что чаще всего библиотека пишется обобщенно. Библиотека в принципе не знает что видит пользователь. Если в форме больше 5 полей, а сообщение об ошибке ни к одному из них не привязано визуально, то шансы на то что вам не будут звонить разгневанные пользователи падают почти до нуля.

G>>Отлично, и кто будет формировать UserFriendlyException ?


0K>Библиотека, которая напрямую работает с сервисом/базой данных и пр. Или вы предлагаете номера ошибок передавать, а уже в пользовательском интерфейсе сделать сопоставление: номер ошибки — текст????


Зачем номера, есть же типы

try
{
//...
}
catch(Ex1 e1)
{
//...
}
catch(Ex2 e2)
{
//...
}



Все что ты пытаешься придумать было продумано до тебя и гораздо тщательнее, если не пошло "в массы", значит на это есть свои причины.
Re[8]: Исключения для пользователя и для программиста -- раз
От: 0K Ниоткуда  
Дата: 12.08.10 11:06
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Давай более реальный сценарий:

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

Я очень хорошо знаком с подобными сервисами и реализовал несколько.

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

G>А потом буду громко ругать авторов бизнес-слоя за то что я не смогу использовать их код в сервисе, потому что на клентской стороне надо будет парсить текст для аналогичного результата.


Не понял, в чем проблема использовать в сервисе? Исключения они ведь обязательно сериализуемые. В чем проблема то?

G>

G>Ты правда считаешь себя умнее программистов в MS?

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

G>И что? Если там простой текст мне на клиенте это никак не поможет.


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

0K>>По поводу ошибки в текстовом виде. Я бы предложил в теле исключения сделать Enum и расшифровку. Enum будет представлять состояние. А расшифровка в ресурсах библиотеки (с локализацией).

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

Это для случая если ошибки по номерам.

0K>>Библиотека работает с финансовым сервисом. Сервис вообще не на .Net написан. Он возвращает описание ошибки в текстовом виде. Что ваша библиотека, строку будет возвращать? Или сообщение со специальным Message?

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

Что плохого в том, что исключения выводятся в нужном для пользователя виде?
Re[12]: Исключения для пользователя и для программиста -- ра
От: 0K Ниоткуда  
Дата: 12.08.10 11:10
Оценка:
Здравствуйте, mrjeka, Вы писали:

M>И я твержу уже сколько. Не надо полагаться на сообщение исключения!!! формируйте своё на основании типа и другой информации исключения. Вам никто не гарантирует, что в e.Message сторонней библиотеки, даже как бы предназначенной для показа пользователю будет лежать то, что вам нужно.


Автор библиотеки это должен гарантировать. И такие исключения нужно наследовать от специального системного класса.

Зачем делать двойную работу??? Почему каждый пользователь библиотеки должен расшифровывать тысячи вариантов ошибок?

Давайте практический смысл.

0K>>При локализации вы меняете язык. Можете кое-чего добавить. А что вам еще нужно?

M>Ну тогда вам нужно будет менять все во всех файлах ресурсов. 10 библиотек с ресурсами, полезете во все 10 библиотек.

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

M>Не проще ли на уровне приложения создать 1 файл ресурсов, который бы на одинаковые типы ошибок выдавал одинаковые сообщения?


Нет, не проще. Это работа программиста и стоит дороже. Переводчик сделает все качественнее, быстрее и дешевле.

Зачем каждый дожен расшифровывать коды ошибок библиотеки, если можно один раз в самой библиотеке создать файл ресурсов с корректными сообщениями об ошибках? Зачем делать дурную работу?
Re[9]: Исключения для пользователя и для программиста -- раз
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 12.08.10 11:16
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Здравствуйте, gandjustas, Вы писали:


G>>Давай более реальный сценарий:

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

0K>Я очень хорошо знаком с подобными сервисами и реализовал несколько.


0K>Вы не сможете все валидировать все, там около 500 разных вариантов, почему возникла ошибка.

Пофигу, не надо проблемы валить на пользователя.

0K>Данные, вводимые пользователем, конечно нужно проверить. Но вы не проверить существует ли номер телефона (не всегда), не заблокирован ли номер телефона, есть ли связь с ЦПП, проводятся ли сейчас платежи. 500 разных ошибок.

Ну и все они относятся к этому самому телефону и выводиться должны именно там.

Особенно ситуация усугубляется если полей ввода много. Или например два поля с телефонами, а к тебе из глубин бизнес-слоя прилетает эксепшен "телефон заблокирован".

G>>А потом буду громко ругать авторов бизнес-слоя за то что я не смогу использовать их код в сервисе, потому что на клентской стороне надо будет парсить текст для аналогичного результата.

0K>Не понял, в чем проблема использовать в сервисе? Исключения они ведь обязательно сериализуемые. В чем проблема то?
Читай выше

G>>

G>>Ты правда считаешь себя умнее программистов в MS?
0K>Они однозначно лучше меня знают свои библиотеки (которую через 20 лет никто и не вспомнит), но далеко не во всех базовых вещах имеют понимание выше моего.
То есть ты таки считаешь себя умнее программистов MS. Говорит о многом

G>>И что? Если там простой текст мне на клиенте это никак не поможет.

0K>Поможет. Вы этот текст отображаете пользователю -- ему все становится понятно. Вам как программисту этот текст не нужен, это не ошибка в программе.
Пример с двумя полями телефонов я уже привел.


0K>>>Библиотека работает с финансовым сервисом. Сервис вообще не на .Net написан. Он возвращает описание ошибки в текстовом виде. Что ваша библиотека, строку будет возвращать? Или сообщение со специальным Message?

G>>Ну если кто-то профакапил архитектуру до меня, то уже ниче сделать не смогу. Но мы тут обсуждаем как самому не профакапить.
0K>Что плохого в том, что исключения выводятся в нужном для пользователя виде?
Ну как тебе сказать...
Пользователю не нужны эти самые исключения, ему нужно свою работу делать. А исключения нужны тебе, чтобы не протерять ошибку.
Вот тут есть проблема, ошибка должна быть обнаружена как можно раньше и выброшена в виде исключения, а сообщение пользователю нужно формировать как можно позже, чтобы удобно было. Вот тут и возникает проблема.
Re[10]: Исключения для пользователя и для программиста -- ра
От: 0K Ниоткуда  
Дата: 12.08.10 11:27
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Пофигу, не надо проблемы валить на пользователя.


Как раз надо. Если пользователь узнает что номер заблокирован -- он его пополнит на 25 грн., а не на 5 (чтобы разбокировали).

Не считайте пользователей идиотами. Они прекрасно поймут текст ошибки в 80% случаев он им будет полезен.

G>Особенно ситуация усугубляется если полей ввода много. Или например два поля с телефонами, а к тебе из глубин бизнес-слоя прилетает эксепшен "телефон заблокирован".


Нет. Не не UserFriendlyException. Нужно указать какой именно номер и по какой причине. Тот кто делает библиотеку -- лучше вас знает в каком виде нужно выдать исключения пользователю.

G>>>А потом буду громко ругать авторов бизнес-слоя за то что я не смогу использовать их код в сервисе, потому что на клентской стороне надо будет парсить текст для аналогичного результата.

0K>>Не понял, в чем проблема использовать в сервисе? Исключения они ведь обязательно сериализуемые. В чем проблема то?
G>Читай выше

Читал, и что?

G>То есть ты таки считаешь себя умнее программистов MS. Говорит о многом


А вы считаете себя глупее? Как это вообще можно измерять? Это только в конце жизни будет видно кто чего достиг, да и то не всегда это отражает уровень интеллекта.

0K>>Поможет. Вы этот текст отображаете пользователю -- ему все становится понятно. Вам как программисту этот текст не нужен, это не ошибка в программе.

G> Пример с двумя полями телефонов я уже привел.

Просто вы привели текст, который никогда не включат в UserFriendlyException.

0K>>Что плохого в том, что исключения выводятся в нужном для пользователя виде?

G>Ну как тебе сказать...
G>Пользователю не нужны эти самые исключения, ему нужно свою работу делать. А исключения нужны тебе, чтобы не протерять ошибку.

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

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


Это не ошибка с т.з. работы программы. Это просто ошибка в бизнес-процессе. Логировать ее не нужно и реакции на нее не нужно. Она нужна только пользователю. Показать ее нужно сразу, т.к. чем бысрее пользователь узнает -- тем быстрее решит проблему.
Re[11]: Исключения для пользователя и для программиста -- ра
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 12.08.10 11:40
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Здравствуйте, gandjustas, Вы писали:


G>>Пофигу, не надо проблемы валить на пользователя.


0K>Как раз надо. Если пользователь узнает что номер заблокирован -- он его пополнит на 25 грн., а не на 5 (чтобы разбокировали).

Разговор не об этом.

0K>Не считайте пользователей идиотами. Они прекрасно поймут текст ошибки в 80% случаев он им будет полезен.

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

G>>Особенно ситуация усугубляется если полей ввода много. Или например два поля с телефонами, а к тебе из глубин бизнес-слоя прилетает эксепшен "телефон заблокирован".


0K>Нет. Не не UserFriendlyException. Нужно указать какой именно номер и по какой причине. Тот кто делает библиотеку -- лучше вас знает в каком виде нужно выдать исключения пользователю.

Сильное завявление, обосновать сможешь?
Учитывая что тот кто делает библиотеку даже не может предполагать будет ли пользователь.

G>>>>А потом буду громко ругать авторов бизнес-слоя за то что я не смогу использовать их код в сервисе, потому что на клентской стороне надо будет парсить текст для аналогичного результата.

0K>>>Не понял, в чем проблема использовать в сервисе? Исключения они ведь обязательно сериализуемые. В чем проблема то?
G>>Читай выше
0K>Читал, и что?
Твой вариант решения. Два поля с телефонами, вываливается сообщение "телефон заблокирован". Что будешь делать?

G>>То есть ты таки считаешь себя умнее программистов MS. Говорит о многом


0K>А вы считаете себя глупее?

Конечно, поэтому изучаю много.

0K>Как это вообще можно измерять?

Не можешь измерить — считай себя глупее.



0K>>>Поможет. Вы этот текст отображаете пользователю -- ему все становится понятно. Вам как программисту этот текст не нужен, это не ошибка в программе.

G>> Пример с двумя полями телефонов я уже привел.
0K>Просто вы привели текст, который никогда не включат в UserFriendlyException.
А что тогда включат? И как ты можешь гарантировать что вообще туда включат, если ты не сам пишешь текст ошибки?



0K>>>Что плохого в том, что исключения выводятся в нужном для пользователя виде?

G>>Ну как тебе сказать...
G>>Пользователю не нужны эти самые исключения, ему нужно свою работу делать. А исключения нужны тебе, чтобы не протерять ошибку.

0K>Нет. Вы ПЕРЕПУТАЛИ исключения, вызываемые ошибками в коде и исключения, предназначенные для вывода информации пользователю. Не путайтесь, это разные виды исключений. Не все исключения нужно логировать.

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

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


0K>Это не ошибка с т.з. работы программы. Это просто ошибка в бизнес-процессе. Логировать ее не нужно и реакции на нее не нужно. Она нужна только пользователю. Показать ее нужно сразу, т.к. чем бысрее пользователь узнает -- тем быстрее решит проблему.

Ну а причем тут исключения?
Re[10]: Исключения для пользователя и для программиста -- ра
От: 0K Ниоткуда  
Дата: 12.08.10 12:07
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Зачем номера, есть же типы


G>
G>try
G>{
G>//...
G>}
G>catch(Ex1 e1)
G>{
G>//...
G>}
G>catch(Ex2 e2)
G>{
G>//...
G>}

G>



И так 200 рвз:

G>Все что ты пытаешься придумать было продумано до тебя и гораздо тщательнее, если не пошло "в массы", значит на это есть свои причины.


Где и кем? Ссылка?
Re[11]: Исключения для пользователя и для программиста -- ра
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 12.08.10 12:13
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Здравствуйте, gandjustas, Вы писали:


G>>Зачем номера, есть же типы


G>>
G>>try
G>>{
G>>//...
G>>}
G>>catch(Ex1 e1)
G>>{
G>>//...
G>>}
G>>catch(Ex2 e2)
G>>{
G>>//...
G>>}

G>>



0K>И так 200 рвз:

Именно поэтому исключениями в UI мало пользуются.

G>>Все что ты пытаешься придумать было продумано до тебя и гораздо тщательнее, если не пошло "в массы", значит на это есть свои причины.

0K>Где и кем? Ссылка?
Framework desingn guidelines и блоги разработчиков. Ссылки не собираю, ищи сам.
Re: Исключения для пользователя и для программиста -- разниц
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 12.08.10 12:18
Оценка:
Здравствуйте, 0K, Вы писали:

0K>В продолжение темы об исключениях (см. тег).


0K>90% Exception'ов генерируются для программиста. Для пользователя они не информативны. Они служат для реализации контрактов и инвариантов (к примеру, проверка аргументов функции на null).


Хм... а что, нет единого обработчика всех исключений, вроде как Application.OnException в Delphi? Там, в одном месте, собственно говоря, и должна выполняться вся работа по преобразованию исключений в понятные сообщения.
Re[2]: Исключения для пользователя и для программиста -- раз
От: 0K Ниоткуда  
Дата: 12.08.10 12:45
Оценка:
Здравствуйте, Mystic, Вы писали:

M>Хм... а что, нет единого обработчика всех исключений, вроде как Application.OnException в Delphi? Там, в одном месте, собственно говоря, и должна выполняться вся работа по преобразованию исключений в понятные сообщения.


Т.е. вы предлагаете каждому разработчику, кто использует библиотеку, самостоятельно расшифровывать для пользователя все коды исключений? А зачем, простите, делать дурную работу? Разве разработчик библиотеки с этим не справится?
Re[8]: –
От: 0K Ниоткуда  
Дата: 12.08.10 13:47
Оценка:
Здравствуйте, Qbit86, Вы писали:

0K>>Давайте проще: разработчик, разработчик библиотеки и пользователь. Деньги откуда идут? От конечного пользователя. Нахрен вообще о программистах говорить?


Q>Откровенная ерунда.


Как раз не ерунда. На .Net большая часть публичных приложений создана для разработчиков. Каждый лепит свой велосипед. Разработчик -- это строитель, а не пользователь.

Q>То, что ты предлагаешь — оно и есть, только имеет тип не int, а string, и называется не код ошибки, а сообщение исключения.


Вы вообще не поняли о чем речь. Вообще нуль. Читали читали -- и не поняли.

Q>Информация об ошибке передаётся:

Q>1) В типе исключения. Позволяет сепарировать исключения в момент ловли.

А я разве не об этом же? Тип исключения + структуризация: наследование от UserFriendlyException.

Q>2) В полях исключения. Позволяет восстанавливать контекст исключения, состояние возникновение ошибки.

Q>3) В тексте сообщения. В случае usage exception'ов содержит указание, как изменить код, чтобы избежать выброс исключения;

Да поймите же вы! Не нужно менять код для этого исключения! Оно ожидаемо. Нет ошибки в коде. Сколько можно повторять???

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

Q>Вот ты приводил пример, когда у тебя стописят разных ошибок, и все возвращаются через один класс EndUserFriendly-исключения, отличаясь только сообщениями. Отлично, ты просто выводишь месседж. А завтра начальник говорит тебе: а в случае, если тип ошибки «Номер +755щ2713141 имеет ниверный формат.», выдавать не сообщение с орфографической ошибкой, а окошко ввода нового номера.


Здесь просто. Данные, которые вводит пользователь обрабатываем сразу. Исключения не генерируются. Кроме того, UserFriendly может содержать и Enum с типом. Об этом я выше писал.

Q>И у тебя начнётся ад. Тебе придётся сепарировать исключения по тексту сообщения. Да не просто равенством, а парсингом. Да учесть все возможные (как существующие, так и будущие) локализации. Это намного, намного хуже кодов ошибок! Ты проклянёшь автора библиотеки, который взял на себя смелость вместо пользователя API решать, что увидит конечный пользователь.


Ничто не мешает добавить Enum с типом. Выше я писал об этом.

А вы будуте для каждого использования библиотеки вручную расшифровывать все варианты этого Enum. Я же предлагаю сделать эту расшифровку в библиотеке в Message.

Q>Если нужно — легко. В классе FileNotFoundException содержится поле ex.FileName. Мне не важно, что в поле ex.Message содержится «Файл „filename.xml“ не найден». Я всегда смогу (и по умолчанию — буду) формировать своё сообщение, допустим, «Проверьте, пожалуйста, наличие файла {0}.»; и подставлю ex.FileName, а не выпарсенное между кавычками название файла.


А нахрена? Вы знаете, что вы допустили ошибку сейчас? В данном случае слово пожалуйста не уместно и пользователь будет чувствовать себя неловко. Оставьте все как есть, там все хорошо без ваших стараний сделано.
Re[9]: –
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 12.08.10 13:56
Оценка:
Здравствуйте, 0K, Вы писали:

Q>>Информация об ошибке передаётся:

Q>>1) В типе исключения. Позволяет сепарировать исключения в момент ловли.

0K>А я разве не об этом же? Тип исключения + структуризация: наследование от UserFriendlyException.


Нет, ты ровно о противоположном. Ты предлагаешь делать

try
{
 //code
}
catch(UserFriendlyException e)
{
  ReportToUser(e.Message)
}


Те фактически забить на тип исключения, а тупо передавать одну строку. Или строку + код ошибки.

Q>>2) В полях исключения. Позволяет восстанавливать контекст исключения, состояние возникновение ошибки.

Q>>3) В тексте сообщения. В случае usage exception'ов содержит указание, как изменить код, чтобы избежать выброс исключения;

0K>Да поймите же вы! Не нужно менять код для этого исключения! Оно ожидаемо. Нет ошибки в коде. Сколько можно повторять???

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

0K>Не нужно его логировать. Не нужно о нем знать разработчику и беспокоить его лишний раз этим исключением. Оно только для пользователя!

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

Q>>Вот ты приводил пример, когда у тебя стописят разных ошибок, и все возвращаются через один класс EndUserFriendly-исключения, отличаясь только сообщениями. Отлично, ты просто выводишь месседж. А завтра начальник говорит тебе: а в случае, если тип ошибки «Номер +755щ2713141 имеет ниверный формат.», выдавать не сообщение с орфографической ошибкой, а окошко ввода нового номера.


0K>Здесь просто. Данные, которые вводит пользователь обрабатываем сразу. Исключения не генерируются.

Вот, то есть исключения для "ожидаемых ошибок" не нужны.

0K>Кроме того, UserFriendly может содержать и Enum с типом. Об этом я выше писал.

То есть получили они класс UserFriendlyException с Enum_ом (кодом ошибки), потрясающе. Все умы, которые разрабатывали исключения, должны непременно посыпать голову пеплом.
Re[3]: Исключения для пользователя и для программиста -- раз
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 12.08.10 14:06
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Здравствуйте, Mystic, Вы писали:


M>>Хм... а что, нет единого обработчика всех исключений, вроде как Application.OnException в Delphi? Там, в одном месте, собственно говоря, и должна выполняться вся работа по преобразованию исключений в понятные сообщения.


0K>Т.е. вы предлагаете каждому разработчику, кто использует библиотеку, самостоятельно расшифровывать для пользователя все коды исключений? А зачем, простите, делать дурную работу? Разве разработчик библиотеки с этим не справится?


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

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

Но если такая обработка централизована, это удобно. Надо улучшить сообщение об ошибке --- знаешь где
Re[5]: О глобальном перехвате исключений
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 12.08.10 14:14
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>Мне больше по нраву другой вариант. Перехватываю исключение не в глобальном обработчике, а как только оно поднимается до уровня, где хватает данных о контексте. Тогда я сформирую сообщение «К этому отделу не приписан ни один сотрудник.», проброшу свой тип исключения, определяемый в моей бизнес-логике, а presentation layer доблестно отобразит понятное пользователю сообщение. Все рады, довольны, багрепорты разработчику не шлют, профит!


А я такое поведение запрещал? Это вообще штатная ситуация, которая проверяется условием и последующим бросанием исключения.
Re[10]: Offtop
От: mrjeka Россия  
Дата: 12.08.10 14:36
Оценка:
Автору объяснили как могли разными примерами, фразами, сценариями. Одно и тоже и в фаз и профиль.
Он или стебётся или в самом деле просто не понимает.
Re[10]: —
От: 0K Ниоткуда  
Дата: 13.08.10 01:09
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>Без «моих стараний» пользователь так и не узнает, что filename.xml содержит даты рождения его друзей (если это необходимо). Иными словами, в сообщении отсутствует семантика. Библиотека не знает, в каком окружении будет применяться: к файлу с датами рождения или с телефонными номерами.


Зависит от уровня библиотеки. Некоторые библиотеки (большинство) не должны выдавать UserFriendly ислючений. А другие должны.

Вот PayPal, к примеру, поставляет свою библиотеку. При возникновении исключения -- там четкая ошибка (текст для пользователя). Зачем каждый разработчик должен расшифровывать исключение, если это легче сделать разработчику библиотеки?
Re[9]: –
От: midcyber
Дата: 13.08.10 02:22
Оценка:
Здравствуйте, 0K, Вы писали:

Q>>3) В тексте сообщения. В случае usage exception'ов содержит указание, как изменить код, чтобы избежать выброс исключения;


0K>Да поймите же вы! Не нужно менять код для этого исключения! Оно ожидаемо. Нет ошибки в коде. Сколько можно повторять???


Если нет ошибки в коде, значит, с большой степенью вероятности ошибка в дизайне.
Re[10]: –
От: 0K Ниоткуда  
Дата: 13.08.10 02:25
Оценка:
Здравствуйте, midcyber, Вы писали:

0K>>Да поймите же вы! Не нужно менять код для этого исключения! Оно ожидаемо. Нет ошибки в коде. Сколько можно повторять???


M>Если нет ошибки в коде, значит, с большой степенью вероятности ошибка в дизайне.


А как влияет исчерпание лимита операций пользователя в системе на ваш код? Как это связано?
Re[11]: –
От: midcyber
Дата: 13.08.10 02:48
Оценка:
Здравствуйте, 0K, Вы писали:

0K>>>Да поймите же вы! Не нужно менять код для этого исключения! Оно ожидаемо. Нет ошибки в коде. Сколько можно повторять???


M>>Если нет ошибки в коде, значит, с большой степенью вероятности ошибка в дизайне.


0K>А как влияет исчерпание лимита операций пользователя в системе на ваш код? Как это связано?


Я вообще не понимаю, что ты спрашиваешь. Какой еще лимит операций?
Если исключение ожидаемо, нафига его делать исключением изначально?
Проверяй условие completedOperations <= limit
Re[13]: –
От: midcyber
Дата: 13.08.10 03:57
Оценка:
Здравствуйте, samius, Вы писали:

S>С такой логикой далеко не уедешь. Ситуации с отсутствием файла, недопустимым индексом, и т.п. вполне ожидаемы. Нафига было городить исключения?


Я не очень согласен с такой трактовуой "ожидаемости"

1) Случай с файлом — основной codepath как раз ожидает, что файл есть, он на месте, хватает прав для открытия и т.д.
Какой именно файл открывается? Тут могут быть варианты:
-Список файлов получен перечислением всех файлов в каталоге.
Если во время работы программы такой файл переместили/удалили — это исключительная ситуация, возможно аварийная.
-Какой-нибудь статичный файл, например конфиг. Нормально ли ожидать, что его нет?
-Ввод пользователя — его в любом случае придется проверять на валидность.
Итого, в случае с файлом оба способа (исключения и проверки) более-менее равноправны.

2) Недопустимый индекс чего?
Если речь идет об индексе массива, то я против строить логику на исключениях.
Пусть это исключение пробрасывается до самого верха, поскольку кто-то где-то не проверил валидность индексов, надо исправлять ошибку в коде.
Re[14]: –
От: samius Япония http://sams-tricks.blogspot.com
Дата: 13.08.10 04:10
Оценка:
Здравствуйте, midcyber, Вы писали:

M>Здравствуйте, samius, Вы писали:


S>>С такой логикой далеко не уедешь. Ситуации с отсутствием файла, недопустимым индексом, и т.п. вполне ожидаемы. Нафига было городить исключения?


M>Я не очень согласен с такой трактовуой "ожидаемости"


M>1) Случай с файлом — основной codepath как раз ожидает, что файл есть, он на месте, хватает прав для открытия и т.д.

M>Какой именно файл открывается? Тут могут быть варианты:
M>-Список файлов получен перечислением всех файлов в каталоге.
M>Если во время работы программы такой файл переместили/удалили — это исключительная ситуация, возможно аварийная.
M>-Какой-нибудь статичный файл, например конфиг. Нормально ли ожидать, что его нет?
M>-Ввод пользователя — его в любом случае придется проверять на валидность.
M>Итого, в случае с файлом оба способа (исключения и проверки) более-менее равноправны.

M>2) Недопустимый индекс чего?

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

Значит я что-то не так понял по поводу

Я вообще не понимаю, что ты спрашиваешь. Какой еще лимит операций?
Если исключение ожидаемо, нафига его делать исключением изначально?
Проверяй условие completedOperations <= limit

Здесь код должен либо совершить операцию, либо бросить исключение. Замалчивание того факта что операция не была произведена — наименее ожидаемый сценарий работы.
Re[15]: –
От: midcyber
Дата: 13.08.10 04:43
Оценка:
Здравствуйте, samius, Вы писали:

S>Значит я что-то не так понял по поводу

S>

S>Я вообще не понимаю, что ты спрашиваешь. Какой еще лимит операций?
S>Если исключение ожидаемо, нафига его делать исключением изначально?
S>Проверяй условие completedOperations <= limit


Ну грубо говоря, 0K болеет за такой вариант:
class User
{
  void DoOperation(Operation op)
  {
    throw new LimitExceedException("Превышено количество попыток, попробуйте позже");
  }
}

void Usage()
{
  try
  {
    user.DoOperation(op);
  }
  catch(LimitExceedException ex)
  {
    gui.SetText(ex.Message);
  }
}


А мне более близка такая идея:
class User
{
  void DoOperation(Operation op)
  {
    throw new LimitExceedException("Пользователь исчерпал лимит попыток. 
     Вы можете проверить возможность операции с помощью метода CanCompleteOperation");
  }

  bool CanCompleteOperation(Operation op) { return completedOperations < operationsLimit); }
}

void Usage()
{
  if(user.CanCompleteOperation(op))
   user.DoOperation(op);
  else
   gui.SetText(user.GetLocalizedError(op));
}
Re[16]: –
От: samius Япония http://sams-tricks.blogspot.com
Дата: 13.08.10 04:59
Оценка:
Здравствуйте, midcyber, Вы писали:

M>Здравствуйте, samius, Вы писали:


S>>Значит я что-то не так понял по поводу

S>>

S>>Я вообще не понимаю, что ты спрашиваешь. Какой еще лимит операций?
S>>Если исключение ожидаемо, нафига его делать исключением изначально?
S>>Проверяй условие completedOperations <= limit


M>Ну грубо говоря, 0K болеет за такой вариант:


M>А мне более близка такая идея:

M>
M>class User
M>{
M>  void DoOperation(Operation op)
M>  {
M>    throw new LimitExceedException("Пользователь исчерпал лимит попыток. 
M>     Вы можете проверить возможность операции с помощью метода CanCompleteOperation");
M>  }

M>  bool CanCompleteOperation(Operation op) { return completedOperations < operationsLimit); }
M>}

M>void Usage()
M>{
M>  if(user.CanCompleteOperation(op))
M>   user.DoOperation(op);
M>  else
M>   gui.SetText(user.GetLocalizedError(op));
M>}
M>

Этот вариант мне ближе тем, что сообщение для пользователя берется не из исключения. Но плох тем что
Re[17]: –
От: midcyber
Дата: 13.08.10 05:05
Оценка:
Здравствуйте, samius, Вы писали:

S>Этот вариант мне ближе тем, что сообщение для пользователя берется не из исключения. Но плох тем что

S>
Зачем try/catch в данном случае? Пусть приложение падает, если программист забыл вызвать CanComplete
С остальным согласен, я особо не старался, да и способ получения локализованного сообщения не продумал, смотрится ужасненько
Re[19]: –
От: midcyber
Дата: 13.08.10 05:23
Оценка:
Здравствуйте, samius, Вы писали:

S>Даже если программист не забыл вызвать CanComplete, со времени успешной проверки до времени выполнения операции может многое что измениться в системе. Проверка не блокирует записи в БД на изменение! Проверка тут вообще может говорить лишь о прогнозе выполнения операции, потому как если даже она закончилась неудачно, то через пол секунды наступит завтра и счетчики операций будут обнулены.


Ну тогда мой вариант вообще жить не может, всю логику надо строить на исключениях. Учту на будущее.
Re[20]: –
От: samius Япония http://sams-tricks.blogspot.com
Дата: 13.08.10 05:47
Оценка:
Здравствуйте, midcyber, Вы писали:

M>Здравствуйте, samius, Вы писали:


S>>Даже если программист не забыл вызвать CanComplete, со времени успешной проверки до времени выполнения операции может многое что измениться в системе. Проверка не блокирует записи в БД на изменение! Проверка тут вообще может говорить лишь о прогнозе выполнения операции, потому как если даже она закончилась неудачно, то через пол секунды наступит завтра и счетчики операций будут обнулены.


M>Ну тогда мой вариант вообще жить не может, всю логику надо строить на исключениях. Учту на будущее.


Звучит слишком категорично. Предварительная проверка может быть оправдана, но надо ее воспринимать именно как хинт, а не гарант выполнения операции.
Re[5]: Исключения для пользователя и для программиста -- раз
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.08.10 18:26
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Давайте на конкретных примерах. Библиотека для работы с базой. Не удалось подключиться. Есть детали ошибки, которые нужны и понятны пользователю. Как вы их передадите, чтобы пользователь внятно увидел все детали ошибки?

Ок. Вот это "не удалось подключиться" — это что на самом деле? Это "incorrect login/password" или "unexpected reply during TDS handshake; packet seq=0x23, offset=0x2f"? Или, может быть, "Could not resolve target host name"? Или, скажем, "could not make a connection because target host actively refused it"? А может, это вовсе был "not enough permissions to access target database"?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Исключения для пользователя и для программиста -- разниц
От: SpaceConscience  
Дата: 13.08.10 20:22
Оценка:
Ты смешиваешь в кучу "пользователей" библиотеки — программистов, и конечных пользователей приложения. Выбери что-то одно, а то это две большие разницы.
Собрался ставить минус? Да сам иди в жопу!

































































.
Re: Исключения для пользователя и для программиста -- разниц
От: IT Россия linq2db.com
Дата: 14.08.10 05:44
Оценка:
Здравствуйте, 0K, Вы писали:

0K>В продолжение темы об исключениях (см. тег).


Что-то тебя на эту тему реально заколбасило. Не позновато ли через 8 лет после выхода первой версии фрейворка?
Если нам не помогут, то мы тоже никого не пощадим.
Re[7]: Исключения для пользователя и для программиста -- раз
От: mrTwister Россия  
Дата: 14.08.10 12:37
Оценка:
Здравствуйте, 0K, Вы писали:

0K>А накой вам stacktrace предсказуемого исключения? Если у пользователя исчерпан лимит операций по счету -- накой вам stacktrace? Вы что будете действительно разбирать такие вот ошибки от 10 тыс. пользователей использующих программу?


Если эта ситуации ожидаема, то она будет описана в SRS в виде отдельных use-case'в со своей собственной логикой. Реализовывать эту логику через обработчики исключений — это называется использование исключений не по назначению. Таким образом, мы строим логику на исключениях, делая код более запутанным.

0K>А вы знаете что по стандарту все исключения должны быть сериализуемыми?

Ссылку можно?
лэт ми спик фром май харт
Re[17]: –
От: mrTwister Россия  
Дата: 14.08.10 12:40
Оценка:
Здравствуйте, samius, Вы писали:

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

Может занимать, а может и нет. Это проблема оптимизации, которая далеко не всегда нас волнует, и даже если волнует, посмотри на методы типа TryParse, TryGetValue и т.д.

S>Проверка перед операцией не гарантирует выполнение операции, потому для вызова операции try/catch все равно необходим.

Неправда. Это зависит от ситуации: иногда гарантирует, иногда нет.
лэт ми спик фром май харт
Re[18]: –
От: samius Япония http://sams-tricks.blogspot.com
Дата: 14.08.10 18:47
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Здравствуйте, samius, Вы писали:


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

T>Может занимать, а может и нет. Это проблема оптимизации, которая далеко не всегда нас волнует, и даже если волнует, посмотри на методы типа TryParse, TryGetValue и т.д.

Коды ошибок? Да, можно оправдать в случае критических требований к производительности кода. А методы с единственным значением под код ошибки (bool) хороши когда не важна причина неудачи, либо ее можно установить однозначно, как в случае с TryParse и TryGetValue.
Но здесь вроде бы не обсуждаются случаи, когда отказ от исключения в пользу кода ошибки серьезно увеличит производительность. Так к чему были помянуты эти методы? Вариант без предварительной проверки условий выполнения операции был представлен. Правда методом, выкидывающим исключение, а не возвращающим код ошибки.

S>>Проверка перед операцией не гарантирует выполнение операции, потому для вызова операции try/catch все равно необходим.

T>Неправда. Это зависит от ситуации: иногда гарантирует, иногда нет.

Ситуация без специальных оговорок предполагает внешние хранилища информации (БД, удаленный сервер, файловая система ...), наличие множества источников изменений состояния системы (в том числе возможность изменения настроек лимита операций). Даже если можно достоверно предположить что лимит не наступит в течении какого-то времени, то гарантировать выполнение операции все равно нельзя.
Re[19]: –
От: mrTwister Россия  
Дата: 14.08.10 19:00
Оценка:
Здравствуйте, samius, Вы писали:

S>Коды ошибок?

Именно

S>Да, можно оправдать в случае критических требований к производительности кода.

А что, если нет критических требований к производительности кода, то коды возврата использовать нельзя?

S>А методы с единственным значением под код ошибки (bool) хороши когда не важна причина неудачи, либо ее можно установить однозначно, как в случае с TryParse и TryGetValue.

Во-первых, не код ошибки, а скорее код возврата.
Во-вторых никто не мешает сделать так: http://msdn.microsoft.com/en-us/library/ee762437(v=PandP.50).aspx

S>Ситуация без специальных оговорок предполагает внешние хранилища информации (БД, удаленный сервер, файловая система ...),

С чего это вдруг?
лэт ми спик фром май харт
Re[9]: Исключения для пользователя и для программиста -- раз
От: GarryIV  
Дата: 14.08.10 20:46
Оценка:
Здравствуйте, 0K, Вы писали:

M>>Библиотека может передавать на клиента всю необходимую информацию об ошибке. Какие детали выводить пользователю решает программист.


0K>Как раз таки может и должна. Вы думаете почему существует ТРЕБОВАНИЕ ЛОКАЛИЗОВАТЬ СООБЩЕНИЯ ОБ ОШИБКАХ???


Сообщения об ошибках (те которые в UI видно) и исключения имеют мало общего.
Локализированный текст в исключениях зло в 99% случаев. И локализовано может быть не на тот язык и текст не тот и не погуглить нормально.
WBR, Igor Evgrafov
Re[20]: –
От: samius Япония http://sams-tricks.blogspot.com
Дата: 15.08.10 05:02
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Здравствуйте, samius, Вы писали:


S>>Коды ошибок?

T>Именно

S>>Да, можно оправдать в случае критических требований к производительности кода.

T>А что, если нет критических требований к производительности кода, то коды возврата использовать нельзя?
Можно, но их хреново комбинировать с исключениями.

S>>А методы с единственным значением под код ошибки (bool) хороши когда не важна причина неудачи, либо ее можно установить однозначно, как в случае с TryParse и TryGetValue.

T>Во-первых, не код ошибки, а скорее код возврата.
+1
T>Во-вторых никто не мешает сделать так: http://msdn.microsoft.com/en-us/library/ee762437(v=PandP.50).aspx
Я не знаком с этой технологией. Не уверен, что в результаты валидации можно впихнуть исключение. Полагаю что эта кухня хороша для проверки правильности заполнения формы. Для того чтобы описать таким образом результат операции, потребуется скрестить ежа с ужом, т.е. исключения с неким OperationResults.

S>>Ситуация без специальных оговорок предполагает внешние хранилища информации (БД, удаленный сервер, файловая система ...),

T>С чего это вдруг?
"лимит операций" подразумевает банки, кассы, аукционы и т.п. Все это предполагает хранилища данных, многопользовательский доступ. Если ты говоришь о каких-то других лимитах, то дай знать, может я соглашусь с тобой.
Re: Исключения для пользователя и для программиста -- разниц
От: minorlogic Украина  
Дата: 15.08.10 12:52
Оценка:
Информация из исключения и показываемое пользователю сообщение , это разные вещи. Разные задачи и разная функциональность.
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[2]: Исключения для пользователя и для программиста -- раз
От: Other Sam Россия  
Дата: 16.08.10 13:04
Оценка:
....
M>Как правило, все исключения поднимаются для разработчиков. Разработчик должен позаботится о том, чтобы пользователь увидел нормальное исключение, а не непонятную, для его мозга, информацию.
M>Вы можете вообще не выдавать пользователю никаких исключений, а писать свой текст на своё усмотрение, либо вообще придумать своё поведение приложения.

Ну я рассматриваю этот вопрос еще более формально.
Приложение A, находится в состоянии S и в окружени K.
Пользователь подает команду X. Приложение либо переходит в состояние S2, либо меняет окружение на K2 (это оба успешные варианты развития событий), либо переходит в состояине S3 (отказ выполнить команду X), либо падение приложения с отчетом о причине падения.

Состояние S3 (отказ выполнить команду X) может давать пользователю выбор "вернуться в S, вернуться в S и снова попытаться выполнить X, или что-то еще".
Как видите ни о каких исключениях здесь речи нет.

Но вот в случае падения приложения нужно отобразить исключение, чтобы иметь возможность получить отчет об аварии. Здесь нет никаких "локализаций" и любой другой мишуры. Никаких замен исключений. Однако бывает что используется "ядро" приложения, которое использует библиотеку, которая использует системыне вызовы, и в таком случае исколючения могут выстроиться в цепочку:
CanNotSaveFileException ("ядро")
caused by: IOException (библиотека)
caused by: AccesViolationException "Не могу создать файл abc.xyz, нет доступа на запись в каталог "ffff".
И разумеется в отчете все эти исключения должны присутствовать.
Re[20]: –
От: 0K Ниоткуда  
Дата: 17.08.10 09:18
Оценка:
Здравствуйте, midcyber, Вы писали:

M>Ну тогда мой вариант вообще жить не может, всю логику надо строить на исключениях. Учту на будущее.


Ну слава Богу! Хоть до одного дошло. Если бы я говорил -- то ради упрямства бы не принял.

Вот, собственно, для этого и нужны информационно-логические исключения. Кроме того, исключение обязано содержать локализованную информацию для пользователя -- без этого никак.
Re[6]: Исключения для пользователя и для программиста -- раз
От: 0K Ниоткуда  
Дата: 17.08.10 09:20
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Ок. Вот это "не удалось подключиться" — это что на самом деле? Это "incorrect login/password" или "unexpected reply during TDS handshake; packet seq=0x23, offset=0x2f"? Или, может быть, "Could not resolve target host name"? Или, скажем, "could not make a connection because target host actively refused it"? А может, это вовсе был "not enough permissions to access target database"?


А вот любой из этих вариантов и пишите. Пользователи не (все) идиоты -- поймут.
Re[12]: Исключения для пользователя и для программиста -- ра
От: 0K Ниоткуда  
Дата: 17.08.10 09:26
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Это какая-то очень странная библиотека. Фактически, она заранее знает, какого вида UI будет ею пользоваться. В частности, она почему-то в курсе, что есть пользователь, который выполняет операцию, и которому могут быть интересны подробности.


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

S>Большинство программистов заинтересованы в написании библиотек, предназначенных для повторного использования. Это означает, что ими будут пользоваться разные приложения с разными стратегиями. Например, метод "перевода денег" будет использован в контексте метода "раскидать деньги участникам кооператива в соответствии с их долями". Здесь вылет исключения из одного из методов ничем не поможет разработчику приложения.


Вы что? Как это не поможет? Еще как поможет. Текст можно вывести в ListBox с результатом проведения операций.

Но обрывать серию операций вовсе не обязательно -- нужно попробовать эту же операцию провести повторно. А вы как хотели -- вообще не выбрасывать исключения?

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


Садись, два (с)

S>То есть выбрасывают что-то типа BusinessRuleException, у которого есть список обнаруженных проблем — с кодами (чтобы пользователь мог погуглить) и текстами.


Ну это не то же самое, что код ошибок (которые через return). Но все-же лучше применить Enum без привязки к цифрам.

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


Я об этом же писал выше. Только вместо просто непонятных цифр (которые еще нужно упомнить) -- применить Enum.
Re[9]: Исключения для пользователя и для программиста -- раз
От: samius Япония http://sams-tricks.blogspot.com
Дата: 17.08.10 09:43
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Читайте выше как опозорился midcyber с таким же мнением.


Не было никакого позора со стороны midcyber-а. Увидел аргументы, согласился с ними. Это норма поведения. В свою очередь мой ответ ему не связан с желанием опозорить.
Re[9]: Исключения для пользователя и для программиста -- раз
От: Mamut Швеция http://dmitriid.com
Дата: 17.08.10 11:36
Оценка:
0K>Вы хоть представляете какую вы сейчас ерунду спороли? Вы знаете сколько может быть вариантов почему деньги со счета на карту перевести не удалось? Около сотни. И вы будете создавать и обрабатывать все 100 типов исключений Атхнитесь!!!

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

Более того, "user friendly" сообщение для части этих ошибок даром не нужны, так как они могут быть типа «карта украдена, обратитесь в полицию», что не надо показывать пользователю.

И срать я хотел на «локализацию» этих ошибок, которые предоставляет банк. Потому что нам банк присылает целых два "user friendly" сообщения — на турецком и английском. При том, что английский там именно, что турецкий по качеству перевода, а турецкий нам даром не нужен, у нас сайт на английском и русском.

Ах, да, я еще хотел срать на 80 из 100 этих ошибок, так как 99% случаев у нас — это неверно введенный номер карточки или expiry date


dmitriid.comGitHubLinkedIn
Re[9]: Исключения для пользователя и для программиста -- раз
От: mrTwister Россия  
Дата: 17.08.10 16:10
Оценка:
Здравствуйте, 0K, Вы писали:

T>>Если эта ситуации ожидаема, то она будет описана в SRS в виде отдельных use-case'в со своей собственной логикой. Реализовывать эту логику через обработчики исключений — это называется использование исключений не по назначению. Таким образом, мы строим логику на исключениях, делая код более запутанным.


0K>Читайте выше как опозорился midcyber с таким же мнением. Вот что изменило его мнение и привело к полному позору:


0K>

0K>Даже если программист не забыл вызвать CanComplete, со времени успешной проверки до времени выполнения операции может многое что измениться в системе. Проверка не блокирует записи в БД на изменение! Проверка тут вообще может говорить лишь о прогнозе выполнения операции, потому как если даже она закончилась неудачно, то через пол секунды наступит завтра и счетчики операций будут обнулены.


К чему ты это написал? Паттерн tester-doer — это не единственный возможный способ организации условной логики.

0K>MSDN.microsoft.com Запустите FxCop с несериализуемым, там будет конкретная ссылка.


На стандарт или рекомендацию?
лэт ми спик фром май харт
Re[21]: –
От: mrTwister Россия  
Дата: 17.08.10 16:19
Оценка:
Здравствуйте, samius, Вы писали:


S>>>Да, можно оправдать в случае критических требований к производительности кода.

T>>А что, если нет критических требований к производительности кода, то коды возврата использовать нельзя?
S>Можно, но их хреново комбинировать с исключениями.

Почему? Каждой задаче — свой инструмент. Где-то лучше исключения, где-то коды возврата.

T>>Во-вторых никто не мешает сделать так: http://msdn.microsoft.com/en-us/library/ee762437(v=PandP.50).aspx

S>Я не знаком с этой технологией. Не уверен, что в результаты валидации можно впихнуть исключение.

Да легко, можно было бы сделать так, что если данные на форме валидны, то ничего не делать, а если невалидны, то кидать ValidationException. Клиент поймал бы это исключение, и нарисовал красиво какие именно контролы невалидны. Но разработчики Enterprise Library вполне обоснованно не стали так делать, так как пользователю пришлось бы для валидации писать try/catch. Вообще, исключения надо использовать там, где предполагается, что клиент кода будет не ловить эти исключения, а пробрасывать выше. Если мы предполагаем, что клиент кода должен обработать исключение и в соответствии с этим исключением выполнить ту или иную логику, значит лучше вместо исключений использовать коды возврата.

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

Я то думал, что мы обсуждаем способы работы с исключениями, поскольку тема называется "Парадигма работы с исключениями". "лимит операций" — это лишь один из примеров. Но тем не менее, этот пример подразумевает такую вещь, как транзакции, которые защищают нас от проблем с совместным доступом к общим данным.
лэт ми спик фром май харт
Re[22]: –
От: samius Япония http://sams-tricks.blogspot.com
Дата: 17.08.10 16:50
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Здравствуйте, samius, Вы писали:



S>>>>Да, можно оправдать в случае критических требований к производительности кода.

T>>>А что, если нет критических требований к производительности кода, то коды возврата использовать нельзя?
S>>Можно, но их хреново комбинировать с исключениями.

T>Почему?

Почему хреново? Потому как придется и коды проверять и catch-и делать. Лучше что-нибудь одно.

T>Каждой задаче — свой инструмент. Где-то лучше исключения, где-то коды возврата.

Я ж не спорю.

T>>>Во-вторых никто не мешает сделать так: http://msdn.microsoft.com/en-us/library/ee762437(v=PandP.50).aspx

S>>Я не знаком с этой технологией. Не уверен, что в результаты валидации можно впихнуть исключение.

T>Да легко, можно было бы сделать так, что если данные на форме валидны, то ничего не делать, а если невалидны, то кидать ValidationException. Клиент поймал бы это исключение, и нарисовал красиво какие именно контролы невалидны. Но разработчики Enterprise Library вполне обоснованно не стали так делать, так как пользователю пришлось бы для валидации писать try/catch. Вообще, исключения надо использовать там, где предполагается, что клиент кода будет не ловить эти исключения, а пробрасывать выше. Если мы предполагаем, что клиент кода должен обработать исключение и в соответствии с этим исключением выполнить ту или иную логику, значит лучше вместо исключений использовать коды возврата.


Одно дело валидация контролов на форме, другое — прогнозирование результата операции.

T>Я то думал, что мы обсуждаем способы работы с исключениями, поскольку тема называется "Парадигма работы с исключениями". "лимит операций" — это лишь один из примеров. Но тем не менее, этот пример подразумевает такую вещь, как транзакции, которые защищают нас от проблем с совместным доступом к общим данным.


А от проблем с сетью и сервером приложений/БД транзакции защитят? Или транзакции сами не выкидывают исключений?
Re[23]: –
От: mrTwister Россия  
Дата: 17.08.10 18:40
Оценка:
Здравствуйте, samius, Вы писали:


T>>Почему?

S>Почему хреново? Потому как придется и коды проверять и catch-и делать. Лучше что-нибудь одно.

catch будет где-то на высоком уровне.

T>>Да легко, можно было бы сделать так, что если данные на форме валидны, то ничего не делать, а если невалидны, то кидать ValidationException. Клиент поймал бы это исключение, и нарисовал красиво какие именно контролы невалидны. Но разработчики Enterprise Library вполне обоснованно не стали так делать, так как пользователю пришлось бы для валидации писать try/catch. Вообще, исключения надо использовать там, где предполагается, что клиент кода будет не ловить эти исключения, а пробрасывать выше. Если мы предполагаем, что клиент кода должен обработать исключение и в соответствии с этим исключением выполнить ту или иную логику, значит лучше вместо исключений использовать коды возврата.


S>Одно дело валидация контролов на форме, другое — прогнозирование результата операции.


При чем тут прогнозирование?

OperationResult PerformOperation()



S>А от проблем с сетью и сервером приложений/БД транзакции защитят? Или транзакции сами не выкидывают исключений?


Проблемы с сетью и пр. имеют мало общего с бизнес-логикой и вполне логично, что обрабатываться они должны совсем иначе. Мы же обсуждаем сейчас бизнес-логику, не так ли?
лэт ми спик фром май харт
Re[24]: –
От: samius Япония http://sams-tricks.blogspot.com
Дата: 17.08.10 19:04
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>>>Да легко, можно было бы сделать так, что если данные на форме валидны, то ничего не делать, а если невалидны, то кидать ValidationException. Клиент поймал бы это исключение, и нарисовал красиво какие именно контролы невалидны. Но разработчики Enterprise Library вполне обоснованно не стали так делать, так как пользователю пришлось бы для валидации писать try/catch. Вообще, исключения надо использовать там, где предполагается, что клиент кода будет не ловить эти исключения, а пробрасывать выше. Если мы предполагаем, что клиент кода должен обработать исключение и в соответствии с этим исключением выполнить ту или иную логику, значит лучше вместо исключений использовать коды возврата.


S>>Одно дело валидация контролов на форме, другое — прогнозирование результата операции.


T>При чем тут прогнозирование?


Притом что мы с midcyber обсуждали следующий кусок кода

void Usage()
{
  if(user.CanCompleteOperation(op))
   user.DoOperation(op);
  else
   gui.SetText(user.GetLocalizedError(op));
}


S>>А от проблем с сетью и сервером приложений/БД транзакции защитят? Или транзакции сами не выкидывают исключений?


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


В контексте процитированного кода тот код, которому достанется исключение, даже не узнает, была ли начата операция или нет.
Хоть проблемы с сетью и прочим имеют другой уровень, но они довольно тесно связаны с бизнес-логикой. Блокировать ли деятельность пользователя до появления сети, предоставлять ли ему доступ к локальным фичам — это решается в контексте производимой операции и случившейся проблемы. А мы тут даже не знаем, на проверке срезало, на операции, или на доставании кода ошибки.
Re[13]: Исключения для пользователя и для программиста -- ра
От: fmiracle  
Дата: 17.08.10 20:27
Оценка:
Здравствуйте, 0K, Вы писали:

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


Во-первых, я (читай — пользователь/заказчик) хочу, например, в своем веб приложении вывести пользователю сообщение об ошибке примерно так:

Внимание! Сервер maps.yandex.ru не отвечает!


Как в строковом сообщении об исключении должно быть выделено название сервера? А если оно там не будет выделено, то нафига мне такое готовое сообщение нужно?

Во-вторы, как тебе уже не раз говорили, что вот такое сообщение пользователю:

Файл базы телефонных номеров не найден. Создать новый? (Ok) (Cancel)


Выглядит (для пользователя, как умного так и не очень) гораздо лучше чем вот такое:

Отсутствует файл c:\users\documents and settins\appdata\sandbox\myapp.dat.


Опять же — сообщение снова не становится особенно важным, а важны детали в объекте исключения.


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

- Это патентное бюро? Я изобрел уникальный автоматический аппарат для бритья!
— О, это интересно, как работает?
— Ну вот опускаете сюда лицо и автоматические лезвия быстро и чисто бреют.
— Хммм. Но постойте, ведь у каждого человека уникальная форма лица?!
— Ну, это только на первый раз.



Тебе тут все пытаются объяснить, что Message в исключении придуман не для показа пользователю, а для общей информации разработчику, чтобы быстрее понять в целом что за проблема (основная же информция — в типе исключения и его полях). Показ Message сообщения пользователю напряму — это неправильное использование придуманного механизма.
Потому твое предложение выглядит странно и забавно. Как что-то вроде жалобы пользователя "Я пытался забивать отверткой гвозди, но получилось плохо. Почему до сих пор никто не выпускает ответок с утяжеленными рукоятками? Тогда ведь гвозди забивались бы ими гораздо лучше!".
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Re[25]: –
От: mrTwister Россия  
Дата: 21.08.10 10:20
Оценка:
Здравствуйте, samius, Вы писали:

S>В контексте процитированного кода тот код, которому достанется исключение, даже не узнает, была ли начата операция или нет.

S>Хоть проблемы с сетью и прочим имеют другой уровень, но они довольно тесно связаны с бизнес-логикой. Блокировать ли деятельность пользователя до появления сети, предоставлять ли ему доступ к локальным фичам — это решается в контексте производимой операции и случившейся проблемы.

Значит в данном случае, это часть бизнес-логики

S>А мы тут даже не знаем, на проверке срезало, на операции, или на доставании кода ошибки.


Почему не знаем?
В OperationResult — мы можем поместить любую информацию, какую сочтем нужным
лэт ми спик фром май харт
Re[26]: –
От: samius Япония http://sams-tricks.blogspot.com
Дата: 21.08.10 11:29
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Здравствуйте, samius, Вы писали:


S>>А мы тут даже не знаем, на проверке срезало, на операции, или на доставании кода ошибки.


T>Почему не знаем?

Потому что обсуждаемый код не возвращает вызывающему такой информации.

T>В OperationResult — мы можем поместить любую информацию, какую сочтем нужным

Можем, только это уже будет совсем другой код.
Re[27]: –
От: mrTwister Россия  
Дата: 21.08.10 11:57
Оценка:
Здравствуйте, samius, Вы писали:


T>>Почему не знаем?

S>Потому что обсуждаемый код не возвращает вызывающему такой информации.

Что ты зациклился на том примере. Если тебе паттерн tester-doer не подходит, то это не значит, что тебе надо использовать исключения. Альтернативный вариант я привел.
лэт ми спик фром май харт
Re[28]: –
От: samius Япония http://sams-tricks.blogspot.com
Дата: 21.08.10 12:46
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Здравствуйте, samius, Вы писали:



T>>>Почему не знаем?

S>>Потому что обсуждаемый код не возвращает вызывающему такой информации.

T>Что ты зациклился на том примере. Если тебе паттерн tester-doer не подходит, то это не значит, что тебе надо использовать исключения.

Конечно не значит. Но при всем богатсве выбора я склонен использовать исключения.

T>Альтернативный вариант я привел.

Ты привел ссылку на Validator.Validate. Давай хотя бы псевдокод альтернативного варианта в студию.
Re[29]: –
От: mrTwister Россия  
Дата: 21.08.10 20:20
Оценка:
Здравствуйте, samius, Вы писали:

T>>Альтернативный вариант я привел.

S>Ты привел ссылку на Validator.Validate. Давай хотя бы псевдокод альтернативного варианта в студию.


void Usage()
{
    var operationResult = user.TryDoOperation();
    if(operationResult.Success)
    {
        MessageBox.Show("Success");
    }
    else
    {
        MessageBox.Show("Failed. Params: {0}, {1}", operationResult.param1, operationResult.param2);
    }
}


Таким образом, control flow алгоритма выражен явно и чисто. Я не говорю что этот способ универсален. Где-то лучше исключения, а где-то коды возврата.
лэт ми спик фром май харт
Re[30]: –
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.08.10 06:24
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Здравствуйте, samius, Вы писали:


T>>>Альтернативный вариант я привел.

S>>Ты привел ссылку на Validator.Validate. Давай хотя бы псевдокод альтернативного варианта в студию.


T>
T>void Usage()
T>{
T>    var operationResult = user.TryDoOperation();
T>    if(operationResult.Success)
T>    {
T>        MessageBox.Show("Success");
T>    }
T>    else
T>    {
T>        MessageBox.Show("Failed. Params: {0}, {1}", operationResult.param1, operationResult.param2);
T>    }
T>}
T>


T>Таким образом, control flow алгоритма выражен явно и чисто.

Для меня в таком явном чистом control flow не очевидно, что будет если внутри TryDoOperation возбудится то или иное исключение.

T>Я не говорю что этот способ универсален. Где-то лучше исключения, а где-то коды возврата.

Давай таки разберемся, где лучше и чем.
В случае с Dictionary.TryGetValue — я с тобой соглашусь, потому как Dictionary отлажен и получить что либо кроме ArgumentNullException практически нереально. При внутри вызова метода не происходит обращений к внешним источникам данных и сервисам, которое может окончится неудачей. В случае с user.TryDoOperation — нет. Это во-первых сфероконь, реализация которого может быть неверна, он скорее всего обращается к внешним сервисам и источникам данных, наличие и состояние которых может быть под вопросом (если речь идет не о крестиках-ноликах).

Твой Usage заставляет меня сделать два взаимоисключающих предположения:
1) TryDoOperation катчит все исключения и пакует их в OperationResult. Тогда я не понимаю, как можно сделать пакетную обработку
foreach(user in users) user.TryDoOperation()
судя по всему придется анализировать результат после каждого пользователя и решать, стоит ли продолжать или какой-то сервис не доступен...
2) TryDoOperation катчит не все исключения. Тогда видимо в случае таких исключений пользователь не увидит MessageBox с надписью "Failed".

А что если все операции над моделью данных возвращают OperationResult? Их же придется комбинировать, а значит в каждой операции анализировать чем окончилась вложенная...

Ты работал плотно с COM из C++, где после каждого чиха нужно проверить HRESULT?
Re[31]: –
От: mrTwister Россия  
Дата: 22.08.10 08:54
Оценка:
Здравствуйте, samius, Вы писали:

T>>
T>>void Usage()
T>>{
T>>    var operationResult = user.TryDoOperation();
T>>    if(operationResult.Success)
T>>    {
T>>        MessageBox.Show("Success");
T>>    }
T>>    else
T>>    {
T>>        MessageBox.Show("Failed. Params: {0}, {1}", operationResult.param1, operationResult.param2);
T>>    }
T>>}
T>>


T>>Таким образом, control flow алгоритма выражен явно и чисто.

S>Для меня в таком явном чистом control flow не очевидно, что будет если внутри TryDoOperation возбудится то или иное исключение.

Если внутри TryDoOperation возбудится то или иное исключение, то это исключение будет проброшено выше и обработано на верхнем уровне с логгированием и показом некоторого обобщенного сообщения об ошибке. Ничего осмысленного внутри Usage() ты все равно сделать не сможешь. Откуда ты знаешь, какое исключение может прилететь из TryDoOperation? Это может быть и OutOfMemoryException, и StackOverflowException и ThreadAbortException. Ты их будешь обрабатывать? Даже если касаться ситуации отсутствия соединения, какие исключения ты собрался ловить? Там могут быть какие угодно исключения. Если у нас на транспортном уровне WCF, то это одни исключения, если Remoting, то другие, если сокеты, то третьи. Более того, сам факт отсутствия соединения может быть сигнализирован целой группой разных исключений. Это и DNS не может имя разрезолвить, и таймаут, и отсутствует листенер на порту, и удаленный сервер закрывает соединение, и протокол не тот, отсутствие сетевых интерфейсов — да мало ли чего? Ты что, собрался в обработчике каждой кнопки перехватывать всю тонну исключений? Или ты будешь перехватывать обобщенный, а потому и неизвестно какой базовый Exception?

T>>Я не говорю что этот способ универсален. Где-то лучше исключения, а где-то коды возврата.

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

S>В случае с Dictionary.TryGetValue — я с тобой соглашусь, потому как Dictionary отлажен и получить что либо кроме ArgumentNullException практически нереально. При внутри вызова метода не происходит обращений к внешним источникам данных и сервисам, которое может окончится неудачей.


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

if(!dictionary.ContainsKey(key))
{
    dictionary[key] = value;
}
return dictionary[key];


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

S>В случае с user.TryDoOperation — нет. Это во-первых сфероконь, реализация которого может быть неверна, он скорее всего обращается к внешним сервисам и источникам данных, наличие и состояние которых может быть под вопросом (если речь идет не о крестиках-ноликах).


Ну да, и что?

S>Твой Usage заставляет меня сделать два взаимоисключающих предположения:

S>1) TryDoOperation катчит все исключения и пакует их в OperationResult.
Нет, он точно не перехватывает все исключения. Он перехватывает только те исключения, которые ожидает. Все исключения перехватывать нельзя.

S>Тогда я не понимаю, как можно сделать пакетную обработку

S>foreach(user in users) user.TryDoOperation()
S>судя по всему придется анализировать результат после каждого пользователя и решать, стоит ли продолжать или какой-то сервис не доступен...
S>2) TryDoOperation катчит не все исключения. Тогда видимо в случае таких исключений пользователь не увидит MessageBox с надписью "Failed".
Да, он увидит обобщенное сообщение об ошибки. Это значит, что произошла какая-то непредвиденная ситуация. Например, закончилась память (OutOfMemory), или сгорела сетевая карта, у процесса нехватает прав на обращение к сетевому интерфейсу, либо где-то есть ошибка в коде (например, ArgumentNullException). В этом случае лучшее, что мы можем сделать — это сообщить службе поддержки о проблеме, предоставив ей максимум информации. Следовательно ошибку надо подробно залоггировать, можно послать соответствующий email кому надо, а пользователю показать окно с текстом "Упс, что-то хреновое произошло!"

S>А что если все операции над моделью данных возвращают OperationResult? Их же придется комбинировать, а значит в каждой операции анализировать чем окончилась вложенная...

S>Ты работал плотно с COM из C++, где после каждого чиха нужно проверить HRESULT?
Замечательно, ты наверное, придумал случай, где коды возврата подходят плохо. Тогда я цитирую самого себя:

Я не говорю что этот способ универсален. Где-то лучше исключения, а где-то коды возврата.

лэт ми спик фром май харт
Re[32]: –
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.08.10 13:38
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Здравствуйте, samius, Вы писали:


S>>Для меня в таком явном чистом control flow не очевидно, что будет если внутри TryDoOperation возбудится то или иное исключение.


T>Если внутри TryDoOperation возбудится то или иное исключение, то это исключение будет проброшено выше и обработано на верхнем уровне с логгированием и показом некоторого обобщенного сообщения об ошибке. Ничего осмысленного внутри Usage() ты все равно сделать не сможешь. Откуда ты знаешь, какое исключение может прилететь из TryDoOperation? Это может быть и OutOfMemoryException, и StackOverflowException и ThreadAbortException. Ты их будешь обрабатывать? Даже если касаться ситуации отсутствия соединения, какие исключения ты собрался ловить? Там могут быть какие угодно исключения. Если у нас на транспортном уровне WCF, то это одни исключения, если Remoting, то другие, если сокеты, то третьи. Более того, сам факт отсутствия соединения может быть сигнализирован целой группой разных исключений. Это и DNS не может имя разрезолвить, и таймаут, и отсутствует листенер на порту, и удаленный сервер закрывает соединение, и протокол не тот, отсутствие сетевых интерфейсов — да мало ли чего? Ты что, собрался в обработчике каждой кнопки перехватывать всю тонну исключений? Или ты будешь перехватывать обобщенный, а потому и неизвестно какой базовый Exception?

Меня смущает ветка else в твоем коде. При наличии любого исключения пользователь не увидит сообщение "Failed". А значит может думать что операция прошла, чихать что сработал обработчик верхнего уровня и пополнил лог... То есть при том, что ты назадавал мне правильных вопросов, твой Usage будет работать странновато.


T>>>Я не говорю что этот способ универсален. Где-то лучше исключения, а где-то коды возврата.

S>>Давай таки разберемся, где лучше и чем.
T>Правило простое. Все зависит от клиента. Если клиент в ответ на результат выполнения операции должен реализовать некоторое определенное поведение, то есть явным образом обработать этот результат, то надо использовать коды возврата. Если же клиент должен просто пробросить ошибку на верхний уровень с надеждой на то, что кто-то там где-то когда-нибудь может быть эту ошибку обработает, то надо использовать исключения.

То что твой user.TryDoOperation ориентирован на конкретного клиента, мешает использовать его в другом клиенте.

S>>В случае с Dictionary.TryGetValue — я с тобой соглашусь, потому как Dictionary отлажен и получить что либо кроме ArgumentNullException практически нереально. При внутри вызова метода не происходит обращений к внешним источникам данных и сервисам, которое может окончится неудачей.


T>Наличие обращений к внешним сервисам вообще не при чем. Метод TryGetValue направлен на реализацию варианта использования, когда пользователь получает элемент словаря и явным образом обрабатывает ситуацию отсутствия элемента в словаре. То есть в данном случае у клиента в коде будет стоять if, который что-то определенное сделает, когда в словаре отсутствует элемент (например, добавит отсутствующий элемент в словарь). Без этого метода можно было бы обойтись, например, с помощью такого кода:

T>Но в этом случае поиск по словарю произойдет дважды. TryGetValue позволяет обойтись одним поиском то есть этот метод используется для оптимизации.

А что оптимизирует TryDoOperation?

S>>В случае с user.TryDoOperation — нет. Это во-первых сфероконь, реализация которого может быть неверна, он скорее всего обращается к внешним сервисам и источникам данных, наличие и состояние которых может быть под вопросом (если речь идет не о крестиках-ноликах).


T>Ну да, и что?


S>>Твой Usage заставляет меня сделать два взаимоисключающих предположения:

S>>1) TryDoOperation катчит все исключения и пакует их в OperationResult.
T>Нет, он точно не перехватывает все исключения. Он перехватывает только те исключения, которые ожидает. Все исключения перехватывать нельзя.

S>>Тогда я не понимаю, как можно сделать пакетную обработку

S>>foreach(user in users) user.TryDoOperation()
S>>судя по всему придется анализировать результат после каждого пользователя и решать, стоит ли продолжать или какой-то сервис не доступен...
S>>2) TryDoOperation катчит не все исключения. Тогда видимо в случае таких исключений пользователь не увидит MessageBox с надписью "Failed".
T>Да, он увидит обобщенное сообщение об ошибки. Это значит, что произошла какая-то непредвиденная ситуация. Например, закончилась память (OutOfMemory), или сгорела сетевая карта, у процесса нехватает прав на обращение к сетевому интерфейсу, либо где-то есть ошибка в коде (например, ArgumentNullException). В этом случае лучшее, что мы можем сделать — это сообщить службе поддержки о проблеме, предоставив ей максимум информации. Следовательно ошибку надо подробно залоггировать, можно послать соответствующий email кому надо, а пользователю показать окно с текстом "Упс, что-то хреновое произошло!"

"Упс" показал, а "Failed" — не показал. А бизнес-исключительные ситуации не нуждаются в отправке email-а и логировании?

S>>А что если все операции над моделью данных возвращают OperationResult? Их же придется комбинировать, а значит в каждой операции анализировать чем окончилась вложенная...

S>>Ты работал плотно с COM из C++, где после каждого чиха нужно проверить HRESULT?
T>Замечательно, ты наверное, придумал случай, где коды возврата подходят плохо.
Ты мне льстишь, не я его придумал.

T>Тогда я цитирую самого себя:

T>

T>Я не говорю что этот способ универсален. Где-то лучше исключения, а где-то коды возврата.

Re[33]: –
От: mrTwister Россия  
Дата: 22.08.10 18:04
Оценка:
Здравствуйте, samius, Вы писали:

S>Меня смущает ветка else в твоем коде. При наличии любого исключения пользователь не увидит сообщение "Failed". А значит может думать что операция прошла, чихать что сработал обработчик верхнего уровня и пополнил лог... То есть при том, что ты назадавал мне правильных вопросов, твой Usage будет работать странновато.

Работать он будет абсолютно правильно. Осмысленно обработать мы можем только те исключения, которые ожидаем. Если же из операции вылетела неведомая хрень, например NullReferenceException, ArgumentException, StackOverflowException, OutOfMemoryException и т.д., то лучшее, что мы можем сделать — это срочно завершить текущую операцию и сообщить что надо куда надо. Хуже если мы будем пытаться строить хорошую мину при плохой игре, выполняя обработчик ошибок в ситуациях, на которые этот обработчик не был рассчитан.

S>То что твой user.TryDoOperation ориентирован на конкретного клиента, мешает использовать его в другом клиенте.

Он ориентирован не столько на конкретного клиента, сколько на конкретный вариант использования. Это нормально. Благодаря чему в этом варианте использования библиотека очень удобна. Когда ты разрабатываешь библиотеку обычно можно вполне определенно предположить, как эту библиотеку будут использовать. Если же библиотека очень обобщенная и варианты использования могут быть какими угодно, то можно оставить и пару методов: один с исключениями, а другой с кодами возврата. Посмотри, например на LINQ — это как раз пример такой обобщенной библиотеки. Дак вот, там есть, например, метод First, который бросает исключения, и метод FirstOrDefault, который делает тоже самое, но исключение не кидает, а возвращает код возврата.

S>А что оптимизирует TryDoOperation?

Количество обращений к серверу и возможность обойтись без бизнес-транзакций.

S>"Упс" показал, а "Failed" — не показал. А бизнес-исключительные ситуации не нуждаются в отправке email-а и логировании?

Если мы их ожидаем, то не нуждаются.
лэт ми спик фром май харт
Re[34]: –
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.08.10 19:49
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Здравствуйте, samius, Вы писали:


S>>Меня смущает ветка else в твоем коде. При наличии любого исключения пользователь не увидит сообщение "Failed". А значит может думать что операция прошла, чихать что сработал обработчик верхнего уровня и пополнил лог... То есть при том, что ты назадавал мне правильных вопросов, твой Usage будет работать странновато.

T>Работать он будет абсолютно правильно. Осмысленно обработать мы можем только те исключения, которые ожидаем. Если же из операции вылетела неведомая хрень, например NullReferenceException, ArgumentException, StackOverflowException, OutOfMemoryException и т.д., то лучшее, что мы можем сделать — это срочно завершить текущую операцию и сообщить что надо куда надо. Хуже если мы будем пытаться строить хорошую мину при плохой игре, выполняя обработчик ошибок в ситуациях, на которые этот обработчик не был рассчитан.
В случае ожиданных исключений, юзер увидит сообщение "Failed". В случае неожиданных — не увидит. Вот это я называю странным поведением.

S>>То что твой user.TryDoOperation ориентирован на конкретного клиента, мешает использовать его в другом клиенте.

T>Он ориентирован не столько на конкретного клиента, сколько на конкретный вариант использования. Это нормально. Благодаря чему в этом варианте использования библиотека очень удобна. Когда ты разрабатываешь библиотеку обычно можно вполне определенно предположить, как эту библиотеку будут использовать. Если же библиотека очень обобщенная и варианты использования могут быть какими угодно, то можно оставить и пару методов: один с исключениями, а другой с кодами возврата. Посмотри, например на LINQ — это как раз пример такой обобщенной библиотеки. Дак вот, там есть, например, метод First, который бросает исключения, и метод FirstOrDefault, который делает тоже самое, но исключение не кидает, а возвращает код возврата.
Ты путаешь. Код возврата — это прежде всего число. FirstOrDefault возвращает значение или default(T), которое в общем случае с числом не имеет ничего общего.

S>>А что оптимизирует TryDoOperation?

T>Количество обращений к серверу и возможность обойтись без бизнес-транзакций.
Чем количество обращений к серверу будет меньше чем при DoOperation?

S>>"Упс" показал, а "Failed" — не показал. А бизнес-исключительные ситуации не нуждаются в отправке email-а и логировании?

T>Если мы их ожидаем, то не нуждаются.
Вот скажи, попытка закрытия счета при отрицательном балансе для тебя неожиданная ситуация, или ее не нужно логировать?
Re[35]: –
От: mrTwister Россия  
Дата: 22.08.10 20:14
Оценка:
Здравствуйте, samius, Вы писали:

S>В случае ожиданных исключений, юзер увидит сообщение "Failed". В случае неожиданных — не увидит. Вот это я называю странным поведением.

И чем же оно странно? В Windows тоже пользователь может увидеть и messagebox с сообщением "Access denied", и "программа выполнила недопустимую операцию и будет закрыта" или, даже, синий экран. Как думаешь, зачем майкросовтовцы сделали синий экран, дураки?

S>Ты путаешь. Код возврата — это прежде всего число.

Кто это тебе такую глупость сказал?

S>>>А что оптимизирует TryDoOperation?

T>>Количество обращений к серверу и возможность обойтись без бизнес-транзакций.
S>Чем количество обращений к серверу будет меньше чем при DoOperation?
Нет. Оно будет меньше, чем при tester-doer

S>Вот скажи, попытка закрытия счета при отрицательном балансе для тебя неожиданная ситуация, или ее не нужно логировать?

Это зависит от того, как мы реализовали систему. Если мы её реализовали таким образом, что у нас в принципе не может возникнуть попытка закрытия счета при отрицательном балансе и наличие такой попытки говорит либо об ошибке в программном коде, либо неконсистентности данных, либо о хакерской атаке, то это неожиданная ситуация. Если же эта ситуация может возникнуть в рамках штатного функционирования системы, то это ожидаемая ситуация и логгировать её не надо. Но только не путаем логгирование с аудированием.
лэт ми спик фром май харт
Re: Исключения для пользователя и для программиста -- разниц
От: Pzz Россия https://github.com/alexpevzner
Дата: 22.08.10 21:07
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Почему их (эти 2 категории исключений) никак не отличают? Сделали бы стандарт: все исключения, содержащие информацию полезную для пользователя наследовать от UserFriendlyException. А остальные инсключения -- контрактные -- не должны показываться пользователю.


А что делать с этими самыми UserFriendlyException, если они на английском, а разговор с пользователем строится на китайском?
Re[36]: –
От: samius Япония http://sams-tricks.blogspot.com
Дата: 23.08.10 02:51
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Здравствуйте, samius, Вы писали:


S>>В случае ожиданных исключений, юзер увидит сообщение "Failed". В случае неожиданных — не увидит. Вот это я называю странным поведением.

T>И чем же оно странно? В Windows тоже пользователь может увидеть и messagebox с сообщением "Access denied", и "программа выполнила недопустимую операцию и будет закрыта" или, даже, синий экран. Как думаешь, зачем майкросовтовцы сделали синий экран, дураки?

Т.е. для тебя норма, когда приложение вместо внятного сообщения о том что операция "Failed" показывает что-то вроде "Object reference not set to an instance of an object.", на который я смотрел 4 года в 2005/2008 студиях?

S>>Ты путаешь. Код возврата — это прежде всего число.

T>Кто это тебе такую глупость сказал?
Про число — это я глупость ляпнул. Но все равно, код возврата и специальное значение это далеко не одно и то же.

S>>>>А что оптимизирует TryDoOperation?

T>>>Количество обращений к серверу и возможность обойтись без бизнес-транзакций.
S>>Чем количество обращений к серверу будет меньше чем при DoOperation?
T>Нет. Оно будет меньше, чем при tester-doer

Если ты не заметил, то я был против tester-doer. Так что ты мне какой-то странный аргумент привел.

S>>Вот скажи, попытка закрытия счета при отрицательном балансе для тебя неожиданная ситуация, или ее не нужно логировать?

T>Это зависит от того, как мы реализовали систему. Если мы её реализовали таким образом, что у нас в принципе не может возникнуть попытка закрытия счета при отрицательном балансе и наличие такой попытки говорит либо об ошибке в программном коде, либо неконсистентности данных, либо о хакерской атаке, то это неожиданная ситуация. Если же эта ситуация может возникнуть в рамках штатного функционирования системы, то это ожидаемая ситуация и логгировать её не надо.
Ты воспринимаешь систему как однажды отлитую в железобетоне, а на самом деле система может развиваться годами, причем разными людьми. Необходимость лоГирования попытки закрытия счета при отрицательном балансе обуславливается ТЗ, а не фантазией программиста.

T>Но только не путаем логгирование с аудированием.

Если я правильно тебя понял, то под лоГГированием ты подразумеваешь запись в лоГГ файл (то есть логирование), а под аудированием — понимание воспринимаемой на слух речи... А кто тут путает эти вещи? К чему реплика?
Re[37]: –
От: mrTwister Россия  
Дата: 23.08.10 04:07
Оценка:
Здравствуйте, samius, Вы писали:

S>Т.е. для тебя норма, когда приложение вместо внятного сообщения о том что операция "Failed" показывает что-то вроде "Object reference not set to an instance of an object.", на который я смотрел 4 года в 2005/2008 студиях?

Нет, с чего ты взял?

S>>>Ты путаешь. Код возврата — это прежде всего число.

T>>Кто это тебе такую глупость сказал?
S>Но все равно, код возврата и специальное значение это далеко не одно и то же.
А в чем разница?

S>Если ты не заметил, то я был против tester-doer. Так что ты мне какой-то странный аргумент привел.

Какой еще аргумент?

S>Ты воспринимаешь систему как однажды отлитую в железобетоне, а на самом деле система может развиваться годами, причем разными людьми. Необходимость лоГирования попытки закрытия счета при отрицательном балансе обуславливается ТЗ, а не фантазией программиста.


В этом случае это называется аудит. Это не тоже самое, что логгирование.
лэт ми спик фром май харт
Re[38]: –
От: samius Япония http://sams-tricks.blogspot.com
Дата: 23.08.10 06:09
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Здравствуйте, samius, Вы писали:


S>>Т.е. для тебя норма, когда приложение вместо внятного сообщения о том что операция "Failed" показывает что-то вроде "Object reference not set to an instance of an object.", на который я смотрел 4 года в 2005/2008 студиях?

T>Нет, с чего ты взял?
Ты сам написал что не видишь ничего странного в таком поведении.

И чем же оно странно? В Windows тоже пользователь может увидеть...


S>>>>Ты путаешь. Код возврата — это прежде всего число.

T>>>Кто это тебе такую глупость сказал?
S>>Но все равно, код возврата и специальное значение это далеко не одно и то же.
T>А в чем разница?
В том что в код возврата не принято паковать возвращаемое значение функции. При наличии кода возврата возвращаемое значение передается через выходные параметры. В код возварта пакуют код ошибки и (внимание!) специальное значение кода ошибки — признак успеха.
В свою очередь специальное значение используют для информирования о неудачах выполнения функции (типа значение не найдено), но не об ошибках выполнения функции или о несоблюдении инварианта.
Примеры:
Array.IndexOf — возвращает индекс и в качестве специального значения (-1) признак отсутствия искомого элемента.
Enumerable.FirstOrDefault — возвращает T и в качестве специального значения default(T) признак отсутствия элемента. То что это спорное решение для значимых типов неоднократно обсуждалось.
Dictionary.TryGetValue — возвращает признак наличия записи.
WinAPI FindWindow возвращает HWND и в качестве специального значения (NULL) признак неудачи, при этом за кодом ошибки (возврата) следует обращаться к GetLastError, которая вернет код возврата.

IUnknown::QueryInterface — возвращает код возврата, и искомый интерфейс через out параметр.

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


S>>Если ты не заметил, то я был против tester-doer. Так что ты мне какой-то странный аргумент привел.

T>Какой еще аргумент?
Что TryDoOperation минимизирует число обращений к серверу

S>>Ты воспринимаешь систему как однажды отлитую в железобетоне, а на самом деле система может развиваться годами, причем разными людьми. Необходимость лоГирования попытки закрытия счета при отрицательном балансе обуславливается ТЗ, а не фантазией программиста.


T>В этом случае это называется аудит. Это не тоже самое, что логгирование.

То есть ты под аудированием подразумевал аудитирование?
Re[39]: –
От: mrTwister Россия  
Дата: 23.08.10 06:47
Оценка:
Здравствуйте, samius, Вы писали:

S>Здравствуйте, mrTwister, Вы писали:


T>>Здравствуйте, samius, Вы писали:


S>>>Т.е. для тебя норма, когда приложение вместо внятного сообщения о том что операция "Failed" показывает что-то вроде "Object reference not set to an instance of an object.", на который я смотрел 4 года в 2005/2008 студиях?

T>>Нет, с чего ты взял?
S>Ты сам написал что не видишь ничего странного в таком поведении.
S>

S>И чем же оно странно? В Windows тоже пользователь может увидеть...

Смотри, у нас есть две ситуации:

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

Ситуация Б.
Пользователь пробует выполнить операцию и тут наступает песец. Умирает винчестер, а в дата-центр попала ядерная бомба. В этом случае пользователь видит сообщение:
"Произошел непредвиденный сбой в системе. Приносим свои извинения. Пожалуйста, обратитесь в саппорт. Телефон саппорта: 123-123-123"

Это две совершенно разные ситуации, которые надо обрабатывать совершенно по-разному.

S>В том что в код возврата не принято паковать возвращаемое значение функции...

Ок, предлагаю не углубляться в терминологический сбор, это бессмысленно. Я под кодом возврата имел ввиду возврат статуса выполнения функции через прямой поток выполнения (то есть через возвращаемое значение, или out параметры). Исключения — это альтернативный поток выполнения. Дак вот, правило, о котором я толкую, можно переформлировать так: проектировать библиотеку надо стараться таким образом, чтобы клиенту не надо было перенаправлять один поток выполнения в другой (альтернативный поток в прямой и прямой поток в альтернативный). Таких точек перенаправления должно быть минимум.

S>>>Если ты не заметил, то я был против tester-doer. Так что ты мне какой-то странный аргумент привел.

T>>Какой еще аргумент?
S>Что TryDoOperation минимизирует число обращений к серверу
Минимизирует в сравнении с tester-doer, а не в сравнении с try/catch. Если касаться кода со словарем, то код
if(!dictionary.ContainsKey(key))
{
    dictionary[key] = value;
}
return dictionary[key];


можно было бы переписать не только через TryGetValue, но и вот так:

try
{
    return dictionary[key];
}
catch(KeyNotFoundException)
{
    dictionary.Add(key, value);
    return value;
}

Причем, если не учитывать оверхеда на сами исключения, то этот код алгоритмически эквивалентен коду с TryGetValue, что не помешало Майкросовту добавить в класс словаря метод TryGetValue.

S>То есть ты под аудированием подразумевал аудитирование?

Да
лэт ми спик фром май харт
Re[40]: –
От: samius Япония http://sams-tricks.blogspot.com
Дата: 23.08.10 08:03
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Смотри, у нас есть две ситуации:


T>Ситуация А.

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

T>Ситуация Б.

T>Пользователь пробует выполнить операцию и тут наступает песец. Умирает винчестер, а в дата-центр попала ядерная бомба. В этом случае пользователь видит сообщение:
T>"Произошел непредвиденный сбой в системе. Приносим свои извинения. Пожалуйста, обратитесь в саппорт. Телефон саппорта: 123-123-123"

T>Это две совершенно разные ситуации, которые надо обрабатывать совершенно по-разному.


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

S>>В том что в код возврата не принято паковать возвращаемое значение функции...

T>Ок, предлагаю не углубляться в терминологический сбор, это бессмысленно. Я под кодом возврата имел ввиду возврат статуса выполнения функции через прямой поток выполнения (то есть через возвращаемое значение, или out параметры). Исключения — это альтернативный поток выполнения. Дак вот, правило, о котором я толкую, можно переформлировать так: проектировать библиотеку надо стараться таким образом, чтобы клиенту не надо было перенаправлять один поток выполнения в другой (альтернативный поток в прямой и прямой поток в альтернативный). Таких точек перенаправления должно быть минимум.

Можно ссылку на это правило?

S>>Что TryDoOperation минимизирует число обращений к серверу

T>Минимизирует в сравнении с tester-doer, а не в сравнении с try/catch. Если касаться кода со словарем, то код
T>можно было бы переписать не только через TryGetValue, но и вот так:

T>
T>try
T>{
T>    return dictionary[key];
T>}
T>catch(KeyNotFoundException)
T>{
T>    dictionary.Add(key, value);
T>    return value;
T>}
T>

T>Причем, если не учитывать оверхеда на сами исключения, то этот код алгоритмически эквивалентен коду с TryGetValue, что не помешало Майкросовту добавить в класс словаря метод TryGetValue.
Во избежание оверхеда на исключения и для упрощения кода для доступа к содержимому.
Какие проблемы решает TryDoOperation vs DoOperation, кроме оверхеда на исключения?

S>>То есть ты под аудированием подразумевал аудитирование?

T>Да
Тогда отвечу что аудитирование и логирование может выполняться одним аппаратом типа ExceptionPolicy, при этом нет смысла различать на уровне кода бизнес-исключения от других типа ресолва DNS. Это может быть сделано на уровне конфигурации программы.
Re[7]: Исключения для пользователя и для программиста -- раз
От: The Lex Украина  
Дата: 24.08.10 14:20
Оценка:
Здравствуйте, 0K, Вы писали:

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


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

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

б) ситуации, которые пользователь не может решить самостоятельно, но которые могут объяснить службе поддержки что вообще происходит. Далее — см. по этапам процесса поддержки ПО.

На этом, собственно, все. То, что пользователь может быть умнее, чем рядовой потребитель — ни о чем не говорит. Если пользователь умнее и инструмент-программа на это рассчитан — рассчитан на то, что им будет пользоваться именно умный пользователь — ситуация при этом ровным счетом не меняется, только сообщения уровня а) становятся шире и глубже — охватывают большее количество кейзов и позволяют делать более глубокую аналитику "что вообще происходит". Опять-таки, если программа пользуется файлом xxx213456.tmp как "внутренними данными" и в документации для _пользователя_ это не описано и вообще не предполагается, что пользователь будет об этом знать — сообщение "не могу открыть вайл кптфхцч2110345.var" не должны появляться в принципе. Разве что в качестве дополнительной расширенной информации к сообщениями типа б).

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

имхо, библиотеки уровня прикладного API сообщения о своих ошибках:

а) _должны_ предоставлять на уровне кодов прикладного API;
б) _могут_, но не должны, предоставлять сервис для формирования человеко-удобных сообшений на основании кода ошибки прикладного API.

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

имхо, где-то так.
Голь на выдумку хитра, однако...
Re[7]: Исключения для пользователя и для программиста -- раз
От: The Lex Украина  
Дата: 24.08.10 14:46
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Вот! Теперь, похоже, вы поняли проблему. Вы же сами написали "Не факт, что e.Message содержит текст сообщения в читабельном виде... Мало ли, мож еще и перевести надо". Нужно перевести или нет -- зависит от локализации библиотеки. Если нет локализации -- добавить ее (это обязательно!).


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

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

0K>А вот как узнать можно ли данное сообщение выводить пользователю? Является ли оно UserFriendly? Вот этого механизма и не хватает. Понимаете о чем речь? Ведь в сообщении могут быть очень полезные данные (имя файла, имя сетевой ошибки и пр.) а могут быть абсолютно не понятные пользователю контрактные данные (которые выводить ни в коем случае нельзя).


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

M>>Если уж библиотека должна выдавать читабельные эксепшены


0K>А кто должен выдавать? Вот вызываете вы метод для перевода денег со счета на банковскую карту. И он выдает исключение: превышен лимит операций. А вы что пользователю скажите? НЕ удалось перевести средства? И все? А причину он откуда может узнать? Может просто сетевая ошибка? А может его счет заблокирован по подозрению в мошенничестве? А может денег нет? Откуда бедному пользователю узнать, что именно превышен лимит операций?


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

А не положено бедному пользователю знать!
Вот у нас снаружи библиотеки стоит простой фильтр: вот этот пользователь может увидеть только вот эти сообщения. Остальные показывать как "общая ошибка — обратитесь к администратору". И все. Решает что и как показывать — _приложение_, не библиотека.

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

0K>Вот только как узнать является ли исключение контрактным или предназначено для вывода пользователю -- этого механизма нет.


Вот именно. Потому все сообщения должны быть контрактными. Если хочется сделать для вывода пользователю — отдельный сервис/API. Кстати, в Видне именно так.

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


0K>Зачем изменять, не понял?


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

0K>Ну хорошо. Вот возникла ошибка при попытке перевести деньги со счета на банковскую карту. Вы что напишите? Не удалось перевести средства? Причин же может быть десятки! И это очень важно для пользователя.


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

Еще раз: библиотека пользователю _приложения_ ничего не должна — всем _обязано_ управлять именно приложение. И никак иначе. Впрочем, случаи когда таки иначе я тоже упомянул выше.
Голь на выдумку хитра, однако...
Re[5]: Исключения для пользователя и для программиста -- раз
От: The Lex Украина  
Дата: 24.08.10 14:55
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Еще раз повторяю: пользователю нужно отобразить только Message UserFriendlyException. Не любого Exceptin, а именно UserFriendly. Как его отличить -- в этом то и вопрос. Механизма нет, хотя должен быть.


Еще раз повторяю: механизма отличить ошибку user-friendly от не user-friendly на уровне _библиотеки_ быть не может в принципе и именно в принципе самой структуры "библиотека — приложение — user" быть не должно. Решать "user — не user" именно приложению, и никак иначе. Иначе сама библиотека уже перебирает на себя часть функций приложения и либо становится его, приложения, непосредственной частью (а не "библиотекой", как "собранием отдельных решений задач") и, собственно, становится самим приложением. Тогда уже библиотека пользуется функциями приложения для общения с пользователем.

0K>Простите, а каким образом вы предлагаете передавать сообщения об ошбках пользователю?


А зачем их передавать пользователю? Может я по плану хочу сперва 3 раза сделать Ку! — попробовать подключиться — и только потом выдать пользователю "А ннэ палучилась! Спробуйтэ щэ!"

0K>На конкретном примере. Библиотека для работы с финансовой системой. Метод для перевода средств со счета на карту. Клиент вызывает этот метод -- происходит ошибка. В Message -- детальное описание причины ошибки (причин может быть несколько десятков). Вы выведете это сообщение пользователю, или вы будете out-параметр добавлять в метод и описание ошибки в него записывать?


Зависит от вашей архитектуры. Как я уже только что написал, ваша "библиотека" на самом деле может как раз и являться основным блоком всего комплекса, а само приложение только выполнять функции непосредственной связи с конечным пользователем. В таком случае библиотека в своем исключении присылает детальный (точнее, заданного уровня детализации) user-friendly message, а задача приложения — просто передать его пользователю. Исходя из того, что вы стремитесь вложить в свою "библиотеку" также уровень локазации, я склоняюсь именно к такой архитектуре вашего случая "библиотека — приложение — пользователь".
Голь на выдумку хитра, однако...
Re[9]: Исключения для пользователя и для программиста -- раз
От: The Lex Украина  
Дата: 24.08.10 15:01
Оценка:
Здравствуйте, 0K, Вы писали:

0K>Здравсти! MSDN изредка почитывайте. Локализация сообщений об ошибках -- обязательное требование.




0K>Почему, по вашему, MS сами локализуют сообщения об ошибках в своей .Net платформе? Локализовать может и тот, кто будет использовать вашу библиотеку. Для этого перекомпиляция не нужна, есть специальная тулуза в SDK.


Мы говорим о .NET, как о framework, сиречь "библиотеке библиотек", включая в т.ч. и "специальный сервис для выдачи и локализации user-friendly сообщений", или как о библиотеке в более узком понимании?

А то Win API тоже как бы "библиотека", и там тоже есть генерация сообщений читаемых для пользователя и локализация этих сообщений. Что ж теперь — каждый отдельный контейнер специального образца тоже "пользоватевать и локализировать"?

0K>Локализация -- это не больно. Открываете файл ресурсов и быстренько переводите все UserFriendly-сообщения об ошибках.


имхо, вы говорите о чем-то очень-очень конкретном о своем, обобщая это очень-очень конкретное свое до совсем-совсем общего.
Голь на выдумку хитра, однако...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.