Stop Using Magic Numbers


Infographic explaining to avoid magic numbers

Are you familiar with the term magic number? Let’s imagine a programming world where we never used variables, instead we just used literals and direct numbers everywhere. Is this a world you want to live in? Can you imagine trying to maintain code like this, having so dig through hundreds of functions and classes, trying find each and every reference to a particular value. This is what magic numbers are.

What is a magic number?

A magic number is a direct usage of a number in code. This is in contrary to a variable or constant, where a symbolic name is created to reference a value instead.

Let’s take this JavaScript code for example:

let grossPrice = netSalesPrice * (0.06 + 1);

This code should be simple enough to understand. It’s calculating the gross price given a net sales price and assuming a 6% tax rate.

While this code is simple, it’s also using a magic number, which is considered anti-pattern. It’s hard to imagine in such a short snippet like this, but when you start adding in all the other functionality needed for an application to run, things can get out of hand pretty quickly.

For example, the tax rate may be used in other places of the application too, so what happens when the tax rate changes? Surely a simple “Find and Replace” can work, right?

let grossPrice = netSalesPrice * (0.06 + 1);
let totalPrice = grossPrice + 0.06; // add the bagger's fee!

Uh oh, what’s going on now? Turns out there’s also bagger’s fee that needs to be added on, and that fee also happens to be $0.06. Now the “Find and Replace” just unintentionally updated other values in the application!

While this example is a very specific and pretty unlikely case, the concept still remains true. There are many times when a magic number is used more than once, as well as the actual value being used for more than just one arbitrary reference.

You can read more about some of the horror stories other senior developers have experience in this StackOverflow thread, What is a magic number, and why is it bad?

Use a constant instead of a magic number

Refactoring magic numbers out of your code is an easy solution, make use of a constant.

  1. Declare a constant (keep in mind good variable name practices and the Proximity Principle)
  2. Assign the magic number to the new constant
  3. Find all instances of the appropriate magic number
  4. Replace the magic number with the constant
    • Note: be sure you’re replacing only the appropriate magic numbers, as the same number can mean different things and be used for different purposes

Refactoring our code from above could look something like this:

const TAX_RATE = 0.06;
let grossPrice = netSalesPrice * (TAX_RATE + 1);

const BAGGERS_FEE = 0.06; 
let totalPrice = grossPrice + BAGGERS_FEE;

Now we can clearly see what’s happening with the code, it’s easier to understand, and will be a lot easier to maintain throughout the life of the application.

Let’s see it in another example:

function getTicketPrice(age) {
  if (age <= 2) {
    return 5.99;
  } else if (age < 18) {
    return 8.99;
  } else if (age < 65) {
    return 15.99
  } else {
    return 9.99;
  }
}

Here, it’s not hard to see what’s going on, but it takes an extra couple seconds to really understand it- more time needed when creating constants would significantly help with readability:

function getTicketPrice(age) {
  const TODDLER_AGE = 2;
  const ADULT_AGE = 18;
  const SENIOR_CITIZEN_AGE = 65;

  if (age <= TODDLER_AGE) {
    return 5.99;
  } else if (age < ADULT_AGE) {
    return 8.99;
  } else if (age < SENIOR_CITIZEN_AGE) {
    return 15.99;
  } else {
    return 9.99;
  }
}

However, we still have magic numbers here in the actual ticket rates themselves. We should take it a step further and create constants for those as well:

function getTicketPrice(age) {
  const TODDLER_AGE = 2;
  const ADULT_AGE = 18;
  const SENIOR_CITIZEN_AGE = 65;

  if (age <= TODDLER_AGE) {
    const TODDLER_RATE = 5.99;
    return TODDLER_RATE;

  } else if (age < ADULT_AGE) {
    const CHILD_RATE = 8.99;
    return CHILD_RATE;

  } else if (age < SENIOR_CITIZEN_AGE) {
    const ADULT_RATE = 15.99;
    return ADULT_RATE;

  } else {
    const SENIOR_CITIZEN_RATE = 9.99;
    return SENIOR_CITIZEN_RATE;
  }
}

This is a lot more verbose and helps the next developer who comes in after you to better understand what’s happening.

1 and 0 are exceptions to this rule

Not all numbers are magic numbers though. You can in fact go overboard when trying to refactor out all magic numbers. Take for example the classic for loop:

for (int i = 0; i < array.length; i++) {
    // do cool stuff
}

In this case, it’d be pretty silly to create a constant for the starting index. This is a classic for loop, it’s very obvious why we’re using the number 0 here, as it’s the starting index of an array.

Now if, for whatever reason, you needed to start at a specific index other than 0, then creating a constant or variable would be ideal:

int midpoint = array.length / 2;
for (int i = midpoint; i < array.length; i++) {
    // do cool stuff with half of the array
}

Conclusion

  • Magic numbers are numbers written directly in the code that have no obvious meaning
  • Magic numbers make it harder to understand and maintain code
  • Magic numbers are bad, don’t use magic numbers
    • (1 and 0 are the exceptions)
  • Use a symbolic constant or named variable, that’s literally what they’re made for
  • Using constants instead of magic numbers helps with readability and maintainability of the code

WAIT! Before you go, have you signed up for the Newsletter?

Adam Allard

Father of 2 - Husband of 1 - Developer of many. I'm a Software Engineer for Northrop Grumman creating web applications for the DoD. Currently I'm primarily working with Java and Angular based applications, although I have some years of experience in various languages and frameworks as well. My hobbies include time with my family, wondering when the Green Bay Packers will win their next Super Bowl, drinking beer that's over-priced, and learning.

Recent Content