Ikigai's blog
Home
/
Blog
/
Understanding the 3 Main Principles of Clean Code with Simple TypeScript Examples

Understanding the 3 Main Principles of Clean Code with Simple TypeScript Examples

What is Clean Code?

Clean code is a term used to describe code that is easy to read, understand, and maintain. It is a set of principles that help developers write code that is not only functional but also easy to read and understand by others. In this blog post, we will explore the main principles of clean code and provide code examples in TypeScript of what to do and what not to do, along with explanations of why they are either good or bad.

First Principle: Readability

The code should be easy to read and understand by anyone who looks at it (sometimes even people unitiated at the subject). This can be achieved by using meaningful variable and function names, consistent indentation, and commenting.

Example of good code:

function calculateTotalPrice(price: number, tax: number): number {
    /*
    This function calculates the total price of an item, including tax.
    */
    
    const totalPrice = price + (price * tax)
    return totalPrice
};

In this example, the function name calculateTotalPrice clearly describes its purpose. The comment above the function also provides additional information about what the function does. This makes it easy for someone to understand the code at a glance.

Example of bad code:

function ctp(p: number, t: number): number {
    const tp = p + (p * t);
    return tp;
}

In this example, the function name ctp and variables p and t are not meaningful, making it harder to understand what the code is doing. The lack of comments also makes it difficult to understand the purpose of the function. The code author probably thought that anyone would understand that, clearly, ctp are the initials for "calculate", "total" and "price", right? But the recently hired developer didn't, unfortunately.

Second Principle: Maintainability

The code should be easy to modify and fix when needed. This can be achieved by writing modular and reusable code.

Example of good code:

function calculateTotalPrice(price: number, tax: number): number {
    /*
    This function calculates the total price of an item, including tax.
    */
    const totalPrice = price + (price * tax);
    return totalPrice;
}

function calculateDiscount(price: number, discount: number): number {
    /*
    This function calculates the discount of an item.
    */
    const discountedPrice = price - (price * discount);
    return discountedPrice;
}

function calculateFinalPrice(price: number, tax: number, discount: number): number {
    /*
    This function calculates the final price of an item after applying tax and discount.
    */
    const totalPrice = calculateTotalPrice(price, tax);
    const discountedPrice = calculateDiscount(totalPrice, discount);
    return discountedPrice;
}

In this example, the code is modular and reusable. Each function has a specific purpose, and they are called in the calculateFinalPrice function to achieve the final result. This makes it easy to modify or fix any of the functions without affecting the other parts of the code.

Example of bad code:

function calculateFinalPrice(price: number, tax: number, discount: number): number {
    
    const totalPrice = price + (price * tax);
    const discountedPrice = price - (price * discount);
    
    return discountedPrice;
}

In this example, the code is not modular. The same calculation is being repeated multiple times, making it harder to maintain. If we need to change the way we calculate the total price or the discount, we'll have to update this one and only function, making it more complex with every iteration. Better to keep things separate.

Third Principle: Reusability

The code should be written in a way that allows it to be easily reused in other parts of the codebase. This can be achieved by using functions and classes that are designed to be used in multiple places and by abstracting away complex logic.

Example of good code:

class Item {
    private _price: number;
    private _tax: number;
    private _discount: number;

    constructor(price: number, tax: number, discount: number) {
        this._price = price;
        this._tax = tax;
        this._discount = discount;
    }

    public getTotalPrice(): number {
        /*
        This function calculates the total price of an item, including tax.
        */
        
        return this._price + (this._price * this._tax);
    }

    public getDiscountedPrice(): number {
        /*
        This function calculates the discounted price of an item.
        */
        
        return this._price - (this._price * this._discount);
    }

    public getFinalPrice(): number {
        /*
        This function calculates the final price of an item after applying tax and discount.
        */
        
        return this.getDiscountedPrice();
    }
}

In this example, we have a class Item that encapsulates the logic for calculating the total price, discounted price, and final price of an item. This class can be reused in multiple parts of the codebase, and any changes made to the class will not affect the rest of the code.

Example of bad code:

function calculateFinalPrice(price: number, tax: number, discount: number): number {
    
    const totalPrice = price + (price * tax);
    const discountedPrice = price - (price * discount);
    
    return discountedPrice;
}

We've seen this example before, because it also violates the third principle: the code is not reusable. The same calculation is being repeated multiple times and cannot be easily reused in other parts of the codebase. Say you have an item with €10.00 price, 0.1 (10%) tax, and 0.3 (30%) discount: every time you wanted to print or use that item's final price in your code, you would have to provide these values to the function. Otherwise, in our previous code example, we only have to state these values once, when we instantiate an object of the Item class.

In conclusion, clean code is essential for making sure that your code is easy to read, understand, and maintain. By following the principles of readability, maintainability, and reusability, you can ensure that your code is not only functional but also easy to work with for yourself and others. It's always good to keep reviewing your code and see if it meets these principles, and if not, make necessary adjustments to make it cleaner.

Now that you know more about clean code, how about implementing these practices in your company? At Ikigai we help companies with:

  • Developing better and cleaner software
  • Upgrading your product to meet your business needs
  • Building incredible products from scratch

Get in touch and let us know how we can help! We'll be glad to be your full-stack digital partner for everything tech.

January 20, 2023
Alexandre Dias
More blog posts