Sáu quy tắc đặt tên và cách áp vào TypeScript, NestJS Cơ bản
Thời gian đọc ước tính: 6 phút
Cần đọc trước
Trang này trả lời: quy tắc chung nào áp cho mọi cái tên, và áp vào code TypeScript, NestJS cụ thể ra sao.
Đang tải diagram…
Sáu quy tắc cốt lõi
Phần tiêu đề “Sáu quy tắc cốt lõi”1. Tên nói ý định, không nói cách làm
Phần tiêu đề “1. Tên nói ý định, không nói cách làm”Người đọc cần biết giá trị này là gì, dùng để làm gì, không phải nó được tính ra sao.
// Trướcconst d = 30;const list2 = orders.filter((o) => o.s === 3);
// Sauconst refundWindowDays = 30;const shippedOrders = orders.filter((order) => order.status === OrderStatus.SHIPPED);Tên một chữ cái chỉ chấp nhận cho biến sống rất ngắn (Google TS Style Guide: phạm vi từ 10 dòng trở xuống), như i trong vòng lặp.
2. Một từ cho một khái niệm
Phần tiêu đề “2. Một từ cho một khái niệm”Codebase có cả getUser, fetchUser, loadUser, retrieveUser thì người đọc sẽ đoán chúng khác nhau. Chọn nghĩa cho từng động từ và giữ ở mọi module:
| Động từ | Nghĩa trong team | Khi không có kết quả |
|---|---|---|
find... |
Truy vấn, có thể không thấy | Trả null / mảng rỗng |
get... |
Bắt buộc phải có | Ném lỗi (NotFoundException) |
fetch... |
Gọi qua mạng (HTTP, service khác) | Tuỳ, nhưng luôn có timeout |
list... |
Trả danh sách có phân trang | Mảng rỗng |
create / update / delete |
Ghi | Dùng thống nhất, không trộn add / remove / insert |
Bảng này là một lựa chọn, không phải chuẩn. Giá trị nằm ở chỗ cả team dùng cùng một bảng.
3. Cấm từ rỗng nghĩa
Phần tiêu đề “3. Cấm từ rỗng nghĩa”data, info, item, obj, manager, helper, utils, handle, process đúng với mọi thứ, nên không nói gì. Chúng còn là nam châm hút code: utils.ts sau hai năm thành bãi rác 3.000 dòng.
// Trướcclass OrderManager { handle(data: any) { /* ... */ } }// utils.ts: formatMoney, retry, parseJwt, slugify...
// Sauclass OrderCancellationService { cancel(command: CancelOrderCommand) { /* ... */ } }// money-format.ts, retry-with-backoff.ts, jwt-claims.tsMẹo review: không đặt được tên cụ thể cho class thì nó thường đang làm hai việc. Tách ra trước, tên sẽ tự hiện.
4. Boolean là câu hỏi có/không, không phủ định
Phần tiêu đề “4. Boolean là câu hỏi có/không, không phủ định”Dùng tiền tố is, has, can, should để đọc lên như câu hỏi. Tránh tên phủ định: !isNotActive buộc não đảo hai lần.
// Trướcif (!user.notVerified && !disableRetry) { ... }
// Sauif (user.isVerified && shouldRetry) { ... }Với field của API có quan điểm ngược lại: Google AIP-140 khuyên bỏ is (disabled thay vì is_disabled). Chọn một quy tắc cho JSON contract và giữ nó.
5. Đơn vị nằm trong tên
Phần tiêu đề “5. Đơn vị nằm trong tên”timeout = 30 là 30 giây hay 30 mili giây? Giá trị trông hợp lý ở cả hai cách hiểu, nên sự cố rất khó tìm.
// Trướcconst timeout = 30;const maxSize = 10;
// Sauconst timeoutMs = 30_000;const maxUploadSizeBytes = 10 * 1024 * 1024;Khi có thể, đẩy đơn vị vào kiểu (ví dụ type Duration). Còn là number thì đơn vị phải ở trong tên: Ms, Seconds, Bytes, Cents. AIP-140 cũng khuyên viết tắt đơn vị quen thuộc trong field name, như distance_km.
6. Không tiền tố kiểu, không viết tắt tự chế
Phần tiêu đề “6. Không tiền tố kiểu, không viết tắt tự chế”Kiểu đã có trong TypeScript, đừng lặp lại trong tên. Google TS Style Guide cấm Hungarian notation và cấm viết tắt bằng cách bỏ chữ giữa từ (ví dụ cstmrId).
| Tránh | Dùng | Lý do |
|---|---|---|
strName, arrOrders, bIsPaid |
name, orders, isPaid |
Kiểu đã có trong type |
IOrderRepository |
OrderRepository |
Style guide không đánh dấu interface |
_balance cho private |
private balance |
Dùng modifier, không dùng _ |
cstmr, qty, amt, usrCfg |
customer, quantity, amount, userConfig |
Viết tắt tự chế làm grep thất bại |
loadHTTPURL, userID |
loadHttpUrl, userId |
Viết tắt coi như một từ |
Viết tắt được chấp nhận khi ai cũng biết: id, url, http, db, config, api.
TypeScript: theo Google TS Style Guide
Phần tiêu đề “TypeScript: theo Google TS Style Guide”Google TypeScript Style Guide là chuẩn công khai, đầy đủ và có lý do cho từng điều. Những điểm hay gặp trong review:
UpperCamelCasecho class, interface, type, enum, decorator, type parameter.lowerCamelCasecho biến, tham số, hàm, method, property.CONSTANT_CASEchỉ cho hằng số cấp module, static field cấp module và giá trị enum.consttrong hàm vẫn làlowerCamelCase.- Không
Iprefix cho interface, không_prefix/suffix cho private. - Viết tắt coi như một từ:
loadHttpUrl, không phảiloadHTTPURL.
// Trướcconst Max_Retry = 3;interface IPaymentGateway { ChargeCard(amt: number): Promise<any>; }class paymentService { private _gw: IPaymentGateway; }
// Sauconst MAX_RETRY_ATTEMPTS = 3;interface PaymentGateway { chargeCard(amountCents: number): Promise<ChargeResult>; }class PaymentService { constructor(private readonly gateway: PaymentGateway) {} }Đưa phần lớn quy tắc này vào ESLint (@typescript-eslint/naming-convention) để máy kiểm; review chỉ bàn về nghĩa.
NestJS: file và class
Phần tiêu đề “NestJS: file và class”Docs NestJS dùng một mẫu nhất quán trong mọi ví dụ (dù không phát biểu thành luật): file kebab-case có hậu tố theo loại, class UpperCamelCase có hậu tố tương ứng. CLI nest g resource orders cũng sinh theo mẫu này.
| Loại | File | Class |
|---|---|---|
| Module | orders.module.ts |
OrdersModule |
| Controller | orders.controller.ts |
OrdersController |
| Service | orders.service.ts |
OrdersService |
| DTO tạo mới | dto/create-order.dto.ts |
CreateOrderDto |
| DTO cập nhật | dto/update-order.dto.ts |
UpdateOrderDto (thường PartialType(CreateOrderDto)) |
| Entity | entities/order.entity.ts |
Order |
| Guard, pipe, decorator | roles.guard.ts, tenant-id.decorator.ts |
RolesGuard, TenantId |
DTO đặt theo hành động: CreateOrderDto, CancelOrderDto, không phải OrderDto dùng chung. DTO dùng chung sẽ dần có field tuỳ chọn cho từng use case, và validation mất ý nghĩa. Xem modules, providers, controllers.
Before → after: những cái tên gặp trong review
Phần tiêu đề “Before → after: những cái tên gặp trong review”| Trước | Vấn đề | Sau |
|---|---|---|
processData(data) |
Hai từ rỗng nghĩa | reconcileSettlementReport(report) |
flag |
Không biết bật nghĩa là gì | shouldNotifyCustomer |
isNotDeleted |
Phủ định kép khi ! |
isActive (hoặc deletedAt IS NULL) |
timeout: 5 |
Thiếu đơn vị | timeoutMs: 5_000 |
getUser() trả null |
Sai nghĩa get của team |
findUserById() |
UserManager |
“Manager” của mọi thứ | UserRegistrationService, UserProfileService |
IOrderRepo |
Tiền tố I, viết tắt |
OrderRepository |
Tên ở database, API và event có bảng riêng ở các trang sau.
Tiếp theo: PostgreSQL.