Поводження з помилками - якщо програма виходить з ладу або помилково їх ігнорує


20

Я пишу просту маленьку програму для передачі MIDI по мережі. Я знаю, що програма зіткнеться з проблемами передачі та / або іншими винятками, які я не зможу передбачити.

Для обробки винятків я бачу два підходи. Чи потрібно написати програму, щоб вона:

  • не вдається з ударом, коли щось піде не так або
  • чи варто просто ігнорувати помилку і продовжувати, за рахунок цілісності даних?

Якого підходу розумно очікував би користувач?
Чи є кращий спосіб поводження з винятками?

Крім того, чи має впливати на моє рішення про обробку винятків те, чи маю я справу з мережевим підключенням (тобто чимось там, де я можу з розумом очікувати виникнення проблем)?



Чи є спосіб змінити +1? ;) О, чекай, я йду за тобою. Звичайно, зроби :)
Арлен Бейлер

2
"Який підхід може обґрунтовано очікувати користувач?". Ви спробували запитати когось із своїх користувачів? Тестування на корисність передпокою може бути надзвичайно ефективним. Дивіться blog.openhallway.com/?p=146
Брайан Оуклі

У мене немає користувачів :)
Arlen Beiler

Відповіді:


34

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

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


18
Недостатньо, щоб гарантувати -1, але "ніколи" не є сильним словом, і є ситуації, коли ігнорування помилок - це правильний хід дій. Наприклад, програмне забезпечення для декодування широкомовної передачі HDTV. Коли ви стикаєтесь з деякими помилками, які ви часто будете, все, що ви можете зробити, це ігнорувати її та продовжувати розшифровувати те, що з’являється після цього.
whatsisname

1
@whatsisname: правда, але ви повинні чітко документувати, чому ви її ігноруєте. Оновлена ​​відповідь, щоб врахувати ваш коментар.
marco-fiset

1
@ marco-fiset Я не згоден. Збій всієї програми є лише рішенням, якщо це ситуація, коли перезапуск її вирішить проблему. Це не завжди так, тому збої в роботі часто є безглуздим і неприпустимим, що поведінка є просто дурною. Чому ви хочете призупинити всю свою операцію через локалізовану помилку? В цьому немає сенсу. Більшість застосунків це роблять, і, чомусь, програмісти з цим цілком чудово.
MaiaVictor

@Dokkat: справа в тому, щоб не продовжувати неправильних значень, які дадуть неправильне рішення (сміття, сміття). Збій вирішує проблему: він змушує користувача або надавати різні матеріали, або домагатися розробника виправляти свою програму;)
Андре Парамеш

1
@whatsisname Я думаю, ви можете подумати над своїм визначенням "помилки" в цьому випадку. Помилки в отриманих даних - це не те саме, що помилки в структурі та виконанні програмної програми.
joshin4colours

18

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

Річ у тім, що коли накопичуються помилки, з часом ви зіткнетеся з настільки великою помилкою, що не зможете її проігнорувати, оскільки вона буде полягати в тому, що щось буде надано користувачеві, і що щось буде зовсім не так. Потім у вас з’являться скарги користувачів на те, що ваша програма не працює належним чином, і вам доведеться виправити це. І якщо частина "дай щось користувачеві" знаходиться на етапі 28, і ти не маєш уявлення, що початкова помилка, яка спричиняє весь цей безлад, була на кроці 3, оскільки ти ігнорував помилку на кроці 3, у тебе буде чорт часу налагодження проблеми!

З іншого боку, якщо ця помилка на кроці 3 змушує все вибухнути перед обличчям користувача та створити помилку SOMETHING WENT BADLY WRONG IN STEP 3!(або її технічний еквівалент, слід стека), то результат той самий - користувач скаржиться на вас програма не працює належним чином - але на цей раз ви точно знаєте, з чого почати шукати, коли переходите її виправляти .

EDIT: У відповідь на коментарі, якщо щось піде не так, що ви передбачили і знаєте, як впоратися, це інакше. Наприклад, у випадку отримання неправильного повідомлення це не помилка програми; це "користувач надав неправильний вхід, який не вдався до перевірки". Відповідна відповідь полягає в тому, щоб сказати користувачеві, що він дає вам недійсні дані, і це виглядає так, як ви робите. Не потрібно руйнувати та генерувати слід стека у такому випадку.


Як щодо повернення до останнього відомого хорошого становища, або у випадку циклу, що отримує, просто скинути це повідомлення та перейти до наступного.
Арлен Бейлер

@Arlen: Навіть це може бути поганою ідеєю. Помилки трапляються через те, що сталося щось таке, чого ви не передбачили, коли кодували його . Це означає, що всі ваші припущення вийшли за вікно. Ця "остання відома хороша позиція" може вже не бути хорошою, якби ви пройшли на півдорозі змінивши структуру даних, а зараз, наприклад, перебуваєте в непослідовному стані.
Мейсон Вілер

Що робити, якщо я цього очікую, як пошкоджені повідомлення, що запобігають дезаріалізації. У деяких випадках виняток я серіалізував і надсилав назад через провід. Там дивіться мою редакцію питання.
Арлен Бейлер

@Arlen: Якщо ви цього передбачали, і ви впевнені, що знаєте, які наслідки помилки і що вони містяться належним чином, то це інакше. Мені звучить так, як ви обробляєте помилку та відповідаєте відповідним чином, не ігноруючи її. Я говорив про ігнорування несподіваних помилок. Це звучало так, як ви просили.
Мейсон Вілер

16

Є й інші варіанти між "підірвати" та "ігнорувати".

Якщо помилку можна передбачити і уникнути, змініть свій дизайн або рефакторний код, щоб уникнути його.

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

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

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

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

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


1
Найкраща відповідь поки що, на мій погляд.
четверггек

6

Це мої погляди на питання:

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

Після застосування цього принципу ви можете додати код відновлення для конкретних умов помилки, які виникають. Ви також можете ввести кілька "безпечних станів", до яких можна повернутися. Відмова від програми здебільшого безпечна, але іноді ви можете повернутись до іншого відомого хорошого стану. Прикладом є те, як сучасна ОС поводиться з правопорушною програмою. Це вимикає лише програму, а не всю ОС.

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

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

Незалежно від того, чи знаєте ви про випадки відмов, чи не менш важливе значення. Але якщо ви, наприклад, маєте справу з мережевим з'єднанням, для якого відомо певна кількість станів помилок, відкладіть додавання обробки помилок, поки ви також не додасте код відновлення. Це відповідає принципам, викладеним вище.


6

Ніколи не слід мовчки ігнорувати помилки. І особливо не за рахунок цілісності даних .

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

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

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

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


Ви справді мали намір поставити знак питання в кінці першого рядка?
CVn

@ MichaelKjörling: Ні. Помилка копіювання та вставки (скопіювала формулювання з питання і помилково включила знак питання).
Ян Худек

4

Існує один клас випадків, коли ігнорування помилок - це правильно: коли немає нічого, що могло б зробити в ситуації, і коли погані та, можливо, неправильні результати краще, ніж результати.

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


1

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

Що я роблю з внутрішнім програмним забезпеченням, пишу для своєї компанії ...

Це залежить від помилки, скажімо, якщо це критична функція, яка вводить дані в MySQL, вона повинна повідомити користувачеві про те, що вона не вдалася. Обробник помилок повинен спробувати зібрати якомога більше інформації та надати користувачеві уявлення про те, як виправити помилку, щоб вони могли зберегти дані. Мені також подобається мовчки надіслати нам інформацію, яку вони намагаються зберегти, якщо гірше погіршиться, ми можемо ввести її вручну після виправлення помилки.

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

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

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

Якщо помилка пов'язана з мережею - чому б не запропонувати функції виконати простий тест мережевого зв’язку перед виконанням функції, щоб уникнути помилки в першу чергу? Тоді просто попередивши користувача, що з'єднання недоступне, перевірте свій Інтернет і т. Д. І спробуйте ще раз?


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

1

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

Помилки потрібно виправляти якомога швидше, тому підхід « Дизайн за контрактом» є відповідним. У C ++ мені подобається перевіряти всі мої передумови (входи) із твердженнями у верхній частині функції, щоб якнайшвидше виявити помилку та полегшити приєднання налагоджувача та виправити помилку. Якщо розробник або тестер замість цього вирішить спробувати продовжити запуск програми, то втрата цілісності даних стає їх проблемою.

І в першу чергу знайдіть способи запобігання помилок. Будьте суворі з коректністю коректності та вибору типів даних, відповідних для даних, які вони матимуть - це два способи ускладнити створення помилок. Fail-Fast також хороший за межами критичного коду безпеки, який потребує способу відновлення.

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

  1. Введіть помилку.
  2. (Необов’язково) Спроба безшумно повторити або іншим чином відновитися після операції.
  3. Якщо операція продовжує виходити з ладу або не підлягає відновленню, повідомляйте про помилку помітно користувачеві. Потім, як зазначено вище, користувач може вирішити, що робити. Пам’ятайте про Принцип найменшого здивування , оскільки втрата цілісності даних дивує користувача, якщо ви не попередили їх достроково.

0

Невдача - це правильний варіант, коли у вас є підстави вважати, що загальний стан програми нестабільний і може статися щось погане, якщо ви дозволите їй працювати зараз. Дещо «ігноруючи» його (тобто, як зазначали інші, записати його десь або записати повідомлення про помилку користувачеві, а потім продовжувати), це нормально, коли ви знаєте, що, звичайно, поточну операцію виконувати не можна, але програма може продовжуй бігти.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.