7 Tips for Clean Code in JavaScript You Should Know

published

As a developer, you'll spend much more time reading code than writing it. That's why it's important to write code that's quick to grasp and easy to maintain. In this post, I want to introduce you to 7 tips that will help you create a clean and robust codebase.

Please note that these are opinionated guidelines. Some of you may not agree with me. In general, these tips will not be universal. Also, this list is not exhaustive at all.

1. Use meaningful names

There are only two hard things in Computer Science: cache invalidation and naming things.

-- Phil Karlton

Yeah, naming things is hard. However, meaningless names will trigger chaos in the long run. Whenever you have to choose a name - be it for a variable, a class, a function or anything else - please use meaningful names. The name should tell you the purpose and context.

❌ Bad

function su(e, pw) {
  const u = new U(e, pw);
  // What the §*{$ is this?
}

✔️ Good

function signup(email, password) {
  const user = new User(email, password);
  // Ah, now I understand!
}

2. Replace magic numbers with constants

What is a magic number? A magic number is a hard coded numeric value. It's an anti-pattern and obscures the developer's intent. Thus, it should be replaced with a constant that describes its purpose. See, you can instantly apply your knowledge from the first tip.

❌ Bad

for (let i = 0; i < 52; i++) {
  // ...um, why again do we use `52` here?
}

✔️ Good

const DECK_SIZE = 52;

for (let i = 0; i < DECK_SIZE; i++) {
  // It's about a deck of playing cards.
}

Here, you may ask why i = 0 is okay. Well, I'd count this as acceptable use. The intent here is clear - using i and initializing it with 0 is widely known among developers.

3. Do not use boolean flags to determine behavior

Often, you encounter a function that has two very similar behaviors. To switch between those, you might be tempted to simply add a boolean flag. However, this makes your code less readable and harder to understand. Try to split the function into two functions without the flag instead.

❌ Bad

function loadSchema(schema, sync = false) {
  //
}

// One eternity later…

loadSchema("…", true);
// Wait, what is `true` here? Sync? Async? 
// Something else? I'm so forgetful.

✔️ Good

function loadSchema(schema) {
  //
}

function loadSchemaSync(schema) {
  //
}

// One eternity later…

loadSchemaSync("…");
// Ah, it's the synchronous variant.

4. Reduce nesting in your code

Nesting makes code harder to read and especially harder to understand. With some simple tricks you can reduce nesting to a minimum.

❌ Bad

async function handle(request) {
  if (request.user) {
    if (request.user.can("CREATE_POST")) {
      // Wow, this is deep.
      // Handle request here.
    } else {
      // User is not authorized.
      return new Response({ status: 403 });
    }
  } else {
    // User is not authenticated.
    return new Response({ status: 401 });
  }
}

✔️ Good

async function handle(request) {
  if (!request.user) {
    // User is not authenticated.
    return new Response({ status: 401 });
  }

  if (!request.user.can("CREATE_POST")) {
    // User is not authorized.
    return new Response({ status: 403 });
  }

  // We can safely assume the user
  // is authenticated and authorized.
  // Handle request here.
}

5. Make use of newer language features

JavaScript is constantly changing. This brings you awesome new features that can improve your codebase. You can use destructuring, classes, the async-await syntax, the numeric separator and much more. My favorites are probably the spread-Operator (...), the optional-chaining operator (?.) and nullish-coalescing (??).

❌ Bad

// Assigning a default value should be easier...
const port = typeof config.port !== "undefined" ? config.port : 3000;

// Did I mess up? It's nine zeros, right?
const oneBillion = 1000000000;

// Deep properties and nesting...urghs
if (user.team) {
  if (user.team.subscription) {
    if (user.team.subscription.invoices) {
      //
    }
  }
}

✔️ Good

// Let's use nullish-coalescing (`??`).
const port = config.port ?? 3000;

// The numeric separator makes it easy to tell.
const oneBillion = 1_000_000_000;

// Here, we can use optional-chaining.
if (user.team?.subscription?.invoices) {
  //
}

Note that you cannot use optional-chaining on a non-existent root object. So if user could be undefined, we'd have to check with something like typeof user !== "undefined" first.

6. Make your code easy to refactor

Refactoring is the restructuring of your code without changing the observable behavior. To make this easy, you should consider writing automated tests. Therefore, you can use testing frameworks like Jest. If you are using automated tests you can verify that your code is behaving like you'd expect.

Then, you are ready for refactoring. You can change your code however you want. As long as your tests are passing, everything is fine. This should enable you to be confident about your codebase. No more fear that you are accidentally breaking something.

Unfortunately, setting up a testing framework like Jest is beyond the scope of this article. If you want, I can create a post about testing (and refactoring) your JavaScript code.

7. Use ESLint

This is the final tip of this post. Use this awesome tool called ESLint. It's free and easy to use and surely will improve your codebase. It detects and fixes common problems. Also, you can install useful presets and plugins to detect even more and reformat your code according to a style guide.

I use ESLint with plugins for standard and prettier. Besides, if I'm working with Vue, I'll add eslint-plugin-vue. Unfortunately, explaining the installation and configuration of ESLint is also beyond the scope of this article. Tell me, if you'd like to hear more about this.

Bonus: Consider using TypeScript

If you've read any of my posts in the past, you might know that I'm using TypeScript, a superset of JavaScript. It's basically JavaScript on steroids and helps you writing more robust and maintainable code. If you are still undecided, take a look at these 6 Reasons Why You Should Learn TypeScript in 2021 .

Conclusion

There's so much more you can do to create a clean and maintainable codebase. With my post, you should have a overview about small things you can do to improve your code. In the future, I'll publish more content to make you a better programmer.

If you like my content and you want to see more, please follow me on Twitter!
Questions, feedback or just wanna chat? Come and join my Discord!

You May Also Be Interested in the Following Posts