+2

Nghệ thuật viết mã sạch: Hướng dẫn thực hành JavaScript dễ bảo trì

Viết mã sạch không chỉ là lựa chọn thẩm mỹ mà còn là thực hành cơ bản giúp giảm lỗi, tăng cường hợp tác và đảm bảo khả năng bảo trì lâu dài cho các dự án phần mềm. Hướng dẫn trong bài viết này sẽ giúp bạn khám phá các nguyên tắc, thực hành và phương pháp thực dụng để viết mã JavaScript sao cho gọn gàng và sạch sẽ.

Nguyên tắc cốt lõi để viết các đoạn mã sạch

1. Khả năng đọc là trên hết

Mã được đọc nhiều hơn rất nhiều lần so với việc nó được viết. Mã tốt kể một câu chuyện mà các lập trình viên khác (bao gồm cả chính bạn trong tương lai) có thể dễ dàng hiểu được.

VD về đoạn mã tệ:

const x = y + z / 3.14;

Đoạn mã tốt nên viết như thế này:

const radius = diameter / Math.PI;

2. Khả năng bảo trì là quan trọng

Mã có thể bảo trì được là mã dạng module, tuân theo các nguyên tắc SOLID và giảm thiểu các dependency.

VD về đoạn mã tệ:

function calculateArea(radius) {
    // ...lots of nested logic...
    // ...complex calculations...
    // ...multiple responsibilities...
    return result;
}

Đoạn mã tốt nên viết như thế này:

function calculateArea(radius) {
    return Math.PI * radius * radius;
}

3. Đảm bảo khả năng kiểm thử

Mã sạch vốn đã có thể kiểm thử được. Hãy chia nhỏ các hoạt động phức tạp thành các đơn vị nhỏ hơn, có thể xác minh được.

VD về đoạn mã tệ:

function getRandomNumber() {
    return Math.random();
}

Đoạn mã tốt nên viết như thế này:

function getRandomNumber(randomGenerator = Math.random) {
    return randomGenerator();
}

4. Khả năng mở rộng

Mã sạch sẽ góp phần phát triển một cách nhịp nhàng cùng với dự án của bạn.

VD về đoạn mã tệ:

function handleUserData(data) {
    if (data.type === 'admin') {
        // 50 lines of admin logic
    } else if (data.type === 'user') {
        // 50 lines of user logic
    } else if (data.type === 'guest') {
        // 50 lines of guest logic
    }
}

Bạn nên sửa chúng như thế này sẽ tốt hơn:

const userHandlers = {
    admin: handleAdminData,
    user: handleUserData,
    guest: handleGuestData
};

function handleUserData(data) {
    return userHandlers[data.type](data);
}

Những cạm bẫy thường gặp khi viết code và giải pháp

1. Thế tiến thoái lưỡng nan về đặt tên

Khi viết code thì tên nên thể hiện ý định và ngữ cảnh.

VD về đoạn mã tệ hại:

function calc(a, b) {
    return a * b + TAX;
}

Chúng nên sửa lại thế này:

function calculatePriceWithTax(basePrice, taxRate) {
    const TAX_MULTIPLIER = 1;
    return basePrice * taxRate + TAX_MULTIPLIER;
}

2. Tránh Callback Hell càng tốt

Thay thế các callback lồng nhau bằng các mẫu async hiện đại.

VD về đoạn mã tệ hại:

getUserData(userId, function(user) {
    getOrders(user.id, function(orders) {
        processOrders(orders, function(result) {
            // More nesting...
        });
    });
});

Chúng nên được viết lại như sau:

async function processUserOrders(userId) {
    try {
        const user = await getUserData(userId);
        const orders = await getOrders(user.id);
        return await processOrders(orders);
    } catch (error) {
        handleError(error);
    }
}

3. Quản lý cấu hình

Thiết lập một nguồn duy nhất cho các giá trị cấu hình.

VD không nên làm theo:

// Scattered across multiple files
const API_KEY = 'abc123';
const API_ENDPOINT = 'https://api.example.com';

Bạn nên sửa chúng như thế này:

// config.js
export const config = {
    api: {
        key: process.env.API_KEY,
        endpoint: process.env.API_ENDPOINT
    }
};

Viết mã sạch sẽ phải đánh đổi một vài thứ

1. Hiệu suất so với khả năng đọc

Để viết ra một đoạn mã sạch, bạn có thể sẽ phải đánh đổi khả năng dễ đọc của mã so với hiệu suất mà nó đem lại.

VD:

// Dễ đọc hơn, hiệu suất kém hơn một chút
const doubledNumbers = numbers.map(n => n * 2);
// Ít dễ đọc hơn, nhưng hiệu suất cao hơn (khi hiệu suất là rất quan trọng)
for (let i = 0; i < numbers.length; i++) numbers[i] *= 2;

2. Sử dụng các hàm thuần túy luôn đi kèm tác dụng phụ

Mặc dù các hàm thuần túy là lý tưởng nhưng các ứng dụng thực tế cần các tác dụng phụ. Hãy cô lập và quản lý chúng cẩn thận:

VD:

// Hàm thuần túy
function calculateTotal(items) {
    return items.reduce((sum, item) => sum + item.price, 0);
}

// Tác dụng phụ cần thiết, được phân tách rõ ràng
async function saveOrderToDatabase(order) {
    await database.orders.save(order);
    logOrderCreation(order);
}

Kết luận

Mã sạch là một hành trình chứ không phải là đích đến. Mặc dù sự sạch sẽ hoàn hảo có thể sẽ không đạt được, nhưng việc phấn đấu cho mã sạch thông qua các thực hành nhất quán và sự đánh đổi tính thực dụng sẽ dẫn bạn đạt được trình độ viết ra các cơ sở mã dễ bảo trì, đáng tin cậy và hợp tác hơn. Hãy nhớ rằng ngữ cảnh khi viết code rất quan trọng — những gì sạch sẽ trong một tình huống có thể không đúng trong tình huống khác. Điều quan trọng là tìm ra sự cân bằng phù hợp cho nhu cầu cụ thể của bạn trong khi vẫn duy trì mã mà những người khác (bao gồm cả chính bạn trong tương lai) sẽ cảm ơn bạn vì đã viết.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí