Swizec Teller - a geek with a hatswizec.com

    Stop SHOUTING = 'shouting'

    You've seen this pattern before – CONSTANT = 'constant' – common in dynamic languages.

    Please stop. It's a kludge.

    Swizec Teller published ServerlessHandbook.dev avatarSwizec Teller published ServerlessHandbook.dev@Swizec
    A hill I will die on πŸ‘‰ stop using CONSTANT = 'constant'

    Use the type system instead.
    Tweet media

    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!

    Great autocomplete
    Great autocomplete

    Squiggly lines on change
    Squiggly lines on change

    😍

    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

    Did you enjoy this article?

    Published on September 21st, 2021 in Opinions, TypeScript, JavaScript, Programming Lessons

    Learned something new?
    Want to become an expert?

    Here's how it works πŸ‘‡

    Leave your email and I'll send you thoughtfully written emails every week about React, JavaScript, and your career. Lessons learned over 20 years in the industry working with companies ranging from tiny startups to Fortune5 behemoths.

    Join Swizec's Newsletter

    And get thoughtful letters πŸ’Œ 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. πŸ‘Œ"

    ~ Ashish Kumar

    Join over 14,000 engineers just like you already improving their careers with my letters, workshops, courses, and talks. ✌️

    Have a burning question that you think I can answer?Β I don't have all of the answers, but I have some! Hit me up on twitter or book a 30min ama for in-depth help.

    Ready to Stop copy pasting D3 examples and create data visualizations of your own? Β Learn how to build scalable dataviz components your whole team can understand with React for Data Visualization

    Curious about Serverless and the modern backend? Check out Serverless Handbook, modern backend for the frontend engineer.

    Ready to learn how it all fits together and build a modern webapp from scratch? Learn how to launch a webapp and make your first πŸ’° on the side with ServerlessReact.Dev

    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 ❀️

    Created bySwizecwith ❀️