Clean Code – Javascript

It is not enough for code to work. – Robert C. Martin

Having spent hours of time writing, reviewing, and architecting web products, if there is one thing that gives me utmost satisfaction is a well-written code.

Writing clean code, to me, should not be a cliché rather a table stake for any software product. During the initial days of my career, I’ve been fortunate(and grateful) to be mentored by developers for whom “Clean Code” was a matter of habit. As I grew up the ladder in engineering teams, I felt the necessity to document my learnings to a blog.

In this blog, I have addressed ten ideas that will help you start your journey towards writing clean maintainable code. Since I’ve spent the majority of my career writing code in Javascript my examples here are in Javascript. The concepts, however, can be applied to any programming language.



1. Meaningful Variable Names

// Don't do this 💩
const a = 3.14;`

// Do this 👌 
const PI = 3.14



2. No Magic Numbers or Strings


// Don't do this 💩
const circumference = 2*3.14*radius;
const isAdminUser = user.type === "ADMIN";

// Do this 👌 
const PI = 3.14;
const USER_ROLES = 
    admin : "ADMIN",
    clerk : "CLERK"


const circumference = 2*3.14*radius;
const isAdminUser = user.type === USER_ROLES.admin;

Why?

  • If a magic string is being written in multiple places you have to change all of them.
  • More manual work increases chances of typos.
  • Magic numbers/Strings are not self-documenting.



3. Avoid Unwanted context

// Don't do this 💩
const car = 
    carMake: "BMW",
    carColor: "Black",
    carModel: "X5",
;

// Do this 👌 
const car = 
    make: "BMW",
    color: "Black",
    model: "X5",
;



4. Functions should do one thing

This has to be the most important rule of software engineering. When a function does more than one thing, it is very difficult to write concise test cases for it.

// Don't do this 💩
function calculateAndDisplaySum(number1, number2) 
   let sum = number1 + number2;
   console.log(`Sum is $sum`);

calculateAndDisplaySum(5, 6);


// Do this 👌 
function calculateSum(number1, number2) 
   let sum = number1 + number2;
   return sum;


function displaySum(number)
   console.log(`Sum is $number`);


const sum = calculateSum(5,6);
displaySum(sum);



5. Less than 2 arguments

When the number of arguments is less than two, it makes easier for writing effective test cases.

// Don't do this 💩

function createButton(name, title, disabled, onClick)
  //....


// Do this 👌 

function createButton(name, title, disabled, onClick)
  //....


const addToCartBtn = createButton(
    name: "addToCart",
    title: ""Add to Cart","
    disabled: false,
    onClick: handleClick,
);



6. No Booleans as function arguments

Flags tell that this function does more than one thing. Functions should do one thing(Refer #4). Split out your functions if they are following different code paths based on a boolean. This helps your code to stick to Single Responsibility Principle.

// Don't do this 💩
distance(pointA, pointB, true)

// Do this 👌 
distanceInKms(pointA, pointB);
distanceInMiles(pointA, pointB);



7. Naming functions – Right approach

Function names should say what they do. It is a good idea to set a baseline among your development team members on how to approach this. Once this is done it is easier for anyone in the team to understand what the function is expected to do.

// This fetches data instantaneously.
const getUser = () => ;
// This function sets data to an object.
const setUser = (user) => ;
// This function gets data asynchronously.
const fetchUser = () => 
// This function helps to render DOM.
const renderUser = () => 
// This function helps to modify a object.
const updateUser = () => 
// This function helps to handle event.
const handleUserCardClick = (evt) => 
// These functions returns booleans to take decisions.
const shouldRenderUser = () => 
const isAdminUser = () => 



8. Polymorphism over conditionals

function test (condition) 
    if (condition === "A") 
        // do something related to "A" here
     else if (condition === "B") 
        // do something related to "B" here
     else if (condition === "C") 
        // do something related to "C" here
    


test('A');
test('B');
test('C');

// Write it this way instead

const A = 
    doTheThing: function()
        // code related to "A" here
    


const B = 
    doTheThing: function()
        // code related to "B" here
    


const C = 
    doTheThing: function()
        //  code related to "C" here
    


function test (condition) 
    condition.doTheThing();    


test(A);
test(B);
test(C);



9. Use Promises, not callbacks

Javascript functions are first class citizens, but they are messy as callbacks! They are not clean and cause excessive amount of nesting.

// Don't do this 💩
get("https://datasource.url/endpoint"),
  (requestErr, response, body) => 
    if (requestErr) 
      console.error(requestErr);
     else 
      writeFile("newfile.html", body, writeErr => 
        if (writeErr) 
          console.error(writeErr);
         else 
          console.log("File written");
        
      );
    
  
);

// Do this 👌 
get("https://datasource.url/endpoint"),
  .then(body => 
    return writeFile("newfile.html", body);
  )
  .then(() => 
    console.log("File written");
  )
  .catch(err => 
    console.error(err);
  );



10. Comments

How much comment is too much comment? There are various schools of thoughts for this. I firmly believe in the idea of
“Good code mostly documents itself.”.

I follow the principle of only commenting things that have business logic complexity.

Learning to write clean code is a journey and not a destination.

For further reading, do consider reading these books.

  1. Clean Code by Robert C Martin
  2. Clean Coder by Robert C Martin

Source link