Как научить обработку исключений для новых программистов? [закрыто]

21

Как вы относитесь к обучению обработки исключений для программистов. Все остальные вещи учат легко - структуры данных, ASP.NET, WinForms, WPF, WCF - вы называете это, все можно легко научить.

С обработкой исключений, обучение их try-catch-finally является просто синтаксической природой обработки исключений.

Однако чему следует учить: какую часть кода вы помещаете в блок try ? Что вы делаете в блоке catch ?

Позвольте мне проиллюстрировать это на примере.

Вы работаете над Windows Forms Project (небольшой утилитой) и разработали его, как показано ниже, с 3 различными проектами.

  1. UILayer
  2. BusinessLayer
  3. DataLayer

Если в DataLayer возникает исключение (скажем, загрузка XDocument вызывает исключение) (UILayer вызывает BusinessLayer, который, в свою очередь, вызывает DataLayer), вы просто делаете следующее

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

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

Это то, что вы делаете с обработкой исключений?

Kanini
источник
15
Если вы были собираетесь сделать это, вы не хотите , чтобы поймать (Exception ех) {броска ех; } - вместо этого просто поймать {throw; }
Стивен Эверс
4
Не забудем наконец о блоках?
Крис
1
Вы должны указать язык в тегах. Вы получаете больше деталей, чем обычно для большинства реализаций исключений, и игнорируете вещи вне блоков. Например, в C ++ наиболее важной частью обработки исключений является знание того, как писать безопасные для исключений программы.
Дэвид Торнли
Надеюсь, вы знаете, что ловить любое «исключение» - плохая идея. Вы должны иметь вложенные блоки catch, чтобы перехватывать определенные исключения и обрабатывать их соответствующим образом (а не просто генерировать исключение).
минус семь

Ответы:

29

Чтобы объяснить обработку исключений, объясните концепцию, лежащую в основе этого: код, где часто происходит ошибка, не знает, как правильно обрабатывать эту ошибку. Код, который знает, как правильно его обрабатывать, может быть функцией, которая вызвала его, или может быть дальше по стеку вызовов.

Когда вы пишете подпрограмму, которая вызывает подпрограмму, которая может вызвать исключение, если вы знаете, как правильно обрабатывать эту ошибку, поместите вызов в блок try и поместите код обработки ошибок в блок catch. Если нет, оставьте это в покое и позвольте чему-то выше вас в стеке вызовов обработать ошибку.

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

Мейсон Уилер
источник
4
+1 за "... поскольку он на самом деле ничего не обрабатывает", люди, плохо знакомые с обработкой исключений, часто думают, что перехватывать означает обработку, и не понимают, что если вы что-то не делаете для устранения проблемы, это не обработка исключений, просто раздувать код.
Джимми Хоффа
13

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

Итог: демонстрация того, как обработка ошибок была сделана в C, поможет студентам понять, для чего действительно нужны исключения и почему перехват исключений, которые вы не можете реально обработать, в основном имитирует то, как все происходило в темные века.

dsimcha
источник
2
+1 за преподавательскую практику: приведите их к традиционным кодам возврата в стиле C и кодам ошибок и покажите им, что это работает плохо, и, следовательно, научить их, как это будет работать, просто великолепно!
Канини
3
@ Канини: В общем, я думаю, что большинство сравнительно новых / высокоуровневых конструкций кажутся решениями в поиске проблем и их легко использовать неправильно, если вы не понимаете, какую проблему они должны были решить и почему они были изобретены.
дсимча
Я согласен с тем, что показывать, как это будет сделано без исключений, хорошо, но потом возникает бремя объяснения, когда использовать исключения, а когда использовать другую технику (поскольку не все ситуации исключительны)
Матье М.
@Matthieu: Верно. Но если вы понимаете, какие исторические проблемы должны решать исключения, а не узнавать о них в вакууме, становится более очевидным, что глупо использовать их в неисключительных ситуациях.
дсимча
правильно, вот почему вы получили мой +1. Я просто чувствовал, что ваш ответ можно интерпретировать как «никогда не используйте другой механизм» :)
Матье М.
5

Я бы начал с краткого руководства по проектированию исключений, которое включает в себя DO, NOT и AVOID. Это также дает причины почему.

В вашем примере, раздел revelvent будет Wrapping Исключения

И ожидал, что это будет написано так. Обратите внимание, что он перехватывает конкретное исключение и пытается добавить информацию для распространения более значимого сообщения. Также обратите внимание, что внутреннее исключение все еще сохраняется для целей регистрации

//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");

Не пытайся, не лови.

Лично я чувствую, что если ваш уровень данных не может сделать что-то полезное, например, использовать стандартный файл systems.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-> модели-> file_io

Человек, являющийся читателем файла, должен сообщить следующему ....

Сначала сделайте это с кодами возврата. (использовать заметки?)

если взаимодействия - это просто «то, что написано в коде», то очень скоро вы можете заставить людей понять, что исключения являются исключительными.

для кодов возврата передайте сообщение об этом.

за исключением, поднимите руки вверх и скажите, в чем проблема.

затем заставьте их выполнить команду «поймать х, выбросить х» и увидеть, что гораздо хуже диагноз - это то, что GUI просто получает: «модель имела исключение»

Я думаю, что это будет работать для обучения ваших людей, потому что люди очень хорошо понимают взаимодействие с другими людьми.

Тим Виллискрофт
источник
+1 за идею ролевых игр. Мы никогда не думали об этом раньше. Кто бы мог подумать, что обучение программированию можно осуществить через ролевую игру?
Канини
1

Я хотел бы представить себе, чтобы понять исключения, которые вы должны сначала понять, например, отношения ребенка с родителем классов. Если вы понимаете, что ребенок может наследовать функциональность от родителя, он может на начальном уровне понять, что, если у ребенка есть проблема, с которой он не может справиться, он передаст эту проблему (исключение) своему родителю и разрешит родительской операции с этим.

Это становится цепным отношением, пока вы не получите место, где что-то знает, как обрабатывать исключение.

И что касается, наконец, это тривиальная часть ... когда возникает проблема, что-то должно с ней справиться, чтобы программа не заканчивала работу фатально, после того, как это исключение было обработано, там есть блок finally, который всегда будет выполняться независимо от попытки catch ,

Хороший пример этого может быть с сетью:

  • мы устанавливаем связь
  • соединение в порядке, поэтому мы используем его
  • когда закончим мы закрываем и освобождаем ресурсы

или в исключительном случае:

  • установить связь
  • происходит исключение, которое что-то обрабатывает
  • в этот момент мы освобождаем связь и ресурсы, связанные
Крис
источник
1

Подайте заявку новичку с очень хорошей обработкой исключений. Создайте какое-нибудь исключение и дайте им отладить его с помощью журналов. Отслеживая распространение исключения, они должны быть в состоянии отладить его. Сделайте это упражнение 3 или 4 раза. Теперь просто удалите всю обработку Exception из кода и позвольте им попытаться отследить одно и то же исключение.

Я верю, что оценка кода обработки исключений будет сразу оценена.

Компьютерщик
источник
Похоже на план. У вас есть пример кода, доступного в Интернете (например, sourceforge.net), который вы бы порекомендовали?
Канини
0

ИМО, вы должны думать, что операторы обработки исключений и управления потоками в основном совпадают. Вы используете их для управления потоком ваших программ в зависимости от того, в каком состоянии они находятся. Разница в том, что обработка исключений будет реагировать только при возникновении ошибки (или исключения).


источник
@denny: Хотя я согласен с тем, что «обработка исключений будет реагировать только при возникновении ошибки (или исключения)», я совершенно не уверен в утверждении, что «операторы обработки исключений и управления потоком в основном совпадают». Я с уважением не согласен там. Блок catch по общему признанию делает то, что должен делать в этих условиях. Блок try, однако, совсем не относится к потоку или управлению. Блок finally, опять же, совсем не о потоке или контроле. Может быть, я неправильно понял ваш ответ, но не могли бы вы уточнить в интересах меня и других?
Канини
0

Возможно, это не поможет новому программисту, но я обнаружил, что понял концепцию исключений намного лучше, когда начал использовать монады в функциональном программировании. Монада вынуждает вас рассматривать каждый «канал», через который данные могут перемещаться в программу или из нее, поскольку все, что она делает, обеспечивает удобную абстракцию, чтобы «скрыть» часть этого потока данных.

Идея о том, что функция может иметь различные типы выходных данных, а исключение похоже на более высокий приоритет возврата из функции, довольно опрятна.

Имейте в виду, я понимаю, что не так, как исключения работают в большинстве языков (детали реализации), но в абстрактном смысле, это то, что происходит.

CodexArcanum
источник
0

Притворись, что обезьяна использует клавиатуру

Я обычно говорил моим парням, когда они пишут код, притворяясь, что обезьяна будет сидеть за клавиатурой и использовать это приложение.

Это научило их, как предвидеть все виды вещей:

  • Отсутствуют данные
  • Недостающие файлы
  • Альфа-символы, когда вы ожидаете цифры
  • Деление на ноль

Я думаю, что слово «обезьяна», которая просто стучала по клавишам и делала все, что ей хотелось, вместо того, чтобы хорошо следовать за этим, добилось цели. Это сработало для меня.

Майкл Райли - AKA Gunny
источник
Monkeys? Я полагаю, ваши бизнес-пользователи никогда не слышали об этом ;-)
Kanini
@ Канини - Хорошо. Это было в дни моей морской пехоты. Я просто хотел, чтобы мои ребята мыслили нестандартно, когда дело доходит до ловушки ошибок. Я только что сказал, перехват ошибок ... Я имел в виду обработку исключений.
Майкл Райли - AKA Gunny