Девиации и разветвление личности: как лечить?

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

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

Часть 1: обработка ошибок без ошибок

Уж давно отшумели холивары между консерваторами, возвращающими коды ошибок из функций и модернистами, что смело кидаются эксепшенами. Поэтому не будем заострять на этом внимания – все современные языки программирования умеют метать исключения и отлавливать их. Это позволяет хоть как-то «отделять зерна от плевел», бизнес-логику от обработки ошибочных ситуаций. Но, даже воспользовавшись этим несомненным благом, остается много вопросов: а как же коды ошибок? На свалку истории? Когда кидать исключения? Где ловить? Какие типы исключений нужны? Нужны ли проверяемые исключения на уровне языка?
Давайте попробуем разобраться. Самое простое это так называемы проверяемые исключения – быстрый ответ «в топку». Эксперимент в Java показал, что «овчинка выделки не стоит», загрязнение сигнатуры метода списком возможных исключений, кроме набора лишних букв не приносит никакого ощутимого профита.
Даже безобидное внесение списка возможных исключений в документацию к методу чревато обманом, если в дереве вызовов какой-нибудь нижележащий метод вдруг будет изменен (например, даже в каком-то другом модуле) и начнет кидать новый тип исключения.
В современном C++ рекомендуют только отмечать метод, который никогда не вызывает исключений. Это строгая гарантия подразумевает, что и все вызываемые методы по цепочке не бросают исключений так же.
Многие современные языки отказались от практики проверяемых исключений (например, Kotlin, Scala и пр.) и изначально не включали в дизайн языка их поддержку.
Значит, на каком бы современном языке вы не остановили свой выбор, у вас, скорее всего, будут под рукой непроверяемые исключения (или далее просто исключения) и механизмы их обработки. Это инструмент, осталось понять, как им ловчее пользоваться.
Любые ошибочные ситуации можно условно разделить на две категории: те, которые не должны были случиться, и те, которые могут произойти и должны быть должным образом обработаны.
К первой категории я отношу состояние, при котором входные данные отсутствуют (например, null), не соответствуют ожиданиям (нарушают контракт) или находятся в несогласованном состоянии (противоречат друг другу). Предпринять в этом случае нечто осмысленное сложно, налицо нарушение логики, о которой следует немедленно известить создателя ПО. Назовем эту категорию логические ошибки. Для себя я дополнительно делю их на два подтипа – недопустимый аргумент, переданный в функцию/метод, либо недопустимое состояние данных объекта в целом. Практически в любом языке уже существуют готовые исключения для этих случаев:
С++: std::invalid_argument и std::logic_error
Java: IllegalArgumentException и IllegalStateException
C#: ArgumentException и InvalidOperationException
В С/C++ существует практика покрывать такого рода ошибки ассертами. Считается, что при отладке и тестировании в отладочном варианте всплывут все ошибочные ассерты, будут исправлены, а в продакшене из соображений производительности все проверки удаляются. На мой взгляд, это рискованная идея. Надежное ПО должно контролировать свое состояние как в отладке, так и в релизном варианте. Вопрос лишь насколько параноидальными должны быть эти проверки.
Я считаю, что любой публичный метод класса (т. е. его API для общения с внешним миром) должен проверять корректность переданных ему параметров, причем делать это в первых же строчках кода. Что касается проверки состояния объекта, то его нужно проводить непосредственно перед началом работы с этим состоянием, которое должно отвечать определенным ожиданиям. Например, вызван некий метод, который работает с приватным списком и ожидает, что он не пуст – иначе запускать алгоритм не имеет смысла. Если этот список пуст значит, вероятно, не был вызван другой метод, который заполняет его данными. Эта серьезная ошибка в логике программы, так не должно было быть по замыслу автора. Бросаем исключение ошибочного состояния и пусть там «наверху» разбираются что пошло не так.
Вторая категория ошибок, это скорее возможные варианты развития событий, которые необходимо учитывать. Например, попытка распарсить JSON файл – файл может отсутствовать на диске, быть эксклюзивно открыт другим процессом, внутри может оказаться не JSON, а нечто совсем ужасное и т. д. Все это ошибочные ситуации, но ожидаемые. Качественная библиотека должна предоставить максимум информации о произошедшем. Далее я буду называть эту категорию ошибок доменными.
Де-факто практически любое исключение в большинстве языков программирования будет иметь текстовое поле для идентификации события исключения. Подходит ли это поле для полноценной передачи информации о причине исключения? На мой взгляд нет. Во-первых, потому что это просто текст в свободном формате, а во-вторых, он, скорее всего, даже не будет локализован и не может быть показан пользователю приложения. Наилучшее применение текстового сопровождения исключения, это журнал, который после может быть изучен разработчиками. В случае логических ошибок вполне достаточно будет поместить в текстовое поле имя исходного файла и номер строки, желательно это делать автоматически (см. пример ниже).
Каким же образом передать подробную информацию о сути ошибки? Можно создать иерархию исключений на каждую ситуацию, но, во-первых, это большое количество шаблонного кода, во-вторых, это всегда лень делать

Источник: https://habr.com/ru/post/597271/


Интересные статьи

Интересные статьи

Привет, Хабр!Меня зовут Дмитрий Матлах. Я тимлид в AGIMA. Мы с коллегами обратили внимание, что в сообществе часто возникает вопрос о том, как совместить на одном проекте Bitrix-компоненты и реактивны...
Всем привет! Не так давно на работе в рамках тестирования нового бизнес-процесса мне понадобилась возможность авторизации под разными пользователями. Переход в соответствующий р...
У некоторых бизнес-тренеров в области е-коммерса и консультантов по увеличению интернет-продаж на многие вопросы часто можно слышать универсальную отмазку — «надо тестировать» или другую (чтобы не...
Приветствую вас (лично вас, а не всех кто это читает)! Сегодня мы: Создадим приложение (навык) Алисы с использованием нового (октябрь 2019) сервиса Yandex Cloud Functions. Настроим н...
В Челябинске проходят митапы системных администраторов Sysadminka, и на последнем из них я делал доклад о нашем решении для работы приложений на 1С-Битрикс в Kubernetes. Битрикс, Kubernetes, Сep...