49 điểm bởi rtyu1120 2025-01-14 | 8 bình luận | Chia sẻ qua WhatsApp

Chương Frontend của Toss đã đăng một trang giới thiệu về các tiêu chí mà họ cho là một đoạn mã frontend tốt.

  • Giải thích dựa trên TypeScript, ngôn ngữ mà các lập trình viên frontend thường sử dụng
  • Đưa ra best practice từ 4 góc nhìn: khả năng đọc, tính dễ dự đoán, tính gắn kết và độ kết nối
  • Cung cấp ví dụ sử dụng các thư viện thường được dùng trong frontend thực tế

4 tiêu chí

  1. Khả năng đọc
    Khả năng đọc (Readability) là mức độ dễ đọc của mã. Muốn mã dễ chỉnh sửa thì trước hết phải có thể hiểu được nó đang thực hiện hành vi gì.

  2. Tính dễ dự đoán
    Tính dễ dự đoán (Predictability) là mức độ mà các đồng nghiệp cùng cộng tác có thể dự đoán được hành vi của hàm hoặc component. Mã có tính dễ dự đoán cao tuân theo các quy tắc nhất quán, và chỉ cần nhìn vào tên hàm hoặc component, tham số và giá trị trả về cũng có thể biết nó hoạt động như thế nào.

  3. Tính gắn kết
    Tính gắn kết (Cohesion) là việc những phần mã cần được sửa đổi có luôn được sửa cùng nhau hay không. Mã có tính gắn kết cao sẽ không vô tình gây lỗi ở phần khác khi sửa một phần của mã. Đó là vì cấu trúc của nó bảo đảm rằng những phần cần sửa cùng nhau chắc chắn sẽ được sửa cùng nhau.

  4. Độ kết nối
    Độ kết nối (Coupling) là phạm vi ảnh hưởng khi chỉnh sửa mã. Mã có phạm vi ảnh hưởng nhỏ khi được sửa, nên có thể dự đoán được phạm vi thay đổi, là loại mã dễ chỉnh sửa.

8 bình luận

 
savvykang 2025-01-15

Tôi muốn hỏi vì sao người ta dùng file làm đơn vị quản lý tối thiểu cho component và hook. Tôi cũng đoán có thể là do hỗ trợ từ IDE hoặc tree shaking còn hạn chế, nhưng không chắc nên xin được hỏi.

Khi đọc code, mỗi lần gặp một file chỉ có đúng một hàm, hoặc file index.ts chỉ có câu lệnh import/export, thì số thứ phải ghi nhớ lại tăng lên. So với cách trộn hook và component trong một file duy nhất, tôi thấy đây là một cách tổ chức làm tăng tải nhận thức nhiều hơn mức cần thiết. Dù vậy, cách bố trí như vậy có ưu điểm hay lý do gì để người ta vẫn sử dụng không?

 
firea32 2025-01-20

Thông thường, tiền đề lớn của cái gọi là “phát triển tốt” trong những chỗ như thế này là có rất nhiều lập trình viên cùng làm việc.
Việc như bạn nói, có nhiều thứ phải nhớ hơn = nghĩa là bản thân bạn đang chịu trách nhiệm cho toàn bộ dự án, nhưng
trong môi trường có nhiều lập trình viên thì mỗi người chỉ phát triển phần mình phụ trách thôi.
Khi có vấn đề phát sinh thì chỉ cần xem phần đó, chứ không cần phải nhìn vào tất cả các phần liên quan.
Xét theo một góc độ nào đó, tôi nghĩ đó là việc chọn năng suất thay vì tối ưu hóa cực đoan.

 
savvykang 2025-01-20

Đúng như bạn nói, trong môi trường có thể phân chia công việc một cách chi tiết thì nội dung của bài viết là một lựa chọn phù hợp. Tôi nghĩ bài viết sẽ hoàn chỉnh hơn nếu có thêm phần giải thích về trade-off khi tách mã và các tiêu chí để đưa ra quyết định.

 
beenzinozino 2025-01-16

Trong trường hợp của tôi, khi phát triển frontend, lý do tôi dùng file làm đơn vị quản lý tối thiểu cho component hoặc hook là như sau.

  1. Dễ kiểm thử.

Tức là dễ ghép một mô-đun với một unit test.

Tôi cho rằng phát triển frontend chủ yếu dựa trên mô hình dùng hàm thuần, nhưng nếu có nhiều hàm trong một file thì sẽ khó ghép 1:1 khi viết unit test.

Ví dụ, nếu trong một file tên là remark-plugin.js có nhiều hàm utility, thì nên viết test như thế nào? Có phải là một lựa chọn tốt khi chỉ tạo một file remark-plugin.test.js rồi viết gộp test cho nhiều hàm utility đó không?

Trong tình huống này, nếu tạo một thư mục tên là remark-plugins và tách từng hàm utility ra riêng để viết test, thì về sau có thể làm rõ vai trò của từng hàm hơn, đồng thời cũng có những lợi ích như việc theo dõi commit trên GitHub trở nên gọn gàng hơn rất nhiều.

  1. Cấu trúc hóa thư mục

Các module bundler như commonjs ở phía server hoặc webpack ở phía client thường chỉ định file index.js làm file đầu vào của một thư mục cụ thể. Đây cũng là một tập quán đã được dùng từ lâu, nên một phần lý do là cứ thế chấp nhận và sử dụng.

Tuy nhiên, theo tôi lý do quan trọng nhất là trong mô hình hàm thuần của lập trình hàm, không nên phụ thuộc vào trạng thái bên ngoài, nên nếu nhiều hàm bị dồn vào một file thì xác suất vô tình tham chiếu trạng thái bên ngoài sẽ cao hơn. (Có lẽ sẽ hữu ích nếu nghĩ về lý do module scope xuất hiện trong ES6.)

  1. Dễ theo dõi commit.

Cá nhân tôi thấy rằng thay vì để nhiều hàm utility trộn trong một file, nếu tách chúng ra thành các file riêng thì việc lần theo commit history sẽ đơn giản hơn nhiều.

Khi một chức năng được thêm vào hoặc một bug được sửa trong một mô-đun nào đó, ta có thể chỉ tập trung vào đúng mô-đun đó mà không cần tham khảo các mô-đun khác.


Viết đến đây thì bài hơi dài nên có phần thiếu mạch lạc. (Vì tôi vẫn chưa hiểu sâu về tree shaking nên xin phép không nói nhiều về phần đó...) Tất nhiên, ý kiến của tôi có thể không phải là đáp án đúng, nên mong bạn chỉ xem như tài liệu tham khảo!

 
thkimdev 2025-01-15

Cái này hay đấy

 
illiil1lii 2025-01-15

Bài viết được trình bày rất mượt mà, dễ đọc. Mình khuyên nên đọc.

 
tsboard 2025-01-15

Cảm ơn bạn đã chia sẻ! Tôi cũng cần đọc thật kỹ mới được.

 
bbulbum 2025-01-14

Dù được viết giới hạn trong phạm vi FE, nhưng có vẻ đây là những câu chuyện rất đáng áp dụng cho phần mềm nói chung. Cảm ơn bạn đã chia sẻ những góc nhìn sâu sắc.