Nội dung

DaiPhan

DaiPhan

Full-Stack Developer

Full-stack developer passionate about modern web technologies, best practices, and sharing knowledge with the community.

Skills & Expertise

JavaScript TypeScript React Node.js DevOps
150+
Articles
50k+
Readers
4.9
Rating

Clean Code Principles: Viết Code Sạch Như Thế Nào?

Tìm hiểu các nguyên tắc viết code sạch giúp code dễ đọc, dễ bảo trì và mở rộng

Clean Code Principles: Viết Code Sạch Như Thế Nào?

Clean Code không chỉ là code chạy đúng, mà là code dễ đọc, dễ hiểu và dễ bảo trì. Trong bài viết này, chúng ta sẽ tìm hiểu các nguyên tắc cơ bản để viết code sạch.

1. Đặt tên có ý nghĩa

❌ Code xấu

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

let x = 10;
let y = 20;
let z = d(x, y);

✅ Code sạch

function calculateTotalPrice(itemPrice, taxAmount) {
  return itemPrice + taxAmount;
}

const itemPrice = 10;
const taxAmount = 20;
const totalPrice = calculateTotalPrice(itemPrice, taxAmount);

2. Functions nên nhỏ và làm một việc

❌ Function làm quá nhiều việc

function processUserData(users) {
  // Validate users
  for (let user of users) {
    if (!user.email) throw new Error('Email required');
    if (!user.name) throw new Error('Name required');
  }
  
  // Save to database
  for (let user of users) {
    database.save(user);
  }
  
  // Send emails
  for (let user of users) {
    emailService.sendWelcomeEmail(user.email);
  }
  
  // Log activities
  for (let user of users) {
    logger.log(`User ${user.name} processed`);
  }
}

✅ Tách thành nhiều functions nhỏ

function validateUsers(users) {
  return users.every(user => {
    if (!user.email) throw new Error('Email required');
    if (!user.name) throw new Error('Name required');
    return true;
  });
}

function saveUsersToDatabase(users) {
  return users.map(user => database.save(user));
}

function sendWelcomeEmails(users) {
  return users.map(user => 
    emailService.sendWelcomeEmail(user.email)
  );
}

function logUserActivities(users) {
  return users.map(user => 
    logger.log(`User ${user.name} processed`)
  );
}

function processUserData(users) {
  validateUsers(users);
  saveUsersToDatabase(users);
  sendWelcomeEmails(users);
  logUserActivities(users);
}

3. Tránh comments không cần thiết

❌ Comments dư thừa

// Increment counter by 1
counter++;

// Check if user is logged in
if (isLoggedIn) {
  // Show dashboard
  showDashboard();
}

✅ Code tự giải thích

function updateProgress() {
  counter++;
}

function displayUserDashboard() {
  if (isLoggedIn) {
    showDashboard();
  }
}

4. Xử lý lỗi một cách rõ ràng

❌ Error handling mơ hồ

function getUser(id) {
  try {
    return database.find(id);
  } catch (error) {
    return null;
  }
}

✅ Error handling cụ thể

class UserNotFoundError extends Error {
  constructor(userId) {
    super(`User with ID ${userId} not found`);
    this.name = 'UserNotFoundError';
    this.userId = userId;
  }
}

function getUser(id) {
  try {
    const user = database.find(id);
    
    if (!user) {
      throw new UserNotFoundError(id);
    }
    
    return user;
  } catch (error) {
    if (error instanceof UserNotFoundError) {
      throw error;
    }
    
    throw new Error(`Failed to get user: ${error.message}`);
  }
}

5. Sử dụng Constants và Configuration

❌ Magic numbers

function calculatePrice(quantity) {
  if (quantity > 100) {
    return quantity * 0.9; // 10% discount
  }
  return quantity * 1.0;
}

✅ Sử dụng constants

const PRICING = {
  BULK_DISCOUNT_THRESHOLD: 100,
  BULK_DISCOUNT_RATE: 0.9,
  STANDARD_RATE: 1.0,
  DISCOUNT_PERCENTAGE: 10
};

function calculatePrice(quantity) {
  if (quantity > PRICING.BULK_DISCOUNT_THRESHOLD) {
    return quantity * PRICING.BULK_DISCOUNT_RATE;
  }
  return quantity * PRICING.STANDARD_RATE;
}

6. SOLID Principles

Single Responsibility Principle (SRP)

Mỗi class/function chỉ nên có một lý do để thay đổi.

// ❌ Vi phạm SRP
class UserService {
  createUser(userData) {
    // Validate user
    // Save to database
    // Send welcome email
    // Log activity
  }
}

// ✅ Tuân thủ SRP
class UserValidator {
  validate(userData) {
    // Validation logic
  }
}

class UserRepository {
  save(userData) {
    // Database logic
  }
}

class EmailService {
  sendWelcomeEmail(email) {
    // Email logic
  }
}

class UserService {
  constructor(validator, repository, emailService) {
    this.validator = validator;
    this.repository = repository;
    this.emailService = emailService;
  }
  
  async createUser(userData) {
    this.validator.validate(userData);
    const user = await this.repository.save(userData);
    await this.emailService.sendWelcomeEmail(user.email);
    return user;
  }
}

7. Testing Clean Code

Viết test cho code sạch

describe('UserService', () => {
  let userService;
  let mockValidator;
  let mockRepository;
  let mockEmailService;
  
  beforeEach(() => {
    mockValidator = { validate: jest.fn() };
    mockRepository = { save: jest.fn() };
    mockEmailService = { sendWelcomeEmail: jest.fn() };
    
    userService = new UserService(
      mockValidator,
      mockRepository,
      mockEmailService
    );
  });
  
  test('should create user successfully', async () => {
    const userData = { name: 'John', email: 'john@example.com' };
    const savedUser = { id: 1, ...userData };
    
    mockRepository.save.mockResolvedValue(savedUser);
    
    const result = await userService.createUser(userData);
    
    expect(mockValidator.validate).toHaveBeenCalledWith(userData);
    expect(mockRepository.save).toHaveBeenCalledWith(userData);
    expect(mockEmailService.sendWelcomeEmail).toHaveBeenCalledWith(userData.email);
    expect(result).toEqual(savedUser);
  });
});

8. Tools hỗ trợ Clean Code

ESLint Configuration

{
  "extends": ["eslint:recommended", "plugin:import/recommended"],
  "rules": {
    "max-lines-per-function": ["error", { "max": 20 }],
    "max-depth": ["error", { "max": 3 }],
    "complexity": ["error", { "max": 5 }],
    "no-nested-ternary": "error",
    "prefer-const": "error",
    "no-var": "error"
  }
}

Prettier Configuration

{
  "semi": true,
  "trailingComma": "es5",
  "singleQuote": true,
  "printWidth": 80,
  "tabWidth": 2
}

Kết luận

Clean Code là một journey, không phải destination. Bắt đầu với:

  1. Đặt tên có ý nghĩa - Đây là bước đơn giản nhất nhưng có impact lớn nhất
  2. Functions nhỏ - Mỗi function chỉ làm một việc
  3. Tránh comments dư thừa - Code phải tự giải thích
  4. Xử lý lỗi rõ ràng - Không bao giờ swallow exceptions
  5. Sử dụng constants - Không có magic numbers
  6. Follow SOLID principles - Đặc biệt là SRP

💡 Remember: Code bạn viết hôm nay sẽ được đọc bởi bạn trong tương lai hoặc đồng nghiệp. Hãy viết code như thể người maintain nó là một psychopath biết nơi bạn sống! 😄


Bài viết này là phần đầu trong series về Clean Code. Trong các bài tiếp theo, chúng ta sẽ explore design patterns, refactoring techniques, và code review best practices.