Сможете ли вы писать красивый код и при этом обрабатывать ошибки? Однозначно - ДА!
Когда дело доходит до написания красивого кода, одним из ключевых аспектов, которые становятся камнем преткновения на пути его чистоты, является обработка исключений. Именно обработка исключений вносит путаницу и размывает код делая его сложным для чтения и понимания.
Сегодня мы разберем правила и принципы, которых необходимо придерживаться для того, чтобы при обработке исключений читаемость кода не страдала.
Если по какой-то причине вы не применяете в своем коде обработку исключений, то могу вам с уверенностью сказать, что это очень плохая практика.
Обработка исключений позволяет предвидеть и управлять возможными ошибками в программе, что не только помогает избежать вылета программ и непредвиденного поведения, но и способствует созданию более надежного кода.
Поэтому стабильная программа та, которая имеет обработку ошибок в коде. Но цель статьи не научить обрабатывать ошибки в коде, а научить делать это таким образом, чтобы код оставался читаемым.
Проблема
В контексте кода обработка исключений может повлиять на размытие кода. О том, что такое размытие кода мы разбирали в статье и секретах читаемого кода.
Давайте для примера возьмем элементарную задачу, где необходимо получить два целых числа и разделив первое на второе число выдать результат.
Это простой программный код будет выглядеть так:
Я буду приводить примеры на Python, но на остальных языках принцип останется таким же, изменится только синтаксис.
В целом это очень простой код и достаточно понятный.
Мы берем два числа, переводим их командой int в целочисленный тип. Затем делим первое число на второе и выводим результат в консоль.
Но как адекватные программисты мы должны задуматься, а могут ли в этом коде произойти ошибки, которые может вызвать пользователь?
Давайте попробуем протестировать.
Ух ты, а ведь пользователь может попробовать ввести не целое число, и тогда нас выбрасывает из программы с исключением ValueError.
Давайте его обработаем используя конструкцию try .. except.
Можно проверить.
Какие мы молодцы, смогли нашей программе позволить выполниться успешно даже с некорректно введенными данными.
Но никогда нельзя останавливаться. А могут ли еще произойти ошибки? Давайте дальше тестировать.
А вот и еще одна найденная проблема. Ведь на ноль делить нельзя. А вдруг пользователь не помнит этого правила математики и введет это значение? Значит программа сломается, как в примере выше и выдаст исключение, что на ноль делить нельзя ZeroDivisionError.
Как прилежные программисты обрабатываем это исключение.
Проверяем.
Мы молодцы. А может ли быть так, что мы не учли какой-то проблемный момент при тестировании и он может всплыть в результате работы программы? Конечно же да.
Поэтому необходимо написать обработку для остальных исключений.
Мы просто молодцы! Обезопасили наш код от возможных ошибок. Ой, правда посмотри теперь каким он стал.
Легко ли его читать? Видишь какую сильную размытость добавила обработка исключений? Мы теперь бегаем глазами по коду, чтобы вычленить контекст полезного действия и процесс обработки исключений.
Решение
Для начала нужно уйти от структурной парадигмы программирования и перейти к функциям.
Надуюсь вы прочитали предыдущую статью, ссылку на которую давалась выше. Там мы подробно обсуждали, каким образом должна строиться последовательность кода.
Функции должны идти друг за другом по ходу объяснения. Также хочу напомнить правило, что функция должна выполнять лишь одно действие.
Отсюда и начнем. В первую очередь концепцию кода необходимо разделить на две части:
- Обработка ошибок;
- Полезное действие.
Звучит прям, как две отдельные функции:
- Проверка на исключения - checking_for_exceptions();
- Получить результат деления двух чисел - get_the_result_of_dividing_two_numbers().
Теперь распределим наш код в каждую из этих функций. Думаю, что вы понимаете - функция получения результата будет находить в блоке успешного выполнения try.
Теперь при разделении кода на две концепции мы четко видим, что в первой функции код обрабатывает все возможные исключения, которые могут возникнуть в функции получения результата.
Но если вы помните из предыдущей статьи, то код должен читаться по правилу газетной статьи. От общего к частному.
В функции get_the_result_of_dividing_two_numbers это правило нарушается, т.к. там код просто навален кучей.
Разделим код внутри на две функции. Ведь функция использует глагол получить результат. Поэтому остальные детали нужно вывести в другое место.
Вот мы добавили две новые функции и код стал более структурным. Мы теперь можем его четко читать сверху вниз, как газетную статью.
Мало того, работая над чистотой кода мы получили еще один результат. Смотрите:
Теперь обработка ошибки происходит сразу в тот момент, когда пользователь ввел неверное значение.
Это доступно как раз благодаря разделению кода по функциям. Теперь каждое действие проверяется отдельно.
Но вы заметили, что для запуска нам необходимо вызвать функцию checking_for_exceptions. А ведь запускаем процесс деления чисел, а не процесс проверки исключений. Значит нашей газетной статье (коду) не хватает чего, как думаете?
Нам не хватает точного заголовка, который отражает суть нашей газетной статьи (кода). В нашем коде это будет выражаться в видео функции, которая будет находиться сверху. Ведь заголовки появляются первыми в статье, значит и в коде необходимо держать его в самом начале.
Напоминаю, код должен читать строго сверху вниз. Читатель не должен искать функции бегая вверх и вниз теряя внимание. Поэтому следуем этому правилу.
Функцию назовем начать деления целых чисел.
Фактически мы добавили функцию, которая играет роль интерфейса для пользователя. Он просто видит название функции “Начать деление целых чисел” и сразу становится все понятно.
С точки зрения чтения кода, теперь не отвлекаясь ведите глаза сверху вниз и вам откроется следующее повествование статьи, отображу её как отдельный раздел.
Итак, код читающийся, как газетная статья:
Начать деление целых чисел
Для запуска расчета мы должны обезопасить себя проверкой всех возможных ошибок, поэтому начнем с этого.
Если пользователь вдруг введет неверные данные, то перехватим ошибку и выведем соответствующее сообщение.
При условии, что все хорошо, попробуем получить результат деления двух чисел.
В таком случае попросим пользователя их ввести и сразу переведем их в целочисленный тип.
Затем разделим первое введенное число на второе.
Полученный результат выведем в консоль.
Выводы
Помните, каждый ваш файл с кодом должен читаться именно так. Человек, который будет читать ваш код должен понимать все без лишних комментариев. У него не должно возникать дополнительных вопросов.
Пока вы будете придерживаться этого правила, ваш код будет занимать меньше времени для понимания и останется больше времени на работу с ним.
Как только вы начнете игнорировать это правило и просто писать код по правилу “лишь бы работало”, то и стресса в вашей жизни будет много.
Подписывайся, чтобы писать чистый код и следи за этой рубрикой.