Node.js đã rất nhanh chóng bắt kịp các ngôn ngữ Java, Python, Ruby, .Net,...  để trở thành 1 trong những sự lựa chọn cho công việc lập trình ứng dụng web. Đội Node.js đã làm cho JavaScript runtime trở nên tốt hơn, nhanh hơn, đẹp hơn qua từng ngày. Cộng đồng của nó cũng ngày 1 phát triển.

Với sự tăng trưởng đó, ngày càng nhiều các developer nhảy vào công nghệ mới mẻ này, đối mặt với cùng vấn đề và code những tính năng tương tự nhau. Vì lý do đó, cộng đồng Node.js đã tạo ra các framework và các design pattern để "giúp đỡ" các lập trình viên, không chỉ giúp họ giải quyết các vấn đề thường gặp mà còn giúp cấu trúc ứng dụng Node.js.

Các framework thông thường sẽ implement MV pattern như MVC (Model-View-Controller),  MVVM (Model-View-ViewModel), MVP (Model-View-Presenter) hay chỉ đơn giản là MV (Model-View). Các pattern kể trên giúp cấu trúc code, cho biết phần code model, hay view, hay controller, nằm ở đâu; vị trí phần code cho nhiệm vụ route; code cấu hình ứng dụng, .... Rất nhiều các lập trình viên Node.js trẻ không thực sự hiểu design pattern hay OOP hay là cách cấu trúc code trong ứng dụng.

Đấy chính là lúc mà các framework Node.js như Express.js hay Sail.js trở nên lợi hại. Đương nhiên cũng có rất nhiều framework hữu ích cho các lập trình viên lựa chọn để phát triển ứng dụng web. Cho dù là framework nào, bạn cũng nên cân nhắc khi cấu trúc ứng dụng.

Dưới đây là 7 quy tắc chính mà tôi vạch ra:

Cấu trúc folder hợp lý cho ứng dụng

http://images.idgesg.net/images/article/2017/06/nodejs-directory-structure-100727502-medium.jpg

Khi quyết định cấu trúc thư mục cho ứng dụng, bạn nên cân nhắc chọn design pattern nào. Điều này sẽ giúp bạn rất nhiều trong việc tìm kiếm code, phân vùng các issue khi ứng dụng có vấn đề 1 cách nhanh chóng. Cá nhân tôi thích sử dụng MVC pattern để cấu trúc 1 ứng dụng Node.js. Nó giúp tôi develope ứng dụng nhanh hơn, sự linh hoạt mà pattern này cung cấp giúp tôi thoải mái tạo thêm nhiều view cho cùng dữ liệu, cho phép tương tác bất đồng bộ và biệt lập giữa các component.

Hình trên là cấu trúc thư mục mà tôi thông thường sử dụng, 1 sự kết hợp giữa Ryby on Rail và Express.

Tham khảo các khóa học lập trình online, onlab, và thực tập lập trình tại TechMaster

Map ER Diagram với model

"Một Entity-Relationship Diagram (sơ đồ thực thể quan hệ - ERD) là 1 kỹ thuật trình bày dữ liệu, biểu diễn các entity và mối quan hệ giữa các entity đó". Một ERD sẽ bố cục các entity có trong hệ thống và định nghĩa những tương tác giữa chúng như:

  • Bất cứ thứ gì trừu tượng hay vật lý trở thành entity trong model.
  • Liên kết 1 model với 1 bảng trong database.
  • 1 thuộc tính của entity thành 1 thuộc tính của model, thứ sẽ trở thành 1 cột trong bảng.

Ví dụ, nếu entity của bạn là 1 user, thì model tương ứng sẽ là "User" với các thuộc tính như first_name, last_name, address,.. , tương ứng với đó là 1 bảng User với các cột tương ứng với các thuộc tính.

Sử dụng 1 kiến trúc dữ liệu đơn giản sẽ giúp ta dễ dàng trong việc truy dấu database bất cứ khi nào 1 Schema mới được tạo.

Sử dụng MVP pattern

Để implement MVC pattern không đơn giản chỉ là cấu trúc thư mục thành controller, model, view mà bạn cần phải chia nhỏ code và logic dựa trên mô hình đó. Code trong phần model chỉ nên được sử dụng để truy vấn các định nghĩa schema database. Lập trình viên thường quên rằng code phần model cũng thường sử dụng các thao tác CRUD dữ liệu. Tương tự, bất kể hàm hay thao tác nào được cụ thể hóa với model đó chỉ nên nằm trong chính file đó.

Một lỗi thường thấy đó là lập trình viên thường vứt tất cả code logic vào trong controller. Controller về cơ bản chỉ là nơi gọi các function từ model hay các component khác, truyền dữ liệu giữa các component, điều khiển luồng request, trong khi thư mục view chứa code để convert object thành các văn bản hiển thị. Không nên có bất kì logic nào như format dữ liệu hay sắp xếp hay lọc được nằm trong view. Giữ cho phần view gọn gàng không chỉ cung cấp 1 trải nghiệm người dùng tốt hơn mà còn giúp thay đổi code mà không ảnh hưởng đến các component khác.

Chia nhỏ code logic thành các module

Là 1 lập trình viên, ta thường được bảo là hãy chia nhỏ code thành các file và module. Chia nhỏ code theo logic và tính năng luôn là cách tốt nhất khi làm việc với các ứng dụng. Gom nhóm các chức năng liên quan đến 1 entity hay object đơn lẻ vào 1 file và cấu trúc lại thư mục dựa theo logic có rất nhiều lợi ích. Đầu tiên nó giúp ta tiết kiệm thời gian fix bug. Thứ 2 nó giúp tách riêng các component, thuận tiện cho việc thay thế các chức năng riêng rẽ mà không cần động chạm đến các dòng code khác. Thứ 3, giúp dễ viết test hơn.

Tầm quan trọng của test case

Có 1 điều rất quan trọng là đừng bao giờ viết test 1 cách hời hợt, vì nó chính là vệ sĩ cho những dòng code của bạn. Khi ứng dụng ngày càng lớn, việc nhớ tất cả các ngữ cảnh trong khi code là 1 điều bất khả thi. Các test case lúc này sẽ giúp cho code của bạn ổn định hơn. Viết test giúp code luôn chạy đúng, đảm bảo các tính năng luôn được kiểm tra, sửa chữa, tiết kiệm thời gian quý báu. Đương nhiên nó giúp phát hiện ra những lỗi trước khi ứng dụng được public. Cuối cùng việc viết test cũng đảm bảo ứng dụng của bạn sẽ không crash giữa chừng vì những lỗi vớ vẩn.

Tầm quan trọng của log

Log rất hữu ích để debug và hiểu về trạng thái của ứng dụng. Chúng cung cấp các giá trị bên trong các hành vi của ứng dụng. Dưới đây là 1 danh sách ngắn các điều cần nhớ:

  • Tìm đúng balance khi log. Có "quá nhiều thông tin" không hẳn là tệ, tuy nhiên over-logging thì lại khác, làm cho công việc của bạn khó khăn hơn. Tìm kim trong đống cỏ thì dễ hơn dưới đáy biển. Mặt khác, under-logging trong nhiều trường hợp lại quá ít thông tin để debug hay phân tích.
  • Chia log ra thành 2 loại: offline và online; các log thường gặp nhất nên được giữ để lấy ra nhanh chóng, phục vụ nhu cầu debug hay phân tích, trong khi các log cũ hơn sẽ được thu gom và xóa nếu không cần nữa.
  • Cân nhắc đến tần suất và khoảng thời gian mà log sẽ ảnh hưởng đến bộ nhớ. Trong hầu hết các trường hợp dung lượng bộ nhớ bạn cần và số lượng log bạn có nên tương xứng.

1 điều nữa cần nhớ, đó là đừng có log những dữ liệu nhạy cảm nhưu ID email, password, thông tin credit card, số điện thoại. Không hẳn là lỗi bảo mật lớn nhưng làm thế là bất hợp pháp.

Liệu ứng dụng có mở rộng hay không?

Cách tiếp cận tệ nhất trong việc phát triển ứng dụng đó là nghĩ về việc mở rộng ứng dụng sau khi đã có 1 lượng traffic. Thay vào đó, việc cần làm chính là xây dựng 1 kiến trúc có khả năng mở rộng cao, giúp tiết kiệm thời gian và tiền bạc.

Nâng cấp server không phải là mở rộng. Phân tán load dữ liệu mới là mở rộng. Điều này không có nghĩa là bạn nên đẻ thêm 1 server khi việc load gia tăng. Đầu tiên bạn nên load balancing bên trong các tài nguyên hiện có để xử lý việc load tăng lên. Khi load balancing không thể quản lý workload hiệu quả nữa thì đấy chính là lúc để mở rộng theo chiều ngang, kiếm thêm server. Có thể thực hiện thông qua 1 quá trình independent stateless hoặc module. Mỗi process hoặc module sẽ làm việc độc lập. Điều này không chỉ giúp ứng dụng mở rộng hiệu quả mà còn khiến hệ thống dễ recover hơn.

Cách mà bạn cấu trúc ứng dụng cũng quan trọng không kém việc bạn chọn công nghệ nào. Nếu nền tảng không hoàn thiện, ứng dụng cuối cùng cũng sẽ crash, hoặc khó mở rộng, hoặc trong nhiều trường hợp, fail ngay từ bước đầu. Đừng bao giờ nhảy thẳng vào phát triển tính năng mà chưa lên kế hoạch tốt và kiến trúc ứng dụng hợp lý. Cấu trúc, kiến trúc ứng dụng tồi tệ thì cũng chả khác gì việc bạn đang ôm trong người 1 quả bom hẹn giờ.

Bài viết được dịch từ: http://www.infoworld.com/article/3204205/node-js/7-keys-to-structuring-your-nodejs-app.html