Magic number và hằng số: làm code dễ hiểu và dễ thay đổi

  • author-image

    Nguyễn Đình Cường

  • blog-tag
  • blog-comment 0 comment
  • created-date 09 Nov, 2026
blog-thumbnail

Bạn đọc thấy if (status === 3) hoặc price * 0.08 trong code và tự hỏi: 3 là gì, 0.08 là gì? Những con số hoặc chuỗi xuất hiện không có giải thích gọi là "magic number" (số ma thuật). Chúng khiến code khó đọc và rất dễ sinh lỗi khi cần thay đổi.

Vấn đề của magic number

function calculateFee(amount, status) {if (status === 3) {return amount * 0.08 + 15000;}return amount * 0.05;}

Câu hỏi đặt ra:

  • Trạng thái 3 nghĩa là gì: đã duyệt, đã hủy, hay đang chờ?
  • 0.08 là thuế, phí dịch vụ, hay lãi suất?
  • 15000 là phí cố định gì, đơn vị tiền tệ nào?
  • Nếu phí dịch vụ đổi thành 0.09, bạn phải tìm mọi chỗ có 0.08, và có chỗ nào 0.08 mang nghĩa khác không?

Giải pháp: đặt tên cho giá trị

const STATUS_PREMIUM = 3;const PREMIUM_FEE_RATE = 0.08;const PREMIUM_FIXED_FEE = 15000; // VNDconst STANDARD_FEE_RATE = 0.05;function calculateFee(amount, status) {if (status === STATUS_PREMIUM) {return amount * PREMIUM_FEE_RATE + PREMIUM_FIXED_FEE;}return amount * STANDARD_FEE_RATE;}

Giờ đọc code là hiểu ngay. Muốn đổi mức phí chỉ sửa một chỗ. Tên hằng số trở thành tài liệu và tìm kiếm cũng dễ hơn.

Quy ước đặt tên hằng số

Hầu hết ngôn ngữ dùng UPPER_SNAKE_CASE cho hằng số: MAX_LOGIN_ATTEMPTS, DEFAULT_PAGE_SIZE, SECONDS_PER_DAY. Tên nên nói về ý nghĩa, không nói về giá trị. THREE hay EIGHT_PERCENT chẳng hơn gì con số. Nếu giá trị đổi, tên vẫn nên đúng.

Dùng enum cho nhóm giá trị liên quan

Khi có một tập các trạng thái hoặc loại hữu hạn, enum tốt hơn một chùm hằng số rời:

// TypeScriptenum OrderStatus {Pending = 'pending',Paid = 'paid',Shipped = 'shipped',Cancelled = 'cancelled',}function canCancel(status: OrderStatus): boolean {return status === OrderStatus.Pending || status === OrderStatus.Paid;}
# Pythonfrom enum import Enumclass OrderStatus(Enum):PENDING = "pending"PAID = "paid"SHIPPED = "shipped"CANCELLED = "cancelled"

Lợi ích: trình soạn thảo gợi ý các giá trị hợp lệ, trình biên dịch bắt lỗi gõ sai, và mọi nơi dùng cùng một nguồn sự thật. Chuỗi như "shiped" (gõ sai) sẽ không còn lặng lẽ sinh bug.

Nên và không nên đặt hằng số

Không phải con số nào cũng là magic number. Những giá trị sau thường chấp nhận được:

  • 0 và 1 trong ngữ cảnh hiển nhiên (khởi tạo bộ đếm, chỉ số đầu mảng).
  • 2 khi dùng để kiểm tra chẵn lẻ (n % 2 === 0).
  • Các hằng số toán học mà ý nghĩa rõ qua ngữ cảnh, như 100 để đổi phần trăm, nhưng nếu muốn rõ thì PERCENT = 100 cũng không thừa.

Ngược lại, hãy đặt tên cho: ngưỡng nghiệp vụ, thời gian chờ, giới hạn kích thước, mã trạng thái, tỷ lệ, URL, đường dẫn, tên khóa cấu hình, chuỗi lặp lại nhiều nơi.

Đặt hằng số ở đâu?

  1. Gần nơi dùng: hằng số chỉ dùng trong một file thì đặt đầu file.
  2. Trong class hoặc module liên quan: ví dụ OrderStatus nằm trong module đơn hàng.
  3. File hằng số chung: cho các giá trị dùng nhiều nơi, nhưng đừng tạo một file "constants" khổng lồ chứa mọi thứ.
  4. File cấu hình / biến môi trường: với giá trị thay đổi theo môi trường (URL dịch vụ, timeout, khóa), tránh viết cứng trong code.
  5. Cơ sở dữ liệu / bảng cấu hình: cho giá trị nghiệp vụ cần thay đổi mà không phải deploy lại, như mức phí, tỉ lệ giảm giá.

Cẩn thận với đơn vị

Nhiều lỗi nghiêm trọng đến từ nhầm đơn vị. Hãy đặt đơn vị vào tên hoặc comment: TIMEOUT_MS = 5000, MAX_UPLOAD_MB = 10, FEE_VND = 15000. Khi cộng, so sánh các giá trị, đảm bảo cùng đơn vị. Với tiền tệ, hãy tránh dùng số thực (float) để tính tiền vì sai số làm tròn, thay vào đó dùng số nguyên theo đơn vị nhỏ nhất hoặc kiểu decimal.

Cách tìm và dọn magic number trong dự án cũ

  1. Tìm kiếm các con số lạ trong điều kiện, phép tính (regex đơn giản như [^a-zA-Z_]\d{2,} giúp lọc nhanh).
  2. Với mỗi số, tìm hiểu ý nghĩa qua code xung quanh, lịch sử Git hoặc hỏi đồng đội.
  3. Đặt tên rõ nghĩa và thay thế tại mọi chỗ cùng nghĩa.
  4. Chạy test để đảm bảo hành vi không đổi.
  5. Commit riêng thành một thay đổi refactor.

Kết luận

Đặt tên cho các con số và chuỗi quan trọng là thay đổi rất rẻ nhưng làm code dễ đọc, dễ sửa và ít lỗi hơn hẳn. Lần tới khi định gõ một số lạ vào code, hãy dừng lại và đặt cho nó một cái tên.

Muốn học thêm các thói quen viết code chuyên nghiệp, bạn có thể bắt đầu với những khóa học tại codebem.com.

author_photo
Nguyễn Đình Cường

0 comment