Nghệ Thuật Viết Code Dễ Đọc

Code được đọc nhiều hơn rất nhiều lần so với khi nó được viết. Đây là những gì tôi học được về việc viết code giao tiếp rõ ràng.

10 thg 3, 2026 4 phút đọc
  • lập trình
  • phần mềm
  • kỹ năng
  • dễ đọc
Trong bài này

Hầu hết code chỉ được viết một lần nhưng được đọc hàng chục lần. Bởi chính tác giả sáu tháng sau, bởi một đồng nghiệp đang tìm lỗi, bởi người bảo trì trong tương lai chưa từng gặp bạn. Khi bạn viết code, bạn đang viết một thông điệp cho những người bạn chưa gặp.

Cách nhìn đó thay đổi mọi thứ.

Tên Biến Là Bản Nháp Đầu Tiên

Một biến tên d không nói lên điều gì. Một biến tên daysSinceLastLogin cho bạn biết chính xác nó là gì, từ đâu đến, và khoảng giá trị nó có.

Đặt tên là bản nháp đầu tiên của tài liệu. Nó diễn ra trước khi có comment, trước khi có test, trước khi có kiến trúc. Và không giống comment, tên biến không thể bị lỗi thời so với code — nó chính là code.

// Tệ: d là gì? u là gì?
const d = Date.now() - u.ts;
if (d > 86400000) logout(u);

// Tốt: code đọc như một câu văn
const daysSinceLastLogin = (Date.now() - user.lastLoginAt) / MS_PER_DAY;
if (daysSinceLastLogin > 1) logoutInactiveUser(user);

Phiên bản thứ hai dài hơn. Nhưng nó cũng đúng rõ ràng khi đọc lần đầu, có nghĩa là chi phí bảo trì thấp hơn.

Hàm Nên Làm Một Việc

Một hàm vừa xác thực email, vừa lưu vào cơ sở dữ liệu, vừa gửi email chào mừng là ba hàm trong một bộ quần áo. Khi nó bị lỗi — và nó sẽ bị lỗi — bạn sẽ không biết phần nào đang có vấn đề.

Nguyên tắc là đặt tên cho mỗi hàm sao cho có thể nói to không cần giải thích thêm. Nếu cái tên đòi hỏi từ “và”, hãy tách hàm đó ra.

// Khó test, khó tái sử dụng, khó tin tưởng
async function handleSignup(email: string) {
  if (!email.includes('@')) throw new Error('Email không hợp lệ');
  await db.insert('users', { email });
  await sendEmail(email, 'Chào mừng!');
}

// Mỗi phần có thể test và kết hợp độc lập
function validateEmail(email: string): boolean {
  return email.includes('@') && email.includes('.');
}

async function createUser(email: string): Promise<User> {
  return db.insert('users', { email });
}

async function sendWelcome(user: User): Promise<void> {
  await sendEmail(user.email, 'Chào mừng!');
}

Phiên bản thứ hai cần nhiều dòng hơn. Đổi lại bạn có được tính tổ hợp: createUser có thể được gọi trong test mà không gửi email. sendWelcome có thể tái sử dụng cho chiến dịch tái kích hoạt. validateEmail có thể nằm trong module tiện ích dùng chung.

Comment Giải Thích Tại Sao, Không Phải Cái Gì

Comment tệ nhất là diễn lại code bằng tiếng Việt:

# tăng bộ đếm thêm 1
counter += 1

Đây là tiếng ồn. Code đã nói điều nó làm rồi. Điều code không thể nói là tại sao.

# Cloudflare KV có tính nhất quán cuối cùng; chúng ta tăng lạc quan
# và đối chiếu trong lần chạy cron tiếp theo thay vì chặn request
counter += 1

Comment đó đáng giữ lại. Nó bảo tồn lý do đằng sau một quyết định mà nếu không sẽ có vẻ tùy tiện. Sáu tháng sau, ai đó sẽ muốn “sửa” cái tăng lạc quan kia — ghi chú này sẽ ngăn họ lại.

Sự Phức Tạp Là Nợ

Mỗi thủ thuật thông minh bạn viết ra, bạn đang gửi vào tài khoản nợ mà người khác có thể phải trả. Thao tác bit, regex dày đặc, toán tử ba ngôi lồng nhau sâu — đây đều là những khoản rút từ ngân sách nhận thức của người đọc.

Câu hỏi không phải là “Tôi có thể viết điều này trong một dòng không?” Câu hỏi là “Người đọc tiếp theo có hiểu điều này trong năm giây không?”

// Thông minh
const roles = user?.roles?.reduce((a, r) => ({ ...a, [r]: true }), {}) ?? {};

// Rõ ràng
const roles: Record<string, boolean> = {};
for (const role of user?.roles ?? []) {
  roles[role] = true;
}

Phiên bản thứ hai chạy giống hệt. Nó cũng kể một câu chuyện: bắt đầu rỗng, điền vào, xong. Không cần mô hình tư duy trung gian.

Cấu Trúc Truyền Đạt Ý Định

Hình dạng của code trên trang truyền tải ý nghĩa trước khi đọc bất kỳ token nào. Một hàm 300 dòng báo hiệu: cái này phức tạp, hãy cẩn thận. Một module với 12 hàm xuất ra báo hiệu: đây là bộ công cụ. Một file import 40 thứ báo hiệu: nơi này có quá nhiều mối quan tâm.

Khi code khó đọc, thường là vì cấu trúc không trung thực về sự phức tạp nó chứa đựng. Tái cấu trúc, ở mức tốt nhất, là hành động làm cho cấu trúc phản ánh thực tế.


Code dễ đọc không phải là sở thích về phong cách. Đó là sự tôn trọng chuyên nghiệp dành cho mọi người sẽ chạm vào code này sau bạn — bao gồm cả bạn khi quay lại trong trạng thái mệt mỏi, áp lực, ba tháng sau.

Hãy viết cho họ.

Cập nhật mới