Bắt đầu từ KISS và DRY
KISS (Keep It Simple, Stupid): giải pháp đơn giản nhất hoạt động được. DRY (Don’t Repeat Yourself): một logic chỉ tồn tại một nơi. Đừng sinh ra “thư viện” cho thứ mới dùng một lần.
Gộp 2 chỗ giống nhau 50% thành một hàm “linh hoạt” với 4 tham số boolean — rồi sau này ai gọi cũng phải đọc hàm để hiểu. DRY áp cho ý nghĩa logic, không phải cho khuôn dạng code.
SOLID: 5 nguyên tắc kiến trúc
| Nguyên tắc | Ý nghĩa | Dấu hiệu vi phạm |
|---|---|---|
| S — Single Responsibility | Mỗi class/hàm có đúng một lý do để thay đổi | Hàm vừa gọi API vừa render UI vừa lưu DB |
| O — Open/Closed | Mở cho mở rộng, đóng cho sửa đổi | Mỗi tính năng mới lại sửa hàm cũ bằng if |
| L — Liskov | Class con thay thế được class cha mà không phá vỡ | Overrride method ném lỗi bất ngờ |
| I — Interface Segregation | Đừng bắt class phụ thuộc method nó không dùng | Interface có 10 method nhưng chỉ dùng 2 |
| D — Dependency Inversion | Phụ thuộc abstraction, không phụ thuộc implementation | Hàm new Redis trực tiếp thay vì nhận qua tham số |
S và D — hai cái bạn gặp hằng ngày
Single Responsibility: tách controller (nhận request), service (logic), repository (truy cập data). Dependency Inversion: truyền dependency vào qua tham số/constructor thay vì tự new bên trong — đó chính là nền của việc test (bạn sẽ thay DB thật bằng mock).
// File: before.js
// Một hàm làm quá nhiều việc, khó test
export async function registerUser(email, password) {
const redis = new Redis(); // tự new, khó thay thế
const user = await User.create({ email, password });
await redis.set("user:" + user.id, JSON.stringify(user));
await mailer.sendWelcome(email); // gọi service bên trong
return user;
}
// File: after.js
// Nhận dependency qua tham số -> thay được, test được
export function registerUser(userRepo, cache, mailer) {
return async function (email, password) {
const user = await userRepo.create({ email, password });
await cache.set("user:" + user.id, JSON.stringify(user));
await mailer.sendWelcome(email);
return user;
};
}
// Trong test: truyền fake cache, fake mailer vào
Thước đo đơn giản: 3 câu hỏi
Khi review code, hỏi: (1) Tôi có hiểu hàm này làm gì trong 10 giây không? (2) Nếu thay đổi một yêu cầu, tôi sửa ít chỗ nhất có thể chứ? (3) Tôi có thể test nó mà không cần khởi động cả hệ thống không?
❓ Dấu hiệu rõ nhất của vi phạm Single Responsibility?
- Áp dụng KISS và DRY có chừng mực
- Thuộc 5 chữ cái của SOLID
- Truyền dependency qua tham số để test được
- Review code bằng 3 câu hỏi nhanh