Autumn SALE

Замена магического числа символьной константой

Также известен как: Replace Magic Number with Symbolic Constant

Проблема

В коде используется число, которое несёт какой-то определённый смысл.

Решение

Замените это число константой с человеко-читаемым названием, объясняющим смысл этого числа.

До
double potentialEnergy(double mass, double height) {
  return mass * height * 9.81;
}
После
static final double GRAVITATIONAL_CONSTANT = 9.81;

double potentialEnergy(double mass, double height) {
  return mass * height * GRAVITATIONAL_CONSTANT;
}
До
double PotentialEnergy(double mass, double height) 
{
  return mass * height * 9.81;
}
После
const double GRAVITATIONAL_CONSTANT = 9.81;

double PotentialEnergy(double mass, double height) 
{
  return mass * height * GRAVITATIONAL_CONSTANT;
}
До
function potentialEnergy($mass, $height) {
  return $mass * $height * 9.81;
}
После
define("GRAVITATIONAL_CONSTANT", 9.81);

function potentialEnergy($mass, $height) {
  return $mass * $height * GRAVITATIONAL_CONSTANT;
}
До
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 {
  return mass * height * 9.81;
}
После
static const GRAVITATIONAL_CONSTANT = 9.81;

potentialEnergy(mass: number, height: number): number {
  return mass * height * GRAVITATIONAL_CONSTANT;
}

Причины рефакторинга

Магические числа — это числовые значения, встречающиеся в коде, но при этом неочевидно, что они означают. Данный антипаттерн затрудняет понимание программы и усложняет её рефакторинг.

Дополнительные сложности возникают, когда нужно поменять определённое магическое число. Это нельзя сделать автозаменой, так как одно и то же число может использоваться для разных целей, а значит, вам нужно будет проверять каждый участок кода, где используется это число.

Достоинства

  • Символьная константа может служить живой документацией смысла значения, которое в ней хранится.

  • Значение константы намного проще заменить, чем искать нужное число по всему коду, при этом рискуя заменить такое же число, которое в данном конкретном случае использовалось для других целей.

  • Убирает дублирование использования числа или строки по всему коду. Это особенно актуально, если значение является сложным и длинным (например, -14159, 0xCAFEBABE).

Полезные факты

Не все числа являются магическими.

Если предназначения чисел очевидны, их не надо заменять константами, классический пример:

for (i = 0; i < сount; i++) { ... }

Альтернативы

  1. Иногда, магическое число можно заменить вызовом метода. Например, если у вас есть магическое число, обозначающее количество элементов коллекции, вам не обязательно использовать его для проверок последнего элемента коллекции. Вместо этого можно использовать встроенный метод получения длины коллекции.

  2. Магические числа могут быть использованы для реализации кодирования типа. Например, у вас есть два типа пользователей, и чтобы обозначить их, у вас есть числовое поле в классе, в котором для администраторов хранится число 1, а для простых пользователей — число 2.

    В этом случае имеет смысл использовать один из рефакторингов избавления от кодирования типа:

Порядок рефакторинга

  1. Объявите константу и присвойте ей значение магического числа.

  2. Найдите все упоминания магического числа.

  3. Для всех найденных чисел проверьте, согласуется ли это магическое число с предназначением константы. Если да, замените его вашей константой. Эта проверка важна, так как одно и тоже число может означать совершенно разные вещи (в этом случае, они должны быть заменены разными константами).