Что такое магические числа в программировании и как снять это заклятие

Магические числа — пример плохих практик в программировании. Из этой статьи вы узнаете, почему от них надо избавляться и как это делать.
- Что такое магические числа
- Как избавиться от магических чисел
Что такое магические числа
В программировании магическими называют числа в коде, смысл которых сложно понять. Взгляните на пример.
// показываем пользователю окончательную цену товара const showBruttoPrice = (nettoPrice) => const bruttoPrice = nettoPrice * 1.20; return bruttoPrice; >;
Это пример магического числа, потому что невозможно однозначно ответить на вопрос, почему для вычисления bruttoPrice нужно умножить nettoPrice на 1.20 . Смысл числа 1.20 приходится восстанавливать по контексту. Но при работе с большими приложениями в реальной разработке это не всегда возможно.
Магические числа не ломают код. В примере выше пользователь увидит окончательную цену, то есть программа отработает. В чём же проблема?
Код с магическими числами сложно понять без контекста. Это может стать проблемой для разработчиков, которые впервые видят приложение. Да и автор кода может забыть, почему использовал именно это число.
Как избавиться от магических чисел
Это можно сделать с помощью константы с понятным названием. То есть название константы должно передавать смысл числа.
// указываем ставку НДС const vatRate = 1.20; const showBruttoPrice = (nettoPrice) => const bruttoPrice = nettoPrice * vatRate; return bruttoPrice; >;
Очевидное указание ставки НДС делает код более понятным.
Код с магическими числами сложно поддерживать и расширять. Например, если магазин продаёт товары людям из разных стран, магические числа приводят к дублированию:
// в разных странах разные ставки НДС const showBruttoPrice = (nettoPrice, country) => let bruttoPrice; if (country === 'Russia') bruttoPrice = nettoPrice * 1.20; > if (country === 'Germany') bruttoPrice = nettoPrice * 1.19; > // стран может быть 5, 20 или 50 // для каждой придётся использовать // своё магическое число // . return bruttoPrice; >;
Проблему решает избавление от магических чисел:
const getVatRate = (country) => // получаем ставку НДС для конкретной страны из // базы данных или из внешнего источника >; const showBruttoPrice = (nettoPrice, country) => // определяем ставку НДС вместо того, // чтобы указывать её с помощью магических чисел const vatRate = getVatRate(country); // определяем окончательную цену const bruttoPrice = nettoPrice * vatRate; return bruttoPrice; >;
- Магические числа — плохая практика в программировании
- Обычно магические числа не ломают код, а делают его менее понятным
- Чтобы избавиться от магических чисел, достаточно использовать константы или переменные с понятными названиями
Python: Магические числа
Возьмем пример программы, которая считает курс валют:
euros_count = 1000 dollars_count = euros_count * 1.25 # 1250.0 rubles_count = dollars_count * 60 # 75000.0 print(rubles_count)
С точки зрения профессиональной разработки, такой код не соответствует «лучшим практикам» — best practices.
В этом примере сложно понять, что значат числа 60 и 1.25 . Представьте, что вам придется разбираться в этом коде через месяц или через год — это будет сложно. Также сложно будет программисту, который не видел код ранее.
В нашем примере контекст легко восстановить, потому что переменные названы грамотно. Но в реальных проектах код значительно сложнее, поэтому догадаться до смысла чисел зачастую невозможно.
Проблема кроется в «магических числах» — magic numbers. Это числа, происхождение которых невозможно понять с первого взгляда — приходится глубоко вникать в то, что происходит в коде.
Чтобы предотвратить проблему, нужно создавать переменные с правильными именами. Так все встанет на свои места:
dollars_per_euro = 1.25 rubles_per_dollar = 60 euros_count = 1000 dollars_count = euros_count * dollars_per_euro # 1250.0 rubles_count = dollars_count * rubles_per_dollar # 75000.0 print(rubles_count)
В этой программе:
- Используется именование snake_case
- Две новые переменные отделяются от последующих вычислений пустой строчкой. Эти переменные имеют смысл и без вычислений, поэтому такое отделение уместно, потому что повышает читаемость
- Получился хорошо именованный и структурированный код, но он длиннее прошлой версии. Так часто бывает — это нормально, ведь код должен быть читабельным
Магические числа и непонятные именования переменных не ломают код, но делают его менее читабельным.
Нужно понимать, что компьютер в любом случае выполнит заданное вычисление. Однако другой программист будет читать код и ничего не поймет — это усложнит работу. Правильное именование переменных — половина успеха анализа кода.
Задание
Вы столкнулись с таким кодом, который выводит на экран общее количество комнат во владении нынешнего короля:
king = "Rooms in King Balon's Castle:" print(king) print(6 * 17)
Как видите, это магические числа: непонятно, что такое 6 и что такое 17. Можно догадаться, если знать историю королевской семьи: каждый новый король получает в наследство все замки от предков и строит новый замок — точную копию родительского.
Эта странная династия просто плодит одинаковые замки…
Избавьтесь от магических чисел, создав новые переменные, а затем выведите текст на экран.
Rooms in King Balon's Castle: 102
Названия переменных должны передавать смысл чисел, но должны при этом оставаться достаточно короткими и ёмкими для комфортного чтения.
Помните: код будет работать с любыми названиями, а наша система всегда проверяет только результат на экране, поэтому выполнение этого задания — под вашу ответственность.
Упражнение не проходит проверку — что делать?
Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:
- Обязательно приложите вывод тестов, без него практически невозможно понять что не так, даже если вы покажете свой код. Программисты плохо исполняют код в голове, но по полученной ошибке почти всегда понятно, куда смотреть.
В моей среде код работает, а здесь нет
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Мой код отличается от решения учителя
Это нормально , в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.
В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Прочитал урок — ничего не понятно
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.
Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.
Полезное
Замена магического числа символьной константой
В коде используется число, которое несёт какой-то определённый смысл.
Решение
Замените это число константой с человеко-читаемым названием, объясняющим смысл этого числа.
double potentialEnergy(double mass, double height)
static final double GRAVITATIONAL_CONSTANT = 9.81; double potentialEnergy(double mass, double height)
double PotentialEnergy(double mass, double height)
const double GRAVITATIONAL_CONSTANT = 9.81; double PotentialEnergy(double mass, double height)
function potentialEnergy($mass, $height)
define(«GRAVITATIONAL_CONSTANT», 9.81); function potentialEnergy($mass, $height)
def potentialEnergy(mass, height): return mass * height * 9.81
GRAVITATIONAL_CONSTANT = 9.81 def potentialEnergy(mass, height): return mass * height * GRAVITATIONAL_CONSTANT
potentialEnergy(mass: number, height: number): number
static const GRAVITATIONAL_CONSTANT = 9.81; potentialEnergy(mass: number, height: number): number
Причины рефакторинга
Магические числа — это числовые значения, встречающиеся в коде, но при этом неочевидно, что они означают. Данный антипаттерн затрудняет понимание программы и усложняет её рефакторинг.
Дополнительные сложности возникают, когда нужно поменять определённое магическое число. Это нельзя сделать автозаменой, так как одно и то же число может использоваться для разных целей, а значит, вам нужно будет проверять каждый участок кода, где используется это число.
Достоинства
- Символьная константа может служить живой документацией смысла значения, которое в ней хранится.
- Значение константы намного проще заменить, чем искать нужное число по всему коду, при этом рискуя заменить такое же число, которое в данном конкретном случае использовалось для других целей.
- Убирает дублирование использования числа или строки по всему коду. Это особенно актуально, если значение является сложным и длинным (например, -14159 , 0xCAFEBABE ).
Полезные факты
Не все числа являются магическими.
Если предназначения чисел очевидны, их не надо заменять константами, классический пример:
for (i = 0; i
Альтернативы
- Иногда, магическое число можно заменить вызовом метода. Например, если у вас есть магическое число, обозначающее количество элементов коллекции, вам не обязательно использовать его для проверок последнего элемента коллекции. Вместо этого можно использовать встроенный метод получения длины коллекции.
- Магические числа могут быть использованы для реализации кодирования типа. Например, у вас есть два типа пользователей, и чтобы обозначить их, у вас есть числовое поле в классе, в котором для администраторов хранится число 1 , а для простых пользователей — число 2 . В этом случае имеет смысл использовать один из рефакторингов избавления от кодирования типа:
- замена кодирования типа классом
- замена кодирования типа подклассами
- замена кодирования типа состоянием/стратегией
Порядок рефакторинга
- Объявите константу и присвойте ей значение магического числа.
- Найдите все упоминания магического числа.
- Для всех найденных чисел проверьте, согласуется ли это магическое число с предназначением константы. Если да, замените его вашей константой. Эта проверка важна, так как одно и тоже число может означать совершенно разные вещи (в этом случае, они должны быть заменены разными константами).
Устали читать?
Сбегайте за подушкой, у нас тут контента на 7 часов чтения.
Или попробуйте наш интерактивный курс. Он гораздо более интересный, чем банальный текст.

Скидки!
Этот рефакторинг — малая часть интерактивного онлайн курса по рефакторингу.


- Премиум контент
- Книга о паттернах
- Курс по рефакторингу
- Рефакторинг
- Введение в рефакторинг
- Чистый код
- Технический долг
- Когда рефакторить
- Как рефакторить
- Каталог
- Запахи кода
- Раздувальщики
- Длинный метод
- Большой класс
- Одержимость элементарными типами
- Длинный список параметров
- Группы данных
- Нарушители объектно-ориентированного дизайна
- Операторы switch
- Временное поле
- Отказ от наследства
- Альтернативные классы с разными интерфейсами
- Утяжелители изменений
- Расходящиеся модификации
- Стрельба дробью
- Параллельные иерархии наследования
- Замусориватели
- Комментарии
- Дублирование кода
- Ленивый класс
- Класс данных
- Мёртвый код
- Теоретическая общность
- Опутыватели связями
- Завистливые функции
- Неуместная близость
- Цепочка вызовов
- Посредник
- Остальные запахи
- Неполнота библиотечного класса
- Раздувальщики
- Техники
- Составление методов
- Извлечение метода
- Встраивание метода
- Извлечение переменной
- Встраивание переменной
- Замена переменной вызовом метода
- Расщепление переменной
- Удаление присваиваний параметрам
- Замена метода объектом методов
- Замена алгоритма
- Перемещение функций между объектами
- Перемещение метода
- Перемещение поля
- Извлечение класса
- Встраивание класса
- Сокрытие делегирования
- Удаление посредника
- Введение внешнего метода
- Введение локального расширения
- Организация данных
- Самоинкапсуляция поля
- Замена простого поля объектом
- Замена значения ссылкой
- Замена ссылки значением
- Замена поля-массива объектом
- Дублирование видимых данных
- Замена однонаправленной связи двунаправленной
- Замена двунаправленной связи однонаправленной
- Замена магического числа символьной константой
- Инкапсуляция поля
- Инкапсуляция коллекции
- Замена кодирования типа классом
- Замена кодирования типа подклассами
- Замена кодирования типа состоянием/стратегией
- Замена подкласса полями
- Упрощение условных выражений
- Разбиение условного оператора
- Объединение условных операторов
- Объединение дублирующихся фрагментов в условных операторах
- Удаление управляющего флага
- Замена вложенных условных операторов граничным оператором
- Замена условного оператора полиморфизмом
- Введение Null-объекта
- Введение проверки утверждения
- Упрощение вызовов методов
- Переименование метода
- Добавление параметра
- Удаление параметра
- Разделение запроса и модификатора
- Параметризация метода
- Замена параметра набором специализированных методов
- Передача всего объекта
- Замена параметра вызовом метода
- Замена параметров объектом
- Удаление сеттера
- Сокрытие метода
- Замена конструктора фабричным методом
- Замена кода ошибки исключением
- Замена исключения проверкой условия
- Решение задач обобщения
- Подъём поля
- Подъём метода
- Подъём тела конструктора
- Спуск метода
- Спуск поля
- Извлечение подкласса
- Извлечение суперкласса
- Извлечение интерфейса
- Свёртывание иерархии
- Создание шаблонного метода
- Замена наследования делегированием
- Замена делегирования наследованием
- Составление методов
- Введение в рефакторинг
- Паттерны
- Введение в паттерны
- Что такое Паттерн?
- История паттернов
- Зачем знать паттерны?
- Критика паттернов
- Классификация паттернов
- Каталог
- Порождающие
- Фабричный метод
- Абстрактная фабрика
- Строитель
- Прототип
- Одиночка
- Структурные
- Адаптер
- Мост
- Компоновщик
- Декоратор
- Фасад
- Легковес
- Заместитель
- Поведенческие
- Цепочка обязанностей
- Команда
- Итератор
- Посредник
- Снимок
- Наблюдатель
- Состояние
- Стратегия
- Шаблонный метод
- Посетитель
- Примеры кода
- C#
- C++
- Go
- Java
- PHP
- Python
- Ruby
- Rust
- Swift
- TypeScript
- Введение в паттерны
What are magic numbers and why do some consider them bad?
You would avoid magic numbers cause other people viewing your code might not understand why you’re doing what you’re doing. e.g. const myNum = 22; const number = myNum / 11; right now my 11 could be people or bottles of beer or something so instead I would change 11 to a constant such as inhabitants.
– user6913790
Sep 17, 2019 at 11:03
Using magic numbers in attributes is unavoidable, so I guess this is appropriate.
Oct 23, 2019 at 12:31
15 Answers 15
A magic number is a direct usage of a number in the code.
For example, if you have (in Java):
public class Foo < public void setPassword(String password) < // don't do this if (password.length() >7) < throw new InvalidArgumentException("password"); >> >
This should be refactored to:
public class Foo < public static final int MAX_PASSWORD_SIZE = 7; public void setPassword(String password) < if (password.length() >MAX_PASSWORD_SIZE) < throw new InvalidArgumentException("password"); >> >
It improves readability of the code and it’s easier to maintain. Imagine the case where I set the size of the password field in the GUI. If I use a magic number, whenever the max size changes, I have to change in two code locations. If I forget one, this will lead to inconsistencies.
The JDK is full of examples like in Integer , Character and Math classes.
PS: Static analysis tools like FindBugs and PMD detects the use of magic numbers in your code and suggests the refactoring.
11.7k 8 8 gold badges 65 65 silver badges 89 89 bronze badges
answered Sep 6, 2008 at 22:46
Marcio Aguiar Marcio Aguiar
14.3k 6 6 gold badges 39 39 silver badges 42 42 bronze badges
0 and 1 are exceptions to this rule.
Apr 7, 2009 at 23:35
@Jonathan Parker, except when they’re not ( TRUE / FALSE )
Jun 2, 2010 at 3:11
Just because a magic number will never change doesn’t mean it shouldn’t be replaced by a constant. My code is full of global constants like HzPerMHz and msecPerSecond. These will never change, but they make the meaning clearer, and provide some protection against typos.
Jun 3, 2010 at 23:33
. It is essential to get in the habit of defining constants to give meaning to otherwise «arbitrary» numbers, even in trivial methods, where it seems obvious. Why? Because in the future, that method may get added to. What at first seemed obvious, is now somewhere within many lines of code. As for being spaghettish, AFAIK all decent modern IDEs make it trivial to find the value of a constant variable. Usually can just hover over any use of the variable. And even back in the day, when we didn’t have such niceties, it was very, very worth it, in the long run.
Sep 29, 2014 at 0:26
@Sergey «What about things like: connection.setTimeout(50); Should 50 be a constant here? It seems to be pretty clear, that 50 is a connection timeout» — It’s a magic number regardless of a single or multiple call. Why 50? Why not 51? You may need to change it because you’re deploying to an environment which requires different timeouts. I’d much rather change a constant than hunt through code.
– user585968
Apr 9, 2015 at 9:47
A Magic Number is a hard-coded value that may change at a later stage, but that can be therefore hard to update.
For example, let’s say you have a Page that displays the last 50 Orders in a «Your Orders» Overview Page. 50 is the Magic Number here, because it’s not set through standard or convention, it’s a number that you made up for reasons outlined in the spec.
Now, what you do is you have the 50 in different places — your SQL script ( SELECT TOP 50 * FROM orders ), your Website (Your Last 50 Orders), your order login ( for (i = 0; i < 50; i++) ) and possibly many other places.
Now, what happens when someone decides to change 50 to 25? or 75? or 153? You now have to replace the 50 in all the places, and you are very likely to miss it. Find/Replace may not work, because 50 may be used for other things, and blindly replacing 50 with 25 can have some other bad side effects (i.e. your Session.Timeout = 50 call, which is also set to 25 and users start reporting too frequent timeouts).
That’s why it’s best to have such ambiguous and arbitrary numbers in exactly 1 place — » const int NumOrdersToDisplay = 50 «, because that makes the code more readable (» if a < NumOrdersToDisplay ", it also means you only need to change it in 1 well defined place.
Places where Magic Numbers are appropriate is everything that is defined through a standard, i.e. SmtpClient.DefaultPort = 25 or TCPPacketSize = whatever (not sure if that is standardized). Also, everything only defined within 1 function might be acceptable, but that depends on Context.
2,126 1 1 gold badge 17 17 silver badges 27 27 bronze badges
answered Sep 6, 2008 at 22:31
Michael Stum Michael Stum
178k 117 117 gold badges 401 401 silver badges 535 535 bronze badges
Even if it can’t change it’s still a bad idea because it’s not clear what’s going on.
Jun 2, 2010 at 3:41
It’s not always unclear. SmtpClient.DefaultPort = 25 is possibly clearer than SmtpClient.DefaultPort = DEFAULT_SMTP_PORT .
Nov 9, 2014 at 10:53
@immibis I suppose that is assuming that there is absolutely no other code that uses the concept of DEFAULT_SMTP_PORT. If the default SMTP port for that application is changed, then it would need to be updated in multiple places causing the possibility of inconsistency.
Apr 1, 2015 at 15:47
It’s also harder to find all usages — you’d have to search for 25 all over the application and make sure you only change the occurrences of 25 that are for the SMTP Port, not the 25’s that are e.g. the width of a table column or the number of records to show on a page.
Apr 1, 2015 at 19:57
In that example, I’d expect the code to use SmtpClient.DefaultPort, not 25. So you’d just have to change it in one place. And the port number is likely to remain the same, it’s not a random magic number, but a number assigned by IANA .
Jun 8, 2015 at 6:59
Have you taken a look at the Wikipedia entry for magic number?
It goes into a bit of detail about all of the ways the magic number reference is made. Here’s a quote about magic number as a bad programming practice
The term magic number also refers to the bad programming practice of using numbers directly in source code without explanation. In most cases this makes programs harder to read, understand, and maintain. Although most guides make an exception for the numbers zero and one, it is a good idea to define all other numbers in code as named constants.
13.4k 12 12 gold badges 43 43 silver badges 54 54 bronze badges
answered Sep 6, 2008 at 22:29
1,156 1 1 gold badge 16 16 silver badges 23 23 bronze badges
Magic Number Vs. Symbolic Constant: When to replace?
Magic: Unknown semantic
Symbolic Constant -> Provides both correct semantic and correct context for use
Semantic: The meaning or purpose of a thing.
«Create a constant, name it after the meaning, and replace the number with it.» — Martin Fowler
First, magic numbers are not just numbers. Any basic value can be «magic». Basic values are manifest entities such as integers, reals, doubles, floats, dates, strings, booleans, characters, and so on. The issue is not the data type, but the «magic» aspect of the value as it appears in our code text.
What do we mean by «magic»? To be precise: By «magic», we intend to point to the semantics (meaning or purpose) of the value in the context of our code; that it is unknown, unknowable, unclear, or confusing. This is the notion of «magic». A basic value is not magic when its semantic meaning or purpose-of-being-there is quickly and easily known, clear, and understood (not confusing) from the surround context without special helper words (e.g. symbolic constant).
Therefore, we identify magic numbers by measuring the ability of a code reader to know, be clear, and understand the meaning and purpose of a basic value from its surrounding context. The less known, less clear, and more confused the reader is, the more «magic» the basic value is.
Basics
We have two scenarios for our magic basic values. Only the second is of primary importance for programmers and code:
- A lone basic value (e.g. number) from which its meaning is unknown, unknowable, unclear or confusing.
- A basic value (e.g. number) in context, but its meaning remains unknown, unknowable, unclear or confusing.
An overarching dependency of «magic» is how the lone basic value (e.g. number) has no commonly known semantic (like Pi), but has a locally known semantic (e.g. your program), which is not entirely clear from context or could be abused in good or bad context(s).
The semantics of most programming languages will not allow us to use lone basic values, except (perhaps) as data (i.e. tables of data). When we encounter «magic numbers», we generally do so in a context. Therefore, the answer to
«Do I replace this magic number with a symbolic constant?»
«How quickly can you assess and understand the semantic meaning of the number (its purpose for being there) in its context?»
Kind of Magic, but not quite
With this thought in mind, we can quickly see how a number like Pi (3.14159) is not a «magic number» when placed in proper context (e.g. 2 x 3.14159 x radius or 2Pir). Here, the number 3.14159 is mentally recognized Pi without the symbolic constant identifier.
Still, we generally replace 3.14159 with a symbolic constant identifier like Pi because of the length and complexity of the number. The aspects of length and complexity of Pi (coupled with a need for accuracy) usually means the symbolic identifier or constant is less prone to error. Recognition of «Pi» as a name is a simply a convenient bonus, but is not the primary reason for having the constant.
Meanwhile: Back at the Ranch
Laying aside common constants like Pi, let’s focus primarily on numbers with special meanings, but which those meanings are constrained to the universe of our software system. Such a number might be «2» (as a basic integer value).
If I use the number 2 by itself, my first question might be: What does «2» mean? The meaning of «2» by itself is unknown and unknowable without context, leaving its use unclear and confusing. Even though having just «2» in our software will not happen because of language semantics, we do want to see that «2» by itself carries no special semantics or obvious purpose being alone.
Let’s put our lone «2» in a context of: padding := 2 , where the context is a «GUI Container». In this context the meaning of 2 (as pixels or other graphical unit) offers us a quick guess of its semantics (meaning and purpose). We might stop here and say that 2 is okay in this context and there is nothing else we need to know. However, perhaps in our software universe this is not the whole story. There is more to it, but «padding = 2» as a context cannot reveal it.
Let’s further pretend that 2 as pixel padding in our program is of the «default_padding» variety throughout our system. Therefore, writing the instruction padding = 2 is not good enough. The notion of «default» is not revealed. Only when I write: padding = default_padding as a context and then elsewhere: default_padding = 2 do I fully realize a better and fuller meaning (semantic and purpose) of 2 in our system.
The example above is pretty good because «2» by itself could be anything. Only when we limit the range and domain of understanding to «my program» where 2 is the default_padding in the GUI UX parts of «my program», do we finally make sense of «2» in its proper context. Here «2» is a «magic» number, which is factored out to a symbolic constant default_padding within the context of the GUI UX of «my program» in order to make it use as default_padding quickly understood in the greater context of the enclosing code.
Thus, any basic value, whose meaning (semantic and purpose) cannot be sufficiently and quickly understood is a good candidate for a symbolic constant in the place of the basic value (e.g. magic number).
Going Further
Numbers on a scale might have semantics as well. For example, pretend we are making a D&D game, where we have the notion of a monster. Our monster object has a feature called life_force , which is an integer. The numbers have meanings that are not knowable or clear without words to supply meaning. Thus, we begin by arbitrarily saying:
- full_life_force: INTEGER = 10 — Very alive (and unhurt)
- minimum_life_force: INTEGER = 1 — Barely alive (very hurt)
- dead: INTEGER = 0 — Dead
- undead: INTEGER = -1 — Min undead (almost dead)
- zombie: INTEGER = -10 — Max undead (very undead)
From the symbolic constants above, we start to get a mental picture of the aliveness, deadness, and «undeadness» (and possible ramifications or consequences) for our monsters in our D&D game. Without these words (symbolic constants), we are left with just the numbers ranging from -10 .. 10 . Just the range without the words leaves us in a place of possibly great confusion and potentially with errors in our game if different parts of the game have dependencies on what that range of numbers means to various operations like attack_elves or seek_magic_healing_potion .
Therefore, when searching for and considering replacement of «magic numbers» we want to ask very purpose-filled questions about the numbers within the context of our software and even how the numbers interact semantically with each other.
Conclusion
Let’s review what questions we ought to ask:
You might have a magic number if .
- Can the basic value have a special meaning or purpose in your softwares universe?
- Can the special meaning or purpose likely be unknown, unknowable, unclear, or confusing, even in its proper context?
- Can a proper basic value be improperly used with bad consequences in the wrong context?
- Can an improper basic value be properly used with bad consequences in the right context?
- Does the basic value have a semantic or purpose relationships with other basic values in specific contexts?
- Can a basic value exist in more than one place in our code with different semantics in each, thereby causing our reader a confusion?
Examine stand-alone manifest constant basic values in your code text. Ask each question slowly and thoughtfully about each instance of such a value. Consider the strength of your answer. Many times, the answer is not black and white, but has shades of misunderstood meaning and purpose, speed of learning, and speed of comprehension. There is also a need to see how it connects to the software machine around it.
In the end, the answer to replacement is answer the measure (in your mind) of the strength or weakness of the reader to make the connection (e.g. «get it»). The more quickly they understand meaning and purpose, the less «magic» you have.
CONCLUSION: Replace basic values with symbolic constants only when the magic is large enough to cause difficult to detect bugs arising from confusions.