Hướng dẫn Clean Code: Nguyên tắc SOLID viết dễ hiểu cho dev mới

Clean code không chỉ là code chạy được, mà còn phải dễ đọc, dễ bảo trìdễ mở rộng. Bộ nguyên tắc SOLID giúp bạn tổ chức mã tốt hơn, giảm nợ kỹ thuật và tăng tốc phát triển về lâu dài. Bài viết này giải thích ngắn gọn từng nguyên tắc, kèm demo trực quan để bạn áp dụng ngay.

Hướng dẫn Clean Code: Nguyên tắc SOLID viết dễ hiểu cho dev mới

SOLID là gì?

SOLID gồm 5 nguyên tắc thiết kế hướng đối tượng:

  • S – Single Responsibility Principle
  • O – Open/Closed Principle
  • L – Liskov Substitution Principle
  • I – Interface Segregation Principle
  • D – Dependency Inversion Principle

Mục tiêu: mỗi module có một trách nhiệm rõ ràng, dễ mở rộng mà không sửa code cũ, dễ testdễ tái sử dụng.

1. Single Responsibility Principle (SRP)

Mỗi class chỉ nên có một lý do để thay đổi. Đừng nhồi nhiều chức năng vào một class.

# Sai: vừa quản lý user vừa gửi email
class UserService:
    def create_user(self, user): ...
    def send_welcome_email(self, user): ...

# Đúng: tách rõ trách nhiệm
class UserService:
    def create_user(self, user): ...

class EmailService:
    def send_welcome_email(self, user): ...

2. Open/Closed Principle (OCP)

Class nên mở rộng được nhưng không sửa đổi code gốc. Thay vì sửa class, hãy kế thừa hoặc dùng abstraction.

// Sai: phải sửa code nếu thêm loại shape mới
class AreaCalculator {
    double calc(Object shape) {
        if (shape instanceof Circle) ...
        if (shape instanceof Square) ...
    }
}

// Đúng: đóng với sửa đổi, mở với mở rộng
interface Shape {
    double area();
}

class Circle implements Shape { ... }
class Square implements Shape { ... }

class AreaCalculator {
    double calc(Shape shape) {
        return shape.area();
    }
}

3. Liskov Substitution Principle (LSP)

Class con có thể thay thế class cha mà không phá vỡ chương trình.

// Sai: class con vi phạm hành vi cha
class Bird {
    void fly();
}

class Ostrich extends Bird {
    void fly() { throw new UnsupportedOperationException(); }
}

// Đúng: thiết kế hierarchy hợp lý
interface Bird { }
interface Flyable extends Bird {
    void fly();
}

class Sparrow implements Flyable { ... }
class Ostrich implements Bird { ... }

4. Interface Segregation Principle (ISP)

Đừng ép class implement những method không dùng. Chia nhỏ interface để cụ thể hơn.

// Sai: interface quá to
interface Machine {
  start();
  stop();
  print();
  scan();
}

class Printer implements Machine {
  start() {}
  stop() {}
  print() {}
  scan() { throw "Not supported"; }
}

// Đúng: chia nhỏ interface
interface Printer {
  print();
}
interface Scanner {
  scan();
}

5. Dependency Inversion Principle (DIP)

Code nên phụ thuộc vào abstraction thay vì implementation cụ thể để dễ test và thay thế.

// Sai: phụ thuộc trực tiếp vào EmailService
class UserController {
    private EmailService emailService = new EmailService();
}

// Đúng: phụ thuộc abstraction
interface MessageService {
    void send(String msg);
}

class EmailService implements MessageService { ... }

class UserController {
    private MessageService service;
    public UserController(MessageService s) {
        this.service = s;
    }
}

Demo trực quan: từ “cứng” sang “mềm” với OCP

Giả sử bạn viết app order pizza. Không áp dụng SOLID, code sẽ khó mở rộng:

# Version chưa SOLID
class PizzaOrder:
    def process_order(self, pizza_type):
        if pizza_type == "Margherita":
            print("Making Margherita")
        elif pizza_type == "Pepperoni":
            print("Making Pepperoni")

Muốn thêm loại pizza mới phải sửa trực tiếp vào PizzaOrder → vi phạm OCP.

Áp dụng SOLID (abstraction + composition):

from abc import ABC, abstractmethod

class Pizza(ABC):
    @abstractmethod
    def prepare(self):
        pass

class Margherita(Pizza):
    def prepare(self):
        print("Making Margherita")

class Pepperoni(Pizza):
    def prepare(self):
        print("Making Pepperoni")

class OrderProcessor:
    def __init__(self, pizza: Pizza):
        self.pizza = pizza

    def process(self):
        self.pizza.prepare()

# Demo
order = OrderProcessor(Margherita())
order.process()  # Making Margherita

Khi thêm loại pizza mới, chỉ cần tạo class kế thừa Pizza, không phải chạm vào OrderProcessor. Dễ test, dễ mở rộng.

Kết luận

SOLID giúp code rõ ràng, dễ bảo trì, dễ mở rộngdễ test. Khi mới bắt đầu, hãy tập thói quen: tách trách nhiệm nhỏ, thiết kế hướng abstraction, và luôn tự hỏi “thêm tính năng mới có cần sửa code cũ không?”. Đó là cốt lõi của clean code.

Bình luận


  • Không có bình luận.

Init Toolbox

Nhấn Ctrl + \ trên máy tính, hoặc vuốt sang trái ở bất kỳ đâu trên mobile.

Đăng nhập





Đang tải...