June 26, 2021

What are “Magic Values”?

edit

I recently did a code review for an aspiring developer and instructed them to “get rid of the ‘magic values’ in their code.” It dawned on me that it might not have been obvious what I meant, so I figured I would take a few moments, and paragraphs, to explain.

A “magic value” is a string or number used in a program that is essential to its proper function but provides no context or explanation for why it is what it is. The best explanation is that it “magically” works.

We know that there is no magic in programming, and so we should do our best to remove “magic” from our code so that future you or others understand what we write today more clearly.

Here are some common “magic values” I save as variables in my code.

Time related numbers

Let’s say we are comparing two Dates and we want to see if they are within three days of each other. We could do:

function isWithinThreeDays(date1, date2) {
  const difference = Math.abs(date1 - date2)
  return difference <= 259200000
}

Now, you might be clever enough to figure out that 259200000 is the number of milliseconds in three days, but I doubt you would figure it out with a quick glance. Better is:

const DAY_IN_MS = 1000 * 60 * 60 * 24

function isWithinThreeDays(date1, date2) {
  const difference = Math.abs(date1 - date2)
  return difference <= DAY_IN_MS * 3
}

Now our number isn’t so “magic” anymore. It’s a lot easier to understand that we’re comparing difference with three days worth of milliseconds.

localStorage keys

If I ever have to store something in localStorage for an app, I make sure to turn my storage key into a constant variable. This way I have a single string declared, but a variable I can use over and over and over and know with certainty it will be correct. No typos possible.

const STORAGE_KEY = 'kyleshevlin:theme'

const currentTheme = localStorage.getItem(STORAGE_KEY)

const updateTheme = theme => localStorage.setItem(STORAGE_KEY, theme)

Regexes

Assuming you are a human, you probably can’t read complicated regexes with full comprehension at a glance. Better to give your patterns a really good variable name and use that in your program. Would you rather have:

function isValidEmail(email) {
  return /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
    email.toLowerCase()
  )
}

Or this?

// You can even go the extra mile and leave a comment about the pattern
// or the URL where you found it: https://stackoverflow.com/questions/46155/how-to-validate-an-email-address-in-javascript
const VALID_EMAIL_PATTERN = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/

function isValidEmail(email) {
  return VALID_EMAIL_PATTERN.test(email.toLowerCase())
}

Summary

Avoid “magic values” in your code. Don’t be afraid to pull strings, numbers and more out and give them some context with a great name. It’ll prevent bugs in your code from typos, and make your programs easier to understand in the future.


Liked the post?
Give the author a dopamine boost with a few "beard strokes". Click the beard up to 50 times to show your appreciation.
Kyle Shevlin's face, which is mostly a beard with eyes

Kyle Shevlin is the founder & lead software engineer of Agathist, a software development firm with a mission to build good software with good people.

Logo for Just Enough Functional Programming
Just Enough Functional Programming
Check out my courses!
If you enjoy my posts, you might enjoy my courses, too. Click the button to view the course or go to Courses for more information.
Sign up for my newsletter
Let's chat some more about TypeScript, React, and frontend web development. Unsubscribe at any time.