Привет, дорогой читатель, меня зовут Ксавье Жувено, и в этой статье мы поговорим о магических числах. Этот пост был вдохновлен правилом из четвертой главы Code Craft Пита Гудлиффа Защитное программирование.

Что такое Магическое число?

Магическое число — это необработанное число в коде. Это так просто. Но что случилось с этими необработанными числами, спросите вы? Что ж, давайте поговорим о них!

Представьте, что вы столкнулись с таким кодом:

auto result = function(3);
if(result == 42) {
  otherFunction(3);
  return 42;
}
return -1;

Что означают цифры этого кода? Являются ли два «42» одной и той же информацией? Является ли параметр otherfunction 3, потому что function также принимает 3 в качестве параметра? При возврате -1 это код ошибки или что-то еще?

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

Еще одна проблема с таким числом может возникнуть при рефакторинге вашего кода. Представьте, что 42 представляет собой код ошибки, и теперь это правильный результат (поскольку это Ответ на главный вопрос жизни, Вселенной и всего остального 😉), и вам нужно изменить его на 43.

Во всей вашей кодовой базе у вас есть 42, и ваша задача состоит в том, чтобы изменить правильный на 43, но оставить 42, где они не должны быть, изменены в 43. Этот пример может звучать немного глупо, но рефакторинг такого рода случается, и, если вы не подготовитесь, он будет стоить вам большого количества времени, энергии и денег.

Как работать с магическими числами?

Первое, что нужно сделать, это назвать все. Под этим я подразумеваю хранение всех ваших чисел в хорошо названных переменных. Для этого я рекомендую вам прочитать эту статью о Силе именования.

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

Более того, логика вашего кода будет намного понятнее, так как вы сможете узнать разницу между магическим числом, когда они не представляют одно и то же. Давайте изменим предыдущий пример кода и назовем магические числа:

const auto param = 3;
const auto result_if_success = 42;
const auto result_if_error = -1;
const auto answer_to_the_ultimate_question_of_life_the_universe_and_everything = 42;
auto result = function(param);
if(result == answer_to_the_ultimate_question_of_life_the_universe_and_everything) {
  otherFunction(param);
  return result_if_success;
}
return result_if_error;

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

После того, как вы назовете все, вы можете получить некоторую переменную, имеющую некоторую связь между собой. Вы также можете перегруппировать их в enum или namespace, чтобы сделать эту ссылку более заметной для всех. Например, в нашем коде мы вполне можем представить себе такую ​​структуру:

const auto param = 3;
const auto answer_to_the_ultimate_question_of_life_the_universe_and_everything = 42;
enum class Result {
  success = 42,
  error = -1
}
auto result = function(param);
if(result == answer_to_the_ultimate_question_of_life_the_universe_and_everything) {
  otherFunction(param);
  return Result::success;
}
return Result::error;

Числа, но не только — Магические константы

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

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

Чтобы упростить запоминание правила, вы можете сказать, что вы должны назвать все константы в вашем коде. Таким образом, каждый раз, когда вы сталкиваетесь с необработанным элементом, вы даете ему хорошее имя и улучшаете читаемость кода 😉

Лучшие современные практики C++

В современном C++ есть способы правильно обрабатывать магические константы.

Действительно, начиная с С++ 11, вы можете использовать ключевое слово constexpr для определения переменной во время компиляции, что позволяет вам уменьшить накладные расходы, создаваемые этими переменными в вашей программе, и заставить компилятор лучше оптимизировать ваш код. Таким образом, вы можете иметь constexpr чисел, string_view (начиная с С++ 17) или любую структуру, если вы правильно спроектировали ее.

Кроме того, чтобы дать больше контекста вашим константам и избежать конфликта имен, вы можете использовать enum class и namespace.

Используя их, я могу гарантировать вам, что ваш код будет намного чище без потери производительности. Это абсолютная победа 😃

Вывод

Я могу заявить об этом достаточно, но именование — это трудная, но необходимая вещь. А магические константы — это элементы, которым вы должны дать имя, чтобы сделать ваш код более выразительным, более простым для понимания и с ним легче работать.

Спасибо всем за прочтение этой статьи, и до моей следующей статьи, хорошего дня 😉

Интересные ссылки

- Сила именования

- Волшебные числа в Википедии]

Первоначально опубликовано на http://10xlearner.com 6 марта 2020 г.