Як навчити поводженню з винятками для нових програмістів? [зачинено]


21

Як ви навчаєтеся обробці винятків програмістам. Усі інші речі викладаються легко - Структури даних, ASP.NET, WinForms, WPF, WCF - це ви називаєте, все можна легко навчити.

Завдяки обробці винятків, навчити їх пробувати-нарешті - це лише синтаксичний характер обробки винятків.

Що слід вчити, але це - Яку частину коду ви вводите у блок спробу ? Що ви робите в блоці улову ?

Дозвольте проілюструвати це на прикладі.

Ви працюєте над проектом Windows Forms (невелика утиліта) і розробили його, як показано нижче, з трьома різними проектами.

  1. UILayer
  2. BusinessLayer
  3. DataLayer

Якщо виняток (скажімо, для завантаження XDocument кидає виняток) порушено в DataLayer (UILayer викликає BusinessLayer, який по черзі викликає DataLayer), ви просто зробите наступне

//In DataLayer
try {
    XDocument xd_XmlDocument = XDocument.Load("systems.xml");
} 
catch(Exception ex)
{
    throw ex;
}

який знову кидається в BusinessLayer і який потрапляє в UILayer, де я записую його у файл журналу?

Це так, як ви говорите про обробку винятків?


15
Якщо ви були збираєтеся зробити це, ви не хочете , щоб зловити (Exception ех) {кидка ех; } - замість цього просто зловити {кинути; }
Стівен Еверс

4
Не забудемо остаточно блокувати?
Кріс

1
Ви повинні вказати мову в тегах. Ви розглядаєте детальніше, ніж це стосується більшості реалізацій винятків, і ігноруєте речі поза блоками. Наприклад, у C ++, найважливіша частина обробки винятків - це вміння писати програми, безпечні для винятку.
Девід Торнлі


Я сподіваюся, ви знаєте, що погана ідея зловити будь-який "Виняток". Ви повинні мати вкладені блоки спіймання, щоб ловити конкретні винятки та обробляти їх відповідно (а не просто викидати винятки).
мінусСівень

Відповіді:


29

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

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

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


4
+1 для "... оскільки він насправді нічого не справляється", люди, що не знаходяться в обробці винятків, так часто думають, що вибирати кошти, і не розуміють, якщо ви не зробите щось для усунення проблеми, це не виняток, просто роздуття коду.
Джиммі Хоффа

13

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

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


2
+1 за викладацьку практику вводити їх у традиційні стилі повернення кодів та номерів помилок та показувати їм, що він працює погано, а тому навчити їх, як це працювати, - це геніально!
Каніні

3
@Kanini: Взагалі, я думаю, що більшість нових / високорівневих конструкцій здаються рішеннями в пошуку проблем і їх легко використовувати неправильно, якщо ви не розумієте, яку проблему вони мали вирішити і чому вони були винайдені.
dimimcha

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

@Matthieu: Правильно. Але якщо ви розумієте, які історичні проблеми мають на меті вирішити винятки, а не дізнаватися про них у вакуумі, стає очевиднішим, що дурно використовувати їх у не виняткових ситуаціях.
dimimcha

правильно, тому ти отримав мій +1. Я просто відчував, що вашу відповідь можна інтерпретувати як "ніколи не використовуйте іншого механізму" :)
Матьє М.

5

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

У вашому прикладі випадком розділ, який сподобається, буде обгортанням винятків

І сподівався б, що це буде написано так. Зауважте, що він ловить конкретний виняток і намагається додати інформацію, щоб поширити більш змістовне повідомлення. Також зауважте, що внутрішній виняток все ще зберігається для ведення журналу

//In DataLayer

try
{
XDocument xd_XmlDocument = XDocument.Load("systems.xml");
}
catch(FileNotFoundException ex)
{
        throw new TransactionFileMissingException(
                     "Cannot Access System Information",ex);
}

ОНОВЛЕННЯ Каніні запитує, чи правильним є цей блок виключень у рівні даних даних або чи слід перевіряти файл, доступний для бізнес-рівня.

Ну, спершу я хотів би зазначити, що обґрунтування винятку є виключенням

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

Тож якщо ви вважаєте, що у вас є більш високий рівень, ви повинні взагалі знати про файл, тоді ваш рівень даних повинен виглядати так

//In DataLayer

XDocument xd_XmlDocument = XDocument.Load("systems.xml");

Не намагайся не ловити.

Особисто я відчуваю, що якщо ваш рівень даних не може зробити щось корисне, як, наприклад, використовувати систему default.xml, що є ресурсом збирання, нічого не роблячи або обговорюючи виняток, це хороша ставка, оскільки ваш журнал підкаже, який метод і який файл був проблемою. ( throw exу цьому випадку або кращий також throwробить, але значення не додає). Це означає, що виявивши проблему, ви зможете швидко виправити проблему.

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

  • ArgumentNullException
  • SecurityException
  • FileNotFoundException
  • UriFormatException

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

 if (File.Exists("systems.xml")) 
     XDocument.Load("systems.xml");

SecurityException ще гірше, тому що серед інших причин цього викидається, якщо інший процес захоплення має ексклюзивне блокування файлів, ви не отримаєте помилку, доки не спробуєте відкрити її для читання, оскільки немає методу File.CanIOpenThis (). І якщо такий метод існував, у вас все ще є та сама проблема, що і з File.Exists


Виправлення: Спасибі! Але чи правильним є цей блок виключень у рівні даних? Чи слід перевірити, чи файл доступний чи не є у бізнес-шарі? Інакше я погоджуюся з вашим методом написання коду.
Каніні

Виправлення: моєю рідною мовою Каніні означає комп’ютер, тоді як Кані - фрукт ;-)
Каніні

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

1
Виправлення: засмучений? Зовсім ні. Багато в чому розважав. Мій брат не переставав сміятися, оскільки я вказував на це перш за все тому, що я ні в якому разі не схожий на плід, за винятком, можливо, на дивну форму ...
Каніні

4

Давайте робити рольові ігри. (це не жарт)

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

Використовуйте дійсно просту проблему, як-от файл IO. gui-> model-> file_io

Людина, яка є читачем файлів, повинна сказати наступному…

Спочатку зробіть це з кодами повернення. (використовувати пост-це примітки?)

якщо взаємодія - це лише "те, що говорить код", досить скоро люди можуть зрозуміти, що винятки є винятковими.

для повернення кодів, передайте повідомлення про неї.

за винятком, киньте руки в повітря і скажіть, в чому проблема.

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

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


+1 для ідеї рольової гри. Ми ніколи про це не думали. Хто б міг подумати, що викладання програмування можна зробити за допомогою рольової гри?
Каніні

1

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

Це стає ланцюговим відношенням, поки ви не знайдете місця, де щось знає, як поводитися з винятком.

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

Хорошим прикладом цього може бути мережа:

  • ми робимо зв’язок
  • зв’язок нормальний, тому ми його використовуємо
  • по завершенні ми закриваємо і звільняємо ресурси

або у винятку:

  • встановити зв’язок
  • відбувається виняток, який щось обробляє
  • в який момент ми звільняємо зв’язок і пов’язані ресурси

1

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

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


Схоже на план. Чи є в Інтернеті доступний зразок коду (скажімо, sourceforge.net), який ви б рекомендували?
Каніні

0

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


@denny: Хоча я погоджуюся з тим, що "обробка виключень реагує лише тоді, коли станеться помилка (або виняток)", я зовсім не впевнений у твердженні, що "операції з обробкою винятків та контролем потоку в основному однакові". Я з повагою не згоден. Блок вилову, безумовно, робить те, що повинен робити за цієї умови. Проте блок спроб зовсім не стосується потоку чи контролю. Нарешті блок, знову ж таки, зовсім не стосується потоку чи контролю. Можливо, я неправильно зрозумів вашу відповідь, але чи можете ви уточнити на користь мені та іншим?
Каніні

0

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

Думка про те, що функція може мати різні типи виводу, і виняток - це як тип вищого пріоритету повернення з функції, досить акуратний.

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


0

Прикиньтесь, що мавпа використовує клавіатуру

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

Це навчило їх передбачати всі речі:

  • Відсутні дані
  • Файли відсутні
  • Альфа-символи, коли ви очікуєте числа
  • Ділення на нуль

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


Мавпи? Я думаю, що користувачі вашого бізнесу ніколи цього не чули ;-)
Каніні

@Kanini - Гарний. Це було в мої дні морської піхоти. Я просто хотів, щоб мої хлопці думали нестандартно, коли справа доходила до пастки помилок. Я щойно сказав, що відловлює помилку ... Я мав на увазі обробку виключень.
Майкл Райлі - AKA Gunny
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.