Quy ước đặt tên team: chọn camelCase, PascalCase, snake_case hay kebab-case?【2026】

(Cập nhật: 19 tháng 7, 2026 ) naming convention camelCase PascalCase snake_case kebab-case case converter team
Kết luận

Không có case “đúng tuyệt đối” — chỉ có case đúng theo tầng và ngôn ngữ. JavaScript/TypeScript: biến & hàm = camelCase, class/component = PascalCase. Python & cột DB: snake_case. URL và class CSS: kebab-case. Hằng số / biến môi trường: UPPER_SNAKE. Khi đổi tầng (API ↔ FE), chuyển một lần ở biên — đừng để hai kiểu sống chung trong cùng file. Case converter giúp đổi nhanh trên trình duyệt, không cần đăng ký.

PR review của team outsource Việt Nam hay dừng vì chuyện “nhỏ”: userId vs user_id, UserCard vs user-card, API_KEY vs apiKey. Không phải ai cũng sai — họ đang đứng ở hai tầng khác nhau mà thiếu bảng quy ước chung.

Bài này giúp chọn case theo ngữ cảnh team, không chỉ định nghĩa từng kiểu chữ. Bạn sẽ có ma trận ngôn ngữ, ví dụ lỗi thật khi JSON lệch, checklist merge, và cách dùng tool chuyển case khi phải map hàng loạt.

Bài viết này giúp bạn

  • Phân biệt camel / Pascal / snake / kebab / UPPER_SNAKE bằng ví dụ ngắn
  • bảng quyết định theo tầng để dán vào README
  • Biết chỗ chuyển case (biên API) thay vì đổi lung tung trong UI
  • Tránh lỗi runtime do lệch key JSON
  • Dùng case converter khi rename hoặc map payload

Năm quy ước hay gặp — ví dụ cùng một khái niệm

Cùng ý “tên người dùng”:

Quy ướcVí dụĐọc nhanh
camelCaseuserNametừ đầu thường, từ sau viết hoa
PascalCaseUserNamemọi từ viết hoa đầu
snake_caseuser_namethường + gạch dưới
kebab-caseuser-namethường + gạch ngang
UPPER_SNAKEUSER_NAMEhằng số / env
user_name  →  camel: userName
user_name  →  Pascal: UserName
user_name  →  kebab: user-name
user_name  →  UPPER_SNAKE: USER_NAME

Trên case converter: dán user_name, chọn định dạng đích, copy. Không cần viết script một lần cho năm dòng rename.


Ma trận team: tầng nào → case nào

Quy ước theo tầng (đề xuất mặc định)
Tầng Case mặc định Ví dụ
Biến / hàm JS·TS camelCase orderTotal, fetchUser()
Class / React component / type PascalCase OrderService, <UserCard />
Python / Ruby snake_case order_total, fetch_user
Cột SQL / JSON backend nhiều framework snake_case created_at, user_id
URL slug / CSS class / một số filename kebab-case /user-profile, .btn-primary
Env / hằng số toàn cục UPPER_SNAKE DATABASE_URL, MAX_RETRY

Vì sao không “thống nhất một case cho cả monorepo”?

Vì parser và hệ sinh thái đã chọn giúp bạn:

  • user-name không hợp lệ làm identifier JavaScript.
  • React coi userCard khác <UserCard /> — Pascal báo hiệu component.
  • PostgreSQL identifier không quote thường fold về chữ thường; snake dễ đọc trong migration.
  • SEO và routing quen slug kebab (/bai-viet-moi), không phải /baiVietMoi.

Team fullstack (Next.js + Django/FastAPI) phải sống với hai thế giới. Mục tiêu là rõ biên, không phải ép Python viết camel.


Quyết định nhanh theo tình huống

1. “File React đặt tên thế nào?”

  • Component export: PascalCaseInvoiceTable.tsx, export function InvoiceTable.
  • Hook: camel bắt đầu bằng useuseInvoiceList.
  • Utilities: camel — formatVndAmount.
  • Route URL: kebab — /hoa-don/[id] (slug), trong khi component vẫn Pascal.

2. “API trả user_id mà FE đang dùng TypeScript?”

Giữ snake trên dây nếu backend đã public contract; map sang camel một lần ở lớp client:

// Biên API — chuyển một chỗ, không rải khắp UI
type UserDto = { user_id: string; full_name: string };
type User = { userId: string; fullName: string };

function mapUser(dto: UserDto): User {
  return { userId: dto.user_id, fullName: dto.full_name };
}

Khi đặt tên field mới từ ticket tiếng Việt/Anh, mở case converter, convert full_namefullName để tránh typo full_Name.

3. “CSS và Tailwind?”

  • Class tự viết: kebab (.nav-link).
  • Token JS object (theme): camel phổ biến (colors.primarySoft) hoặc đúng convention của design system bạn đang dùng.
  • Đừng copy class HTML user-name thành biến user-name trong JS.

4. “Biến môi trường và CI?”

Luôn UPPER_SNAKE: NEXT_PUBLIC_API_BASE, POSTGRES_PASSWORD. Nhiều platform chỉ inject env dạng này. Trong code đọc process.env.POSTGRES_PASSWORD, không invent postgresPassword cho tên biến môi trường.


Case study: bug “undefined” vì lệch case

Bối cảnh: Team 4 người (2 FE Việt, 1 BE Việt, 1 BA). Backend FastAPI trả:

{ "order_id": "A-1024", "total_amount": 250000 }

FE viết:

console.log(data.orderId); // undefined

Staging “thỉnh thoảng đúng” vì có mock MSW dùng camel. Production vỡ sau khi nối API thật.

Root cause: Không có bảng quy ước + không có mapper biên. Mock và API nói hai ngôn ngữ.

Cách chốt cho team:

  1. README ghi: JSON API = snake_case; model UI = camelCase; map tại src/api/mappers/.
  2. PR template checkbox: “Payload mới đã có mapper / type DTO”.
  3. Khi BE thêm field discount_rate, FE convert tên bằng tool rồi thêm vào mapper — 30 giây, ít typo hơn đổi tay.

Checklist quy ước cho README (copy được)

Dán và sửa cho stack của bạn:

## Naming conventions

| Layer | Convention | Example |
|-------|------------|---------|
| TS variables / functions | camelCase | `invoiceTotal` |
| React components / classes | PascalCase | `InvoiceTotal` |
| Python modules / functions | snake_case | `invoice_total` |
| DB columns / API JSON | snake_case | `invoice_total` |
| URLs / CSS classes | kebab-case | `invoice-total` |
| ENV / constants | UPPER_SNAKE | `INVOICE_TOTAL_CAP` |

- Do not mix camel and snake in the same TS file for the same concept.
- Convert at API boundary only.

Reviewer chỉ cần hỏi: “Field này thuộc tầng nào?” — tranh luận kết thúc nhanh.


Lỗi thường gặp khi làm việc nhóm

  1. Đổi case trong UI vì “trông đẹp hơn” — phá contract API và diff reviewer.
  2. Pascal cho mọi thứConst Config = … rồi nhầm với component.
  3. kebab trong object JS — phải ghi obj['user-name'], dễ quên.
  4. UPPER_SNAKE cho biến cục bộ — khó đọc; giữ UPPER cho hằng/env thật sự toàn cục.
  5. Tự viết script convert thiếu edge case (XMLHttpRequest, userID) — với danh sách ngắn, converter trên trình duyệt đủ và an toàn hơn (không gửi tên nội bộ lên server lạ).

Workflow đổi tên hàng loạt với case converter

  1. Mở Chuyển đổi kiểu chữ.
  2. Dán một tên hoặc danh sách tên (ví dụ cột export từ DB).
  3. Chọn đích: camelCase, snake_case, kebab-case, PascalCase, UPPER_SNAKE…
  4. Copy kết quả vào mapper, migration note, hoặc commit rename.

Phù hợp khi:

  • Nhận OpenAPI snake và cần đặt tên type camel
  • Đổi folder Vue/React sang kebab theo lint mới
  • Chuẩn hóa tên file trước khi mở PR lớn

Không thay ESLint/ Presetter — tool này là bước thủ công nhanh khi bạn đang quyết định hoặc map biên.


Khi nào được phép “lệch” quy ước?

  • Thư viện bên thứ ba bắt buộc tên field (Stripe, Firebase…) — giữ nguyên ở biên SDK, map vào model nội bộ.
  • Legacy DB đã freeze — đừng rename cột production chỉ vì thẩm mỹ; map ở repository.
  • Design token từ Figma đã đặt sẵn — thống nhất một chiều (FE theo token hoặc token theo FE), ghi rõ trong handoff.

Ngoại lệ phải có chỗ ghi, không phải “tuỳ người merge”.


Tóm tắt quyết định một dòng

  • Viết JS/TS hàng ngày? → camel cho giá trị, Pascal cho kiểu/component.
  • Viết Python/SQL? → snake.
  • Đặt URL hoặc class CSS? → kebab.
  • Env/CI? → UPPER_SNAKE.
  • Hai tầng nói chuyện? → một mapper + case converter khi đặt tên.

Liên kết liên quan