Comments 19
Если в каком-то месте системы может генериться достаточно большое количество исключений разного типа, то метод может оказаться довольно удобен.
Что-то мне подсказывает, что в представленной реализации, мне придется каким-то образом проверить на валидность класс а уже в самом исключении. И развивая мысль дальше, исключения должны уметь работать с какими-то определенными классами/интерфейсам.
Не слишком ли специфичными будут исключения?
Если они будут специфичными, то значит идет проверка бизнес-логики, а её лучше ее строить не на исключениях все же. Валидация ввода пользователя — тоже как-то сомнительно.
Везде упоминаемая совместимость на уровне интерфейсов в исключениях, выглядит сковывающим фактором. Хотя есть над чем подумать, по крайней мере над самой идей нагрузить исключения какой-либо полезной логикой.
Валидность класс a может проверить только сам класс a.
Для этого у класса a (а также у b, c и других, для которых это необходимо) пишем метод
Вообще, я мыслю catchException как шаблонный метод. Таким образом, исключение знает что нужно сделать, а как — это уже не его забота.
Но вы правы, исключения получаются довольно специфичными. Да и сам метод явно не из тех, которые следует применять везде и всюду.
Для этого у класса a (а также у b, c и других, для которых это необходимо) пишем метод
validate()
, но вместо того чтобы вызывать его непосредственно в блоке catch
, мы передаем в метод catchException
нашего исключения $this
и вызываем validate
оттуда. Это гарантирует нам, что мы не забудем сделать нужные проверки.Вообще, я мыслю catchException как шаблонный метод. Таким образом, исключение знает что нужно сделать, а как — это уже не его забота.
Но вы правы, исключения получаются довольно специфичными. Да и сам метод явно не из тех, которые следует применять везде и всюду.
Мне кажется, что те исключения, которые Вы описали, нарушают принцип единственной ответственности (SRP из SOLID): помимо описания типа исключительной ситуации, факта её возникновения, условий (innerException + data) и места (stack trace), такой класс ещё инкапсулирует и логику обработки такой ситуации. Чуть лучше было бы, если тип исключения ссылался на объект типа «обработчик соответствующего исключения», но это приводит к своим неудобствам (к целому ряду). В общем, не изящно.
Кстати, слово «cather» («перехватчик») довольно неточно. Вы скорее говорите о «handler'е» («обработчике»).
Кстати, слово «cather» («перехватчик») довольно неточно. Вы скорее говорите о «handler'е» («обработчике»).
Опечатался. «Cather» читать как «catcher».
И да и нет.
Я себе представлял catchException как шаблонный метод. Он инкапсулирует только «что нужно сделать», но не «как это делается». Я, видимо, зря не написал этого в статье.
Я себе представлял catchException как шаблонный метод. Он инкапсулирует только «что нужно сделать», но не «как это делается». Я, видимо, зря не написал этого в статье.
То, что метод catchException инкапсулирует «что нужно сделать» я понял. Я говорю, что сам класс исключения в такой ситуации выполняет две обязанности, что не очень хорошо.
Кстати, такое применение исключений опасно ещё по одной причине. Очень непривычно их использование. Насколько вероятно, что новый разработчик в команде будет и использовать и реализовывать исключения как надо? Мне кажется, новичок легко и непринуждённо, без задней мысли напишет try-catch в обычном стиле.
Кстати, такое применение исключений опасно ещё по одной причине. Очень непривычно их использование. Насколько вероятно, что новый разработчик в команде будет и использовать и реализовывать исключения как надо? Мне кажется, новичок легко и непринуждённо, без задней мысли напишет try-catch в обычном стиле.
Возможно. Этот метод, вообще гововоря, довольно узкого профиля и если воткнуть его «не туда», то проблем не оберёшься. В этом я с выми полностью согласен.
И да, новым разработчикам будет непривычно. С другой стороны, если интерфейс этого дела хорошо документирован и правильно спроектирован (да я знаю, что это утопия, но мечтать не вредно) то ему не придётся разбираться в десятке разных исключений, порождаемых где-то в недрах системы.
Метод, конечно, сырой. Надо будет ещё раз пересмотреть плюсы и минусы.
И да, новым разработчикам будет непривычно. С другой стороны, если интерфейс этого дела хорошо документирован и правильно спроектирован (да я знаю, что это утопия, но мечтать не вредно) то ему не придётся разбираться в десятке разных исключений, порождаемых где-то в недрах системы.
Метод, конечно, сырой. Надо будет ещё раз пересмотреть плюсы и минусы.
Рад, что Вы так восприняли критику. Уверен, Вы неспроста пришли к такой методике, а на то были свои причины. Если решитесь применять подход, буду рад ознакомиться с плюсами и минусами этой практики из жизни. И да, спасибо за статью, «разрыв шаблона» понравился.
Обработка исключений не может быть универсальной по своей сути.
Это может быть логгирование (тут, наверное, единственное место универсальное) может быть повтор метода (без вариантов переноса кода), может быть какая-то логика (и тут круто увеличится зависимость одного класса от другого), может быть сложная логика с делегированием части обработки другому классу (программист который передаст, например, ну не знаю, репозиторий базы конструктор исключения должен быть жестоко наказан).
Из-за неуниверсальности обработки код получится сложнее: тут исключение само себя обрабатывает (чтобы узнать как читайти внутри), тут нет. Представьте себя читающим свой же код через 3 года. Хренпоймёшь и без этого, сложности и без этого достаточно. А тут ещё эта дополнительная сложность на пустом месте.
Это может быть логгирование (тут, наверное, единственное место универсальное) может быть повтор метода (без вариантов переноса кода), может быть какая-то логика (и тут круто увеличится зависимость одного класса от другого), может быть сложная логика с делегированием части обработки другому классу (программист который передаст, например, ну не знаю, репозиторий базы конструктор исключения должен быть жестоко наказан).
Из-за неуниверсальности обработки код получится сложнее: тут исключение само себя обрабатывает (чтобы узнать как читайти внутри), тут нет. Представьте себя читающим свой же код через 3 года. Хренпоймёшь и без этого, сложности и без этого достаточно. А тут ещё эта дополнительная сложность на пустом месте.
Про Single Responsibility сверху уже отметили.
Проблема в том, что только код, который вызывает метод, бросающий исключения, должен знать как его обработать. Иначе вы пытаетесь предусмотреть все варианты вызова вашего метода.
Проблема в том, что только код, который вызывает метод, бросающий исключения, должен знать как его обработать. Иначе вы пытаетесь предусмотреть все варианты вызова вашего метода.
А мне понравилось.
1. «Сразу скажу, что для меня исключение != ошибка...». Я с Вами.
2. Мне пративно, когда вижу три и более catch-конструкции. А здесь увидел простое и изящное средство от своих комплексов.
3. Помоему есть некоторые проблеммы гибкости с типами исключений и перехватом (возможно я и ошибаюсь — будет ястно когда воспользуюсь советом). На 100% они решаемы.
Аналогичным образом я передаю часть ответственности классам аттрибутов. Может поэтому мне не кажется это нарушением SOLID-принципов.
1. «Сразу скажу, что для меня исключение != ошибка...». Я с Вами.
2. Мне пративно, когда вижу три и более catch-конструкции. А здесь увидел простое и изящное средство от своих комплексов.
3. Помоему есть некоторые проблеммы гибкости с типами исключений и перехватом (возможно я и ошибаюсь — будет ястно когда воспользуюсь советом). На 100% они решаемы.
Аналогичным образом я передаю часть ответственности классам аттрибутов. Может поэтому мне не кажется это нарушением SOLID-принципов.
1. Про «исключение != ошибка» и я с вами обоими. :)
2. А вот три вложенных try-catch намекают на потребность в вынесении методов в большинстве случаев.
2. А вот три вложенных try-catch намекают на потребность в вынесении методов в большинстве случаев.
К сожелению «выделение метода» catch-тел не уменьшает количества catch-блоков.
Если логика разная, то это приведет к появлению нескольких функций в носителе метода с try...catch. Из статьи я вынес возможность перености эти методы в соответствующие exception-классы. И вызывать их через полиморфизм.
Если логика разная, то это приведет к появлению нескольких функций в носителе метода с try...catch. Из статьи я вынес возможность перености эти методы в соответствующие exception-классы. И вызывать их через полиморфизм.
> К сожелению «выделение метода» catch-тел не уменьшает количества catch-блоков.
Ну, тут вариантов два. Либо несколько try-catch блоков, разбросанных по «вложенным методам» это норма для конкретного решения. Либо присутствует какая-то ошибка проектирования. Сами по себе многие try-catch блоки, разбросанные по методам это абсолютно не проблема, если эти блоки необходимы для корректной, ожидаемой, предсказуемой работы метода. Это, кстати, идея не моя, взята из «clean code».
А мне, кстати, понравилась нестандартность решения, описанного в статье.
Ну, тут вариантов два. Либо несколько try-catch блоков, разбросанных по «вложенным методам» это норма для конкретного решения. Либо присутствует какая-то ошибка проектирования. Сами по себе многие try-catch блоки, разбросанные по методам это абсолютно не проблема, если эти блоки необходимы для корректной, ожидаемой, предсказуемой работы метода. Это, кстати, идея не моя, взята из «clean code».
А мне, кстати, понравилась нестандартность решения, описанного в статье.
Я понял, что вам тоже понравилось. За предыдущее высказывание хотел поставить плюс. Но у меня принцип — не оценивать непосредственного собеседника :). Разговаривая с вами, стараюсь понять все грани обсуждаемой идеи.
Несколько try..catch блоков. Получается что-то типа цепочки обязаностей. Вариант. Но по архитектурной сложности это почти тоже самое (по одному методу на catch). Вопрос стоит только в расположении методов.
Я понимаю, что try..catch..catch… — в конкретном месте необходим. Но ощущение дублирования от этого не уменьшается. Понимание необходимости притупляет желание исправить, но код не улучшает.
Кстати. Больше половины моих исключений выглядит так:
До меня сейчас дошло — он же ленив. Вот, что значит новый взгляд на знакомые вещи.
Несколько try..catch блоков. Получается что-то типа цепочки обязаностей. Вариант. Но по архитектурной сложности это почти тоже самое (по одному методу на catch). Вопрос стоит только в расположении методов.
Я понимаю, что try..catch..catch… — в конкретном месте необходим. Но ощущение дублирования от этого не уменьшается. Понимание необходимости притупляет желание исправить, но код не улучшает.
Кстати. Больше половины моих исключений выглядит так:
class MyException: Exception {}
До меня сейчас дошло — он же ленив. Вот, что значит новый взгляд на знакомые вещи.
Честно говоря, я к исключениям отношусь довольно просто. Исключение это просто ситуация, которую сам метод, возбудающий исключение, не обрабатывает сам, т.к. он не знает как, да и вообще это не его ответственность. Ответственность за обработку ложится на пользователя метода, т.к. «ему виднее». Учитывая это, можно ещё раз рассмотреть вложенные методы с исключениями. Получается, что каждый метод снимает с себя ответственность за одни ситуации и передаёт обработку наверх, там в обработке могут возникнуть свои проблемы. Я считаю, это абсолютно нормально.
Намного более насторожил меня такой код, в котором блоки try вставляются в catch-блоки по нескольку раз. Тут уже стоит задуматься о дизайне.
Что касается простых классов исключений, вида
Намного более насторожил меня такой код, в котором блоки try вставляются в catch-блоки по нескольку раз. Тут уже стоит задуматься о дизайне.
Что касается простых классов исключений, вида
class MyException: Exception {}
, то это тоже хорошо. Наследование классов исключений — занятие чреватое. В мире .NET об угрозах такого кодирования написано в «CLR via C#». В общем, широкий набор классов исключений это хорошо. Главная причина в том, что catch (MyConcreteException ex)
будет известно что обрабатывать. А в случае наличия наследников, всё будет сильно сложнее. Например, может потребоваться писать мерзкие проверки вида if (ex is MyConcreteSpecificException)
…Прикольно. С помощью полиморфизма мы решаем проблему «мерзких проверок».
Говоря о ленивости я имел введу отсутствие членов у класса исключения. А значит он имеет хороший потенциал по их принятию (в результате «переноса метода») от других классов.
Говоря о ленивости я имел введу отсутствие членов у класса исключения. А значит он имеет хороший потенциал по их принятию (в результате «переноса метода») от других классов.
Sign up to leave a comment.
Умные эксепшены