Bài 1 · Cơ bản · 16 phút
Vì sao code sạch quan trọng
Biên soạn bởi Nguyễn Anh Tuấn
Code đọc nhiều hơn viết; “sự bừa bộn” (mess) làm chậm cả đội; định nghĩa code sạch & quy tắc Boy Scout. Vì sao dùng TypeScript: kiểu giúp diễn đạt ý định.
Nhiều người tưởng lập trình chủ yếu là gõ code mới. Thực tế phần lớn thời gian là đọc code đã có - của mình tuần trước, của đồng đội - để hiểu rồi mới sửa được một dòng. Tỉ lệ đọc so với viết rất cao.
Hệ quả thẳng tuột: hãy tối ưu code cho người ĐỌC, không phải cho người gõ. Một đoạn khó đọc bắt cả đội trả giá mỗi lần chạm vào nó.
Cùng một logic - mèo con muốn bảo trì cái nào?
// Kho doc: ten bi an, vong lap long, phai giai ma moi hieu
function d(u: User[]): User[] {
const r = [];
for (let i = 0; i < u.length; i++) {
if (u[i].a && u[i].t <= 30) r.push(u[i]);
}
return r;
}
// De doc: ten noi ro y dinh, mot dong dien ta nhu van xuoi
function activeUsersSeenRecently(users: User[]): User[] {
return users.filter((u) => u.isActive && u.daysSinceLogin <= 30);
} - ▸Code được đọc nhiều hơn viết rất nhiều lần trong vòng đời của nó.
- ▸Vậy nên tối ưu cho người ĐỌC: tên rõ, ý định lộ ngay, ít phải “giải mã”.
- ▸Khó đọc không miễn phí - cả đội trả giá mỗi lần quay lại file đó.
Mỗi lần tặc lưỡi “để dọn sau”, code rối thêm một chút. Cái rối đó - sự bừa bộn (mess) - tích tụ: sửa chậm dần, bug nhiều dần, người mới vào đội lâu nắm hơn. Tệ hơn, nó cộng dồn như lãi kép.
Kéo thử slider bên dưới: cắt góc (bỏ qua dọn dẹp) cho cảm giác nhanh lúc đầu, nhưng vận tốc tụt dần khi mess chồng chất - tới một lúc đội giữ code sạch vượt mặt rồi bỏ xa.
Cắt góc nhanh hơn lúc đầu, nhưng đội sạch vượt mặt từ sprint 6. Hết sprint 12: sạch giao 120 tính năng, cắt góc chỉ 93 - và khoảng cách ngày càng giãn.
Trung thực
- ▸“Dọn sau” thường thành “không bao giờ dọn”; mess tích tụ và cộng dồn.
- ▸Cắt góc nhanh trước mắt nhưng vay vào tương lai với lãi suất cao.
- ▸Giữ sạch không phải cầu toàn - là dọn liên tục từng chút để khỏi trả lãi kép.
Không có thước đo máy chấm được, nhưng giới lập trình đồng thuận khá rộng về vài đặc điểm. Gom lại, code sạch là code mà người sau đọc hiểu ngay ý định, ít phải đoán:
- ▸Đọc như văn xuôi: tên & cấu trúc nói RÕ ý định, không bắt người đọc giải mã.
- ▸Mỗi mảnh làm MỘT việc rõ ràng, đúng như tên gọi - ít bất ngờ.
- ▸Không lặp (no duplication): một ý chỉ có một chỗ định nghĩa.
- ▸Dễ kiểm thử (test) và dễ thay đổi mà không sợ gãy chỗ khác.
Cảm hứng từ sách Clean Code
Hướng đạo sinh (Boy Scout) có một luật: “Để khu cắm trại sạch hơn lúc bạn đến.” Áp vào code: mỗi lần chạm một file, cải thiện một điều nhỏ - đổi một cái tên mơ hồ, tách một hàm dài, xoá một dòng comment đã chết - mà không đổi hành vi.
Không cần đại tu hoành tráng. Hàng trăm cải thiện nhỏ an toàn (có test đỡ lưng) làm codebase sạch dần mà không có ngày “dừng mọi thứ để refactor”. Cả khoá này chính là bộ dụng cụ Boy Scout của mèo con.
Lộ trình khoá học
Nếu code sạch là diễn đạt ý định rõ, thì kiểu (type) là một kênh diễn đạt rất mạnh mà JavaScript thuần thiếu. Chữ ký hàm có kiểu tự kể câu chuyện của nó:
Kiểu là một kênh diễn đạt ý định
// JavaScript: chu ky khong noi gi - a, b, c la cai gi?
function pay(a, b, c) { /* ... */ }
pay(o, k, 100); // dung thu tu? dung don vi? khong ai biet
// TypeScript: ten + kieu ke ro cau chuyen; goi sai kieu la bao loi ngay
function pay(order: Order, card: Card, amount: Money): Receipt { /* ... */ } - ▸Kiểu biến chữ ký hàm thành tài liệu sống: đọc là hiểu mỗi tham số là gì.
- ▸Trình kiểm tra kiểu bắt lỗi SỚM và làm refactor (đổi tên, di chuyển) an toàn hơn.
- ▸Nguyên tắc clean code áp dụng cả cho JS thuần - TS chỉ cho thêm một công cụ.
Bài tiếp theo: Đặt tên có ý nghĩa
Câu hỏi thường gặp
“Chạy đúng” là điều kiện cần, không phải đủ. Code sống nhiều tháng, nhiều năm: bạn và đồng đội còn quay lại đọc, sửa, thêm tính năng. Code chạy đúng nhưng rối làm mỗi lần thay đổi sau đó chậm và dễ gãy hơn. Sạch là khoản đầu tư cho chính bạn ở tương lai.
Có một chút lúc đầu, nhưng không phải đánh đổi như nhiều người tưởng. Như mô hình ở Bước 2: cắt góc cho cảm giác nhanh trong vài sprint đầu, rồi “mess” tích tụ kéo tụt vận tốc và bạn bị vượt mặt. Giữ sạch không phải là cầu toàn - là dọn dẹp liên tục từng chút để khỏi trả lãi kép.
Hiếm khi. Viết lại toàn bộ tốn kém khủng khiếp, dễ tái tạo lại bug cũ, và nếu thói quen không đổi thì bản mới rồi cũng bẩn. Cách bền vững hơn là refactor DẦN có test đỡ lưng (cả khoá này dạy điều đó), không phải đập đi xây lại.
Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.
Trả lời vài câu để chắc rằng em đã nắm bài.
Vì sao code sạch nhấn mạnh việc tối ưu cho NGƯỜI ĐỌC?
- 1
Đo tỉ lệ đọc/viết
Trong một buổi code, để ý: bạn dành bao nhiêu thời gian ĐỌC code có sẵn (của mình, của người khác) so với GÕ code mới?
Hoàn thành khi: Một ước lượng tỉ lệ (vd “đọc gấp 3 lần viết”) kèm một câu nhận xét: điều đó nói gì về việc nên tối ưu code cho ai.
- 2
Soi một đoạn “bẩn”
Tìm một hàm khó đọc trong dự án của mèo con (hoặc mã nguồn mở). Viết ra 3 thứ cụ thể khiến nó khó đọc.
Hoàn thành khi: Liệt kê ≥3 vấn đề cụ thể (vd tên viết tắt, hàm dài làm nhiều việc, lồng if sâu) - chỉ tên, chưa cần sửa.
- 3
Định nghĩa của mèo con
Viết 1-2 câu định nghĩa “code sạch” bằng lời của chính bạn (không chép định nghĩa trong bài).
Hoàn thành khi: Một định nghĩa nêu được ≥2 đặc điểm cốt lõi (vd đọc dễ + làm một việc + không lặp).
- 4
Một việc tốt kiểu Boy Scout
Chọn một file, làm MỘT cải thiện nhỏ - đổi một cái tên mơ hồ thành rõ nghĩa - mà KHÔNG đổi hành vi. Commit riêng cải thiện đó.
Hoàn thành khi: Một commit nhỏ chỉ đổi tên cho rõ; chương trình chạy y như trước (không đổi hành vi).
- 5
Chơi với “thuế bừa bộn”
Mở widget ở Bước 2, kéo slider “cắt góc”. Tìm mức cắt góc nhỏ nhất mà đội sạch vẫn vượt mặt TRƯỚC sprint 6.
Hoàn thành khi: Một con số phần trăm cụ thể, kèm một câu rút ra về quan hệ giữa “cắt góc” và thời điểm bị vượt mặt.
- 6
Kiểu kể chuyện
Lấy một chữ ký hàm JavaScript mơ hồ (vd
function pay(a, b, c)). Viết lại bằng TypeScript với tên tham số và kiểu rõ ràng.Hoàn thành khi: Chữ ký mới đọc là hiểu mỗi tham số là gì mà không cần đọc thân hàm; sai kiểu khi gọi sẽ bị báo lỗi.