По вине или не по вине - PullRequest
       24

По вине или не по вине

10 голосов
/ 14 декабря 2010

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

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

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

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

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

Что вы думаете?

Ответы [ 5 ]

12 голосов
/ 14 декабря 2010

Мой взгляд на это ...

Существует три причины сбоя:

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

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

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

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

Для уточнения:

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

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

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

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

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

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

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

2 голосов
/ 14 декабря 2010

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

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

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

2 голосов
/ 14 декабря 2010

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

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

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

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

    Пример: действительная дата присоединения к компании раньше даты рождения этого лица.

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

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

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

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

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

1 голос
/ 14 декабря 2010

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...