Javascript - Clean code practices

Photo by freestocks on Unsplash

Javascript - Clean code practices

Introduction

  • Writing clean code is very essential is easy toread,understand and maintain. It increases quality of a resulting product and faster resolution of bugs.

Things to keep in mind

  • Make it work and then make it right
  • Code should be getting better with time
  • Speed is not the criteria for a developer
  • The attitude that we can go fast now and we can deal with the mess later, is bad.
  • If you are not clean, mess will slow you down within an hour
  • Requirements are urgent but architecture is important
  • A file size should not exceed 100 lines of code.

Naming

  • A variable should be named in camelCase, so that it explains clearly what that variable is.
  • Class should be named as nouns(sometimes as verbs),
  • Functions should be named as verb,
  • Booleans should be named as a question(is, are, should, has etc.).
  • Don't be afraid of writing big names. Its good if it explains what it does clearly

  • Array - e.g fruitArr, fruits, fruitNames, fruitList

  • Boolean - prefix(is, has, have, are, should, can)e.g isUserAuthorized, areChanged, hasFruit, shouldFetchData, canDataChange
  • Numbers - e.g minDogs, totalPersons, filteredBoxLength
  • Functions - prefix(get, set, reset, fetch, remove, delete, handle, update, replace, add, insert, hide, do, mutate, trigger) e.g getUser, calculateTotal, fetchData, setInformation, updateDetails, changeAppearance, createMenu, addMonthToDate,

Functions

  • A function body length should be in the range 1-10 lines, Shorter the function easier it is to understand.
  • A function should do only one thing.
  • use of _functionName to indicate its a utility function that is used by other public function. e.g
// myFunction is exposed to client
function myfunction(){
  _utilFunc1();
}

function _utilFunc1(){
  // do something
}
  • Restrict function arguments to 2, if more then pass them as object e.g
<!-- BAD -->
function f1(p1, p2, p3){
    /do something
  }

<!-- GOOD -->
function f1(paramObj){
  // do something
}

f1({p1, p2, p3});
  • Similar finctions/concepts should be grouped together ( so that developers wont have to jump up and down)
  • Most important functions come first
  • Avoid if-else in a function based on some flag, rather create 2 separate function, same goes for switch case as well
<!-- Bad -->
function createFile(name, temp) {
  if (temp) {
    fs.create(`./temp/${name}`);
  } else {
    fs.create(name);
  }
}
  • Separate Query from modifier : If a function is modifying an object and returning something as well, seprate this function into 2 functions, one for query and other one for modifuying an object.

  • Function callers and callees should be close: If a function calls another, keep those functions vertically close in the source file. Ideally, keep the caller right above the callee. We tend to read code from top-to-bottom, like a newspaper. Because of this, make your code read that way.

If-Else

  • avoid negative conditions
<!-- BAD -->
if(!ispresent){// do something}

<!-- GOOD -->
if(isAbsent){// do something}
  • Always write linear code. If You have a group of nested conditionals and it is hard to determine the normal flow of code execution.
<!-- BAD -->
public double getPayAmount() {
  double result;
  if (isDead){
    doSomething1();
  }
  else {
    if (isSeparated){
      doSomething2();
    }
    else {
      if (isRetired){
        doSomething3();
      }
      else{
       doSomething4();
      }
    }
  }
  return result;
}
<!-- GOOD -->
public double getPayAmount() {
  if (isDead){
    return doSomething1();
  }
  if (isSeparated){
    return doSomething2();
  }
  if (isRetired){
    return doSomething3();
  }
  return doSomething4();
}

Complex Conditionals

  • When a long conditional is used in a If statement, we can extract them into a separate function or a separate const variable
<!-- BAD -->
if (date && date.actual() !== 0 && (date.before(12) || date.after(9)) ) {
  return 'Date is correct'
}

<!-- GOOD -->

const isDateValid = date && date.actual() !== 0 && (date.before(12) || date.after(9))
if(isDateValid){
  return 'Date is correct'
}

<!-- OR GOOD -->

function isDateValid(){
  return date && date.actual() !== 0 && (date.before(12) || date.after(9))
}

if(isDateValid()){
  return 'Date is correct'
}

Special Number

  • Your code uses a number that has a certain meaning to it. name them in SNAKE_CASE
<!-- BAD -->
potentialEnergy(mass: number, height: number): number {
  return mass * height * 9.81;
}

<!-- GOOD -->
static const GRAVITATIONAL_CONSTANT = 9.81;

potentialEnergy(mass: number, height: number): number {
  return mass * height * GRAVITATIONAL_CONSTANT;
}

Comments

  • comments should not explain code; code should explain itself
  • Avoid too much details in comments
  • Reveal intent( like rational, why some decisions were made, or why certain algo were used)
  • To caution the developer of something
  • Remove commented code, we can retrieve them in future if needed from version control
  • Only comment on complex logic or Business logic
  • Add TODO , when yun intend to do something in the future. e.g // TODO: ensure error handling is done properly

Javascript clean code tips

  • variables decalaration
let a = 1, b = 2;

let [a,b] = [1,2];

let a, b = 2;
  • Swapping numbers
let [a,b] = [1, 2];
[a,b] = [b,a]
  • let and const : When we know that some declaration should not be changed, we should maximise use of const.
<!-- BAD -->
let myfunction = ()=>{}

<!-- GOOD -->
const myFunction = ()=>{}
  • Array : use of map, filter, reduce, forEach, for(let item of fruitList)

  • Destructuring object :

<!-- BAD -->
const name = employee.name;
const email = employee.email;
const phone = employee.phone;

<!-- GOOD -->
const {name, email, phone} = employee;
  • Use of promises and async and await
<!-- BAD -->
function1(function (err, data) { 
  ...  
  function2(user, function (err, data) {
    ...
     function3(profile, function (err, data) {
      ...
      function4(account, function (err, data) {
        ....
      }); 
    }); 
  });
});

<!-- GOOD -->
function1() 
.then(function2) 
.then(function3) 
.then(function2) 
.catch((err) => console.error(err));

<!-- VERY GOOD -->
async function myAsyncFunction() {  
try {    
  const data1= await function1();    
  const data2= await function2(data1);    
  const data3= await function3(data2);    
  return function4(data4);  
} 
catch (e) {    
  console.error(err);  
}}
  • Usageof && :
<!-- BAD -->
if(data){
  if(data.person){
    result = data.person.name;
  }
}

<!-- GOOD -->
result = data && data.person && data.person.name;
  • usage of || : Can be used for setting the default value;
<!-- BAD -->
if(!name){
  data = 'defaultName';
}

<!-- GOOD -->
data = name || 'defaultName';