Теория на обработке ошибок?

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

Вот несколько практических вопросов:

  • Как решить, должна ли ошибка быть обработана локально или распространена к высокоуровневому коду?
  • Как решить между входом ошибки или показыванием его как сообщение об ошибке пользователю?
  • Регистрирует что-то, что должно только быть сделано в коде приложения? Или это в порядке, чтобы сделать некоторый вход из кода библиотеки.
  • В случае исключений, где необходимо обычно ловить их? В или высокоуровневом коде низкого уровня?
  • Если Вы боретесь за объединенную стратегию обработки ошибок через все слои кода или пытаетесь разработать систему, которая может адаптироваться ко множеству стратегий обработки ошибок (чтобы смочь иметь дело с ошибками из сторонних библиотек).
  • Имеет смысл создавать список кодов ошибок? Или это старомодно в эти дни?

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

PS: это - общий вопрос, но C++, определенные ответы приветствуются также (C++ является моим основным языком программирования для работы).

53
задан 24 revs 23 May 2017 в 01:54
поделиться

9 ответов

Мой взгляд на протоколирование (или другие действия) из кода библиотеки НИКОГДА.

Библиотека не должна навязывать политику своему пользователю, и пользователь может ИНТЕНДИРОВАТЬ ошибку. Возможно, программа намеренно запрашивала конкретную ошибку, в ожидании ее появления, для проверки какого-то условия. Протоколирование этой ошибки было бы неверным.

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

.
5
ответ дан 7 November 2019 в 08:51
поделиться

Записывает что-то, что должно только быть выполненным в коде приложения? Или это так? можно сделать некоторые записи из библиотеки код.

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

.
14
ответ дан 7 November 2019 в 08:51
поделиться

Как решить, должна ли ошибка обрабатываться локально или переноситься на более высокий уровень кода?

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

Как принять решение между протоколированием ошибки или ее отображением в виде сообщения об ошибке пользователю?. Хорошим подходом является протоколирование ошибок и вся доступная информация об ошибке. Если ошибка прерывает операцию или пользователю необходимо знать о возникновении ошибки, вы должны показать ее пользователю. Обратите внимание, что в windows-сервисе протоколирование очень важно.

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

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

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

В контроллере.

Правка: Нужно немного объяснить, если вы не знакомы с MVC. Контроллер Model View Controller представляет собой шаблон проектирования. В Model вы разрабатываете логику приложения. В окне Вид отображается содержимое для пользователя. В Controller вы получаете пользовательские события и вызываете Model для соответствующей функции, а затем вызываете View для отображения результата пользователю.

Предположим, что у вас есть форма, которая имеет два текстовых поля и ярлык, а также кнопку с названием Add. Как вы можете догадаться, это ваш вид. Событие "Кнопка_клик" определено в контроллере. А метод добавления определен в Model. При щелчке пользователя срабатывает событие Button_Click и контроллер вызывает метод добавления. Здесь значения текстовых ящиков могут быть пустыми, или они могут быть буквами, а не цифрами. В функции добавления возникает исключение, и это исключение выбрасывается. Контроллер обрабатывает его. И выводит сообщение об ошибке в метку.

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

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

Имеет ли смысл создавать список кодов ошибок? Или это старомодно в наши дни?

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

If (error.Message == "User Login Failed")
{
   //do something.
}

If (error.Code == "102")
{
   //do something.
}

Какой из них вам больше нравится?

А в наши дни есть и другой путь для кодов ошибок:

If (error.Code == "LOGIN_ERROR_102") // wrong password
{
   //do something.
}

Может быть и другой: LOGIN_ERROR_103 (например: этот пользователь истек) и т.д...

Этот тоже читается человеком

.
4
ответ дан 7 November 2019 в 08:51
поделиться

Первый вопрос: что можно сделать с ошибкой?

Можете ли вы исправить ее (в этом случае нужно сказать пользователю) или пользователь может исправить ее?

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

.
0
ответ дан 7 November 2019 в 08:51
поделиться

Мои два цента.

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

Как решить, регистрировать ли ошибку или показывать ее пользователю в виде сообщения об ошибке?. Два ортогональных вопроса, которые не являются взаимоисключающими. Регистрация ошибки, в конечном счете, для вас, разработчика. Если вы заинтересованы в ней, зарегистрируйте ее. Покажите это пользователю, если это возможно ("Error: No network connection!").

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

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

Вы определенно не должны ставить блок try/catch вокруг каждой бросающей функции, которую вы вызываете.

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

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

.
1
ответ дан 7 November 2019 в 08:51
поделиться

Вот замечательный пост в блоге, который объясняет, как следует обрабатывать ошибки. http://damienkatz.net/2006/04/error_code_vs_e.html

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

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

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

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

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

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

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

.
1
ответ дан 7 November 2019 в 08:51
поделиться

Книга "Руководство по проектированию фреймворка: Конвенции, идиомы и образцы для многоразовых .NET-библиотек" Кшиштофа Квалина и Брэда Абрамса содержат некоторые хорошие предложения по этому вопросу. См. главу 7 об Исключениях. Например, она благоприятствует бросанию исключений на возврат кодов ошибок.

-Krip

.
0
ответ дан 7 November 2019 в 08:51
поделиться

Я меняю свой дизайн и философию кодирования, так что..:

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

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

В настоящее время я сталкиваюсь с проблемами, которые теряются в кодах возврата; или создаются новые коды возврата.

.
0
ответ дан 7 November 2019 в 08:51
поделиться
  1. Всегда обращайтесь как можно быстрее. Чем ближе вы к его возникновению, тем больше у вас шансов сделать что-то значимое или, по крайней мере, выяснить, где и почему это произошло. В С++ это не просто вопрос контекста, но во многих случаях это невозможно определить.

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

  3. Почему нет?

  4. см. 1.

  5. см. 1.

  6. Нужно все упростить, иначе пожалеешь. Более важным в работе с ошибками во время выполнения является тестирование, чтобы избежать их.

  7. Это как сказать, что лучше централизовать или не централизовать. В одних случаях это может иметь смысл, а в других - быть пустой тратой времени. Для чего-то, что является загружаемым lib/module какого-то рода, который может содержать ошибки, связанные с данными (мусор, мусор), это имеет тонны смысла. Для более общей обработки ошибок или катастрофических ошибок - меньше.

2
ответ дан 7 November 2019 в 08:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: