You've seen this pattern before β CONSTANT = 'constant' βΒ common in dynamic languages.
Please stop. It's a kludge.
A hill I will die on π stop using CONSTANT = 'constant'
β Swizec Teller (@Swizec) September 17, 2021
Use the type system instead. pic.twitter.com/q1p5WwY9Y4
Why SHOUTING
Shouting constants hail from a time when programming languages didn't have constants. You used ALL_CAPS to tell other programmers to treat this variable as a constant.
Now it's common practice.
Global constants like configuration variables are ALL_CAPS, local constants like const foo
are camelCase or snake_case. Every language community is different. JavaScript likes camels, Python and Ruby like snakes π€·ββοΈ
Why SHOUTING = 'shouting'
Global constants like this are a poor man's type system. You see them a lot in early Redux tutorials, some XState tutorials, and other places where different areas of your codebase have to share a string value.
The goal is to avoid typos, get IDE support for code completion, and ensure code changes together. Plus if you rename a value you totally don't have to go make changes everywhere.
Sounds like a good idea at first
Say you're building an appointment booking system and appointments have names for different services. You start like this:
function doSomething(appointmentService) {
if (appointmentService === "acupuncture") {
// special treatment
} else if (appointmentService === "covid") {
// very special treatment
}
}
Those 'acupuncture'
and 'covid'
strings look suspicious. You'll use them in a different function and then how do you ensure that it isn't 'acupuncture'
in this method and 'acpuncture'
in another?
"A-ha!", you think, "I'll make a shared constant! That way they're gonna stay the same everywhere!"
You make a new globals file.
// globals.js
const ACUPUNCTURE = "acupuncture";
const COVID = "covid";
// elsewhere
import { ACUPUNCTURE, COVID } from "globals";
function doSomething(appointmentService) {
if (appointmentService === ACUPUNCTURE) {
// special treatment
} else if (appointmentService === COVID) {
// very special treatment
}
}
Problem solved, right? No.
Why it doesn't work
That looks like it solves the problem. But all you've achieved is create extra work.
Let me explain.
When you rename acupuncture
to pokey_needle_stuff
, for example, will you keep the constant name as ACUPUNCTURE
? You could, but the confusion that would cause with anyone new entering the codebase ... oof
Best keep the value and constant in sync. You now have to change 4 occurrences of "acupuncture" in even our smol example. A 4x increase in work π€
"But Swiz, they're easier to find!"
Are they? git grep "'acupuncture'"
works the same as git grep ACUPUNCTURE
.
"Come on Swiz, at least I get undefined errors."
Yes, if you run the code. Hope you have 100% test coverage otherwise it's a runtime error in production π€
"Wait won't the compiler tell me stuff's undefined?"
Not in a dynamic language. You need static analysis for that.
"Okay, but at least it helps with code completion right?"
Does it? How would your editor know that the appointmentService
argument represents a specific bag of strings? It doesn't even know that's a string!
And how do other programmers on your team know anything about appointmentService
and what to expect from reading the code?
Unless you import the constants nobody knows anything about them. Not your IDE, not you, not others.
Yes once you import the correct constant, you get code completion for that whole file. Big whoop. π
Use the type system
If you don't have a type system, use plain strings. At least they're less work.
For TypeScript string union types fit best. Elsewhere you might use an enum of some sort.
type AppointmentService = "acupuncture" | "covid";
function doSomething(service: AppointmentService) {
if (service === "acupuncture") {
// special treatment
} else if (service === "covid") {
// very special treatment
}
}
You get:
- every programmer knows that
service
is a specific kind of string - your IDE knows what values to expect
- change or drop a value and you get squiggly lines
- build errors, no unit tests required βοΈ
- autocomplete
- no extra work
Look!
π
You can add | string
to AppointmentService
, if you need an else statement that captures anything. You lose a lot of the IDE wonderfulness, but other programmers and future you know what to expect.
Cheers,
~Swizec
PS: yes a typed language gives you squiggly lines and build errors with the SHOUTING approach, but you miss out on the communicate-with-others aspect. Lean into your tools my friend
Continue reading about Stop SHOUTING = 'shouting'
Semantically similar articles hand-picked by GPT-4
- TypeScript's biggest flaw and how you can use ducks to fix it
- Learn TypeScript in 5 minutes
- Don't neglect your upgrades
- How to configure Jest with TypeScript
- I added linting to a 3-year old project. You can totally guess what happened next.
Learned something new?
Read more Software Engineering Lessons from Production
I write articles with real insight into the career and skills of a modern software engineer. "Raw and honest from the heart!" as one reader described them. Fueled by lessons learned over 20 years of building production code for side-projects, small businesses, and hyper growth startups. Both successful and not.
Subscribe below π
Software Engineering Lessons from Production
Join Swizec's Newsletter and get insightful emails π on mindsets, tactics, and technical skills for your career. Real lessons from building production software. No bullshit.
"Man, love your simple writing! Yours is the only newsletter I open and only blog that I give a fuck to read & scroll till the end. And wow always take away lessons with me. Inspiring! And very relatable. π"
Have a burning question that you think I can answer? Hit me up on twitter and I'll do my best.
Who am I and who do I help? I'm Swizec Teller and I turn coders into engineers with "Raw and honest from the heart!" writing. No bullshit. Real insights into the career and skills of a modern software engineer.
Want to become a true senior engineer? Take ownership, have autonomy, and be a force multiplier on your team. The Senior Engineer Mindset ebook can help π swizec.com/senior-mindset. These are the shifts in mindset that unlocked my career.
Curious about Serverless and the modern backend? Check out Serverless Handbook, for frontend engineers π ServerlessHandbook.dev
Want to Stop copy pasting D3 examples and create data visualizations of your own? Learn how to build scalable dataviz React components your whole team can understand with React for Data Visualization
Want to get my best emails on JavaScript, React, Serverless, Fullstack Web, or Indie Hacking? Check out swizec.com/collections
Did someone amazing share this letter with you? Wonderful! You can sign up for my weekly letters for software engineers on their path to greatness, here: swizec.com/blog
Want to brush up on your modern JavaScript syntax? Check out my interactive cheatsheet: es6cheatsheet.com
By the way, just in case no one has told you it yet today: I love and appreciate you for who you are β€οΈ