🛠️ Ngày 5/100: Sức Mạnh Của DRY - Đừng Lặp Lại Chính Mình
Dành cho những người thích đi thẳng vào vấn đề:
DRY là gì? Là nguyên tắc "Don't Repeat Yourself" - Đừng Lặp Lại Chính Mình. Mỗi một đoạn logic chỉ nên tồn tại ở một nơi duy nhất.
Tại sao phải DRY? Vì khi bạn copy-paste code, việc sửa một lỗi hay thay đổi một yêu cầu sẽ biến thành cơn ác mộng. Bạn phải tìm và sửa ở TẤT CẢ các nơi. Bỏ sót một chỗ là sinh ra bug.
Hậu quả của việc "ướt" (WET - Write Everything Twice)? Khó bảo trì, dễ phát sinh lỗi ngớ ngẩn, code phình to và khó hiểu.
Làm sao để "sấy khô"? Sử dụng hàm (function), lớp (class), module, và các file cấu hình (config).
Chắc chắn bạn đã từng ở trong tình huống này: Bạn cần viết một đoạn logic tương tự như một đoạn đã có ở đâu đó trong dự án. Suy nghĩ đầu tiên nảy ra trong đầu là gì?
"À, có sẵn rồi! Copy... Paste... Sửa lại một chút... Xong!"
Nhanh gọn, tiện lợi và code chạy ngay lập tức. Cảm giác thật tuyệt vời.
Nhưng bạn ơi, cái hành động copy-paste tưởng chừng vô hại đó chính là một trong những mầm mống lớn nhất của "nợ kỹ thuật" mà chúng ta đã nói hôm qua. Nó vi phạm một nguyên tắc vàng trong ngành kỹ thuật phần mềm: DRY - Don't Repeat Yourself.
DRY Là Gì và Tại Sao Nó Lại Quan Trọng Đến Vậy?
DRY - Đừng Lặp Lại Chính Mình - là một triết lý vô cùng đơn giản: Mỗi một mẩu thông tin, một đoạn logic xử lý không nên bị lặp lại ở nhiều nơi trong hệ thống. Nó phải có một đại diện duy nhất, rõ ràng và đáng tin cậy.
Nói theo ngôn ngữ của lập trình viên: Nếu bạn phải thay đổi một thuật toán hay một quy tắc nghiệp vụ, bạn chỉ nên phải sửa nó ở MỘT NƠI DUY NHẤT.
Hãy xem một ví dụ đơn giản:
Giả sử bạn cần tính tổng giá trị đơn hàng (đã bao gồm 10% VAT) ở hai nơi khác nhau: trong giỏ hàng và ở trang thanh toán.
Cách viết "ướt" (WET - Write Everything Twice):
JavaScript
// Trong file GioHang.js
function tinhTongTienGioHang(danhSachSanPham) {
let tongTien = 0;
for (let sp of danhSachSanPham) {
tongTien += sp.gia * sp.soLuong;
}
// Lặp lại logic tính VAT
return tongTien * 1.1;
}
// Trong file ThanhToan.js
function hienThiTongTienThanhToan(tongTienChuaThue) {
// Lặp lại logic tính VAT
const tongTienCuoiCung = tongTienChuaThue * 1.1;
console.log("Tổng tiền cần thanh toán: ", tongTienCuoiCung);
}
Mọi thứ có vẻ ổn, cho đến một ngày... chính phủ thay đổi thuế VAT thành 8%. Giờ bạn phải làm gì? Bạn phải lật tung cả dự án lên, tìm mọi nơi có * 1.1 và sửa thành * 1.08. Nếu bạn bỏ sót một chỗ, hệ thống của bạn sẽ tính toán sai, gây thất thoát cho công ty hoặc khách hàng.
Cách viết "khô ráo" (DRY):
JavaScript
// Trong một file tiện ích, ví dụ: utils/tinhToan.js
const VAT = 0.08; // Lưu giá trị ở một nơi duy nhất
export function tinhTienSauThue(soTien) {
// Logic tính thuế chỉ tồn tại ở đây
return soTien * (1 + VAT);
}
// Trong file GioHang.js
import { tinhTienSauThue } from './utils/tinhToan.js';
function tinhTongTienGioHang(danhSachSanPham) {
// ... logic tính tổng tiền
return tinhTienSauThue(tongTien); // Gọi hàm tái sử dụng
}
// Trong file ThanhToan.js
import { tinhTienSauThue } from './utils/tinhToan.js';
function hienThiTongTienThanhToan(tongTienChuaThue) {
const tongTienCuoiCung = tinhTienSauThue(tongTienChuaThue); // Gọi hàm tái sử dụng
console.log("Tổng tiền cần thanh toán: ", tongTienCuoiCung);
}
Bây giờ, nếu thuế VAT thay đổi, bạn chỉ cần sửa giá trị của biến VAT ở một nơi duy nhất. Toàn bộ hệ thống sẽ tự động cập nhật theo. Thật tuyệt vời phải không?
Cái Giá Phải Trả Khi Code Bị "Ướt"
Tôi đã từng thấy những dự án mà việc thay đổi một câu chữ hiển thị trên giao diện cũng mất cả ngày trời, chỉ vì câu chữ đó được copy-paste ở 20 file khác nhau. Đó là một cơn ác mộng thực sự.
Khi bạn không tuân thủ DRY, bạn đang tự gieo mầm cho những thảm họa trong tương lai:
-
Khó bảo trì: Đây là hậu quả lớn nhất. Một thay đổi nhỏ cũng đòi hỏi nỗ lực tìm kiếm và sửa đổi rất lớn.
-
Dễ sinh bug: Rất dễ bỏ sót một vị trí khi sửa đổi, dẫn đến dữ liệu và hành vi không nhất quán trong hệ thống.
-
Lãng phí thời gian: Thay vì tập trung phát triển tính năng mới, bạn lại tốn thời gian vào việc sửa những thứ lặp đi lặp lại.
-
Khó hiểu: Codebase phình to một cách không cần thiết, khiến người mới khó nắm bắt được luồng logic chung.
Làm Sao Để Luôn Giữ Cho Code "Khô Ráo"?
Hãy tập thói quen "dị ứng" với việc lặp lại. Mỗi khi bạn chuẩn bị copy-paste một đoạn code, hãy dừng lại một giây và tự hỏi:
-
Liệu mình có thể đóng gói đoạn logic này vào một hàm (function) không? Đây là cách đơn giản và phổ biến nhất.
-
Liệu mình có thể tạo ra một lớp (class) hoặc một component tái sử dụng không? (Trong lập trình hướng đối tượng và front-end framework).
-
Liệu mình có thể đưa các giá trị hằng số (magic numbers, strings) vào một file cấu hình (config) chung không?
DRY không chỉ là một kỹ thuật, nó là một tư duy. Tư duy của một người làm kỹ thuật chuyên nghiệp, luôn hướng đến sự hiệu quả, tính bền vững và sự tôn trọng dành cho những người đồng đội (và cả chính mình trong tương lai).
Lần tới khi bạn định nhấn Ctrl + C và Ctrl + V, hãy nhớ đến bài viết này nhé!
👀 Ngày mai chúng ta sẽ nói về...
Ngày 6: Hai Người Anh Em Của DRY - KISS và YAGNI
Giữ cho code "khô ráo" là rất quan trọng. Nhưng đôi khi, trong nỗ lực trừu tượng hóa để tránh lặp lại, chúng ta lại vô tình làm cho mọi thứ trở nên phức tạp quá mức cần thiết. Làm thế nào để cân bằng? Ngày mai, chúng ta sẽ tìm hiểu về hai triết lý giúp giữ cho code của bạn đơn giản và hiệu quả: KISS (Keep It Simple, Stupid) và YAGNI (You Ain't Gonna Need It).
