Здорово, ничего подобного не видел. На многих проектах так же использовал Result в связке с ExceptionHandler. А тут такая красота. Привезите нам ещё подобной годноты!
Очень интересное решение, повторял за видео, но один момент остаётся не понятен. Почему бы просто не использовать Optional? И в зависимости есть внутри него что то или нет возвращать нужный нам ResponseEntity (либо ок либо not found)?
Если мы будем возвращать Optional, то как определить, что конкретно пошло не так, чтобы потом транслировать результат не только в Not Found, но и в другие статусы ошибок клиента/сервера?
@@shurik_codes понял! как я понял в видео представлены только 2 исхода (success и CartNotFound), но очень легко добавить еще варианты, в то время как Optional сработал бы в этом примере, но проработать больше вариантов исхода не выйдет. надеюсь правильно вас понял 💯
В случае возникновения исключения есть два варианта обработки: 1. В первом случае можно на уровне метода сервиса перехватывать исключения в блоке try/catch и возвращать соответствующий результат, содержащий перехваченное исключение. Результат можно потом преобразовывать в ответ со статусом 500 Internal Server Error, а исключение, например, логгировать. 2. Во втором случае игнорировать его на уровне сервиса, но перехватывать на уровне контроллера, ну и дальше действовать соответствующим образом. Исключения на то и исключения, что предусмотреть все возможные варианты развития ситуации не получится даже при большом желании. Я лично придерживаюсь именно такого варианта. В случае, если возвращается null или success с null, то тут надо смотреть на код и на процесс его написания. Такое возможно только по недосмотру и при полном отсутствии тестов. Если же для проекта нормально написаны тесты или вовсе применяется TDD, то шансы возникновения такой ситуации сводятся к нулю.
Кажется, что это оверхед в данной ситуации. Попробовал внедрить у себя в одном месте на проекте. Сервис используется в нескольких воркерах и нескольких апи. Возможно несколько причин для ошибок - не найдены метаданные в бд, нет соответствующей записи в obs и т.д. В итоге в каждой точке использования нужно как-то пытаться реагировать на это все. В воркерах удобно сразу упасть с исключением, а в апи в самом коце поймать RuntimeException. Проц бросание исключения нагружает примерно никак
Для простых проектов - да, скорее всего, оверхед. Для серьёзных проектов - вполне годный подход. На мой взгляд исключения нужно рассматривать как инструмент для действительно исключительных ситуаций, возникновение которых невозможно спровоцировать одними лишь действиями пользователя, а следовательно - определить точные условия их возникновения. Примерами таких ситуаций, например, могут быть ошибки, спровоцированные сетевыми сбоями. Если есть возможность предвидеть ошибки, которые могут возникнуть по вине пользователя (ввод некорректных данных, отсутствие прав доступа, отсутствие запрашиваемых данных и т.д.), то такие ошибки должны быть описаны в виде результатов, примерно как показано в ролике, либо в виде проверяемых исключений. Но у исключений есть недостаток - они не бесплатные, т.к. при создании исключения (даже при создании) собирается полный стек-трейс вызова. Да, сбор стек-трейса можно и отключать, но тогда теряется одна из важнейших функций исключений. Так что "Проц бросание исключения нагружает примерно никак" - заблуждение. Более того, использование формализованных ответов вместо исключений позволяет для некоторых случаев использовать константные ответы, когда не требуется уточняющая информация. Чтобы не быть голословным, я написал простой бенчмарк с JMH, в котором замерил производительность всех вариантов (AMD Ryzen R9 5950X 4000MHz, Windows 11, Oracle GraalVM JDK 21): Benchmark Mode Cnt Score Error Units NotFoundBenchmark.returnNotFoundConstant avgt 10 ≈ 10⁻⁴ ms/op NotFoundBenchmark.returnAccessDenied avgt 10 0,940 ± 0,003 ms/op NotFoundBenchmark.throwNoSuchElementException avgt 10 8,882 ± 0,028 ms/op На исключение требуется практически в 10 раз больше времени, чем на простой объект результата, и в 88000 раз - чем на константу. Да, может показаться, что речь идёт о каких-то миллисекундах и далеко не всегда есть смысл в такой экономии. Но когда речь идёт о крупном проекте, где за какой-то короткий промежуток времени без проблем может прилететь 1000 запросов на получение несуществующих или недоступных данных, эти 8 миллисекунд превратятся уже в 8 секунд процессорного времени. В любом случае, что для объекта-результата, что для исключения потребуется обрабатывающий код, просто в случае с исключениями он будет более привычным, т.к. исключения и их обработка - стандартные элементы языка.
@@shurik_codes недавно смотрел доклад как раз про бросание исключений из Новосибирска от Владимира Ситникова: "Бросить нельзя поймать: основы и детальная механика Java исключений". Там в основном про другое доклад, но при замере он указывал про то, что основная "тяжесть" исключений не в них самих, а в стеке, который можно отключить. Т.е. без стека исключения это ровно те же самые обычные классы, как и Object в Java и в этом смысле они вряд ли будут хоть сколько-то тяжелее, чем класс обертка Result.
Урок супер! Очень информативно. Продолжайте, у вас отличный контент!
Спасибо!
Здорово, ничего подобного не видел. На многих проектах так же использовал Result в связке с ExceptionHandler. А тут такая красота. Привезите нам ещё подобной годноты!
Невероятно интересно!
Нужно больше уроков!)
Спасибо за видео! Интересный пример!
Спасибо за видео, очеь полезно
Не видно код ( используйте presentation mode , пожалуйста
Очень интересное решение, повторял за видео, но один момент остаётся не понятен. Почему бы просто не использовать Optional? И в зависимости есть внутри него что то или нет возвращать нужный нам ResponseEntity (либо ок либо not found)?
Если мы будем возвращать Optional, то как определить, что конкретно пошло не так, чтобы потом транслировать результат не только в Not Found, но и в другие статусы ошибок клиента/сервера?
@@shurik_codes понял! как я понял в видео представлены только 2 исхода (success и CartNotFound), но очень легко добавить еще варианты, в то время как Optional сработал бы в этом примере, но проработать больше вариантов исхода не выйдет. надеюсь правильно вас понял 💯
Что если findCardEntries вернет exception? или null? success с нулем?
В случае возникновения исключения есть два варианта обработки:
1. В первом случае можно на уровне метода сервиса перехватывать исключения в блоке try/catch и возвращать соответствующий результат, содержащий перехваченное исключение. Результат можно потом преобразовывать в ответ со статусом 500 Internal Server Error, а исключение, например, логгировать.
2. Во втором случае игнорировать его на уровне сервиса, но перехватывать на уровне контроллера, ну и дальше действовать соответствующим образом. Исключения на то и исключения, что предусмотреть все возможные варианты развития ситуации не получится даже при большом желании. Я лично придерживаюсь именно такого варианта.
В случае, если возвращается null или success с null, то тут надо смотреть на код и на процесс его написания. Такое возможно только по недосмотру и при полном отсутствии тестов. Если же для проекта нормально написаны тесты или вовсе применяется TDD, то шансы возникновения такой ситуации сводятся к нулю.
@@shurik_codes Благодарю за ответ.
Кажется, что это оверхед в данной ситуации. Попробовал внедрить у себя в одном месте на проекте. Сервис используется в нескольких воркерах и нескольких апи. Возможно несколько причин для ошибок - не найдены метаданные в бд, нет соответствующей записи в obs и т.д. В итоге в каждой точке использования нужно как-то пытаться реагировать на это все. В воркерах удобно сразу упасть с исключением, а в апи в самом коце поймать RuntimeException. Проц бросание исключения нагружает примерно никак
Для простых проектов - да, скорее всего, оверхед. Для серьёзных проектов - вполне годный подход. На мой взгляд исключения нужно рассматривать как инструмент для действительно исключительных ситуаций, возникновение которых невозможно спровоцировать одними лишь действиями пользователя, а следовательно - определить точные условия их возникновения. Примерами таких ситуаций, например, могут быть ошибки, спровоцированные сетевыми сбоями.
Если есть возможность предвидеть ошибки, которые могут возникнуть по вине пользователя (ввод некорректных данных, отсутствие прав доступа, отсутствие запрашиваемых данных и т.д.), то такие ошибки должны быть описаны в виде результатов, примерно как показано в ролике, либо в виде проверяемых исключений. Но у исключений есть недостаток - они не бесплатные, т.к. при создании исключения (даже при создании) собирается полный стек-трейс вызова. Да, сбор стек-трейса можно и отключать, но тогда теряется одна из важнейших функций исключений. Так что "Проц бросание исключения нагружает примерно никак" - заблуждение. Более того, использование формализованных ответов вместо исключений позволяет для некоторых случаев использовать константные ответы, когда не требуется уточняющая информация.
Чтобы не быть голословным, я написал простой бенчмарк с JMH, в котором замерил производительность всех вариантов (AMD Ryzen R9 5950X 4000MHz, Windows 11, Oracle GraalVM JDK 21):
Benchmark Mode Cnt Score Error Units
NotFoundBenchmark.returnNotFoundConstant avgt 10 ≈ 10⁻⁴ ms/op
NotFoundBenchmark.returnAccessDenied avgt 10 0,940 ± 0,003 ms/op
NotFoundBenchmark.throwNoSuchElementException avgt 10 8,882 ± 0,028 ms/op
На исключение требуется практически в 10 раз больше времени, чем на простой объект результата, и в 88000 раз - чем на константу. Да, может показаться, что речь идёт о каких-то миллисекундах и далеко не всегда есть смысл в такой экономии. Но когда речь идёт о крупном проекте, где за какой-то короткий промежуток времени без проблем может прилететь 1000 запросов на получение несуществующих или недоступных данных, эти 8 миллисекунд превратятся уже в 8 секунд процессорного времени.
В любом случае, что для объекта-результата, что для исключения потребуется обрабатывающий код, просто в случае с исключениями он будет более привычным, т.к. исключения и их обработка - стандартные элементы языка.
@@shurik_codes недавно смотрел доклад как раз про бросание исключений из Новосибирска от Владимира Ситникова: "Бросить нельзя поймать: основы и детальная механика Java исключений". Там в основном про другое доклад, но при замере он указывал про то, что основная "тяжесть" исключений не в них самих, а в стеке, который можно отключить. Т.е. без стека исключения это ровно те же самые обычные классы, как и Object в Java и в этом смысле они вряд ли будут хоть сколько-то тяжелее, чем класс обертка Result.