Clean Code Principles

Clean Code Principles

Clean Code Principles

Principle 1

Avoiding unnecessary nesting

Adding too much nesting will make it hard to follow.

function processUser(user){
  if(user != null){
    if(user.hasSubscription){
      if(user.age >= 18){
        showFullVersion();
      } else {
        showChildrenVersion();
      }
    } else {
      throw new Error("User needs a subscription");
    }
  } else {
    throw new Error("No user found");
  }
}

The following code snippet is the example of unnecessary nesting. The code checks if the user is not null and if they have a subscription and if they are 18 or above, we show the full version of whatever it is we want to show. Otherwise, we show some child version. And then we have these else cases to throw errors, saying "the user needs a subscription" and "the user is not found". But this whole thing is just a bit hard to follow and there're so many different "if" checks. Let's see how we can optimize this so that it is easier to read and follow.

We can try to avoid this nesting by reorganizing the code like this:

function processUser(user){
  if(user == null){
    throw new Error("No user found");
  }

  if(!user.hasSubscription){
    throw new Error("User needs a subscription");
  }

  if(user.age < 18){
    return showChildrenVersion();
  }

  // Show full version if we gets past all of the above conditions
  showFullVersion();
}

Now we have a very easy-to-follow code that doesn't involve any nesting.


Principle 2

Avoiding ambiguity in code

const MIN_PASSWORD = 6;

function checkPasswordLength(password){
  return password.length >= MIN_PASSWORD;
}

The following code snippets have a lot of ambiguity here even though it seems very simple. First of all, we have MIN_PASSWORD constant. But what does that mean if you just see the word MIN_PASSWORD? We can't see anything else unless we go to search for that original code. Is this the minimum length of a password or something else? And then we have this checkPasswordLength function and if we just saw this function name somewhere where the function is actually invoked, how would you know what this does:

  • Is it throwing an error if this password is not long?
  • Is it returning a Boolean? If it is, what does true mean and what does false mean?
  • Does true mean it is of the appropriate length or does it mean that it is not the appropriate length?

Well, we can optimize it like this:

const MIN_PASSWORD_LENGTH = 6;

function isPasswordLongEnough(password){
  return password.length >= MIN_PASSWORD_LENGTH;
}

MIN_PASSWORD_LENGTH eliminates any ambiguity. Now we have the prefix of is and it means it is going to return a boolean. is long enough is going to tell us what true and false mean. true means it is long enough, and false means that it is not.


Principle 3

Avoiding over commenting

In the following code snippet, comments are just getting in the way and making the code less readable.

// Function to check if a number is prime
function isPrime(number){
  // Check if number is less than 2
  if(number < 2){
    // If less than 2, not a prime number
    return false;
  }

  // At least 1 divisor must be less than square root, so we can stop there
  for(let i = 2; i <= Math.sqrt(number); i++){
    // Check if number is divisible by i
    if(number % i === 0){
      // if divisible, number is not prime
      return false;
    }
  }

  // After all checks, if not divisible by any i, number is prime
  return true;
}

We can get rid of some unnecessary comments which are self-explanatory to fellow developers to improve readability.

function isPrime(number){
  if(number < 2){
    return false;
  }

  // At least 1 divisor must be less than square root, so we can stop there
  for(let i = 2; i <= Math.sqrt(number); i++){
    if(number % i === 0){
      return false;
    }
  }
  return true;
}

As you can see I didn't get rid of one comment because it is actually a good comment. Why? Because

  • It is explaining why we are looping to Math Square root of number which we first look at it, it might not actually be that obvious.
  • It will eliminates some valuable time of the other developers who are working on the code.

So the bottom line is that

  • we don't need to write comments to explain code that are so easy and simple to read.
  • But leave comments to explain any logic that is more complicated that somebody is not going to be able to just look at it and understand why it is there.

Principle 4

Avoiding DRY principle (Don't repeat yourself)

DRY in programming means "Don't Repeat Yourself" or "Don't repeat your code".

The same logic should not exist in two different places. Check out the following code:

function logLogin(){
  console.log('User logged in at ' + new Date());
}

function logLogout(){
  console.log('User logged out at ' + new Date());
}

function logSignUp(){
  console.log('User signed up at ' + new Date());
}

If we take a look at the snippet,

There is no reason to have three different functions that all do the exact same thing. So what we can do instead is

function logAction(action){
  console.log(`User ${action} at ${new Date()}`);
}

Now we don't need all of these repeated functions instead we can just use this one function that does all of these things.