К неисправности или неисправности

У меня есть дискуссия с коллегой о том, когда бросать ошибки и не бросать ошибки в службе WCF.

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

  • ValidateMember (имя строки, строковый пароль, строка) - > выдает ошибку, если обязательные параметры не передаются, поскольку сама проверка не может быть выполнена; - > будет бросать ошибку, если произошла некоторая внутренняя ошибка, например, база данных была опущена - > будет возвращать контракт статуса во всех других случаях, который указывает результат проверки (MemberValidated, WrongPassword, MemberNotKnown,...)

  • GetMember (int memberId) - > будет только бросать ошибку, если что-то не работает, во всех остальных случаях он возвращает элемент или null, если не найден.

Другое мнение состоит в том, что мы также должны бросать ошибки, когда GetMember не находит участника, или в случае ValidateMember пароль неверен.

Как вы думаете?

Ответ 1

Мое занятие этим...

Существует три причины отказа:

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

Это зависит от вас, как вы выбираете отображение фактических контрактов неисправностей по каждой причине отказа. Например, мы делаем это:

  • Для причин 1 и 2 весь код клиента должен знать, что служба не удалась. Мы определяем очень простой контракт с "фатальной ошибкой", который содержит только уникальный идентификатор ошибки. Полная информация об ошибке регистрируется на сервере.
  • Для причины 3 конечный пользователь должен точно знать, что он/она сделал неправильно. Мы определяем "отказ от ошибок проверки", содержащий набор дружественных сообщений об ошибках для отображения кода клиента на экране.

Мы занимаем класс Microsoft EntLib для причины 3 и используем защиту экрана для обработки причин 1 и 2 декларативно. Это делает очень простой код.

Чтобы уточнить:

Мы обрабатываем три причины, подобные этому внутри службы:

  • В служебном коде выбрано непредвиденное исключение. Мы поймаем его на верхнем уровне (на самом деле исключение защищает его, но принцип тот же). Зарегистрируйте полную информацию, затем введите FaultException<ServiceFault> клиенту, содержащему только идентификатор ошибки.
  • Мы проверяем входные данные и намеренно генерируем исключение. Обычно это ArgumentException, но любой подходящий тип. Как только он брошен, он обрабатывается точно так же, как (1), потому что мы хотим сделать его похожим на клиента.
  • Мы проверяем входные данные и намеренно генерируем исключение. На этот раз это a FaultException<ValidationFault>. Мы настраиваем экранирование исключений, чтобы передать это через un-wrapped, поэтому он отображается на клиенте как FaultException<ValidationFault> not FaultException<ServiceFault>.

Конечный результат:

  • Никаких блоков catch внутри службы (чистый чистый код).
  • Клиент должен поймать FaultException<ValidationFault>, если он хочет отображать сообщения пользователю. Все остальные типы исключений, включая FaultException<ServiceFault>, обрабатываются глобальным обработчиком ошибок клиента как фатальные ошибки, поскольку фатальная ошибка в сервисе обычно означает фатальную ошибку в клиенте.

Ответ 2

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

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

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

Ответ 3

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

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

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

  • Подтверждение контекста - вы можете только определить, что контент недействителен по ссылке на сообщение в сочетании с состоянием системы.

    Пример: действительная дата присоединения к компании ранее, чем у тех, кто имеет дату рождения.

  • Ложь в системе - вы можете только определить, что сообщение было ошибкой, когда более позднее сообщение порождает аномалию.

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

Ваша система ДОЛЖНА иметь дело со всеми классами ошибок - хотя в случае трех это может быть ограничено выдачей предупреждения.

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

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

Ответ 4

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

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

Это зависит от вашего проекта. Самое главное, что есть стандартный проект, и каждый делает это одинаково.

Ответ 5

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

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

Я слышал много о проблеме производительности. Я просто сделал простой тест с использованием исключений С# и trow/catch 1000. Время, затрачиваемое на 1 000 экземпляров, составляет 23 мс. Это 23μ за исключение. Я думаю, что производительность больше не является первым аргументом здесь, за исключением того, что вы планируете повышать более 2000 исключений в секунду, и в этом случае у вас будет 5% -ная производительность, и я могу начать рассматривать.

Мое скромное мнение...