Coding Guidelines

Coding guidelines are a set of rules and tips that tell you how to organize, format, and write your code. Think of them as a 'best practices' guide that helps developers write clear, readable, and maintainable code.

The purpose? Coding guidelines aren't just about making code look nice. They're about helping people work together and making the code easy to understand, both for others and for yourself in the future. By following these rules, you keep your code consistent across projects, make it easier to fix bugs, and improve the overall quality of your code.

Why delve into coding guidelines, you might ask? It's like learning how to communicate clearly in the language of programming. This skill helps you write better code and makes it easier to work with other developers. When everyone follows the same rules, it creates an environment where code is a shared language everyone understands.

  • Class Names: Use UpperCamelCase convention for naming them. UpperCamelCase means that each word in the class name starts with a capital letter, without any spaces or underscores between them. For instance, if you have a class related to a car, you might name it CarModel or CarController.

    javascript

    class Animal {
        constructor(name, species) {
          this.name = name;
          this.species = species;
        }
    }         
  • Function Names & Variables: Use lowerCamelCase. In lowerCamelCase, the first letter of the word is in lowercase, while the first letter of each subsequent word is capitalized. For example, if you have a function that calculates the total price, you might name it calculateTotalPrice or getTotalAmount.

    javascript

    function greetUser(userName) {
      return `Hello, ${userName}!`;
    } 
    let favoriteColor = 'blue';
    let numberOfItems = 10; 
  • Constants: Use all uppercase letters and separate words with underscores. This convention is known as UPPER_CASE_UNDERSCORE_SEPARATED.
  • javascript

    const MAXIMUM_VALUE = 1000;
    const API_KEY = 'your_api_key_here';
    const COMPANY_NAME = 'ABC Corp'; 
  • Variable Names
    • Variable naming is crucial in JavaScript, and the key rule here is to make your variable names as descriptive as possible while reflecting their purpose or intention within your code. For instance, if you have a variable that stores a user's age, naming it something like userAge or ageOfUser would be descriptive and clear.
    • Imagine you're explaining your code to someone who has no idea what it does. Your variable names should be so clear that this hypothetical person can easily understand what each variable is meant for just by reading its name.
    • Avoid generic names like temp, x, or data because they don't convey much about the content or purpose of the variable. Instead, opt for names that provide context and meaning to anyone reading your code.

      javascript

      function calculateRectangleArea(length, width) {
        const rectangleLength = length;
        const rectangleWidth = width;
        const area = rectangleLength * rectangleWidth;
        return area;
      }
      
      const sideA = 5;
      const sideB = 10;
      const result = calculateRectangleArea(sideA, sideB);
      console.log(`The area of the rectangle with sides ${sideA} and ${sideB} is: ${result}`); 
    • Variable names shorter than three characters can be quite ambiguous and may not convey much meaning about their purpose or content. However, there's an exception when these shorter names are specifically used as indexers, such as i for a loop index or x and y for coordinates in certain contexts.

      javascript

      function calculateArea(length, width) {
        const len = length; // Shortened version, but not meeting the guideline
        const w = width; // Shortened version, but not meeting the guideline
        const area = len * w;
        return area;
      }
      
      const sideLength = 5;
      const sideWidth = 10;
      const result = calculateArea(sideLength, sideWidth);
      
      console.log(`The area of the shape with dimensions ${sideLength}x${sideWidth} is: ${result}`); 
    • Shortened names or abbreviations can obscure the meaning and purpose of variables, leading to confusion and making the code less readable. It might save a few keystrokes initially, but it sacrifices the clarity and understanding of the code in the long run.

      javascript

      function calculateRectangleArea(length, width) {
        const l = length; // Shorthand name, not descriptive
        const w = width; // Shorthand name, not descriptive
        const area = l * w;
        return area;
      }
      
      const rectangleLength = 5;
      const rectangleWidth = 10;
      const result = calculateRectangleArea(rectangleLength, rectangleWidth);
      
      console.log(`The area of the rectangle with sides ${rectangleLength} and ${rectangleWidth} is: ${result}`);   
  • Use Arrow Functions: Whenever you have a simple function without the need for its own this context, using arrow functions can make your code more elegant and easier to read.

    javascript

    // Traditional function expression
    function multiply(a, b) {
      return a * b;
    }
    
    // Arrow function
    const multiplyArrow = (a, b) => a * b;
    
    // Using the functions
    console.log(multiply(5, 3)); // Output: 15
    console.log(multiplyArrow(5, 3)); // Output: 15 
  • Documenting functions with inputs, outputs, and potential errors is a fantastic practice for improving code clarity and assisting anyone who uses or maintains your code.

    javascript

     /**
     * Calculates the area of a rectangle.
     * @param {number} length - The length of the rectangle.
     * @param {number} width - The width of the rectangle.
     * @returns {number} - The area of the rectangle.
     * @throws {Error} - Throws an error if either length or width is not a number or if they are less than or equal to 0.
     */
    function calculateRectangleArea(length, width) {
      if (typeof length !== 'number' || typeof width !== 'number' || length <= 0 || width <= 0) {
        throw new Error('Length and width must be numbers greater than 0.');
      }
    
      const area = length * width;
      return area;
    }
    
    // Using the function
    try {
      const area = calculateRectangleArea(5, 10);
      console.log(`The area of the rectangle is: ${area}`);
    } catch (error) {
      console.error(error.message);
    } 
  • Keep documentation up-to-date with code changes. Keeping documentation up-to-date is as important as writing it in the first place. As your code evolves, it's crucial to update the associated documentation to ensure it remains accurate and reflects the current behavior of your functions.
  • While documentation for getters and setters in JavaScript isn’t mandatory, it's still beneficial to provide some form of documentation, especially for complex or crucial properties.

    javascript

    class Circle {
      constructor(radius) {
        this._radius = radius;
      }
    
      get radius() {
        return this._radius;
      }
    
      set radius(newRadius) {
        if (newRadius <= 0) {
          throw new Error('Radius must be a positive number.');
        }
        this._radius = newRadius;
      }
    }
    
    const myCircle = new Circle(5);
    console.log(myCircle.radius); // Output: 5
    
    myCircle.radius = 10;
    console.log(myCircle.radius); // Output: 10
    
    myCircle.radius = -3; // Throws an error 
  • Documenting classes with descriptions of their purposes is a great practice that enhances code readability and helps developers understand the role of each class within a codebase.

    javascript

    /**
     * Represents a geometric shape, specifically a circle.
     * @class
     */
    class Circle {
      /**
       * Creates a Circle instance with a specified radius.
       * @constructor
       * @param {number} radius - The radius of the circle.
       */
      constructor(radius) {
        this._radius = radius;
      }
    
      /**
       * Retrieves the radius of the circle.
       * @returns {number} - The radius of the circle.
       */
      get radius() {
        return this._radius;
      }
    
      /**
       * Sets the radius of the circle.
       * @param {number} newRadius - The new radius value.
       * @throws {Error} - Throws an error if the new radius is not a positive number.
       */
      set radius(newRadius) {
        if (newRadius <= 0) {
          throw new Error('Radius must be a positive number.');
        }
        this._radius = newRadius;
      }
    }
    
    // Usage
    const myCircle = new Circle(5);
    console.log(myCircle.radius); // Output: 5
    
    myCircle.radius = 10;
    console.log(myCircle.radius); // Output: 10
    
    myCircle.radius = -3; // Throws an error 
  • Limit the number of function arguments to 7; use payloads for more. The guideline to limit the number of function arguments to a maximum of 7 aims to improve code readability and maintainability. When functions have too many arguments, it can become challenging to understand their purpose and the order in which arguments should be passed.

    javascript

    // Function with multiple arguments
    function calculateVolume(length, width, height, density, temperature, pressure, viscosity) {
      // Perform calculations
      // ...
    }
    
    // Using payloads for more parameters
    function calculateVolumeWithPayloads(data) {
      const { length, width, height, density, temperature, pressure, viscosity } = data;
      // Perform calculations
      // ...
    }
    
    // Usage of the function with multiple arguments
    calculateVolume(10, 5, 3, 2, 25, 100, 0.5);
    
    // Usage of the function with payloads
    const shapeData = {
      length: 10,
      width: 5,
      height: 3,
      density: 2,
      temperature: 25,
      pressure: 100,
      viscosity: 0.5,
    };
    calculateVolumeWithPayloads(shapeData);  
  • Avoid overly long methods; keep methods ideally fitting within a single screen view. Refactor as needed. By refactoring long methods into smaller, more focused ones, you enhance code readability, maintainability, and make it easier for others (and your future self!) to understand and modify the codebase.

    javascript

    //A really long method example
    
    function calculateShapeAttributes(shape) {
      let area = 0;
      let perimeter = 0;
      let diagonal = 0;
      let angles = 0;
    
      // Lengthy calculations for area, perimeter, diagonal, and angles based on the shape
      // ...
    
      return {
        area,
        perimeter,
        diagonal,
        angles,
      };
    } 

    javascript

    //Afer refactoring function will break into small small functions
    
    function calculateArea(shape) {
      let area = 0;
      // Calculate area based on the shape
      // ...
      return area;
    }
    
    function calculatePerimeter(shape) {
      let perimeter = 0;
      // Calculate perimeter based on the shape
      // ...
      return perimeter;
    }
    
    function calculateDiagonal(shape) {
      let diagonal = 0;
      // Calculate diagonal based on the shape
      // ...
      return diagonal;
    }
    
    function calculateAngles(shape) {
      let angles = 0;
      // Calculate angles based on the shape
      // ...
      return angles;
    }
    
    // Combined method calling smaller methods
    function calculateShapeAttributes(shape) {
      const area = calculateArea(shape);
      const perimeter = calculatePerimeter(shape);
      const diagonal = calculateDiagonal(shape);
      const angles = calculateAngles(shape);
    
      return {
        area,
        perimeter,
        diagonal,
        angles,
      };
    }  
  • Consider redesigning classes with too many fields. When a class contains an excessive number of fields, it might be a sign that the class is taking on too many responsibilities and violating the Single Responsibility Principle (SRP). Redesigning such classes can improve code readability and maintainability.

    javascript

    //Class with too many fields example
    class UserProfile {
      constructor(name, age, email, address, phone, bio, interests, education, experience, skills) {
        this.name = name;
        this.age = age;
        this.email = email;
        this.address = address;
        this.phone = phone;
        this.bio = bio;
        this.interests = interests;
        this.education = education;
        this.experience = experience;
        this.skills = skills;
        // ... many more fields
      }
      // Methods related to user profile
    }             

    javascript

    //Refactored into multiple classes 
    class ContactInfo {
      constructor(email, address, phone) {
        this.email = email;
        this.address = address;
        this.phone = phone;
      }
      // Methods related to contact info
    }
    
    class PersonalInfo {
      constructor(name, age, bio) {
        this.name = name;
        this.age = age;
        this.bio = bio;
      }
      // Methods related to personal info
    }
    
    class UserProfile {
      constructor(personalInfo, contactInfo, interests, education, experience, skills) {
        this.personalInfo = personalInfo;
        this.contactInfo = contactInfo;
        this.interests = interests;
        this.education = education;
        this.experience = experience;
        this.skills = skills;
      }
      // Methods related to user profile
    } 
  • Each function should have a single responsibility. adhering to the Single Responsibility Principle (SRP) is crucial for writing clean and maintainable code. This principle suggests that each function should have a single, well-defined responsibility.

    javascript

    //Suppose we have a function that processes user data and sends an email notification:
    
    function processUserDataAndNotify(user) {
      // Process user data
      // ...
    
      // Send email notification
      // ...
    }
                 

    javascript

    //Refactored into multiple functions 
    
    function processUserData(user) {
      // Process user data
      // ...
    }
    
    function sendEmailNotification(user) {
      // Send email notification
      // ...
    }
                
  • Use plural naming convention for methods returning arrays. Adopting a plural naming convention for methods returning arrays is a helpful practice that enhances code readability and communicates the return type effectively.

    javascript

    class ShoppingCart {
      constructor() {
        this.items = [];
      }
    
      // Method returning an array of items
      getItems() {
        return this.items;
      }
    
      // Other methods for adding, removing, or manipulating items in the cart
      addItem(item) {
        this.items.push(item);
      }
    
      // ...
    }
    
    // Usage
    const cart = new ShoppingCart();
    cart.addItem('Apple');
    cart.addItem('Banana');
    
    const items = cart.getItems();
    console.log(items); // Output: ['Apple', 'Banana']
                 
  • Avoid inserting new functions in the middle of existing code. inserting new functions in the middle of existing code can introduce confusion and disrupt the logical flow of the program. Instead, it's advisable to place new functions in a location that maintains the coherence and readability of the codebase.
  • Use const and let instead of var. This shift away from var brings better scoping and reduces the risk of unintended reassignments or scope issues within your code. It's a cleaner and more predictable way to manage variables in JavaScript!

    javascript

    const PI = 3.14159; // Use const for values that remain constant.
    let score = 100; // Use let for variables that might change.
    score = 200; // This is fine with let, but not with const.
                              
  • Avoid global variables. By minimizing the use of global variables and instead utilizing local scopes or appropriate data passing techniques, you create more robust and maintainable code, reducing the chances of unintended side effects and enhancing code readability.

    javascript

    // Instead of: Global variable
    let totalScore = 0;
    
    // Not Preferred
    function updateScore() {
        // Modifying the global variable
        totalScore += 10;
    }
    
    // Preferred
    function updateScore(score) {
        // Work with local variables or parameters
        return score + 10;
    }
    
    let currentScore = 0;
    currentScore = updateScore(currentScore); // Avoids global variable modification
                              
  • Group variable declarations in the highest common code scope. It's a simple yet effective way to improve code readability and reduce potential issues related to variable scope and hoisting.

    javascript

    function calculateArea() {
        // Group variable declarations at the top of the function
        let width = 10;
        let height = 20;
        let area;
    
        // Calculate area using the declared variables
        area = width * height;
        
        return area;
    }
                              
  • Assign default values to all local variables. By providing default values to local variables, you create more robust and predictable code, reducing the chances of unexpected errors due to undefined or null values.

    javascript

    function calculateSumAndAverage(numbers) {
        // Assign default values to local variables
        let sum = 0;
        let average = 0;
    
        for (let i = 0; i < numbers.length; i++) {
            sum += numbers[i];
        }
    
        if (numbers.length > 0) {
            average = sum / numbers.length;
        }
    
        return {
            sum: sum,
            average: average
        };
    }
    const numbers = [5, 10, 15];
    console.log(calculateSumAndAverage(numbers));
  • Remove unused parameters and variables. By removing unused parameters and variables, you streamline your code, making it more manageable, easier to understand, and potentially improving its performance. This practice also encourages a clean and focused codebase.

    javascript

    function calculateTotalPrice(price, quantity) {
        // Only 'price' is used, 'quantity' is unused
        return price;
    }
                              
  • Use strict equality (===) over loose equality (==). By using strict equality (===), you promote code reliability and avoid potential bugs caused by implicit type conversions, leading to more predictable and safer code.

    javascript

    let num = 5;
    let strNum = '5';
    
    console.log(num === strNum); // Outputs: false (Different types)
    console.log(num == strNum); // Outputs: true (Loose equality converts types)
                              
  • Limit one statement per line. While JavaScript allows multiple statements on a single line separated by semicolons, separating each statement onto its own line improves code clarity and makes it easier to understand and work with, especially in complex or large codebases.

    javascript

    let x = 5;
    let y = 10;
    let z = x + y;
                              
  • Use semicolons for statement termination. By consistently using semicolons to terminate statements, you ensure code clarity and mitigate potential issues related to ASI (Automatic Semicolon Insertion), creating more reliable and understandable JavaScript code.

    javascript

    let x = 5;
    let y = 10;
    let z = x + y;
                              
  • Remove duplicate statements. By actively searching for and removing duplicate statements, you ensure that your code is cleaner, more efficient, and easier to comprehend, contributing to better maintainability and readability.

    javascript

    let x = 5;
    let y = 10;
    let z = x + y;
    z = x + y; // Duplicate statement
    
    console.log(z); // Outputs: 15
                              
  • Use ternary operators for simple conditional statements.

    javascript

    // Without ternary operator
    let result;
    if (condition) {
        result = 'Condition is true';
    } else {
        result = 'Condition is false';
    }
    
    // With ternary operator (equivalent to the above)
    let result = condition ? 'Condition is true' : 'Condition is false';
                              
  • Include braces even for one-line code blocks (except for case statements). By consistently using braces, even for one-liners, you maintain a consistent and clear code style, making your code more robust and less prone to potential errors or misunderstandings.

    javascript

    // Without braces
    if (condition)
        doSomething();
    
    // With braces (recommended)
    if (condition) {
        doSomething();
    }  
  • Implement error handling using try-catch blocks or error handling functions. By incorporating try-catch blocks or error handling functions, you ensure that your code gracefully manages exceptions, resulting in more stable and reliable JavaScript applications.

    javascript

    //Example with try-catch block:
    
    try {
        // Code that might throw an error
        let result = someFunction();
    } catch (error) {
        // Handle the error gracefully
        console.log('An error occurred:', error.message);
    }
    
    //Example with Error Handling Function:
    
    
    function handleError(error) {
        // Custom error handling logic
        console.log('An error occurred:', error.message);
    }
    
    try {
        // Code that might throw an error
        let result = someFunction();
    } catch (error) {
        // Call the error handling function
        handleError(error);
    }  
  • Avoid empty catch blocks; log, comment, or perform meaningful logic. By avoiding empty catch blocks and incorporating meaningful error handling, you improve code maintainability, aid in debugging, and ensure a more robust error management strategy in your JavaScript applications.

    javascript

    //Example with Logging:
    
     try {
        // Code that might throw an error
        let result = someFunction();
    } catch (error) {
        // Log the error for debugging purposes
        console.error('An error occurred:', error);
        // Additional logic or error handling can be added here
    }
    
    //Example with Error-Specific Logic:
    
    try {
        // Code that might throw an error
        let result = someFunction();
    } catch (error) {
        if (error instanceof TypeError) {
            // Perform specific handling for TypeErrors
            console.log('Type error occurred:', error.message);
            // Additional logic for handling TypeErrors
        } else {
            // Log other errors and perform generic error handling
            console.error('An error occurred:', error);
            // Generic error handling logic
        }
    }  
  • Place cleanup logic in the finally block if needed. By placing cleanup logic in the finally block, you ensure that essential cleanup operations occur, promoting more reliable and resilient code in scenarios where resource management or final operations are crucial.

    javascript

    try {
        // Code that might throw an error or perform operations
        // Resource allocation, file opening, etc.
    } catch (error) {
        // Handle the error if necessary
        console.error('An error occurred:', error);
    } finally {
        // Cleanup or release resources, executes regardless of error occurrence
        // Close connections, release resources, etc.
    } 
  • Avoid throwing and catching errors within the same code block. By separating the throwing and catching of errors into distinct blocks or functions, you maintain a clearer and more understandable code structure, making it easier to identify and manage errors throughout your application.

    javascript

    try {
        // Code that might throw an error
        if (condition) {
            throw new Error('Some error occurred');
        }
        // Catching the error immediately
    } catch (error) {
        console.error('Caught the error:', error.message);
        // Handling the error here
    }
    
    //Example with Propagation:
    
    function someFunction() {
        if (condition) {
            throw new Error('Some error occurred');
        }
    }
    
    try {
        someFunction();
    } catch (error) {
        console.error('Error occurred:', error.message);
        // Handle or log the error at an appropriate level
    } 
  • Let errors bubble where appropriate and handle them logically. By letting errors bubble up appropriately in your code and handling them logically at higher levels, you maintain a clear and organized error-handling structure, simplifying debugging and ensuring consistent error management throughout your application.

    javascript

    function someFunction() {
        if (condition) {
            throw new Error('Some error occurred');
        }
    }
    
    try {
        someFunction();
    } catch (error) {
        console.error('Error occurred:', error.message);
        // Handle or log the error at a higher level if necessary
    } 
  • In api calls, catch, log appropriate status code for errors. By logging and handling appropriate status codes for API errors, you facilitate effective error diagnosis and resolution, improving the reliability and user experience of your application.

    javascript

    fetch('https://api.example.com/data')
        .then(response => {
            if (!response.ok) {
                throw new Error(`Request failed with status: ${response.status}`);
            }
            return response.json();
        })
        .catch(error => {
            console.error('API Error:', error.message);
            // Log the status code for further investigation
            if (error.message.includes('status')) {
                const statusCode = error.message.split(': ')[1];
                console.error('Status Code:', statusCode);
            }
            // Handle or display the error appropriately
        }); 
  • Clean up all warnings before check-in (if possible, configure in save actions). By adopting these practices and tools, you maintain a cleaner and more consistent codebase, ensuring better code quality and reducing the likelihood of potential issues or bugs.
  • Format the code before check-in (if possible, configure in save actions). By configuring save actions to format code automatically before check-in, you maintain a consistent code style, improve readability, and streamline collaboration among developers working on the same codebase.
  • To configure save actions for formatting in Visual Studio Code (VS Code), you can install extensions like "Prettier" and set the "editor.formatOnSave" option to true in your settings.
  • javascript

    // VS Code settings.json
    {
        "editor.formatOnSave": true
    } 
  • Use template literals for dynamic strings. Using template literals for dynamic strings enhances readability, simplifies string interpolation, and facilitates the creation of complex strings by embedding variables or expressions directly within the string template.
  • javascript

    // Without template literals
    let name = 'JSChamp';
    let greeting = 'Hello, ' + name + '! How are you today?';
    
    // With template literals
    let greetingTemplate = `Hello, ${name}! How are you today?`;
    
    // Multiline string using template literals
    let multiLineString = `This is a 
    multiline 
    string 
    created with 
    template literals.`;
    
    // Expressions within template literals
    let num1 = 5;
    let num2 = 10;
    let result = `The sum of ${num1} and ${num2} is ${num1 + num2}.`;  
  • Provide the most restricted scope for variables and functions (if used in class). By limiting the scope of variables and functions within classes, you enforce encapsulation, providing a clearer and more organized structure to your code, thus improving its maintainability and preventing unintended interference.
  • javascript

    class MyClass {
        constructor() {
            this._privateVariable = 5; // Private variable within the class
        }
    
        #privateMethod() { // Private method using the private class field
            // Logic for the private method
        }
    
        publicMethod() {
            // Accessing private variable and method within the class
            console.log(this._privateVariable);
            this.#privateMethod();
        }
    } 
  • Global Functions are public only if part of a Global scope. By understanding the concept of global scope and encapsulation within modules or closures, you can control the accessibility of functions, ensuring a more structured and organized codebase.
  • javascript

    function globalFunction() {
        // Logic for the global function
    }
    
    // Accessing the global function from any part of the code
    globalFunction(); // Can be called anywhere
    
    // Module encapsulation
    // Not in global scope, hence not directly accessible globally
    let myModule = (function() {
        function moduleFunction() {
            // Logic for the module function
        }
    
        return {
            moduleFunction: moduleFunction // Exported as part of the module's public interface
        };
    })();
    
    myModule.moduleFunction(); // Accessing the module function through the exported interface 
  • Getters/setters in a class may remain public if not consumed externally. By considering the current and future requirements of the class and its properties, you can decide whether to keep getters/setters public or encapsulate them for more controlled access within the class.
  • javascript

    class MyClass {
        constructor() {
            this._value = 0;
        }
    
        get value() {
            return this._value;
        }
    
        set value(newValue) {
            this._value = newValue;
        }
    }
    
    let instance = new MyClass();
    instance.value = 10; // Directly accessing the setter within the class
    console.log(instance.value); // Directly accessing the getter within the class
    
    //Encapsulation with Private Fields (ES6+):
    
    class MyClass {
        #value = 0;
    
        getValue() {
            return this.#value;
        }
    
        setValue(newValue) {
            this.#value = newValue;
        }
    }
    
    let instance = new MyClass();
    instance.setValue(10); // Using a method to set the value internally
    console.log(instance.getValue()); // Using a method to get the value internally  
  • Member and static variables (excluding constants) should be private. By making member (instance) and static variables private and providing controlled access through methods or interfaces, you ensure better encapsulation, stronger data integrity, and a more maintainable codebase.
  • javascript

    class MyClass {
        #privateInstanceVar = 0;
        static #privateStaticVar = 10;
    
        get privateInstanceVar() {
            return this.#privateInstanceVar;
        }
    
        set privateInstanceVar(newValue) {
            // Apply validation logic or rules if needed before setting the value
            this.#privateInstanceVar = newValue;
        }
    
        static get privateStaticVar() {
            return MyClass.#privateStaticVar;
        }
    
        static set privateStaticVar(newValue) {
            // Apply validation logic or rules if needed before setting the value
            MyClass.#privateStaticVar = newValue;
        }
    } 
  • Use comments to explain complex code. By employing comments effectively to explain complex sections of code, you facilitate better understanding and maintainability, ensuring that others (and your future self) can navigate and comprehend intricate parts of the codebase more easily.
  • javascript

    // This function calculates the Fibonacci sequence up to n numbers
    function fibonacci(n) {
        if (n <= 0) {
            // Return an empty array for non-positive values
            return [];
        } else if (n === 1) {
            // Return [0] for the first number in the sequence
            return [0];
        } else {
            // Calculate the Fibonacci sequence for n numbers
            let sequence = [0, 1];
            for (let i = 2; i < n; i++) {
                sequence.push(sequence[i - 1] + sequence[i - 2]);
            }
            return sequence;
        }
    } 
  • Remove commented code before check-in. By removing commented-out code before check-in, you ensure that the codebase stays organized, making it easier for collaborators to understand the current state of the code and maintain its cleanliness for future development.
  • javascript

    // Old implementation - keeping for reference
    /*
    function oldFunction() {
        // Old logic here
    }
    */ 
  • Comment and maintain complex code throughout changes. By consistently commenting and updating complex code throughout changes, you enable better understanding for yourself and other developers interacting with the codebase. This practice promotes maintainability, facilitates future development, and ensures that the logic remains clear and comprehensible.
  • javascript

    // Calculate the total price including tax
    function calculateTotalPrice(price, taxRate) {
        // Apply tax to the base price
        let taxAmount = price * taxRate;
        
        // Add tax to the base price to get the total price
        let totalPrice = price + taxAmount;
        
        return totalPrice;
    }
                              
  • Classes should not exceed 400 lines. While 400 lines is a guideline, the main aim is to ensure that classes remain focused and manageable. Adjust this guideline based on your team's preferences and the specific needs of your codebase.
  • By adhering to a reasonable limit on class size, you promote maintainability and readability, making it easier for developers to understand and work with the codebase over time.
  • javascript

    class MyClass {
        constructor() {
            // Constructor and initializations
        }
    
        // Methods and functionalities for MyClass
        method1() {
            // Logic for method1
        }
    
        method2() {
            // Logic for method2
        }
    
        // ... Other methods
    
        // Ensure the class remains concise and focused on its purpose
    }
                              
  • Functions should not exceed 75 lines. While 75 lines is a guideline, the primary goal is to maintain the function's focus and readability. Adjust the size based on complexity, readability, and the specific needs of your codebase.
  • By adhering to reasonable limits on function size, you improve code readability, maintainability, and understanding, allowing for more efficient development and easier collaboration among team members.
  • Eliminate unnecessary checks in the code. By removing unnecessary checks, you not only improve the performance of your code but also enhance its readability and maintainability by eliminating redundant logic.
  • javascript

    //Before optimization:
    
    function processValue(value) {
        if (value !== undefined && value !== null) {
            // Process the value
        } else {
            // Handle the case where value is undefined or null
        }
    }
    
    //After optimization:
    
    function processValue(value) {
        // Check for valid value before processing
        if (!value) {
            // Handle the case where value is undefined, null, or falsy
            return;
        }
    
        // Process the value
    }
                              
  • Follow OOP principles (encapsulation, inheritance, polymorphism). Following Object-Oriented Programming (OOP) principles—encapsulation, inheritance, and polymorphism—helps create more organized, maintainable, and scalable codebases.
  • javascript

    //Example of Polymorphism:
    
    class Shape {
        calculateArea() {
            // Common method for all shapes
        }
    }
    
    class Circle extends Shape {
        // Override calculateArea() for Circle
    }
    
    class Square extends Shape {
        // Override calculateArea() for Square
    }
    
    //Example of Inheritance
    
    class Animal {
        makeSound() {
            // Common method for all animals
        }
    }
    
    class Dog extends Animal {
        // Dog inherits makeSound() method from Animal
        // Additional methods and properties specific to Dog
    }
    
    //Example of Encapsulation
    
    class Car {
        #speed = 0; // Private speed variable
    
        accelerate() {
            // Method to change speed
            this.#speed += 10;
        }
    
        getSpeed() {
            // Getter method to access speed
            return this.#speed;
        }
    }
  • Utilize the latest language APIs. By staying abreast of and utilizing the latest language APIs and features, you ensure that your code remains up-to-date, takes advantage of modern capabilities, and potentially improves both performance and readability.
  • Create reusable utility classes when functionality can be reused. By creating reusable utility classes, you promote code reusability, improve maintainability, and foster a more organized and modular structure in your application, making development more efficient and scalable.
  • javascript

    //Example of a Reusable Utility Class:
    
    class MathUtils {
        static add(a, b) {
            return a + b;
        }
    
        static subtract(a, b) {
            return a - b;
        }
    
        // Additional methods for mathematical operations
    }
    
  • Inherit from existing classes when appropriate. By appropriately inheriting from existing classes, you capitalize on code reusability, maintainability, and the extensibility of your codebase, facilitating more efficient development and a more organized structure.
  • javascript

    class Animal {
        makeSound() {
            console.log('Some sound...');
        }
    }
    
    class Dog extends Animal {
        bark() {
            console.log('Woof!');
        }
    }
    unction calculateArea(radius) {
        return PI * radius * radius;
    }
    
  • Use modular code and break it into smaller, reusable modules. By adopting modular code practices and breaking down functionalities into smaller, reusable modules, you enhance code maintainability, reusability, and scalability, making your codebase more manageable and adaptable to changes.
  • Prefer Promises over callbacks for asynchronous operations. By adopting Promises for handling asynchronous operations, you can significantly improve code readability, maintainability, and error management, making your asynchronous code more understandable and easier to maintain.
  • Avoid using eval(). By avoiding the use of eval() and opting for safer alternatives or approaches, you mitigate security risks, improve performance, and maintain the readability and maintainability of your codebase.
  • Avoid magic numbers; use constants or variables. By replacing magic numbers with meaningful constants or variables, you enhance code readability and maintainability, reduce the risk of errors, and ensure consistency throughout the codebase.
  • javascript

    // Magic Number
    function calculateArea(radius) {
        return Math.PI * radius * radius;
    }
    
    // Avoiding Magic Number by using a constant
    const PI = Math.PI;
    function calculateArea(radius) {
        return PI * radius * radius;
    }
    
  • Avoid nested callbacks; use Promises or async/await. By using Promises or async/await syntax, you can avoid nested callback structures, leading to cleaner, more readable, and maintainable asynchronous code that is easier to debug and comprehend.
  • javascript

    function getUserDetails(userId) {
        return getUserById(userId)
            .then(user => {
                return getUserPosts(user.id);
            })
            .then(posts => {
                return processPosts(posts);
            })
            .catch(error => {
                // Handle errors
            });
    }
    
  • Use destructuring for object and array manipulation. By utilizing destructuring for array and object manipulation, you can streamline code, make it more expressive, and facilitate the extraction of values from complex data structures with ease.
  • Avoid using the global object (e.g.,window or global). By minimizing reliance on the global object and embracing module-based development practices, you can write more modular, maintainable, and scalable code, leading to better code organization and easier debugging.
  • Utilize ES6 features. By utilizing ES6 features, you can write more modern, expressive, and efficient JavaScript code, enabling better development practices and enhancing the overall quality of your applications.
  • Use linters (e.g., ESLint) for code standards enforcement. By integrating ESLint or similar linters into your workflow, you ensure code consistency, catch potential issues early, and foster a healthier and more standardized codebase across your projects.
  • Use Array.forEach() instead of for loops. By favoring Array.forEach() over traditional for loops, you can write more declarative and expressive code, enhancing readability and reducing cognitive load when iterating through arrays.
  • javascript

                              // Traditional for loop
    const numbers = [1, 2, 3, 4, 5];
    for (let i = 0; i < numbers.length; i++) {
        console.log(numbers[i]);
    }
    
    // Using Array.forEach()
    numbers.forEach(number => {
        console.log(number);
    });
    
  • Use Object.freeze() to prevent object modification. By using Object.freeze() judiciously on objects that require immutability, you maintain data integrity, prevent accidental modifications, and ensure the stability of critical objects in your JavaScript applications.
  • javascript

    const user = {
        name: 'John',
        age: 30
    };
    
    // Freeze the 'user' object
    Object.freeze(user);
    
    // Attempt to modify a property
    user.age = 40; // This modification will be ignored in strict mode
    
    // Attempt to add a new property
    user.email = 'john@example.com'; // This addition will be ignored in strict mode
    
    console.log(user); // Outputs: { name: 'John', age: 30 } 
  • Use JSON.stringify() to serialize objects. By utilizing JSON.stringify() effectively, you can convert JavaScript objects into a standardized JSON string format, enabling seamless data interchange, storage, and communication across different platforms and systems.

    javascript

    const user = {
        name: 'John',
        age: 30,
        email: 'john@example.com'
    };
    
    // Serialize 'user' object to JSON string
    const jsonString = JSON.stringify(user);
    
    console.log(jsonString);
    // Outputs: {"name":"John","age":30,"email":"john@example.com"}    
  • Use console.log() for debugging; remove logs in production code. By using console.log() for debugging during development and subsequently removing or disabling these logs from production code, you maintain a cleaner and more secure codebase while still benefiting from effective debugging aids during development.