May 18, 2024

Articles

10 Essential Clean Code Principles With TS Examples

Clean code is the foundation of efficient, maintainable, and scalable software. It is not just about making code work, but about making it understandable and easy to manage over time. Robert Cecil Martin, also known as Uncle Bob, has been a significant influence on me and in the world of software development with his book “Clean Code: A Handbook of Agile Software Craftsmanship.” The principles he outlines in this book have become essential guidelines for developers aiming to produce high-quality code.

In this blog post, we will explore the top 10 clean code principles, complemented by practical TypeScript examples. We will demonstrate both bad and good coding practices to illustrate how each principle can be applied effectively in a TypeScript context. By adhering to these principles, you can write code that is not only functional but also clean, readable, and maintainable.

1. Meaningful Names

Bad Example

function cn(p: number, q: number): number {
    return p * q;
}

Good Example

function calculateNetPrice(price: number, quantity: number): number {
    return price * quantity;
}

Meaningful names make code easier to understand. In the good example, calculateNetPrice, price, and quantity are clear and descriptive.

2. Functions Should Do One Thing

Bad Example

function processOrder(order: Order) {
    validateOrder(order);
    calculateOrderTotal(order);
    saveOrder(order);
}

Good Example

function validateOrder(order: Order) {
    // validation logic
}

function calculateOrderTotal(order: Order) {
    // calculation logic
}

function saveOrder(order: Order) {
    // saving logic
}

Each function in the good example is responsible for a single task, making the code more modular and maintainable.

3. Avoid Side Effects

Bad Example

let total = 0;

function addToTotal(amount: number) {
    total += amount;
}

Good Example

function calculateNewTotal(currentTotal: number, amount: number): number {
    return currentTotal + amount;
}

Avoiding side effects leads to more predictable and testable code. The good example avoids modifying external state.

4. Use Descriptive Function Names

Bad Example

function handle(data: Data) {
    // handling logic
}

Good Example

function handleUserRegistration(data: Data) {
    // registration logic
}

Descriptive function names clarify the function’s purpose. In the good example, handleUserRegistration specifies what is being handled.

5. Use Objects and Data Structures

Bad Example

function calculateArea(width: number, height: number): number {
    return width * height;
}

Good Example

class Rectangle {
    constructor(public width: number, public height: number) {}

    calculateArea(): number {
        return this.width * this.height;
    }
}

const rectangle = new Rectangle(10, 5);
console.log(rectangle.calculateArea());

Using objects and data structures, as shown in the good example, encapsulates related data and behaviors, improving code organization.

6. Prefer Exceptions Over Returning Error Codes

Bad Example

function readFile(path: string): number {
    if (!fileExists(path)) {
        return -1;
    }
    // read file logic
    return 0;
}

Good Example

function readFile(path: string) {
    if (!fileExists(path)) {
        throw new Error("File not found");
    }
    // read file logic
}

Using exceptions makes error handling more explicit and avoids the pitfalls of checking error codes.

7. Keep Functions Small

Bad Example

function manageOrder(order: Order) {
    validateOrder(order);
    let total = calculateOrderTotal(order);
    saveOrder(order);
    sendOrderConfirmation(order);
}

Good Example

function manageOrder(order: Order) {
    validateOrder(order);
    processPayment(order);
    sendConfirmation(order);
}

function processPayment(order: Order) {
    let total = calculateOrderTotal(order);
    saveOrder(order);
}

function sendConfirmation(order: Order) {
    sendOrderConfirmation(order);
}

Small functions are easier to understand, test, and maintain. Breaking down manageOrder into smaller functions improves clarity.

8. Avoid Magic Numbers

Bad Example

function calculateDiscount(price: number): number {
    return price * 0.1;
}

Good Example

const DISCOUNT_RATE = 0.1;

function calculateDiscount(price: number): number {
    return price * DISCOUNT_RATE;
}

Replacing magic numbers with named constants improves code readability and maintainability.

9. Use Clear and Consistent Formatting

Bad Example

function doSomething(){if(condition){return true;}else{return false;}}

Good Example

function doSomething(): boolean {
    if (condition) {
        return true;
    } else {
        return false;
    }
}

Clear and consistent formatting enhances code readability. The good example follows a consistent style with proper indentation.

10. Write Tests

Bad Example

// No tests
function add(a: number, b: number): number {
    return a + b;
}

Good Example

function add(a: number, b: number): number {
    return a + b;
}

// Tests
describe("add", () => {
    it("should return the sum of two positive numbers", () => {
        expect(add(2, 3)).toBe(5);
    });

    it("should return the sum of a positive and a negative number", () => {
        expect(add(5, -3)).toBe(2);
    });

    it("should return the sum of two negative numbers", () => {
        expect(add(-2, -3)).toBe(-5);
    });

    it("should return 0 when adding 0 and 0", () => {
        expect(add(0, 0)).toBe(0);
    });
});

Writing tests has been personally quite helpful and useful for me. it ensures that your code works as expected and helps prevent bugs. In the good example, tests are written using a testing framework (like Jest, my favorite testing framework), covering various scenarios for the add function.

In conclusion, Writing clean code is more than a best practice; it’s a professional standard that ensures your software is robust, maintainable, and scalable. with tips like the ones that were mentioned in this post, developers can create code that is not only functional but also elegant and efficient and good for teams!