Clean Code: Best Practices for Writing Robust and Maintainable JavaScript Code

Pavithrasandamini
15 min readMar 30, 2023
figure 1.0

Hello falks, today we are going to discuss about clean codes, Clean code is a coding philosophy that emphasizes writing code that is easy to read, understand, and maintain. The goal of clean code is to make code more robust, scalable, and efficient, with the added benefit of reducing the likelihood of bugs and errors. Clean code is not only about following coding best practices, but also about writing code that is easy to read and understand for other developers who may have to work with it in the future.

Clean code involves using meaningful and descriptive variable and function names, avoiding magic numbers and strings, keeping functions small and focused, using consistent formatting and indentation, and using comments sparingly to provide context and explain complex logic. Writing clean code not only improves the quality of the code but also saves time in the long run by making it easier to maintain, debug, and update.

In essence, clean code is about writing code that is easy to read, easy to understand, and easy to modify. It is a continuous process that requires a commitment to excellence, discipline, and attention to detail. By following the principles of clean code, developers can write code that is not only efficient but also elegant and beautiful.

Why developers should use clean codes?

figure 1.2

Those are the advantages of using clean code for development.

Maintainability: Clean code is easy to maintain. It is structured in a way that makes it easy to modify, debug, and update. Clean code has fewer bugs and is easier to refactor, which saves time and effort in the long run.

Readability: Clean code is easy to read and understand. This makes it easier for other developers to work with and reduces the likelihood of errors or misunderstandings. Clean code is also easier to learn from, which can help new developers ramp up more quickly.

Scalability: Clean code is more scalable. It is easier to add new features, modules, or components to clean code. Clean code is also easier to test, which helps to catch errors early in the development process.

Efficiency: Clean code is more efficient. It is optimized for performance and has fewer redundant or unnecessary lines of code. This makes clean code faster and more reliable.

Collaboration: Clean code makes collaboration easier. When code is clean, it is easier for multiple developers to work on the same codebase, without stepping on each other’s toes. Clean code is also easier to review, which helps to ensure that it is of high quality.

Overall, clean code is essential for software development. It helps developers write better code that is more maintainable, readable, scalable, efficient, and collaborative. By using clean code practices, developers can improve the quality of their code, save time and effort, and ultimately deliver better products. Ok, then we can go through the clean code rules one by one.

Use meaningful and descriptive variable and function names:

Variables and functions should have names that accurately reflect their purpose and function. This makes the code more readable and easier to understand. When writing code in JavaScript, it is important to use variable and function names that accurately reflect their purpose and function. This makes the code more readable and easier to understand, not only for yourself but also for other developers who may have to work with your code in the future.

For example, consider the following code snippet:

let x = 5;
let y = 10;
let z = x + y;
console.log(z);

In this code snippet, the variable names x, y, and z are not very descriptive. It is not immediately clear what they represent or how they are related to each other. A more descriptive and meaningful approach would be to name the variables based on their purpose and function, like this:

let firstNumber = 5;
let secondNumber = 10;
let sum = firstNumber + secondNumber;
console.log(sum);

In this updated code snippet, the variables have been named firstNumber, secondNumber, and sum. These variable names accurately reflect their purpose and function, making the code more readable and easier to understand.

Similarly, when writing functions in JavaScript, it is important to use descriptive and meaningful function names. Consider the following code snippet:

function foo(a, b) {
return a + b;
}

The function name foo is not very descriptive and does not give any indication of what the function does. A more descriptive function name would be something like calculateSum, like the code shown below:

function calculateSum(a, b) {
return a + b;
}

In this updated code snippet, the function has been named calculateSum, which accurately reflects its purpose and function. This makes the code more readable and easier to understand.

In summary, using meaningful and descriptive variable and function names in JavaScript code is important for making the code more readable and easier to understand. It is a good practice to choose names that accurately reflect their purpose and function and to avoid using names that are too generic or unclear. That’s the end of that rule description.

Keep functions small and focused:

Functions should be small and focused on a single task. This makes the code more modular, easier to read, and easier to test.Keeping functions small and focused is an important principle of writing clean and maintainable code in JavaScript. When functions are small and focused, they are easier to read, test, and modify. This also makes the code more modular, which helps to reduce complexity and increase the code’s reusability.

Consider this code snippet:

function calculateTotalPrice(price, quantity, discount) {
let total = price * quantity;
if (discount > 0) {
total *= (1 - discount / 100);
}
return total;
}

In here, the calculateTotalPrice function calculates the total price based on the price, quantity, and discount inputs. While this function is relatively simple, it is doing more than one thing. Specifically, it is calculating the total price and applies a discount if there is one. This function could be split into two smaller and more focused functions, according to following method:

function calculatePrice(price, quantity) {
return price * quantity;
}

function applyDiscount(total, discount) {
if (discount > 0) {
return total * (1 - discount / 100);
}
return total;
}

function calculateTotalPrice(price, quantity, discount) {
let total = calculatePrice(price, quantity);
return applyDiscount(total, discount);
}

In this updated code, the calculateTotalPrice function has been split into two smaller functions, calculatePrice, and applyDiscount, each with a single responsibility. The calculateTotalPrice function now simply calls these two functions and returns the result. This makes the code easier to read, understand, and test.

By breaking down functions into smaller and more focused functions, the code becomes more modular, which makes it easier to test and maintain. This also helps to reduce the likelihood of introducing bugs and errors, as smaller functions are easier to reason about and test in isolation. Ok, now let’s continue with our next rule.

Avoid magic numbers and strings:

Magic numbers and strings are hard-coded values that are used throughout the code. They should be avoided because they make the code harder to understand and modify. In JavaScript, magic numbers and strings are hard-coded values that are used throughout the code. They should be avoided because they make the code harder to understand and modify. A magic number or string is a hard-coded value that appears in the code without any explanation of what it represents.

Consider the code snippet shown below:

function calculateTax(amount) {
if (amount > 100) {
return amount * 0.2;
} else {
return amount * 0.1;
}
}

In this above example, the 0.2 and 0.1 values are hard-coded, which makes them magic numbers. These values are used to calculate the tax rate based on the amount of input. However, it is not immediately clear what these values represent, and they may need to be changed in the future. To avoid magic numbers, you can define these values as named constants, like this:

const HIGH_TAX_RATE = 0.2;
const LOW_TAX_RATE = 0.1;

function calculateTax(amount) {
if (amount > 100) {
return amount * HIGH_TAX_RATE;
} else {
return amount * LOW_TAX_RATE;
}
}

In this updated example, the magic numbers 0.2 and 0.1 have been replaced with named constants HIGH_TAX_RATE and LOW_TAX_RATE. These constants clearly define what these values represent, making the code easier to read and understand.

Similarly, magic strings should also be avoided. For example:

function getDiscountCode(discount) {
if (discount > 0.5) {
return "HALFOFF";
} else {
return "10OFF";
}
}

In this example, the string values "HALFOFF" and "10OFF" are hard-coded magic strings. To avoid this, you can define these strings as named constants, like this code snippet:

const HALF_OFF_CODE = "HALFOFF";
const TEN_OFF_CODE = "10OFF";

function getDiscountCode(discount) {
if (discount > 0.5) {
return HALF_OFF_CODE;
} else {
return TEN_OFF_CODE;
}
}

By avoiding magic numbers and strings and using named constants instead, the code becomes more readable, easier to understand, and easier to modify. I hope now you got understand how to avoid magic numbers and strings in clean code.

Use consistent formatting and indentation:

Consistent formatting and indentation make the code more readable and easier to understand. This includes using spaces instead of tabs and indenting code blocks consistently. Consistent formatting and indentation is an important aspects of writing clean code. It makes the code more readable and easier to understand, especially when working on large codebases with multiple contributors.

Here are some guidelines to follow for consistent formatting and indentation in JavaScript code:

  1. Use spaces instead of tabs: While both tabs and spaces can be used for indentation, it is recommended to use spaces for better consistency across different text editors and IDEs.
  2. Use a consistent number of spaces for indentation: Typically, two or four spaces are used for indentation in JavaScript code.
  3. Indent code blocks consistently: Code blocks should be indented consistently to make it easier to understand the structure of the code. Here isan example:
if (condition) {
// Indent this code block by two or four spaces
console.log('This is the first line.');
console.log('This is the second line.');
}

4. Use line breaks to separate code blocks: Separate code blocks with a blank line to improve readability. Like this example:

function foo() {
// Code block 1
// ...

// Code block 2
// ...
}

5. Use consistent capitalization for variables and functions: Consistent capitalization makes it easier to identify variables and functions. For example, use camelCase for variables and functions, and PascalCase for constructor functions.

function greetUser(name) {
const greeting = 'Hello, ' + name + '!';

console.log(greeting);
}

greetUser('Alice');
greetUser('Bob');

In here, the code is indented consistently using two spaces, and code blocks are separated by a blank line. The variables and function names are also written in camelCase for consistency.

By following these guidelines for consistent formatting and indentation, your code becomes more readable, easier to understand, and more maintainable. Let’s contiu=nue our reading with the next rule.

Use comments sparingly:

Comments should be used to provide context and explain complex logic. They should not be used to explain what the code is doing, as this should be clear from the code itself. Comments are a useful tool for providing context and explaining complex logic in code. However, they should be used sparingly and only when necessary. Overuse of comments can make the code harder to read and maintain.

Here are some guidelines to follow when using comments in JavaScript code:

  1. Use comments to provide context: Comments can be used to provide context for why certain code is being used, what problem it solves, and what assumptions were made when designing it. The code example is shown below:
// This function calculates the sum of two numbers
function addNumbers(num1, num2) {
return num1 + num2;
}

By considering this code we can understand, the comment provides context for what the function does.

2. Use comments to explain complex logic: Comments can also be used to explain complex logic or algorithms that may be difficult to understand from the code alone. Follow this code snippet:

// This function sorts an array of numbers in ascending order using the bubble sort algorithm
function bubbleSort(arr) {
let n = arr.length;

for (let i = 0; i < n; i++) {
for (let j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
// Swap the two elements
let temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}

return arr;
}

In here, the comment explains the bubble sort algorithm used by the function.

3. Avoid using comments to explain what the code is doing: Comments should not be used to explain what the code is doing, as this should be clear from the code itself. For example:

// This code adds two numbers together
let sum = 1 + 2;

In this example, the comment is redundant and adds no value to the code.

By following these guidelines, your comments become more useful and informative, improving the overall readability and maintainability of your code. That’s the end of this rule.

Write modular code:

Modular code is code that is broken down into smaller, reusable components. This makes the code more maintainable and scalable. Modular code is an important concept in software development that involves breaking down complex code into smaller, reusable components. By doing so, developers can create code that is easier to maintain, test, and scale. Here are some guidelines to follow when writing modular code in JavaScript:

  1. Separate concerns: Each module should have a single responsibility and should not be responsible for multiple tasks. This ensures that each module is focused on a single concern and is easier to understand and maintain. For example, a module that handles user authentication should not also handle file uploads.
  2. Use functions and classes: Functions and classes are key building blocks for creating modular code. Functions should be small and focused on a single task, while classes should encapsulate related data and behavior. This makes the code more reusable and easier to test. Let’s consider the following code snippet:
// Function that calculates the area of a circle
function calculateCircleArea(radius) {
return Math.PI * radius ** 2;
}

// Class that represents a user
class User {
constructor(name, email, password) {
this.name = name;
this.email = email;
this.password = password;
}

// Method that logs the user in
login() {
// Code to log the user in
}

// Method that logs the user out
logout() {
// Code to log the user out
}
}

By considering this we can understand, the calculateCircleArea() function and User class are both small, focused, and reusable building blocks that can be used throughout the code.

3. Use modules and exports: In JavaScript, modules are used to create separate files or blocks of code that can be imported and used in other parts of the code. By using modules and exports, developers can create a more organized and modular codebase. As an example:

// File: circle.js
const PI = 3.14159;

// Function that calculates the area of a circle
function calculateArea(radius) {
return PI * radius ** 2;
}

module.exports = {
calculateArea,
};

// File: main.js
const circle = require('./circle');

let radius = 5;
let area = circle.calculateArea(radius);

console.log(`The area of a circle with radius ${radius} is ${area}`);

In this above code, the circle.js file exports a calculateArea() function, which is then imported and used in the main.js file. By breaking down the code into separate modules, it becomes more organized, easier to maintain, and easier to scale.

By following these guidelines, you can create modular code that is easier to maintain, test, and scale. Ok falks, now let’s move on with writting testable code rule.

Write testable code:

Testable code is code that is designed to be easily tested. This makes it easier to catch bugs and errors early in the development process. Writing testable code means designing code in a way that enables easy testing. Testable code is essential for ensuring that your application works as expected, catching bugs and errors early in the development process, and maintaining code quality over time.

Here are some key characteristics of testable code:

  1. Separation of concerns: Testable code separates the different concerns of an application into smaller, more manageable parts. This makes it easier to test each part in isolation, without having to worry about dependencies. Checkout the following example:
function fetchUserData(userId) {
return fetch(`/users/${userId}`)
.then(response => response.json());
}

function displayUserData(userData) {
// Code to display user data on the page
}

function handleUserData(userId) {
return fetchUserData(userId)
.then(displayUserData);
}

In here, the code is separated into three parts: fetchUserData to fetch the user data, displayUserData to display the user data on the page, and handleUserData to handle the entire process. This separation makes it easier to test each part of the code in isolation.

2. Clear interfaces: Testable code has clear interfaces between different parts of the application. This means that each part can be tested independently of the others, without having to know about the internal workings of the other parts. Follow this code snippet:

function calculateAverage(numbers) {
return numbers.reduce((total, number) => total + number, 0) / numbers.length;
}

In this code, the calculateAverage function has a clear interface: it takes an array of numbers as input and returns the average. This makes it easy to test this function by simply passing in different arrays of numbers and checking the output.

3. Minimal side effects: Testable code minimizes the use of side effects, such as modifying the global state or accessing external resources. This reduces the complexity of testing and makes it easier to ensure that tests are consistent and repeatable. Go through this code snippet:

function formatCurrency(amount) {
return `$${amount.toFixed(2)}`;
}

By understanding this we can identify, the formatCurrency function has no side effects: it takes an input amount and returns a formatted string. There are no external resources accessed or the global state modified, making it easy to test this function in isolation.

4. Easy to mock and stub: Testable code is easy to mock and stub, which means that you can isolate parts of the code for testing by replacing them with simplified or controlled versions.

function getUser(userId, dataProvider) {
return dataProvider(`/users/${userId}`)
.then(response => response.json());
}

In this code, the getUser function relies on a data provider function to fetch user data. By passing in a different data provider function during testing, you can easily control the data returned and isolate the getUser function for testing.

5. Test-driven development: Testable code is often developed using a test-driven approach, which means that tests are written before the code is written. This ensures that the code is designed with testing in mind from the outset.

function reverseString(str) {
return str.split('').reverse().join('');
}

describe('reverseString', () => {
it('should reverse a string', () => {
expect(reverseString('hello')).toBe('olleh');
});

it('should handle an empty string', () => {
expect(reverseString('')).toBe('');
});
});

In here, the reverseString function is developed using a test-driven approach. Tests are written before the function is written, and the function is designed to pass those tests. This ensures that the function is designed with testing in mind from the outset. I hope you got understand about this rule, let’s continue reading for more.

Keep the code DRY (Don’t Repeat Yourself):

Repeated code should be avoided, as it makes the code harder to maintain and increases the likelihood of errors. Keeping code DRY, or Don’t Repeat Yourself, is a key principle of software development that aims to reduce duplication in code. Repeated code can make the code harder to maintain, increase the risk of introducing bugs, and make it more difficult to understand and change the code.

By keeping code DRY, you can reduce the amount of code you need to write and maintain, improve code quality, and make the code more modular and easier to test.

Here are some key techniques for keeping code DRY:

  1. Extract repeated code into functions or modules.
  2. Use inheritance and polymorphism to avoid duplicating code across classes.
  3. Use template systems or partials to avoid duplicating HTML or other templates.
  4. Use configuration files or environment variables to avoid hard-coding values in multiple places.

Here’s an example of how to apply the DRY principle in JavaScript:

// Repeated code
function greetUser(name) {
console.log(`Hello, ${name}!`);
}

function sayGoodbye(name) {
console.log(`Goodbye, ${name}!`);
}

// DRY code
function saySomething(salutation, name) {
console.log(`${salutation}, ${name}!`);
}

saySomething('Hello', 'John'); // Hello, John!
saySomething('Goodbye', 'Mary'); // Goodbye, Mary!

In the above code, the repeated code of greetUser and sayGoodbye is refactored into a single function saySomething, which takes a salutation and a name as arguments. This makes the code easier to maintain, as changes to the output format only need to be made in one place.

figure 1.3

Conclusion

In conclusion, writing clean code is not just about making your code look pretty, it’s about improving the quality, maintainability, and readability of your code. By following best practices such as keeping your code DRY, using clear and meaningful names, and separating concerns, you can create code that is easier to read, test, and maintain, ultimately making you a better developer. So, invest some time in learning and implementing these practices, and you’ll be amazed at how much more productive and efficient you can be in writing high-quality, maintainable code. Remember, the most beautiful code is the one that is not just functional, but easy to read, understand, and modify.

Thank you all for reading and hope you all got a wide understanding about clean codes. Follow me for more and stay tuned..

--

--