- Khi bảo trì một codebase xa lạ, ta tốn rất nhiều thời gian để tìm kiếm chuỗi
- Ngay cả trong dự án do chính mình viết, vẫn phải tìm nhiều thứ như tên hàm, thông báo lỗi, tên lớp
- Nếu khả năng tìm kiếm kém, bạn có thể không tìm thấy tham chiếu trong codebase và có nguy cơ coi chúng là không cần thiết
- Từ tình huống đó, tác giả rút ra một số quy tắc có thể áp dụng để duy trì Greppability của codebase
Đừng chia tách định danh
- Việc chia tách định danh hoặc xây dựng chúng động là một ý tưởng không hay
- Giả sử có hai bảng cơ sở dữ liệu là
shipping_addresses và billing_addresses, việc xây dựng tên bảng một cách động theo loại đơn hàng có thể trông hợp lý
const getTableName = (addressType: 'shipping' | 'billing') => {
return `${addressType}_addresses`
}
- Cách này có vẻ DRY nhưng không tốt cho bảo trì. Khi ai đó tìm kiếm tên bảng
shipping_addresses trong codebase, họ có thể bỏ sót đoạn này
- Hardcode định danh là cách tốt hơn
- Đoạn mã đã được refactor để tăng khả năng tìm kiếm:
const getTableName = (addressType: 'shipping' | 'billing') => {
if (addressType === 'shipping') {
return 'shipping_addresses'
}
if (addressType === 'billing') {
return 'billing_addresses'
}
throw new TypeError('addressType must be billing or shipping')
}
- Điều này cũng áp dụng tương tự cho tên cột, trường đối tượng, tên phương thức/hàm (trong JavaScript, việc xây dựng tên phương thức động là rất dễ)
Dùng cùng một tên xuyên suốt toàn bộ stack
- Đừng đổi tên trường ở ranh giới ứng dụng chỉ để khớp với một quy ước đặt tên nào đó
- Một ví dụ điển hình là lấy định danh kiểu snake_case của PostgreSQL vào JavaScript rồi chuyển thành camelCase, điều này không tốt
- Nó làm việc tìm kiếm trở nên khó hơn. Để tìm mọi chỗ, bạn phải tìm hai chuỗi thay vì một
const getAddress = async (id: string) => {
const address = await getAddressById(id)
return {
streetName: address.street_name,
zipCode: address.zip_code,
}
}
- Tốt hơn là trả về trực tiếp đối tượng đó
const getAddress = async (id: string) => {
return await getAddressById(id)
}
Phẳng thường tốt hơn lồng sâu
- Lấy cảm hứng từ Zen của Python, khi xử lý namespace thì trong đa số trường hợp, cấu trúc phẳng sẽ tốt hơn việc lồng nhiều tầng trong thư mục/đối tượng
- Nếu có hai cách tổ chức cho tệp cấu hình bản dịch:
{
"auth": {
"login": {
"title": "Login",
"emailLabel": "Email",
"passwordLabel": "Password",
},
"register": {
"title": "Register",
"emailLabel": "Email",
"passwordLabel": "Password",
}
}
}
{
"auth.login.title": "Login",
"auth.login.emailLabel": "Email",
"auth.login.passwordLabel": "Password",
"auth.register.title": "Login",
"auth.register.emailLabel": "Email",
"auth.register.passwordLabel": "Password",
}
- Nên chọn phương án thứ hai. Bạn có thể dễ dàng tìm khóa và tham chiếu chúng như
t('auth.login.title')
- Khi xét đến cấu trúc component React:
./components/AttributeFilterCombobox.tsx
./components/AttributeFilterDialog.tsx
./components/AttributeFilterRating.tsx
./components/AttributeFilterSelect.tsx
- Cách này được ưu tiên hơn cấu trúc sau
./components/attribute/filter/Combobox.tsx
./components/attribute/filter/Dialog.tsx
./components/attribute/filter/Rating.tsx
./components/attribute/filter/Select.tsx
- Xét từ góc độ tìm kiếm, bạn có thể tìm toàn bộ component có kèm namespace như
AttributeFilterCombobox thay vì những tên quá chung chung như Dialog
Ý kiến của GN⁺
- Bài viết blog này giải thích rất rõ tầm quan trọng của việc tìm kiếm định danh khi bảo trì codebase
- Việc xây dựng định danh động hoặc đổi tên ở ranh giới ứng dụng khiến việc bảo trì mã trở nên khó khăn hơn. Định danh cần nhất quán và rõ ràng
- Thay vào đó, hardcode định danh và giữ namespace phẳng sẽ tốt hơn về mặt tìm kiếm
- Nên áp dụng các nguyên tắc này vào dự án để tăng tính dễ đọc và khả năng bảo trì của mã
- Ngoài các quy tắc mà tác giả đề xuất, vẫn còn nhiều cách khác để nâng cao chất lượng mã như viết Self-Documenting Code, dùng chú thích có ý nghĩa, v.v.
5 bình luận
Hãy chuyển thành full path của JSON, mình cũng để lại một công cụ giúp biến nó thành dạng dễ grep!
https://vi.news.hada.io/topic?id=3159
Hay đấy... greppability cơ à...
Có vẻ như việc cố gắng ghi thông tin hữu ích vào cùng một dòng càng nhiều càng tốt cũng khá hữu ích.
Hay đấy
Ý kiến Hacker News
Việc tìm kiếm các ký hiệu như tên hàm và tên lớp kém hiệu quả hơn so với việc dùng công cụ hiểu được cú pháp của mã
Sẽ rất hữu ích nếu công cụ grep có chế độ "siêu không phân biệt hoa thường"
Ủng hộ tính grep được
Khi thiết kế Hamilton, mục tiêu là giúp dễ grep các định nghĩa hàm và các phần sử dụng phụ thuộc vào chúng
'greppable' không phải là một từ/khái niệm thường được dùng riêng lẻ
Từng thấy một ví dụ phức tạp dùng nội suy chuỗi có điều kiện
Nhiều phong cách lập trình và công cụ giữ hằng chuỗi trên một dòng bất kể độ dài dòng
Rust, Javascript, Lisp đặt từ khóa trước định nghĩa hàm nên dễ tìm kiếm
Đồng ý với khả năng tìm kiếm trong mã, nhưng phản đối việc giữ nguyên cùng một tên khi đi qua các ranh giới
Khả năng tìm kiếm trong mã là tốt, nhưng ví dụ này cố tình làm tăng khả năng phát sinh lỗi