Бросать исключение или возвращать коды ошибок/успеха? Является ли исключением то, что метод не может выполнить свою задачу?

104
24 октября 2021, 23:20

Исключения являются для меня самой непонятной темой в программировании(пока что). Даже прочтение кучи информации не помогло мне получить чёткое представление о том как ими ПРАВИЛЬНО пользоваться. В поле "Суть вопроса" сложно передать суть вопроса? Поэтому нужно прочитать всё что ниже :) Простите за много букв.

Допустим есть метод transferMoney($amount, User $recipient) и мы считаем, что любой user input является ожидаемым(даже строка с буквами). А он может быть любым из-за того, что пользователь может отправить запрос с любыми данными в теле прямиком на сервер, также некорректные данные может отправить недоработанное клиентское приложение. Проверить отправлен ли вообще параметр amount на сервер и является ли он числом можно где-нибудь выше метода transferMoney(). Но узнать является ли сумма(amount) корректной по-хорошему можно только в браузере/GUI или в Domain слое в самом методе transferMoney(). А поскольку пользователь может обойти и браузер и GUI, то это может сделать только transferMoney(). В transferMoney() нужно извлечь данные пользователя(который пересылает деньги) из БД и проверить есть ли у него такая сумма. Получается в методе transferMoney() есть одна причина неудачи, а что если добавится ещё одна причина, например, пользователю запрещено временно пересылать деньги? Таким образом получается, что из метода в случае неудачи нужно возвратить причину неудачи, этих причин уже может быть две, но при этом они являются вполне ожидаемыми если смотреть на общий контекст(мы ожидаем некорректные данные). Поскольку они ожидаемые, то бросать исключения не логично. В случае если бы была одна причина неудачи, то можно было бы просто вернуть false. Но поскольку их две, то получается, что нужно возвращать коды ошибок(или код успеха в случае успеха) либо возвращать что-то на подобии [false, $error] и [true, null](я подобное видел в очень популярной книге про PHP, только там вместо null была запись из БД).

Но есть и другой подход к проектированию(вроде как): метод transferMoney() является частью ядра приложения, а в Clean Architecture ясно сказано, что ядро это основа вокруг которой строится приложение. То есть, если я правильно понимаю, то transferMoney() не должен подстраиваться под слой повыше, в нём не должно быть никаких предположений, что пользователь введёт что-то правильно или неправильно, он просто должен ожидать только валидные данные, если они неправильные, то это исключительная ситуация. То есть transferMoney() выбросит исключение, которое подымется до Controller'a, и на основе которого Controller отправит 400 Bad Request и причину неудачи. Я правильно размышляю? Или всё таки первый подход к проблеме лучше(первый абзац)? Я в интернете нашел вот такую вот мысль: "A good rule of thumb is that if a method does not do what its name suggests, it should be considered a method-level failure, resulting in an exception".

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

Answer 1

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

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

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

READ ALSO
Executors. Как прекращать работу потоков?

Executors. Как прекращать работу потоков?

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

308
Есть ли преимущества в использовании числа вместо типа bool в Posgresql?

Есть ли преимущества в использовании числа вместо типа bool в Posgresql?

Несколько раз встречал в таблицах базы, относящейся к веб-приложению на Java, столбцы, играющие роль флага, но имеющие не привычный тип bool, а smallint...

77