When is two a magic number?

A magic number is a number that appears directly in source code, but should really be given a name and used as a variable. The aim of this refactoring step is to improve readability.

Sometimes it can be difficult to decide whether a number is worth giving a name to. Especially the meaning of values like -1, 0, 1 or 2 is often already apparent from the context.

Below you can find a few example scenarios and how they should be handled.

Example 1: checking for even numbers

The modulo operator % can be used to find the remainder in a division. So, for example 5 % 3 is 2, and 13 % 5 is 3.

To check whether a number is even, you can use the modulo operator to divide by two. 3 % 2 is 1, so 3 is an odd number. 4 % 2 is 0, so 4 is an even number.

Therefore, an isEven function could look like this:

function isEven(number){
    return number % 2 === 0;
}

Should 2 be considered a magic number in this case? What about 0?

I think that using 2 directly is acceptable here. The isEven function is very short, and its name gives a good indication of what happens inside the function.

Likewise, if you understand how the modulo operator works, it's clear why we compare to 0.

Example 2: inside an object

What about the two in this code snippet?

var category = {
    name: "T-shirts",
    id: 2
}

Since the value is used together with a property name (id) that already conveys what the 2 stands for.

Example 3: code values

Do you understand what's happening in this code?

person.gender = 2;

Here, using the value 2 directly is very confusing.

Creating a list of available genders and their matching numeric code makes the code much easier to understand:

var GENDERS = {
    male: 1,
    female: 2
}
person.gender = GENDERS.female;

Example 4: calculating a value (e.g. 2^8)

How should the expression Math.pow(2, 8) be handled?

Here it's important to assign the result of the calculation to a variable to show what it stands for. For example, you could write:

var POSSIBLE_VALUES_IN_ONE_BYTE = Math.pow(2, 8);

Or, you could further explain the calculation:

var POSSIBLE_VALUES_PER_BIT = 2;
var BITS_PER_BYTE = 8;
var POSSIBLE_VALUES_IN_ONE_BYTE = 
    Math.pow(POSSIBLE_VALUES_PER_BIT, BITS_PER_BYTE);

While the second example isn't wrong or unreadable it is more verbose than necessary.

The majority of developers will understand and prefer the short one-line version.

For this particular example, it's also not very important to maintain the original calculation. The number of values that can be represented in one byte isn't going to change in the future. Hard-coding the value 256 instead of writing Math.pow(2,8) would be perfectly acceptable, possibly even better.

Example 5: using two as a multiplier for a value

In this example a first class ticket costs twice as much as a regular ticket:

if (ticket.isFirstClass) {
     price *= 2;
}

There's no technical reason why the multiplier should be 2. The company could decide that first class tickets should only be 10% more expensive, or that they should cost 5 times as much as standard tickets.

The 2 is a magic number and the code needs to be refactored.

var FIRST_CLASS_PRICE_MULTIPLE = 2;
if (ticket.isFirstClass) {
     price *= FIRST_CLASS_PRICE_MULTIPLE;
}

By introducing a new variable, we can communicate the meaning the value 2. We could also re-use the variable elsewhere in the code.

Final note: don't create a constant called TWO

The reason for introducing a new variable or constant is to add new information to your code.

However, just because a value is moved into a variable that doesn't automatically make the code more readable. price *= TWO isn't more informative than price *= 2. Therefore, don't create variables with names like TWO, THREE or TEN. It's still a magic number if the new variable name doesn't add any new meaning.