Свитч — очень простая конструкция, которую изучают программисты в самом начале своего пути. Она ни у кого не вызывает вопросов, но с ней связана одна интересная деталь, которую очень часто упускают из виду и, в итоге, используют свитч неправильно. Это дефолтное поведение.
- Освойте азы современных языков программирования
- Изучите работу с Git и командной строкой
- Выберите себе профессию или улучшите навыки
Представьте, что в приложении у нас есть заказ, который может находиться в определенных состояниях. Например, он может быть оплачен, доставлен, передан в службу доставки и так далее. И где-то есть логика, зависящая от этого состояния:
switch (order.state) {
case 'delivered':
// код
break;
case 'paid':
// код
break;
// Ниже все остальные кейсы
}
По логике приложения, в этом коде задействованы все возможные состояния, и на каждое из них есть свое поведение. При такой постановке switch не содержит дефолтного поведения.
Однако линтер с нами не согласится. Практически во всех языках он начнет ругаться на то, что дефолт не определен. С этого момента есть два пути.
Начнем с неправильного. Программист думает, что линтер ошибается, и либо заглушает его, либо добавляет туда код, который ничего не делает. Например, возвращает null или просто содержит один break
.
Так ли ошибается линтер? Путь, описанный выше, чисто механический. Он не учитывает семантику кода (привет, ментальное программирование) и порождает отложенные проблемы.
Подписывайтесь на канал Кирилла Мокевнина в Telegram — чтобы узнать больше о программировании и профессиональном пути разработчика
Главный вопрос, который нужно задать себе в этом месте: «А в каком случае мы туда действительно попадем?» Таких вариантов несколько: программист ошибся в имени состояния либо добавилось новое состояние, на которое еще нет обработчика. Считаем ли мы такое поведение нормальным? В подавляющем большинстве случаев – нет. Это так называемая ошибка программирования. Если программист ошибся, значит программа работает неверно, и лучшим решением в данной ситуации будет максимально быстрое оповещение о проблеме. Это позволит локализовать проблему и отреагировать сразу, как только она появилась. В противном же случае программа может продолжать вести себя «почти» корректно. Иногда корректно, а иногда нет, и узнаем мы об этом, скорее всего, не сразу и, в худшем случае, от клиентов, когда уже возникнут более серьезные проблемы. То же самое касается добавления нового состояния. Наверняка оно потребует своей собственной обработки.
Перепишем switch с учетом вышесказанного:
switch (order.state) {
case 'delivered':
// код
break;
case 'paid':
// код
break;
// оставшиеся кейсы
default:
throw new Error('Unknown state!');
}
Уже значительно лучше, но все еще недостаточно. Любой код, который связан с ошибками, должен помогать отладке. Код выше этого не делает. Да, мы увидим ошибку сразу, но как мы узнаем, а что там было? Куда смотреть? Какое состояние неверное? Исследования потребуют дополнительного времени. Гораздо лучше помочь себе сразу:
switch (order.state) {
case 'delivered':
// код
break;
case 'paid':
// код
break;
// оставшиеся кейсы
default:
throw new Error(`Unknown order state: '${order.state}'!`);
}
Если кратко, то общее правило такое: если логика кода предполагает поведение по умолчанию, то реализуйте в дефолте необходимую логику, если нет, то это ошибочная ситуация, которую надо обработать, выбросив исключение.
Дополнительные материалы:
- Освойте азы современных языков программирования
- Изучите работу с Git и командной строкой
- Выберите себе профессию или улучшите навыки