Как следует обрабатывать бизнес-ошибки в веб-приложении? - PullRequest
3 голосов
/ 16 мая 2009

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

Как эта ошибка чаще всего всплывает от уровня обслуживания к контроллеру, а затем к представлению? Должен ли метод службы генерировать исключение, чтобы контроллер мог перехватить или вернуть значение или какой-либо объект результата?

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

Будем благодарны за любые предложения или ссылки на лучшие практики / примеры приложений.

Ответы [ 6 ]

3 голосов
/ 16 мая 2009

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

Исключения:

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

Проверка бизнес-правил:

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

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

1 голос
/ 16 мая 2009

Должен сказать, что я не большой поклонник паттерна «ошибки валидации - исключения».

Методы Save () моей модели просто создают и возвращают список нарушенных правил (или пустой список). Тогда моя ControllerBase (или сервисный уровень) выполняет эти нарушенные правила так, как им удобно. *

В случае моей ControllerBase я добавляю их один за другим в обработчик проверки MVC через AddModelError. На сервисном уровне это заканчивается добавлением флага «isValid» к моему результату JSON.

1 голос
/ 16 мая 2009

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

Однако в большинстве веб-приложений гораздо проще и понятнее использовать один единственный источник конфигурации. Django, RoR, JBoss Seam и другие используют этот подход. Они используют концепцию, сконцентрированную на наборе классов предметной области, в которую помещена вся логика и ограничения проверки. Исключения модели (такие как NoSuchObject) напрямую отображаются для просмотра исключения (404 Not Found), все они обрабатываются платформой. При таком подходе нет слоев, и основная идея состоит в том, чтобы избежать наслоения до тех пор, пока оно действительно не понадобится. Документы Django являются действительно хорошим источником информации по этим темам, а документы Seam более технические, но и более подробные.

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

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

1 голос
/ 16 мая 2009

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

1 голос
/ 16 мая 2009

Один из способов справиться с этим - создать объект ответа для вашей операции addPerson с кодом состояния. Например:

class AddPersonResponse {
    private Person person;
    private AddPersonStatus status;
    private AddPersonFailureReason failureReason;
}

enum AddPersonStatus {
    SUCCESS, FAILURE
}

enum AddPersonFailureReason {
    DUPLICATE_EMAIL_ADDRESS,
    DUPLICATE_USER_NAME
}

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

0 голосов
/ 16 мая 2009

Подход, который я использую с Spring MVC, заключается в выполнении всей проверки в моем классе Validator. Поэтому из моего метода validate я бы вызвал метод службы, чтобы проверить, был ли уже использован адрес электронной почты. Если бы это был дубликат, я бы добавил ошибку для этой привязки к объекту Errors для отображения в форме. Если объект Person был действительным, вам не нужно беспокоиться о том, что при добавлении его в службу будут возникать исключения.

...