Cập nhật lần cuối:

Hướng dẫn độ dài tên biến & hàm - Quy ước đặt tên trong lập trình

11 phút đọc

Trong lập trình, việc đặt tên là một trong những yếu tố quan trọng nhất ảnh hưởng đến khả năng đọc mã nguồn. Tên quá ngắn không truyền đạt được ý nghĩa; tên quá dài khiến mã nguồn trở nên rườm rà. Việc chọn độ dài phù hợp đòi hỏi sự đánh giá dựa trên phạm vi và độ phức tạp. Bài viết này đề cập đến hướng dẫn về độ dài đặt tên và quy ước riêng cho từng ngôn ngữ. Kiểm tra độ dài định danh của bạn với Bộ đếm ký tự.

Độ dài tên biến theo phạm vi

Độ dài phù hợp của tên biến tỷ lệ thuận với phạm vi của nó, và tỷ lệ nghịch với số lần nó được sử dụng. Nguyên tắc này được nêu trong tài liệu hướng dẫn phong cách của Go (bản hiện hành tính đến tháng 8 năm 2026) và cũng được trình bày trong cuốn "Clean Code" của Robert C. Martin. Cơ chế phía sau khá cụ thể: khi phạm vi rộng, dòng mã đang đọc thường cách xa nơi khai báo, nên một tên không tự giải thích buộc người đọc phải cuộn ngược lại chỗ khai báo để tra ý nghĩa. Ngược lại, trong vòng lặp 2–3 dòng, phần khai báo vẫn nằm trong tầm mắt nên i là đủ; đặt tên dài ở đó chỉ làm dòng mã kéo dài theo chiều ngang và đẩy phần logic quan trọng ra khỏi màn hình.

Phạm viĐộ dài khuyến nghịVí dụLý do
Bộ đếm vòng lặp (1–3 dòng)1–2 ký tựi, j, kQuy ước được hiểu rộng rãi
Lambda / khối ngắn (≤5 dòng)3–8 ký tựitem, user, valNgữ cảnh làm rõ kiểu/vai trò
Biến cục bộ trong hàm8–15 ký tựuserName, totalPriceVai trò phải rõ ràng trong phạm vi hàm
Trường/thuộc tính của lớp10–20 ký tựmaxRetryCount, isAuthenticatedĐược tham chiếu trong toàn bộ lớp
Biến toàn cục / hằng số15–25 ký tựMAX_CONNECTION_TIMEOUT, DEFAULT_PAGE_SIZEPhải rõ ràng trong toàn bộ mã nguồn

Vì sao độ dài đặt tên thay đổi theo văn hóa của từng ngôn ngữ

Cùng một nguyên tắc "độ dài tỷ lệ thuận với phạm vi" lại cho ra kết quả rất khác nhau giữa các ngôn ngữ. Lý do không nằm ở khẩu vị của cộng đồng, mà ở chỗ mỗi ngôn ngữ có cơ chế phân định phạm vi và bổ nghĩa cho định danh khác nhau.

C không có namespace, nên tiền tố module trong tên hàm (tcp_v4_connect, ext4_read_inode) đóng vai trò thay thế namespace. Đó là lý do mã C thường có tên biến rất ngắn nhưng tên hàm lại tương đối dài: phần định danh phải tự mang theo thông tin thuộc về module nào. Đây là yêu cầu về cấu trúc, không phải sự thiếu nhất quán.

Go đi theo hướng ngược lại. Tên gói luôn xuất hiện ở nơi gọi (http.Get, json.Marshal), nên chính tên gói đã làm nhiệm vụ bổ nghĩa; lặp lại tên gói bên trong định danh chỉ tạo ra sự thừa. Vì vậy tên trong Go có xu hướng ngắn, và biến receiver thường chỉ 1–2 ký tự.

Java thì chấp nhận tên dài mang tính mô tả, kể cả với tên lớp. Chẳng hạn AbstractSingletonProxyFactoryBean trong Spring Framework là một lớp tồn tại thực tế và dài 33 ký tự. Khi so sánh giữa các ngôn ngữ, hãy đọc độ dài như hệ quả của cơ chế bổ nghĩa mà ngôn ngữ đó cung cấp, chứ không phải như một thước đo chất lượng mã nguồn.

Hướng dẫn tên hàm và lớp

Loại định danhĐộ dài khuyến nghịNguyên tắc đặt tênVí dụ
Tên hàm10–25 ký tựĐịnh dạng động từ + đối tượngcalculateTotalPrice, sendEmailNotification
Tên lớp10–25 ký tựDanh từ hoặc cụm danh từUserRepository, PaymentProcessor
Tên interface10–25 ký tựTính từ hoặc danh từ mô tả hành viSerializable, EventListener
Tên hằng số10–30 ký tựUPPER_SNAKE_CASE với ý nghĩa cụ thểMAX_RETRY_COUNT, DEFAULT_TIMEOUT_MS
Biến/hàm Boolean10–20 ký tựTiền tố is/has/can/shouldisValid, hasPermission, canExecute

Hàm nên luôn bắt đầu bằng một động từ. fetchData() rõ ràng hơn data(); validateInput() tốt hơn validation().

Quy ước riêng theo ngôn ngữ

Ngôn ngữBiến/HàmLớpHằng sốHướng dẫn phong cách tiêu biểu
JavacamelCasePascalCaseUPPER_SNAKE_CASEGoogle Java Style Guide
Pythonsnake_casePascalCaseUPPER_SNAKE_CASEPEP 8
JavaScriptcamelCasePascalCaseUPPER_SNAKE_CASEAirbnb Style Guide
GocamelCase / PascalCasePascalCasePascalCaseEffective Go
Rubysnake_casePascalCaseUPPER_SNAKE_CASERuby Style Guide
C#camelCase / PascalCasePascalCasePascalCaseMicrosoft C# Conventions

Cột cuối liệt kê tài liệu được tham chiếu phổ biến nhất cho từng ngôn ngữ, nhưng chúng không cùng một hạng: có tài liệu do chính dự án ngôn ngữ phát hành (PEP 8, Effective Go), có tài liệu do một công ty biên soạn cho mã nguồn nội bộ của họ (Google Java Style Guide, Microsoft C# Conventions) và có tài liệu do cộng đồng duy trì (Airbnb, Ruby Style Guide). Vì mức độ ràng buộc khác nhau, việc cần làm đầu tiên trong một dự án là thống nhất xem nhóm lấy tài liệu nào làm chuẩn.

IDE Autocomplete và độ dài tên

Mối lo ngại rằng "tên dài gõ mệt" phần lớn đã được loại bỏ bởi các IDE hiện đại. So sánh tính năng tự động hoàn thành giữa các IDE chính cho thấy độ dài tên có tác động tối thiểu đến tốc độ phát triển.

IDE / Trình soạn thảoKích hoạt hoàn thànhChiến lược khớpHỗ trợ tên dài
IntelliJ IDEATự động khi gõKhớp chữ cái đầu CamelCase (gUN → getUserName)2–3 chữ cái đầu thu hẹp ứng viên; tên dài tốn ít công sức
VS CodeTự động khi gõKhớp mờ (usrnm → userName)Hiển thị khớp một phần; không cần gõ chính xác
Vim / Neovim (LSP)Ctrl+N hoặc tích hợp LSPHoàn thành dựa trên LSP nhận biết kiểuHoàn thành tương đương IDE qua coc.nvim hoặc nvim-cmp

Tính năng khớp CamelCase của IntelliJ IDEA đặc biệt mạnh mẽ - chỉ cần gõ ASPFB là đủ để hoàn thành thành AbstractSingletonProxyFactoryBean (33 ký tự). Điều này có nghĩa là độ dài tên không cần bị giới hạn bởi công sức gõ; bạn có thể chọn độ dài tối ưu hoàn toàn vì mục đích dễ đọc.

Thông tin thú vị về đặt tên

Tài liệu coding-style của Linux kernel yêu cầu tên biến phải "ngắn gọn và đi thẳng vào vấn đề", và nêu thẳng rằng loop_counter là cách đặt tên không hiệu quả so với i (nội dung của bản hiện hành tính đến tháng 8 năm 2026). Đây là quy định trong tài liệu của dự án; cần phân biệt với những phát biểu cá nhân thường được dẫn lại trên mạng mà không kèm nguồn xác minh được. Ở phía đối lập, Google Java Style Guide §5.2.6 chỉ khuyến nghị tránh tham số một ký tự cho các phương thức public, và không đặt ra giới hạn nào đối với biến cục bộ. Sự khác biệt này phản ánh bối cảnh sử dụng: mã kernel được một nhóm nhỏ chuyên gia đọc trực tiếp, còn API public của một dịch vụ lớn lại được rất nhiều lập trình viên bên ngoài gọi đến mà không đọc phần thân hàm.

Vấn đề với tên quá dài và quá ngắn

Lỗi đặt tên rơi vào hai thái cực: quá ngắn để truyền đạt ý nghĩa, và quá dài để đọc thoải mái. Những tên ngắn như d, tmp, hoặc val ngoài bộ đếm vòng lặp trở nên khó hiểu chỉ trong vài ngày - ngay cả với chính tác giả.

Tên quá dài cũng gây vấn đề tương tự. Một biến như numberOfItemsInTheShoppingCartBeforeDiscount không vừa trên một dòng và thực sự làm giảm khả năng đọc. Điểm cân bằng lý tưởng là một tên truyền đạt vai trò của nó trong nháy mắt mà không làm gián đoạn luồng mã xung quanh.

Có thể hình dung quan hệ giữa độ dài định danh và khả năng đọc như một đường cong hình chữ U, nhưng nên hiểu nó qua cơ chế chứ không qua một con số tối ưu cố định. Tên quá ngắn buộc người đọc phải khôi phục ý nghĩa từ ngữ cảnh, tức là cuộn ngược lại chỗ khai báo mỗi lần không chắc. Tên quá dài lại làm dòng mã kéo dài theo chiều ngang, khiến cấu trúc của câu lệnh (điều kiện, phép gán, lời gọi hàm) bị đẩy ra ngoài tầm mắt hoặc phải ngắt dòng nhiều lần. Vì vậy điểm cân bằng phụ thuộc vào phạm vi và mật độ của mã xung quanh, không phải một khoảng ký tự áp dụng chung cho mọi trường hợp.

Tên biến Unicode và Multibyte

Nhiều ngôn ngữ lập trình hỗ trợ định danh Unicode, nhưng việc sử dụng ký tự không phải ASCII trong tên biến gây ra một số cạm bẫy trên thực tế.

Ngôn ngữBiến UnicodeVí dụLưu ý
Python 3Hỗ trợ đầy đủ名前 = "Taro"PEP 8 khuyến nghị chỉ dùng ASCII; tránh trong nhóm quốc tế
RubyHỗ trợ đầy đủ数値 = 42Cần magic comment # encoding: utf-8 (trước Ruby 2.0)
JavaScriptHỗ trợ (viết trực tiếp hoặc bằng ký pháp escape)let café = trueChuẩn hóa NFC/NFD có thể khiến tên trông giống nhau nhưng khác nhau
JavaHỗ trợ đầy đủint 金額 = 1000;Biên dịch được, nhưng hầu hết hướng dẫn phong cách không khuyến khích
GoDanh mục Unicode Letter名前 := "Taro"Chỉ cho phép ký tự thuộc danh mục Letter của Unicode
C / C++Hạn chếint données = 0;Phạm vi ký tự cho phép khác nhau theo phiên bản chuẩn (từ C11/C++11) và theo từng trình biên dịch

Vấn đề chuẩn hóa Unicode của JavaScript đáng được chú ý đặc biệt. Tên biến café có thể được biểu diễn theo hai cách: dạng NFC với é là một ký tự đơn (U+00E9), hoặc dạng NFD với e + dấu kết hợp (U+0065 U+0301). Chúng trông giống hệt nhau nhưng được xử lý như các định danh khác nhau. Trên macOS, HFS+ chuẩn hóa tên tệp về một dạng gần với NFD, còn APFS thì không chuẩn hóa mà giữ đúng chuỗi ký tự đã được ghi. Nghĩa là cùng một cái tên có thể tồn tại ở hai dạng khác nhau tùy hệ thống tệp và tùy nơi tạo ra tệp, và lỗi khó truy vết sẽ xuất hiện khi bạn sinh tên biến từ tên tệp.

Xung đột từ khóa dành riêng là một trường hợp biên thường bị bỏ qua. Trong Python, class, import, và return là từ khóa dành riêng, nhưng các cách giải quyết như cls (viết tắt của class) và klass đã trở thành quy ước phổ biến. JavaScript cũng vậy: class đã nằm trong danh sách từ khóa dành riêng của chuẩn ECMAScript từ trước, chứ không phải bị ES6 chiếm lấy (ES6 chỉ bổ sung cú pháp khai báo class). Nên vấn đề ở đây không phải chuyện di chuyển mã, mà đơn giản là bạn không thể dùng từ khóa làm định danh và phải chọn một cách viết thay thế như cls hoặc klass.

Các lỗi thường gặp

Kỹ thuật đặt tên chuyên nghiệp

Thực thi quy ước đặt tên bằng Linters

Để thống nhất quy ước đặt tên trong nhóm, kiểm tra tự động bằng linter là thiết yếu. Dưới đây là các linter chính và quy tắc liên quan đến đặt tên cho từng ngôn ngữ.

Ngôn ngữLinterQuy tắc đặt tênVí dụ cấu hình
JavaScript / TypeScriptESLint@typescript-eslint/naming-conventionBắt buộc camelCase cho biến, UPPER_CASE cho hằng số, PascalCase cho kiểu
Pythonpylint / RuffC0103 (invalid-name)Bắt buộc snake_case; mẫu regex cho tên hợp lệ có thể cấu hình riêng theo từng loại định danh
JavaCheckstyleMemberName, MethodNameĐịnh nghĩa quy tắc đặt tên qua mẫu regex
Gogolangci-lintrevive's var-namingBắt buộc MixedCaps; thống nhất viết hoa từ viết tắt (ID, URL)
RubyRuboCopNaming/VariableNameChọn snake_case hay camelCase qua tùy chọn EnforcedStyle

Quy tắc @typescript-eslint/naming-convention của ESLint đặc biệt linh hoạt, cho phép quy tắc đặt tên khác nhau cho từng loại định danh (biến, hàm, lớp, interface, v.v.). Bạn thậm chí có thể bắt buộc các ràng buộc ngữ nghĩa như "biến Boolean phải bắt đầu bằng is, has, hoặc should." Tích hợp linter vào pipeline CI/CD giúp tự động phát hiện vi phạm đặt tên trước khi merge.

Kết luận

Độ dài tên phù hợp tỷ lệ thuận với phạm vi: 1–2 ký tự cho bộ đếm vòng lặp, 8–15 cho biến cục bộ, 15–25 cho hằng số toàn cục. Cách đọc nguyên tắc này rất đơn giản: phạm vi càng rộng thì khoảng cách giữa nơi khai báo và nơi sử dụng càng xa, nên tên phải tự mang đủ thông tin để người đọc không cần cuộn ngược lại. Độ dài thực tế còn thay đổi theo cơ chế bổ nghĩa của từng ngôn ngữ - tiền tố module trong C thay cho namespace, tên gói làm nhiệm vụ bổ nghĩa trong Go - nên đừng so sánh số ký tự giữa các ngôn ngữ như một thước đo chất lượng. Mặc dù hỗ trợ tên biến Unicode đang mở rộng, các vấn đề chuẩn hóa và khả năng đọc trong nhóm quốc tế khiến đặt tên chỉ dùng ASCII là lựa chọn thực tế. Tránh viết tắt quá mức và ký pháp Hungary, đồng thời thực thi quy ước đặt tên thông qua linter tích hợp vào pipeline CI/CD. Sử dụng Bộ đếm ký tự để kiểm tra độ dài định danh của bạn.

Chia sẻ bài viết này