Categories
JavaScript Best Practices

JavaScript Clean Code — Functions

Spread the love

Functions are important parts of JavaScript programs. They’re used for dividing code up into reusable chunks that do one thing.

Therefore in order to have clean JavaScript code, we have to have easy to understand functions.

In this article, we’ll look at how to write functions that are clean and easy to read and change. The most important thing is to write small functions.

Small Functions

Functions should be small. Smaller functions do less and it’s easier to read. Each line in a function should be around 100 characters long so they fit on any screen.

Doing less means less code means that it’s easier to read. If a function does more than a few things, then it should be divided into smaller functions.

Making small functions is very difficult in old JavaScript code since functions are used for many things they shouldn’t be used for like creating blocks and namespacing code.

However, now that we have JavaScript modules as a standard, we can gradually transform functions into doing things that functions are supposed to do, which is doing one thing.

For example, instead of creating blocks with functions as follows:

(function() {
  var numFruits = 1;
})();

We can instead write:

{
  let numFruits = 1;
};

They both create isolation, but instead of abusing the use of functions, we instead have just an isolated block of code. We can do this with ES6 or later.

let and const should be used to create block-level variables and constants respectively.

In addition, we can use modules if we want to put related pieces of code into a group. They can be used by importing the exported members of another module.

For example, we can create a file called fruit.js that exports a member as follows:

export color = 'red';

Then we can import it in another module called main.js as follows assuming that they’re in the same folder:

import { color } from './fruit'
console.log(color);

Then we get code isolation without using functions.

Blocks and Indent

Indentation should be automatically done with code formatters. We should have conditional statements and loops that are indented with 2 spaces.

Spaces are better than tabs because they don’t create issues with different operating systems. Tabs might look messed up in some systems.

We can use ESLine, JSLint or other linters to deal with indentation if we aren’t using a text editor that does formats JavaScript code automatically.

Do As Little As Possible

Usually, good functions should only do one thing. Long function is hard to read and if they have a lot going on, then it confuses the reader of the code.

The one thing may be hard to know. If it does more than one action, then it’s probably too much.

For example, code for rendering simple HTML to the user can be one function since that’s all it does.

However, if the HTML has many parts in it like looping through items retrieved from an API in multiple places and if statements, and so on, then they should split up into their own function.

If one function has lots of conditionals and loops, then they can probably be split into their own functions.

Another way to know if we can move something into its own function is that we can describe the piece of code without restating the implementation of the function.

One Level of Abstraction

Each function should only have one level of abstraction. This means if a function does something that has a high level of abstraction then it should only do that.

For example, if we want to write a function that loops through elements of an array and adds it to a list, then it should only do that.

Below is an example of dividing code into functions by the level of abstraction:

const addFruitLis = (fruits, ul) => {
  for (const f of fruits) {
    const li = document.createElement('li');
    li.innerHTML = f;
    ul.appendChild(li);
  };
}

const addFruitUl = (fruits) => {
  const ul = document.createElement('ul');
  addFruitLis(fruits, ul);
  document.body.appendChild(ul);
}

const fruits = ['apple', 'orange', 'grape'];
addFruitUl(fruits);

In the code above, we have a function addFruitLis that create the li elements and append it to the ul element that’s in the parameter.

This is one level of abstraction because we’re adding the li elements after the ul element is generated. It’s one level below the ul in terms of hierarchy.

Then we defined the addFruitUl function to create the ul element and delegate the addition of li elements to the addFruitLis function. Then the ul is appended to the document’s body. This way, each function only does as little as possible.

Finally, we call the addFruitUl function by passing in an array and then we get the elements on our page.

Each function only deals with one level of abstraction, as addFruitLis only deals with the li elements in the ul element and addFruitUl only deals with the ul element.

The wrong way to write the code above would be to combine everything into one function. It makes the function’s code complex and confusing.

Conclusion

Functions should do a little possible. We can do this by isolating them in blocks and modules. Old code that uses functions to do that should be eliminated.

Also, each function should do as little as possible and only deal with one level of abstraction. Otherwise, the function’s code gets long and confusing.

Leave a Reply

Your email address will not be published.

If you like the content of this blog, subscribe to my email list to get exclusive articles not available to anyone else.