camelCase so với snake_case: Nên dùng kiểu nào cho tên trường JSON?

Oliver Kingsley

Oliver Kingsley

17 tháng 12 2025

camelCase so với snake_case: Nên dùng kiểu nào cho tên trường JSON?

Trong thiết kế kiến trúc của các hệ thống phân tán, API không chỉ là cầu nối cho sự tương tác giữa các hệ thống; chúng còn là các hợp đồng kết nối các chồng công nghệ (tech stack), văn hóa tổ chức, và thậm chí cả các kỷ nguyên phát triển khác nhau. Trong các chi tiết thiết kế của API RESTful, một chủ đề tưởng chừng nhỏ lại gây ra những tranh cãi không ngừng: Tên trường JSON nên sử dụng camelCase hay snake_case?

Đây không chỉ là một lựa chọn thẩm mỹ. Nó chạm đến sự "khác biệt trở kháng" (impedance mismatch) giữa các lớp lưu trữ phía backend và các lớp trình bày phía frontend, liên quan đến hiệu suất tuần tự hóa (serialization), hiệu quả truyền tải mạng, Trải nghiệm nhà phát triển (DX), và tâm lý học nhận thức.

Dựa trên lịch sử của các ngôn ngữ lập trình, cơ chế triển khai kỹ thuật cơ bản, và các quyết định kiến trúc của những gã khổng lồ trong ngành như Google và Stripe, bài viết này sẽ cung cấp một hướng dẫn ra quyết định ở cấp độ chuyên gia.

nút


1. Nguồn Gốc Lịch Sử: Một Lựa Chọn Ký Hiệu

Để hiểu cuộc tranh luận này, chúng ta phải theo dõi sự phát triển của các ngôn ngữ máy tính. Các quy ước đặt tên không tự nhiên mà có; chúng là sản phẩm của những hạn chế phần cứng và văn hóa cộng đồng trong các thời kỳ cụ thể.

Nguồn Gốc của snake_case: C và Triết Lý Unix

Sự phổ biến của snake_case (ví dụ: user_id) bắt nguồn từ C và Unix vào những năm 1970. Mặc dù các bàn phím đời đầu (như Teletype Model 33) đã có phím Shift, nhiều trình biên dịch thời đó lại không phân biệt chữ hoa chữ thường. Để phân biệt rõ các từ trên màn hình có độ phân giải thấp, các lập trình viên đã dùng dấu gạch dưới để mô phỏng khoảng trắng trong ngôn ngữ tự nhiên. Thói quen này đã ăn sâu vào các tiêu chuẩn cơ sở dữ liệu SQL. Cho đến ngày nay, kiểu đặt tên cột mặc định cho PostgreSQL và MySQL vẫn là snake_case, tạo tiền đề cho sự 'xung đột ánh xạ' (mapping friction) giữa API và cơ sở dữ liệu trong tương lai.

Sự Trỗi Dậy của camelCase: Thống Trị của Java và JavaScript

camelCase (ví dụ: userId) phát triển cùng với Lập trình Hướng đối tượng (Smalltalk, C++, Java). Java đã thiết lập tiêu chuẩn công nghiệp về "PascalCase cho các lớp, camelCase cho các phương thức/biến." Bước ngoặt quyết định là sự ra đời của JavaScript. Mặc dù JSON có nguồn gốc từ các đối tượng nguyên bản của JS, thư viện chuẩn JS (ví dụ: getElementById) đã áp dụng camelCase trên diện rộng. Khi AJAX và JSON thay thế XML trở thành các định dạng trao đổi dữ liệu thống trị, camelCase đã giành được trạng thái "bản địa" trong lĩnh vực Web.


2. Xung Đột Cốt Lõi: Khác Biệt Trở Kháng Giữa Các Chồng Công Nghệ

Khi dữ liệu lưu chuyển giữa các ngôn ngữ khác nhau, không thể tránh khỏi việc gặp phải "khác biệt trở kháng."

Góc Nhìn Backend (Python/Ruby/SQL)

Ở phía backend, cộng đồng Python (PEP 8) và Ruby đặc biệt khuyến nghị sử dụng snake_case.

class UserProfile(BaseModel):
    first_name: str  # Python convention
    last_name: str

Nếu API yêu cầu camelCase, bạn phải cấu hình các bí danh (alias) hoặc bộ chuyển đổi (converter) trong lớp tuần tự hóa. Mặc dù khả thi, điều này làm tăng thêm một lớp logic ánh xạ.

Góc Nhìn Frontend (JavaScript/TypeScript)

Trong trình duyệt, camelCase là phong cách thống trị tuyệt đối.

const user = await fetchUser();
console.log(user.first_name); // Violates ESLint camelcase rule
render(user.email_address);

ESLint sẽ gắn cờ đây là cảnh báo, buộc các nhà phát triển phải tắt quy tắc hoặc chuyển đổi dữ liệu ngay lập tức khi nhận được.

// Verbose renaming
const { first_name: firstName, last_name: lastName } = response.data;

Điều này làm tăng mã boilerplate và khả năng xảy ra lỗi.


3. Những Hiểu Lầm Về Hiệu Suất: Tuần Tự Hóa và Truyền Tải Mạng

Về hiệu suất, tồn tại hai hiểu lầm phổ biến: "Việc chuyển đổi tên trường quá chậm""Dấu gạch dưới làm tăng kích thước tải trọng." Hãy làm rõ bằng dữ liệu.

Hiểu Lầm 1: Chi Phí Chuyển Đổi Thời Gian Chạy

Lưu ý: Không bao giờ thực hiện chuyển đổi đệ quy toàn cục ở frontend (luồng chính của trình duyệt) bằng cách sử dụng các interceptor (ví dụ: Axios). Đối với các phản hồi lớn, điều này gây ra tình trạng giật lag trang và tiêu tốn bộ nhớ. Kết luận: Backend nên xử lý việc chuyển đổi.

Hiểu Lầm 2: Kích Thước Truyền Tải và Nén

Về lý thuyết, first_name dài hơn firstName một byte. Tuy nhiên, với tính năng nén Gzip hoặc Brotli được bật (cấu hình HTTP tiêu chuẩn), sự khác biệt này gần như biến mất.


4. Trải Nghiệm Nhà Phát Triển (DX) và Tâm Lý Học Nhận Thức

Kiến trúc không chỉ là về máy móc; mà còn là về con người.


5. Tiêu Chuẩn Ngành và Lý Do

Tổ Chức Lựa Chọn Logic Cốt Lõi & Bối Cảnh
Google camelCase Hướng dẫn API của Google (AIP-140) bắt buộc lowerCamelCase cho JSON. Ngay cả khi các định nghĩa Protobuf nội bộ sử dụng snake_case, lớp chuyển đổi bên ngoài sẽ tự động chuyển sang camelCase để phù hợp với hệ sinh thái Web.
Microsoft camelCase Với việc .NET Core đón nhận mã nguồn mở và sự ra đời của TypeScript, Microsoft đã hoàn toàn chuyển sang các tiêu chuẩn Web, từ bỏ PascalCase ban đầu.
Stripe snake_case Một công ty điển hình với chồng công nghệ Ruby. Họ che giấu sự khác biệt bằng cách cung cấp các Client SDK cực kỳ mạnh mẽ. Khi bạn sử dụng Node SDK, mặc dù snake_case được truyền đi, các chữ ký phương thức của SDK thường tuân theo các quy ước của JS.
JSON:API camelCase Đặc tả do cộng đồng phát triển này khuyến nghị rõ ràng camelCase, phản ánh sự đồng thuận của cộng đồng Web.

6. Lời Khuyên Kiến Trúc Chuyên Sâu: Tách Rời và DTO

Một anti-pattern phổ biến là "Truyền thẳng" (Pass-through): trực tiếp tuần tự hóa các thực thể cơ sở dữ liệu để trả về chúng.

Thực hành tốt nhất: Giới thiệu một lớp DTO (Data Transfer Object). Bất kể cơ sở dữ liệu cơ bản được đặt tên như thế nào, bạn nên định nghĩa một hợp đồng API độc lập (DTO). Vì bạn đang định nghĩa một DTO, tại sao không định nghĩa nó là camelCase để tuân thủ các tiêu chuẩn Web? Các công cụ ánh xạ hiện đại (MapStruct, AutoMapper, Pydantic) xử lý việc chuyển đổi này một cách dễ dàng.


7. Hướng Tới Tương Lai: GraphQL và gRPC

GraphQL: Cộng đồng gần như 100% đón nhận camelCase. Nếu nhóm của bạn có kế hoạch giới thiệu GraphQL trong tương lai, việc thiết kế API REST với camelCase ngay bây giờ là một chiến lược "tương thích tiến" khôn ngoan.

gRPC: Tiêu chuẩn Protobuf quy định: các tệp .proto sử dụng snake_case cho định nghĩa trường, nhưng chúng phải được chuyển đổi sang camelCase khi ánh xạ sang JSON. Đây là giải pháp tiêu chuẩn của Google cho các môi trường đa ngôn ngữ.


8. Tóm Tắt và Ma Trận Quyết Định

Không có đúng hay sai tuyệt đối, chỉ có sự đánh đổi. Dưới đây là khuôn khổ quyết định cuối cùng:

Đề Xuất: Mặc Định sử dụng camelCase

Đối với phần lớn các API RESTful mục đích chung mới, phục vụ cho các ứng dụng Web/Di động, camelCase được khuyến nghị mạnh mẽ.

Lý do: Phù hợp với sự thống trị của JSON/JavaScript/TypeScript, chấp nhận thói quen của 90% người tiêu dùng.

Công cụ: Nhận được sự hỗ trợ tốt nhất từ các trình tạo mã OpenAPI, Swagger UI và các IDE hiện đại.

Khi nào nên sử dụng snake_case?

Bảng Quyết Định

Kích Thước Phong Cách Khuyến Nghị
Web Frontend / Ứng dụng Di động camelCase (Không khác biệt trở kháng, an toàn kiểu)
Phân tích Dữ liệu / Tính toán Khoa học snake_case (Phù hợp với thói quen của Python/R)
Backend Node.js / Go / Java camelCase (Hỗ trợ gốc hoặc thư viện hoàn hảo)
Backend Python / Ruby camelCase (Khuyến nghị bộ chuyển đổi) hoặc snake_case (Chỉ dành cho công cụ nội bộ)
Đội ngũ Full-Stack Mức độ full-stack càng cao, camelCase càng được khuyến nghị

Bản chất của thiết kế API là sự thấu cảm. Trong bối cảnh API Web, việc gói gọn sự phức tạp ở backend (xử lý ánh xạ) và mang lại sự tiện lợi cho người dùng (tuân thủ thói quen JS) là lựa chọn thể hiện sự chuyên nghiệp cao hơn.

Thực hành thiết kế API trong Apidog

Khám phá cách dễ dàng hơn để xây dựng và sử dụng API