Що таке «велика кількість» винятків, які можна застосувати для моєї бібліотеки?


20

Мені завжди було цікаво, скільки різних класів виключень я повинен реалізовувати та кидати для різних частин свого програмного забезпечення. Моя конкретна розробка зазвичай пов'язана з C ++ / C # / Java, але я вважаю, що це питання для всіх мов.

Я хочу зрозуміти, що таке велика кількість різних винятків, які можна викинути, і що очікує спільнота розробників від хорошої бібліотеки.

Я бачу компроміси:

  • Більше класів винятків може дозволяти дуже точним рівнем обробки помилок для користувачів API (схильних до конфігурації користувача чи помилок даних або файлів не знайдено)
  • Більш класи класів винятків дозволяють вбувати у виняток інформацію, пов’язану з помилками, а не просто рядкове повідомлення або код помилки
  • Більше класів винятків може означати більше обслуговування коду
  • Більше класів винятків може означати, що API менш доступний для користувачів

Сценарії, в яких я хочу зрозуміти використання виключень, включають:

  • Під час етапу "налаштування", який може включати завантаження файлів або параметрів налаштування
  • Під час фази «операції» введіть, де бібліотека може виконувати завдання та виконувати якусь роботу, можливо, в іншому потоці

Інші моделі звітування про помилки без використання винятків або менших винятків (як порівняння) можуть включати:

  • Менше винятків, але вбудований код помилки, який можна використовувати як пошук
  • Повернення кодів помилок та прапорів безпосередньо з функцій (іноді неможливо з потоків)
  • Реалізовано систему подій чи зворотних дзвінків після помилки (уникає розмотування стека)

Як розробників, що ви віддаєте перевагу бачити?

Якщо є МНОГО винятків, чи не турбуєте ви помилки, обробляючи їх окремо?

Чи маєте ви перевагу типи обробки помилок залежно від етапу роботи?


1
можливо , пов'язані з : programmers.stackexchange.com/questions/3713 / ...
Fuzz

5
"API менш доступний для користувачів" - з ним можна вирішувати наявність декількох класів виключень, які успадковують від загального базового класу для API. Тоді, як тільки ви почнете роботу, ви можете побачити, з якого API виняток вийшов, не турбуючись про всі деталі. До того моменту, коли ви завершуєте свою першу програму за допомогою API, тоді, якщо вам потрібна додаткова інформація про помилку, тоді ви починаєте дивитися, що означають різні винятки. Звичайно, ви одночасно повинні чудово грати зі стандартною ієрархією виключень мови, якою ви користуєтесь.
Стів Джессоп

відповідна точка Стіва
Fuzz

Відповіді:


18

Я тримаю це просто.

Бібліотека має тип базового винятку, розширений від std ::: runtime_error (це з C ++ застосовується у відповідних випадках до інших мов). Цей виняток займає рядок повідомлення, щоб ми могли увійти; кожна точка кидка має унікальне повідомлення (як правило, з унікальним ідентифікатором).

Ось про це.

Примітка 1 : У ситуаціях, коли хтось, хто виловлює виняток, може виправити винятки та повторно розпочати дію. Я додам похідні винятки для речей, які потенційно можна однозначно виправити у віддаленому місці. Але це дуже рідко (Пам'ятайте, що ловець навряд чи буде близьким до точки кидка, тому виправити проблему буде важко (але все залежить від ситуації)).

Примітка 2 : Іноді бібліотека настільки проста, що не варто давати її власним винятком і виконуватиме std :: runtime_error. Важливо мати виключення лише в тому випадку, якщо можливість відрізнити його від std :: runtime_error може дати користувачеві достатньо інформації, щоб зробити щось з ним.

Примітка 3 : У межах класу я, як правило, віддаю перевагу кодам помилок (але вони ніколи не вийдуть через загальнодоступний API мого класу).

Дивлячись на ваші торгові операції

Я бачу компроміси:

Більше класів винятків може дозволяти дуже точним рівнем обробки помилок для користувачів API (схильних до конфігурації користувача чи помилок даних або файлів не знайдено)

Чи справді більше винятків дають точніший контроль над зерном? Постає питання, чи може дійсний код виправити помилку на основі винятку. Я впевнений, що є такі ситуації, і в цих випадках у вас повинен бути інший виняток. Але всі винятки, які ви перерахували вище, єдине корисне виправлення - це генерувати велике попередження та зупиняти програму.

Більш класи класів винятків дозволяють вбувати у виняток інформацію, пов’язану з помилками, а не просто рядкове повідомлення або код помилки

Це чудова причина для використання винятків. Але інформація повинна бути корисною людині, яка її кешує. Чи можуть вони використовувати інформацію для виконання деяких коригуючих дій? Якщо об'єкт є внутрішньою для вашої бібліотеки і не може бути використаний для впливу на будь-який API, то інформація є марною. Вам потрібно бути дуже конкретним, що викинута інформація має корисне значення для людини, яка може її вловити. Особа, яка її ловить, зазвичай знаходиться поза вашим загальнодоступним API, тому адаптуйте вашу інформацію, щоб вона могла використовуватися з речами у вашому загальнодоступному API.

Якщо все, що вони можуть зробити, це ввімкнути виняток, то краще просто викинути повідомлення про помилку, а не багато даних. Оскільки видовище зазвичай будує повідомлення про помилку з даними. Якщо ви будуєте повідомлення про помилку, то воно буде узгоджено для всіх виловлювачів, якщо ви дозволите ловець створити повідомлення про помилку, ви могли б отримати одну і ту ж помилку, повідомлену по-різному, залежно від того, хто дзвонить і ловить.

Менше винятків, але вбудований код помилки, який можна використовувати як пошук

Ви повинні визначити погоду, код помилки може бути змістовно використаний. Якщо це можливо, у вас повинен бути власний виняток. Інакше вашим користувачам тепер потрібно впроваджувати оператори перемикання всередині улову (що перемагає всю точку автоматичного оброблення улову).

Якщо він не може, то чому б не використати повідомлення про помилку за винятком (немає необхідності розділяти код і повідомлення, це болить шукати).

Повернення кодів помилок та прапорів безпосередньо з функцій (іноді неможливо з потоків)

Повернення кодів помилок є чудовим зсередини. Це дозволяє виправляти помилки там і потім, і ви повинні переконатися, що ви виправите всі коди помилок і врахуйте їх. Але витікати їх через ваш загальнодоступний API - погана ідея. Проблема полягає в тому, що програмісти часто забувають перевіряти стан помилок (принаймні, за винятком, неперевірена помилка змусить програму вийти з необробленої помилки, як правило, пошкодить усі ваші дані).

Реалізовано систему подій чи зворотних дзвінків після помилки (уникає розмотування стека)

Цей метод часто використовується спільно з іншими механізмами поводження з помилками (не як альтернатива). Подумайте про свою програму Windows. Користувач ініціює дію, вибравши пункт меню. Це генерує дію в черзі подій. Черга подій врешті-решт призначає потік для обробки дії. Нитка повинна керувати дією і врешті повернутися до пулу потоків і чекати іншого завдання. Тут виняток має бути зачеплений за основу ниткою із завданням. Результат вилучення виключення, як правило, призводить до події, що генерується для основного циклу, що в кінцевому підсумку призведе до відображення повідомлення про помилку користувачеві.

Але якщо ви не можете продовжувати перед винятком, стек буде розмотуватися (як мінімум, для потоку).


+1; Tho "В іншому випадку вашим користувачам зараз потрібно реалізувати заяви переключення всередині там catch (що перемагає всю точку автоматичного оброблення речей)." - Розмотування стека викликів (якщо ви все ще можете ним користуватися) та вимушене поводження з помилками - все ще великі переваги. Але це, безумовно, призведе до погіршення можливості розмотування стека викликів, коли вам доведеться ловити його посередині і знову відкидати.
Мерлін Морган-Грехем

9

Я зазвичай починаю з:

  1. Клас виключення для помилок аргументів . Наприклад, "аргумент не дозволено бути нульовим", "аргумент повинен бути позитивним" тощо. Java та C # мають попередньо визначені класи для них; в C ++ я зазвичай створюю лише один клас, похідний від std :: виключення.
  2. Клас винятку для помилок з попереднім умовою . Це для більш складних тестів, наприклад "індекс повинен бути меншим за розмір".
  3. Виняток класу для тверджень про помилки . Вони призначені для перевірки стану на відповідність методів на півдорозі. Наприклад, під час ітерації над списком для підрахунку елементів, які є негативними, нульовими або позитивними, наприкінці ці три мають додати розмір.
  4. Один базовий клас виключень для самої бібліотеки. Спочатку просто кинь цей клас. Тільки коли виникне потреба, починайте додавати підкласи.
  5. Я вважаю за краще не обробляти винятки, але знаю, що думки з цього приводу різняться (і дуже корелюються з мовою, що використовується). Якщо ви робите обгортку, вам знадобляться додаткові класи виключень із загортання .

Оскільки класи для перших 3 випадків є налагоджувальними засобами, вони не призначені для обробки кодом. Натомість їх повинен спіймати лише обробник верхнього рівня, який відображає інформацію таким чином, що користувач може скопіювати та вставити її розробнику (а ще краще: натиснути кнопку "надіслати звіт"). Тому включайте інформацію, корисну для розробника: файл, функцію, номер рядка та повідомлення, яке чітко визначає, яка перевірка не вдалася.

Оскільки перші 3 випадки однакові для кожного проекту, в C ++ я зазвичай просто копіюю їх з попереднього проекту. Оскільки багато хто робить саме те, дизайнери C # і Java додали стандартні класи для цих випадків до стандартної бібліотеки. [ОНОВЛЕННЯ:] Для ледачих програмістів: одного класу може бути достатньо, і, маючи певну удачу, ваша стандартна бібліотека вже має відповідний клас виключень. Я вважаю за краще додавати інформацію, як-от ім’я файлу та кількість ліній, які класи за замовчуванням у C ++ не передбачені. [Закінчити оновлення]

Залежно від бібліотеки, четвертий випадок може мати лише один клас, або може стати корисним заняттям. Я вважаю за краще спритний підхід починати з простого, додаючи підкласи, коли виникає потреба.

Детальну аргументацію щодо мого четвертого випадку дивіться у відповіді Локі Астарі . Я повністю згоден з його детальною відповіддю.


+1; Існує певна різниця між тим, як слід писати винятки для запису у віршах з рамками, як слід писати винятки в програмі. Відмінність трохи нечітка, але ви це згадуєте (відкладаючи Локі для випадку бібліотеки).
Мерлін Морган-Грехем
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.