Увага! С ++ програміст, що приходить сюди з можливо різними уявленнями про те, як слід робити обробку винятків, намагаючись відповісти на питання, що, безумовно, стосується іншої мови!
Враховуючи цю ідею:
Наприклад, уявіть, що у нас є ресурс отримання, який виконує HTTP-запит і повертає отримані дані. І замість помилок, таких як ServiceTemporaryUnavailable або RateLimitExceeded, ми просто піднімемо RetryableError, запропонувавши споживачеві, що він повинен просто повторити запит і не піклуватися про конкретний збій.
... Я б хотів би сказати, що ви можете змішати проблеми повідомлення про помилку з курсами дій, щоб відповісти на неї таким чином, що може погіршити загальність вашого коду або вимагати багато "точок перекладу" для винятків .
Наприклад, якщо я моделюю транзакцію, що включає завантаження файлу, вона може вийти з ладу з кількох причин. Можливо, завантаження файлу передбачає завантаження плагіна, якого не існує на машині користувача. Можливо, файл просто пошкоджений, і ми зіткнулися з помилкою при його розборі.
Незалежно від того, що трапиться, скажімо, що курс дій полягає в тому, щоб повідомити про те, що сталося з користувачем, і повідомити його про те, що він хоче з цим зробити ("повторити, завантажити інший файл, скасувати").
Кидок проти Ловець
Цей спосіб дії застосовується незалежно від того, з якою помилкою ми стикалися в цьому випадку. Вона не вбудована в загальну ідею помилки розбору, вона не вбудована в загальну ідею невдачі завантажити плагін. Це вкладено в ідею зустріти подібні помилки під час точного контексту завантаження файлу (поєднання завантаження файлу та відмови). Тому, як правило, я бачу це, грубо кажучи, як catcher'sвідповідальність за визначення ходу дії у відповідь на викинутий виняток (наприклад: спонукання користувача до параметрів), а не thrower's.
Інакше кажучи, сайти, у яких throwвинятки, зазвичай не мають такого роду контекстної інформації, особливо якщо функції, які викидають, є загальноприйнятими. Навіть у цілком виродженому контексті, коли вони мають цю інформацію, ви закінчуєте себе в напрямку відновлення відновлення, вставляючи його на throwсайт. Сайти catch, які зазвичай мають найбільшу кількість доступної інформації для визначення ходу дій, і надають вам одне центральне місце для зміни, якщо цей хід дій колись зміниться для даної транзакції.
Коли ви починаєте намагатися кидати винятки, більше не повідомляючи про те, що не так, але намагаєтеся визначити, що робити, це може погіршити загальність та гнучкість вашого коду. Помилка розбору не завжди повинна призводити до такого типу підказки, вона залежить від контексту, в який викидається такий виняток (транзакція, під яку вона була кинута).
Сліпий кидач
Загалом, багато дизайну винятків, що займаються винятком, часто обертається ідеєю сліпого метателя. Невідомо, як виняток буде схоплений, чи де. Те саме стосується і старих форм відновлення помилок, використовуючи ручне поширення помилок. Сайти, які стикаються з помилками, не включають в себе дії користувача, вони вкладають лише мінімальну інформацію, щоб повідомити, яка помилка виникла.
Перевернута відповідальність та узагальнення видовища
Думаючи про це більш ретельно, я намагався уявити собі тип кодової бази, де це може стати спокусою. Моя уява (можливо, неправильна) полягає в тому, що ваша команда все ще відіграє тут роль "споживача" і також реалізує більшість коду дзвінка. Можливо, у вас є безліч розрізнених транзакцій (безліч tryблоків), які можуть стикатися з однаковими наборами помилок, і все, з точки зору дизайну, повинно призвести до рівномірного курсу дій по відновленню.
Беручи до уваги мудрі поради з Lightness Races in Orbit'sтонкої відповіді (на мою думку, насправді виходить із розширеного мислення, орієнтованого на бібліотеку), ви все ще можете спокуситись кинути винятки "що робити" лише ближче до сайту відновлення транзакцій.
Тут можна знайти посередницький, загальний веб-сайт для обробки транзакцій, який фактично централізує проблеми "що робити", але все ще в контексті лову.

Це застосовується лише в тому випадку, якщо ви можете розробити якусь загальну функцію, яку використовують усі ці зовнішні транзакції (наприклад, функція, яка вводить іншу функцію для виклику або абстрактний базовий клас транзакцій із переборною поведінкою, що моделює цей посередницький сайт транзакцій, який виконує складний вилов. ).
Однак це може бути відповідальним за централізацію ходу дій користувача у відповідь на різноманітні можливі помилки, але все ж у контексті лову, а не кидання. Простий приклад (псевдокод Python-ish, і я не є досвідченим розробником Python в найменшій мірі, так що може бути більш ідіоматичний спосіб робити це):
def general_catcher(task):
try:
task()
except SomeError1:
# do some uniformly-designed recovery stuff here
except SomeError2:
# do some other uniformly-designed recovery stuff here
...
[Сподіваюся, краще ім'я, ніж general_catcher]. У цьому прикладі ви можете передати функцію, яка містить завдання, яке потрібно виконати, але все ж виграє від узагальненої / уніфікованої поведінки вилову для всіх типів винятків, які вас цікавлять, і продовжувати розширювати або змінювати частину "що робити" вам подобається з цього центрального місця та все ще в catchконтексті, коли це зазвичай рекомендується. Найкраще, що ми можемо утримати сайти, які кидають, не стосуватися себе "що робити" (збереження поняття "сліпий метальник").
Якщо ви не знайдете жодної з цих пропозицій тут корисною, і все-таки є сильна спокуса кинути винятки "що робити", головним чином пам’ятайте, що це принаймні дуже антиідіоматично, а також потенційно відштовхує узагальнене мислення.