Почему использование магических чисел (Magic Numbers) в коде — это плохой тон и чем их заменить?
Магические числа (Magic Numbers) — это числовые литералы, которые встречаются прямо в коде без какого-либо объяснения их смысла. Например, строка `if (status == 3)` или `timeout = 86400` не говорит читателю ровным счётом ничего о том, что означает «3» или «86400». Это и есть магические числа, и их использование считается плохим тоном по целому ряду причин.
**Почему магические числа — это проблема?**
1. **Снижение читаемости.** Когда другой разработчик (или вы сами спустя несколько месяцев) видит в коде число `42`, он не понимает, что оно означает. Это требует дополнительного времени на изучение контекста, комментариев или документации.
2. **Сложность сопровождения.** Если одно и то же магическое число встречается в 15 местах кода, и его нужно изменить, придётся найти и заменить все вхождения вручную. Пропустить одно — значит получить трудноуловимый баг.
3. **Высокий риск ошибок.** Числа легко перепутать. `0` и `1`, `100` и `1000` — опечатка в одном символе может привести к критической ошибке, которую крайне сложно отловить.
4. **Нарушение принципа DRY (Don’t Repeat Yourself).** Одно и то же значение дублируется в нескольких местах, что противоречит базовым принципам чистого кода.
5. **Затруднение тестирования и рефакторинга.** Магические числа делают код хрупким: любое изменение логики требует «охоты» по всему проекту.
**Чем заменить магические числа?**
— **Именованные константы.** Самый простой и распространённый способ. Вместо `86400` пишем `const int SECONDS_IN_DAY = 86400;`. Теперь смысл числа очевиден.
— **Перечисления (Enum).** Если число представляет одно из нескольких состояний, лучше использовать enum. Вместо `if (status == 3)` — `if (status == UserStatus.BLOCKED)`. Это делает код самодокументируемым.
— **Конфигурационные файлы.** Значения, которые могут меняться в зависимости от среды (таймауты, лимиты, адреса), лучше выносить в конфиги или переменные окружения.
— **Параметры функций.** Если число специфично для конкретного вызова, передавайте его как аргумент с говорящим именем параметра.
— **Комментарии (в крайнем случае).** Если константу создать невозможно, хотя бы объясните значение числа в комментарии рядом с ним.
**Пример до и после:**
Плохо:
python
if user.role == 2:
send_email(user, 7)
Хорошо:
python
ADMIN_ROLE = 2
DAYS_UNTIL_EXPIRY = 7
if user.role == ADMIN_ROLE:
send_email(user, DAYS_UNTIL_EXPIRY)
Итог: замена магических чисел именованными константами и перечислениями — это не просто стилистическое требование, а фундаментальная практика написания поддерживаемого, читаемого и надёжного кода. Это один из первых шагов на пути к профессиональному программированию.
