DEV Community

Cover image for 5 simple changes that will make you a better JavaScript developer
Liam Hall
Liam Hall

Posted on • Updated on • Originally published at Medium

5 simple changes that will make you a better JavaScript developer

Introduction

One of the beautiful things about programming is that there are hundreds of different roads to the same destination. Everyone has their own style and everyone has their own preferences. Whatever your style or preference though, there are some simple techniques you can adopt to make your life, and the life collaborators (including your future self) easier.

Use descriptive names

Using descriptive names is one of the most straight forward changes you can make to your workflow. By using descriptive names for functions and variables, your code can become almost entirely self documenting, although I would still suggest adding comments to complex functionality. We've all been there, you open an old project or a project you've inherited from another developer and it's full of generic names which mean nothing. Take the following example, the code is fetching some items from which it's creating a new Array, Alt items, before setting the icon property to 'star'. In this instance you as the developer, have no idea what those items that are being fetched and manipulated are:

   let items = fetchItems()
   let altItems = items.filter(item => item.featured == true)

   altItems.forEach(item => {
       item.icon = 'star'
   })

Enter fullscreen mode Exit fullscreen mode

You can easily make this code snippet more understandable with descriptive names. For arguments sake, let's say your fetch function is returning an array of articles. Now see the following example for how you may choose to rewrite your previous code snippet with more descriptive names:

   let articles = fetchArticles()
   let featuredArticles = articles.filter(article => article.featured == true)

   featuredArticles.forEach(featuredArticle => {
       featuredArticle.icon = 'star'
   })
Enter fullscreen mode Exit fullscreen mode

Extract common functions

It's not uncommon when writing in any programming language to want perform repetitive tasks within functions and loops. Of course you can repeat yourself each time, however your code will soon become hard to maintain. Take the following example, there are 2 loops, one for articles and one for projects, for each article / project the code will add a standardised formatted date:

articles.forEach(article => {
    let date = new Date(article.createdAt),
        day = date.getDate(),
        month = date.getMonth()+1,
        year = date.getFullYear()

    article.formattedDate = `${day}/${month}/{year}`
})

projects.forEach(project => {
    let date = new Date(project.createdAt),
        day = date.getDate(),
        month = date.getMonth()+1,
        year = date.getFullYear()

    project.formattedDate = `${day}/${month}/{year}`
})
Enter fullscreen mode Exit fullscreen mode

Imagine now you wanted to change the date format, you now have 2 places you need to update your formatting, the articles loop and the projects loop. However by extracting the date functionality from each of the loops and creating a new function, you can reuse the same code in each. Then, should you wish to change your date format, you only need to do it in one place, even if you have hundreds of instances. Now see the following example for how you might choose to refactor your previous snippet and extract the date formatting functionality.

const formatDate = (rawDate) => {
    let date = new Date(rawDate),
        day = date.getDate(),
        month = date.getMonth()+1,
        year = date.getFullYear()

    return `${day}/${month}/{year}`
}

articles.forEach(article => {
    article.formattedDate = formatDate(article.createdAt)
})

projects.forEach(project => {
    project.formattedDate = formatDate(project.createdAt)
})
Enter fullscreen mode Exit fullscreen mode

In situations like this, you could argue that defining variables inside your extracted function offers very little in the way of extra clarity. In that case use the date values directly:

const formatDate = (rawDate) => {
    let date = new Date(rawDate)

    return `${date.getDate()}/${date.getMonth()+1}/{date.getFullYear()}`
}
Enter fullscreen mode Exit fullscreen mode

Avoid nested conditional statements and return early

Conditional statements are common place in almost every Web Application, determining whether statement is true or false and returning or setting the relevant data. The problem with conditionals is that they can very quickly become unsightly and unreadable. Take the following example, the getShopTradingStatement function returns a string based on whether the shop is currently trading and if it is, whether the shop has had its opening day:

const getShopTradingStatement = (shop) => {
    if (shop.isTrading) {
        if (shop.openFrom < Date.now()) {
            return `This shop is currently trading!`
        }
        else {
            return `This shop will open it's doors from ${shop.openFrom}`
        }
    }
    else {
       return `This shop is no longer trading.`
    }
}
Enter fullscreen mode Exit fullscreen mode

Nesting statements in this way, while perfectly valid, already feels cluttered. By switching up your statements and taking advantage of early returns you can make this very same functionality much tidier. Now see the following example for how you might choose to refactor your previous snippet by returning the output of your primary else statement early:

const getShopTradingStatement = (shop) => {
    if (!shop.isTrading) return `This shop is no longer trading.`
    if (shop.openFrom < Date.now()) return `This shop is currently trading!`

    return `This shop will open it's doors from ${shop.openFrom}`
}
Enter fullscreen mode Exit fullscreen mode

Use look up tables

Look up tables are a fantastic way of cleaning up messy, repetitive if statements. Take the following example, you have a userHasAccessPermissionsForTask function which accepts the users role and the task they'd like to perform. The function checks against 3 possible user roles and associated permissions for each. If the user role has permissions to perform the task, the function will return true else it will return false:

const userHasAccessPermissionsForTask = (userRole, task) => {
    if (userRole == 'admin' && ['write', 'edit', 'read'].includes(task)) {
        return true
    }
    if (userRole == 'editor' && ['edit', 'read'].includes(task)) {
        return true
    }
    if (userRole == 'subscriber' && ['read'].includes(task)) {
        return true
    }
    return false
}
Enter fullscreen mode Exit fullscreen mode

The previous code snippet is perfectly valid but it's not particularly clear. You're also repeating your includes function on each if statement, if in future you wanted to test against that data in a different way you'd need to ensure you did it in 3 places. You could make the argument for extracting that functionality as it's own function but creating a function to return a built in function seems a little odd, right? Luckily with look up tables you can avoid all that. Now see the following example for how you might choose to refactor your previous snippet using a look up table. The look up table is an object that, in this case, uses the user roles as keys and permissions as values. You can now return a single includes function which references the permissions object property with the key equal to the given userRole:

const userHasAccessPermissionsForTask = (userRole, task) => {
    const permissions = {
        admin: ['write', 'edit', 'read'],
        editor: ['edit', 'read'],
        subscriber: ['read']
    }
    return permissions[userRole].includes(task)
}
Enter fullscreen mode Exit fullscreen mode

Start sharing your code

I think sharing your code is possibly one of the most valuable things you can do if you want to continue to grow and learn as a developer. Things change fast in tech and it's very easy to be left behind, particularly when you're busy. Sharing your code, whether via code reviews, pair programming*, even through blogging and social media platforms like Twitter allows people to question your approach. That can seem scary at first, but being questioned on your approach does not mean you're wrong, but it allows you to open your mind to new and/or different ways in which you might approach issues in future. In turn, your answers may help serve those questioning you in their future projects.

*If you'd like to pair program while maintaining social distancing or while working remotely you can try pair programming software like Tuple or the VS code Liveshare extention.

Conclusion

Making small changes to the way you approach tasks when programming can make a monumental difference to readability and maintainability, both for yourself and others. Habits can be hard to break but your future self and your colleagues will probably thank you for it.

If you’ve found this article useful, please follow me on Medium, Dev.to and/ or Twitter.

Latest comments (4)

Collapse
 
dmshvetsov profile image
Dmitry Shvetsov

Hey Liam

you can add syntax highlighting like this by using js or javascript .

This will help people to read your code examples.

Collapse
 
wearethreebears profile image
Liam Hall

Awesome, I was unaware, thank you. I've update the snippets.

Collapse
 
dmshvetsov profile image
Dmitry Shvetsov

Yay! Much readable. Thanks!

BTW cool, minimalist title image! 👍

Collapse
 
raresportan profile image
Rares Portan

Good points!
Maybe by accident, but all examples show pure functions. Which is another good idea.