Кажется, существует определенное соглашение о том, что сообщения об исключениях должны содержать полезные детали .
Почему многие распространенные исключения из системных компонентов не содержат полезных деталей?
Несколько примеров:
- .NET
List
доступ индексаArgumentOutOfRangeException
никак не говорит мне значение индекса , который был испытанным и был недействительным, и не говорит мне допустимый диапазон. - В основном все сообщения об исключениях из стандартной библиотеки MSVC C ++ совершенно бесполезны (в том же духе, что и выше).
- Исключения Oracle в .NET, сообщающие вам (перефразировано) «TABLE OR VIEW not found», но не какой именно .
Таким образом, мне кажется, что по большей части сообщения об исключениях не содержат достаточно деталей, чтобы быть полезными. Мои ожидания не соответствуют? Я неправильно использую исключения, что я даже замечаю это? Или , может быть , мое впечатление обманчиво: большинство исключений делать на самом деле обеспечивают полезные детали?
c#
c++
exceptions
Мартин Ба
источник
источник
Ответы:
Исключения не содержат полезных подробностей, поскольку концепция исключений еще недостаточно сформировалась в рамках дисциплины разработки программного обеспечения, поэтому многие программисты не понимают их полностью и поэтому не обращаются с ними должным образом.
Да,
IndexOutOfRangeException
должен содержать точный индекс, выходящий за пределы диапазона, а также диапазон, который был действителен в момент его создания, и это презренно со стороны создателей среды выполнения .NET, чего нет. Да,table or view not found
исключение Oracle должно содержать имя таблицы или представления, которое не было найдено, и, опять же, тот факт, что это не так, является презренным от имени того, кто несет за это ответственность.В значительной степени путаница проистекает из ошибочной первоначальной идеи о том, что исключения должны содержать понятные человеку сообщения, что, в свою очередь, связано с отсутствием понимания того, что такое исключения, так что это порочный круг.
Поскольку люди думают, что исключение должно содержать удобочитаемое сообщение, они считают, что любая информация, содержащаяся в исключении, также должна быть отформатирована в удобочитаемое сообщение, а затем им надоедает написать все читаемое человеком сообщение. строительный кодекс, или они боятся, что это может разглашать неоправданное количество информации любопытным глазам, которые увидят сообщение. (Проблемы безопасности, упомянутые в других ответах.)
Но правда в том, что они не должны беспокоиться об этом, потому что исключение не должно содержать удобочитаемого сообщения. Исключения - это вещи, которые должны видеть и / или иметь дело только программисты. Если когда-либо возникает необходимость представить пользователю информацию об ошибках, это необходимо сделать на очень высоком уровне, сложным образом и на языке пользователя, который, по статистике, вряд ли будет английским.
Таким образом, для нас, программистов, «сообщение» об исключении является именем класса исключения , и любая другая информация, относящаяся к исключению, должна быть скопирована в (окончательные / только для чтения) переменные-члены объекта исключения. Предпочтительно, каждый мыслимый маленький кусочек этого. Таким образом, сообщение не должно (или должно) генерироваться, и поэтому никакие посторонние глаза не могут его увидеть.
Чтобы ответить на озабоченность, выраженную Томасом Оуэнсом в комментарии ниже:
Да, конечно, на каком - то уровне, вы будете создавать сообщение журнала относительно исключения. Но вы уже видите проблему с тем, что говорите: с одной стороны, сообщение журнала исключений без трассировки стека бесполезно, но, с другой стороны, вы не хотите, чтобы пользователь видел всю трассировку стека исключений. Опять же, наша проблема здесь заключается в том, что наша перспектива искажена традиционными методами. Файлы журналов традиционно были в виде простого текста, что, возможно, было хорошо, когда наша дисциплина была в зачаточном состоянии, но, возможно, уже не так: если существует проблема безопасности, тогда файл журнала должен быть двоичным и / или зашифрованным.
Бинарный или простой текстовый файл должен рассматриваться как поток, в который приложение сериализует отладочную информацию. Такой поток предназначен только для глаз программистов, и задача генерации отладочной информации для исключения должна быть такой же простой, как сериализация исключения в поток журнала отладки. Таким образом, просматривая журнал, вы видите имя класса исключения (которое, как я уже говорил, для всех практических целей - «сообщение»), каждая из переменных-членов исключения, которые описывают все, что уместно, - и - практическое включение в журнал и трассировка всего стека. Обратите внимание, что форматирование читаемого человеком сообщения об исключении явно отсутствует в этом процессе.
PS
Еще несколько моих мыслей на эту тему можно найти в этом ответе: Как написать хорошее сообщение об исключении
PPS
Похоже, что многие люди были помечены моим предложением о бинарных файлах журналов, поэтому я еще раз изменил ответ, чтобы сделать еще более ясным то, что я предлагаю здесь не то, что файл журнала должен быть двоичным, а что файл журнала может быть двоичным, если это необходимо.
источник
По моему опыту, есть ряд причин, по которым исключения не содержат полезной информации. Я ожидаю, что такого рода причины будут также относиться к системным компонентам - но я не знаю точно.
Вроде? Я имею в виду, что исключения должны иметь хорошие сообщения, но они также являются исключениями . Вы должны тратить свое время на разработку кода, чтобы избежать исключительных условий, или написание кода для обработки исключительных условий (игнорирование сообщения), а не использование их в качестве своего рода интерактивного механизма обратной связи при кодировании. Их неизбежно использовать для целей отладки, но в большинстве случаев их следует сводить к минимуму. То, что вы заметили эту проблему, заставляет меня беспокоиться, что вы недостаточно хорошо справляетесь с их предотвращением.
источник
У меня нет опыта работы с C # или C ++, но я могу сказать вам следующее - написанные разработчиком исключения в 9 из 10 раз более полезны, чем любое общее исключение, которое вы когда-либо найдете, точка.
В идеале да, универсальное исключение укажет вам точно, почему произошла ошибка, и вы сможете легко ее исправить - но реально, в больших приложениях с несколькими классами, которые могут генерировать множество различных видов исключений, или Исключения того же типа, всегда более ценно написать собственный вывод для возврата ошибки, чем полагаться на сообщение по умолчанию.
Так и должно быть, потому что, как отмечали многие люди, некоторые приложения не хотят выдавать сообщение об ошибке, которое не хотят видеть пользователь, из соображений безопасности или во избежание путаницы.
Вместо этого вы должны предвидеть в своем дизайне, какие типы ошибок могут возникать в вашем приложении (и всегда будут ошибки), и писать сообщения об обнаружении ошибок, которые помогут вам определить проблему.
Это не всегда поможет вам - потому что вы не всегда можете предвидеть, какое сообщение об ошибке будет полезно - но это первый шаг к лучшему пониманию вашего собственного приложения в долгосрочной перспективе.
источник
Вопрос, в частности, заключается в том, почему так много исключений, создаваемых «системными компонентами» (то есть классами стандартной библиотеки), не содержат полезных деталей.
К сожалению, большинство разработчиков не пишут основные компоненты в стандартных библиотеках, а подробные проектные документы или другие обоснования дизайна не обязательно публикуются. Другими словами, мы никогда не узнаем наверняка.
Однако следует помнить о двух ключевых моментах: почему подробная информация об исключениях может быть нежелательной или важной:
Исключение может быть использовано при вызове кода любым способом: стандартная библиотека не может накладывать ограничения на то, как используется исключение. В частности, он может отображаться для пользователя. Рассмотрим индекс массива вне границ: это может дать полезную информацию злоумышленнику. Разработчик языка не имеет представления о том, как приложение будет использовать выбрасываемое исключение или даже о типе приложения (например, веб-приложение или рабочий стол), поэтому исключение информации может быть более безопасным с точки зрения безопасности.
Исключения не должны отображаться пользователю. Вместо этого отобразите понятное сообщение об ошибке и зарегистрируйте исключение в месте, к которому у злоумышленника нет доступа (если применимо). Как только ошибка обнаружена, разработчик должен выполнить отладку кода, проверяя кадры стека и логические пути. На данный момент разработчик имеет больше информации, чем когда-либо может ожидать исключение.
источник
Прежде всего, позвольте мне разорвать пузырь, сказав, что даже если сообщение diag загружено информацией, которая приводит вас к точной строке кода и подкоманде за 4 секунды, есть вероятность, что пользователи никогда не запишут ее или не передадут ее специалистам службы поддержки. и вам скажут "Ну, это что-то говорило о нарушении ... Я не знаю, что это выглядело сложно!"
Я пишу программное обеспечение и поддерживаю результаты другого программного обеспечения уже более 30 лет, и лично мое текущее качество сообщения об исключении практически не имеет ничего общего с безопасностью, независимо от того, каким образом конечные результаты соответствовали их модели. Вселенная, гораздо больше связано с тем фактом, что многие в нашей отрасли изначально самоучки, и они просто никогда не включали уроки в общение. Возможно, если бы мы на пару лет заставили всех новых кодеров перейти на техническое обслуживание, где им пришлось бы выяснять, что пошло не так, они бы поняли важность хотя бы некоторой формы точности.
Недавно в приложении, которое было перестроено, было принято решение, что коды возврата будут относиться к одной из трех групп:
(100 было почему-то опущено)
В любом конкретном рабочем процессе наша мысль использовалась повторно, или универсальный код использовал бы универсальные возвраты (> 199) для фатальных ошибок, в результате чего у нас было 100 фатальных ошибок, возможных для рабочего процесса. При небольшом различении данных в сообщении ошибки, такие как не найденный файл, могут использовать один и тот же код и различаться в сообщениях.
Когда код возвращался от подрядчиков, вы не поверите нашему удивлению, когда практически КАЖДАЯ ОДНА ФАТАЛЬНАЯ ОШИБКА была кодом возврата 101.
Я считаю, что ответ на ваш вопрос заключается в том, что сообщения настолько бессмысленны, потому что при создании они должны были быть заполнителями, к которым никто не вернулся. В конце концов, люди выяснили, как решить проблемы не из-за сообщений, а из-за их игнорирования.
С тех пор у самоучек просто не было хорошего примера того, что должно содержать исключение. Добавьте к этому, что больше пользователей не читают сообщения, тем более пытаются передать его в службу поддержки (я видел сообщения об ошибках, которые были вырезаны и вставлены использованным, а затем отредактированы перед отправкой с последующим комментарием, что это мне показалось, что информации много, и я не мог хотеть всего этого, поэтому они случайно удалили кучу информации.
И давайте посмотрим правде в глаза, со слишком большим количеством (не все, но слишком много) кодеров следующего поколения, если это больше работы и не добавляет флэш, просто не стоит этого ...
Последнее замечание: если сообщение об ошибке содержит код ошибки / возврата, мне кажется, что где-то в исполняемых модулях должна быть строка, которая читает что-то вроде «если условие возвращает код-значение», а условие должно сообщать вам, почему код возврата произошло. Это кажется простым логическим подходом, но, на мой взгляд, просто ПОПРОБУЙТЕ, чтобы Microsoft рассказала вам, что произошло, когда обновление Windows не удалось выполнить по CODE 80241013 или какому-то другому уникальному идентификатору. Вроде печально, не правда ли?
источник
chances are the users will never write it down... and you will be told "Well it said something about a violation..."
Вот почему вы используете инструмент регистрации исключений, чтобы автоматически генерировать отчет об ошибках, содержащий трассировку стека, и, возможно, даже отправлять его на ваш сервер. У меня был один пользователь, который не был очень техническим. Каждый раз, когда она отправляла сообщение из регистратора ошибок, оно показывало что-то вроде «Я не уверен, что я сделал неправильно, но ...», независимо от того, сколько раз я объяснял, что эта ошибка означала, что ошибка была на моей стороне , Но я всегда получал сообщения об ошибках от нее!Хотя я согласен, что исключения должны содержать как можно больше информации или, по крайней мере, быть менее общими. В случае таблицы не найден, имя таблицы будет хорошим.
Но вы знаете больше о том, что вы пытались сделать в том месте кода, где вы получили исключение. Хотя вы часто действительно мало что можете сделать, чтобы исправить ситуацию, когда что-то идет не так в библиотеке, находящейся вне вашего контроля, вы можете добавить гораздо больше полезной информации о том, в какой ситуации что-то пошло не так.
В случае, если таблица не найдена, это не очень вам поможет, если вам скажут, что таблица, которую невозможно найти, называется STUDENTS, потому что у вас нет такой таблицы, и эта строка нигде в вашем коде.
Но если вы поймаете исключение и сбросите его с помощью SQL-оператора, который вы пытались выполнить, вам будет лучше, так как оказывается, что вы попытались вставить запись с полем имени, являющимся Robert '); КАПЛИ СТОЛБОВ; (Всегда есть xkcd!)
Так что для борьбы с менее информативными исключениями: попробуйте поймать-перебросить больше информации, конкретно относящейся к тому, что вы пытались сделать.
Я, вероятно, должен добавить, чтобы это было скорее ответом на вопрос «почему в вопросе», что вероятная причина, по которой создатели библиотек не уделяют больше внимания улучшению сообщений об исключениях, заключается в том, что они не знают почему что-то было опробовано, что не удалось, эта логика в коде вызова.
источник
throw_with_nested
много.Чтобы дать немного другой ответ: нарушающий код, вероятно, был сделан для спецификации:
Добавьте давление, чтобы доставить точно к спецификации (из-за страха быть отклоненным в обзоре / тестировании) в минимальное время и с минимальными усилиями, тогда у вас есть рецепт для полностью совместимого и бесполезного исключения из библиотеки.
источник
Исключения имеют стоимость, зависящую от языка и реализации.
Например, исключения C ++ требуются для уничтожения всех живых данных между бросанием фрейма вызова и перехватом фрейма вызова, и это дорого. Следовательно, программисты не хотят часто использовать исключения.
В Ocaml генерирование исключений происходит почти так же быстро, как C
setjmp
(его стоимость не зависит от количества пройденных фреймов вызовов), поэтому разработчики могут использовать его очень часто (даже для неисключительных, очень распространенных случаев). Напротив, исключения C ++ достаточно тяжелые, поэтому вы, вероятно, не будете использовать их так часто, как в Ocaml.Типичным примером является некоторый рекурсивный поиск или исследование, которое можно «остановить» внутри довольно глубокой рекурсии (например, найти лист в дереве или функцию объединения). В некоторых языках это (идиоматично) быстрее распространить это условие на каждого абонента. На других языках бросить исключение быстрее.
Таким образом, в зависимости от языка (и привычек разработчиков, использующих его), исключение может содержать много полезных деталей или, наоборот, использоваться как быстрый нелокальный переход и переносить только очень полезные данные.
источник
Что заставляет вас думать, что значение индекса или требуемый диапазон или имя таблицы являются полезными подробностями, за исключением?
Исключения не являются механизмом обработки ошибок; они механизм восстановления .
Точка исключений состоит в том, чтобы подняться до уровня кода, который может обработать исключение. Где бы ни находился этот уровень, либо у вас есть необходимая информация, либо она неактуальна. Если есть информация, которая вам нужна, но у вас нет немедленного доступа, вы не обрабатываете исключение на соответствующем уровне.
Один раз, когда я могу подумать, где может быть полезна дополнительная информация , это на самом верхнем уровне вашего приложения, где вы аварийно завершаете работу и генерируете дамп ошибок; но это не работа исключения для доступа, компиляции и хранения этой информации.
Я не говорю, что вы можете просто поставить «бросить новое исключение» везде и назвать его хорошим, можно написать плохие исключения. Но в том числе неактуальной информации не обязательно использовать их должным образом.
источник