Термин «магический номер» (англ. magic number) широко используется в сообществе разработчиков. Он описывает числовые литералы, которые появляются в коде без поясняющего контекста. Такие значения «магически» появляются в функциях, классах и скриптах, заставляя читающего задуматься: «Что же значит 42?», «Зачем здесь 0x4C554B53BABE?». В этой статье мы разберём, откуда возникло понятие, какие проблемы оно создаёт и какие практики позволяют «снять заклятие» с кода.
Что такое магический номер?
В программировании магическим считается любое числовое значение, которое:
- встроено в код в виде литерала (например,
if (age < 18) …); - не сопровождается поясняющим именем, константой или комментарарием;
- неочевидно, почему именно оно выбрано и каково его назначение.
Согласно Википедии, магическое число имеет три основных значения:
- Уникальные идентификаторы (например, сигнатуры файлов);
- Константы, которые «не должны совпадать» с другими значениями;
- Литералы, смысл которых скрыт от читателя кода.
Почему магические номера считаются плохой практикой?
Существует несколько причин, по которым разработчики стараются избегать магических чисел:
Пониженная читаемость
Код, в котором встречаются «необъяснённые» числа, трудно понять. Например:
if (temperature < -40) {
// … some logic …
}
Без комментария или константы читатель не знает, почему именно -40 считается критическим порогом.
Трудности поддержки
Если значение меняется, его необходимо поправить во всех местах, где оно использовано. Пропуск одного из таких мест может привести к багу.
Ошибки в тестировании
Магические числа часто «засоряют» тесты, делая их менее выразительными. Вместо того, чтобы писать assertEquals(0, result), лучше использовать assertEquals(ExitCode.SUCCESS, result).
Нарушение принципов SOLID
Согласно принципу Single Responsibility Principle, каждый элемент кода должен иметь одну ответственность. Магический номер смешивает логику с «знанием» конкретного значения.
Примеры магических номеров в реальном коде
- Файловые сигнатуры – в Unix‑подобных системах часто ищут «магическое число»
0x4C554B53BABEдля идентификации специфических образов. - Пороговые значения –
if (score > 90) grade = 'A';без пояснения, почему именно 90. - Размеры UI‑элементов –
padding = 12;без указания, что это «стандартный внутренний отступ согласно гайдлайну». - Коды ошибок –
return 13;вместоreturn ERR_INVALID_INPUT;.
Как избавиться от магических номеров?
Существует несколько проверенных техник, позволяющих заменить «загадочные» литералы на понятные конструкции.
Использовать именованные константы
// Плохой вариант
if (age < 18) { … }
// Хороший вариант
const MIN_AGE_FOR_VOTING = 18;
if (age < MIN_AGE_FOR_VOTING) { … }
Перечисления (enum)
Для наборов взаимосвязанных значений удобно применять enum:
enum HttpStatus {
OK = 200,
NOT_FOUND = 404,
INTERNAL_ERROR = 500
}
// Использование
if (response.status === HttpStatus.NOT_FOUND) { … }
Конфигурационные файлы
Если значение может изменяться без перекомпиляции, вынесите его в .json, .yaml или в переменные окружения.
Специальные типы‑обёртки
В некоторых языках (например, Kotlin) можно объявлять typealias или value class, чтобы явно указать смысл числа.
Документировать в комментариях
Если по какой‑то причине нельзя вынести значение в константу, хотя бы добавьте поясняющий комментарий:
// Пороговое значение, определённое бизнес‑правилом «Скорость выше 120 км/ч считается превышением»
if (speed > 120) { … }
Лучшие практики и рекомендации
- Не допускайте «один‑разовых» чисел – если число встречается более одного раза, вынесите его в константу.
- Дайте константе осмысленное имя – имя должно отражать бизнес‑логику, а не тип данных.
- Группируйте связанные константы в отдельные файлы или классы (например,
class HttpStatus). - Используйте статический анализ – инструменты вроде
SonarQube,ESLint(правилоno-magic-numbers) илиPylintавтоматически находят магические числа. - Пишите unit‑тесты – тесты помогут убедиться, что заменив магический номер на константу, поведение программы осталось тем же.
- Обновляйте документацию – если значение меняется, обновляйте как код, так и сопутствующие описания.
Инструменты для обнаружения магических чисел
| Инструмент | Язык | Как работает |
|---|---|---|
| SonarQube | Java, C#, JavaScript, PHP и др. | Анализирует AST и выдаёт правило MagicNumberCheck. |
| ESLint (no-magic-numbers) | JavaScript / TypeScript | Выявляет числовые литералы, не объявленные в константах. |
| Pylint (magic-number) | Python | Отмечает «hard‑coded» числа, если их количество превышает порог. |
| Cppcheck | C / C++ | Ищет «magic numbers» в условных выражениях и инициализациях. |
Магические номера – это не просто «неудобные» детали кода, а потенциальные источники ошибок, снижающие читаемость и усложняющих поддержку проекта. Применяя простые приёмы (константы, перечисления, конфиги) и используя статический анализ, можно «снять заклятие» с любого проекта, сделав его более чистым и понятным.
Помните: читаемый код – это код, который легко поддерживать. А избавление от магических чисел – один из самых быстрых способов повысить качество вашего программного продукта.
Статья составлена на основе открытых источников (Stack Overflow, Хекслет, Википедия) и актуальна на дату .