Viết một app dựa trên Mini-Web-Server và Clean Architecture

Mỗi khi nghe đến SOLID hay Clean Architecture, nhiều người cứ nghĩ nó phải là cái gì đó phức tạp và khó hiểu lắm. Nhưng không, người ta luôn cố gắng làm cho mọi thứ thật đơn giản để càng nhiều người học được càng tốt, công nghệ càng dễ nắm bắt sẽ càng phổ biến. Clean Architecture cũng vậy, thực chất nó rất đơn giản và dễ hiểu, ngay cả trong cuốn sách “Clean Architecture: A Craftsman’s Guide to Software Structure and Design” thì phần nói riêng về nó cũng chỉ đâu đó tầm chục trang (trong khi cả cuốn sách là hơn 300 trang). Tất nhiên, muốn hiểu về nó bạn cũng cần phải trang bị trước những kiến thức khác, nhưng tôi muốn khẳng định rằng, nó không hề phức tạp như bạn nghĩ.

Xin giới thiệu với các bạn 1 project nhỏ demo cho Clean Architecture, dựa trên Mini-Web-Server, sử dụng MVC, và được viết ngắn gọn hết sức có thể, hầu như mọi thứ “râu ria” đều bị loại bỏ, ngay cả những phần như xác thực dữ liệu cũng không có. Mục đích là để bạn có thể tập trung cho câu hỏi: Trong Clean Architecture, cái gì sẽ nằm ở đâu?

Các bạn có thể truy cập tại đây: https://github.com/daohainam/minishop

Nếu đọc thử một file Controller (https://github.com/…/Mini…/Controllers/HomeController.cs) nếu không để ý có lẽ các bạn sẽ nhầm đây là một controller của ASP.NET🙂.

Ghi chú:

– Phần giỏ hàng mình chưa làm, phần Product đã hoàn thành. Thật ra thì chỉ cần phần Product là đủ demo rồi.

– Template được dùng ở đây: https://startbootstrap.com/template/shop-homepage.

– Tên các project được đặt theo các lớp trong Clean Architecture để giúp các bạn dễ theo dõi (Entity, UseCase, Adapter).

– Sử dụng Repository pattern để phân tách phần truy xuất dữ liệu, phần này thuộc vào tầng Adapter, nhưng mình vẫn tách ra để dễ theo dõi hơn.

– Dữ liệu được lưu trong file https://github.com/…/master/MiniShop/Data/products.json, bạn không cần cài bất cứ phần mềm CSDL nào thêm để chạy được MiniShop. Tất nhiên nếu muốn bạn có thể tạo thêm một SqlServerProductRepository chẳng hạn, và thay thế nó với InMemoryProductRepository.

– Một số phần như Authentication và Session mình thêm vào sẵn nhưng chưa dùng tới, các bạn xóa đi cũng không sao (tìm trong file Program.cs).

Open – Close Principle – Phần 2

Xem bài 1 tại đây: https://daohainam.com/2023/10/24/open-close-principle-phan-1/

Các bạn có thể xem loạt clip về SOLID tại đây: https://www.youtube.com/playlist?list=PLRLJQuuRRcFlRei0t0wbbCdzU8ujTD3jE

Trước hết, vấn đề chúng ta cần phải giải quyết là gì? Đó là tìm ra nghiệm của một phương trình bậc 1 với đầu vào là a và b cho trước, kết quả có thể là vô nghiệm, vô số nghiệm hoặc một x cụ thể nào đó.

Điều tôi muốn nhấn mạnh ở đây chính là mục đích mà chương trình được tạo ra. Thực chất khách hàng của bạn có quan tâm tới việc dữ liệu đầu vào đến từ bàn phím hay từ file không? Không! Họ có quan tâm dữ liệu sẽ được đưa ra màn hình, file PDF hay Excel không? Cũng không! Việc tìm nghiệm mới là mục đích tồn tại của chương trình này, mọi thứ khác diễn ra xung quanh và chỉ nhằm phục vụ cho mục đích này mà thôi.

Khi nhìn vào một bài toán, chúng ta sẽ phải tìm ra những thành phần tham gia vào hệ thống, cái nào quan trọng hơn cái nào, cái nào thường xuyên và cái nào không bao giờ thay đổi… Xác định đúng các thành phần này là bước quan trọng sống còn trong thiết kế, bởi chúng sẽ định hình sự phụ thuộc sau này.

Continue reading “Open – Close Principle – Phần 2”

MVC design pattern và cách chúng ta hỗ trợ trong Mini-Web-Server – phần 2

MVC là gì?

Model-View-Controller là một mẫu thiết kế cho phép ta phân tách các thành phần theo 3 chức năng:

  • Các thực thể (entity) chứa dữ liệu, hay còn gọi là Model.
  • Các View có nhiệm vụ hiển thị dữ liệu.
  • Các Controller có nhiệm vụ điều phối Model đến View.

Việc phân tách này giúp chúng ta tách biệt các thành phần với các chức năng hoàn toàn độc lập, và mang lại những lợi ích sau:

  • Dễ thay đổi: Một thay đổi nào đó trên giao diện chỉ ảnh hưởng đến View. Giả sử chương trình của bạn cần cung cấp các trang hiển thị thông tin sản phẩm khác nhau: cho người dùng web, cho người dùng trên các thiết bị màn hình nhỏ, cho máy in… thì chỉ cần tạo ra các view khác nhau, tất cả những gì trong Model hoặc code tải thông tin sản phẩm trong Controller đều không cần thay đổi.
  • Dễ test: bạn hoàn toàn có thể viết các unit test riêng biệt cho Controller (chứa business logic) hoặc View (để test giao diện), một tester cũng có thể test các view thông qua các Fake/Mock object mà không cần chờ Controller hoàn thiện.
Continue reading “MVC design pattern và cách chúng ta hỗ trợ trong Mini-Web-Server – phần 2”

MVC design pattern và cách chúng ta hỗ trợ trong Mini-Web-Server – phần 1

Loạt bài này sẽ nói về MVC design pattern, cách chúng ta thiết kế các thành phần để hỗ trợ MVC trong Mini-Web-Server.

Mô hình MVC, lưu ý hướng các mũi tên, các bạn có thể sẽ nhìn thấy nhiều hình minh họa khác với số lượng/hướng mũi tên khác nhau. Tôi sẽ giải thích kỹ hơn về điều này khi chúng ta đi vào chi tiết.

Nếu theo dõi blog này và trang Facebook Nam.NET chắc mọi người không lạ gì project Mini-Web-Server (trang github), một web server đơn giản để thông qua đó giới thiệu về những công nghệ, mẫu thiết kế, kiến trúc phổ biến, giúp các bạn hiểu sâu hơn về những gì các bạn đang sử dụng hàng ngày. Hiện tại chúng ta đã có một mini server gọn nhẹ, chạy nhanh và hỗ trợ đầy đủ các method, hỗ trợ HTTPS, các nội dung tĩnh, cho phép viết các hàm phục vụ người dùng giúp phát triển các API, cung cấp đầy đủ session, authentication/authorization thông qua JWT và cookie…

Nhưng điều quan trọng nhất mà chúng ta đạt được (cũng như tôi muốn nhấn mạnh) khi viết Mini-Web-Server không phải là nó đã hỗ trợ những gì, mà lại là việc thêm vào những tính năng mới dễ dàng như thế nào. Thông qua một kiến trúc rõ ràng và nhiều design pattern, chúng ta có một ứng dụng với các module độc lập với nhau, gắn kết với nhau thông qua các policy. Khi thay thế module phân tích các request từ sử dụng Regular Expression sang việc phân tích trực tiếp mảng byte, chuyển từ mô hình sync sang async…, chúng ta hầu như không phải làm gì khác ngoài viết module mới và thay thế với module cũ, tất cả các phần khác đều giữ nguyên. Thông qua một loạt các cơ chế dựa trên “Dependency Inversion” như Callable, Callable filters, middleware… ta có thể mở rộng ra tới chừng nào ta muốn. Và đó là thứ quan trọng nhất mà tôi muốn mang đến cho các bạn thông qua project này.

Tất cả các ứng dụng trong thực tế đều sẽ thay đổi theo thời gian, lớn hơn, nhiều yêu cầu mới phát sinh, mô hình triển khai thay đổi và thậm chí các chức năng cũng thay đổi, do vậy việc quan trọng nhất đối với một người thiết kế đó là làm ra một ứng dụng có thể dễ dàng chỉnh sửa và bảo trì, hơn là làm cho nó chạy đúng. Điều này nghe có vẻ buồn cười nhưng thử nghĩ xem, nếu chỉ để một chương trình chạy đúng (vào một thời điểm cụ thể) thì bạn đâu cần phải thiết kế? Bạn không cần các interface, không cần đa hình, khi thêm một chức năng mới, bạn chỉ việc copy từ một chức năng tương tự đã có và sửa lại một chút… Bạn sẽ có những file mã nguồn, những function hàng ngàn dòng mà đến người viết còn không hiểu nó chạy thế nào, và khi có một yêu cầu mới, bạn chỉ mong ước có thể đập ra làm lại từ đầu. Một chương trình dễ bảo trì sẽ dễ dàng được làm cho chạy đúng, nhưng một chương trình chạy đúng với một thiết kế tồi lại không chắc sẽ chạy đúng mãi (sau khi thêm các chức năng mới hoặc thay đổi trong tương lai).

Quay lại với Mini-Web-Server, chúng ta đã hỗ trợ nhiều tính năng (như quảng cáo :D), nhưng những gì các bạn nhìn thấy chỉ là một trang web đơn giản, với vài tính năng demo. Thực sự mà nói, chừng đó cũng đã đủ để bạn viết một ứng dụng web, với nội dung tĩnh trong các trang HTML, và dữ liệu động được cung cấp bởi các API. Các tính năng cơ bản này cho phép bạn viết các ứng dụng SPA (single page app) dễ dàng, hoặc cung cấp backend API cho một mobile app. Nhưng nếu muốn viết một web app bình thường với nhiều trang thì sao? Có lẽ chúng ta cần thêm một cơ chế khác nữa.

Một lựa chọn phổ biến với người viết web .NET là ASP.NET MVC, một framework cực kỳ mạnh mẽ, hỗ trợ nhiều tính năng và cực kỳ mềm dẻo (flexible), cho phép chúng ta phát triển các ứng dụng với code .NET, render nội dung với Razor, các tham số được tiền xử lý và gửi đến các action, người lập trình hầu như chỉ cần tập trung vào việc viết code xử lý, các request/response sẽ được xử lý tự động thông qua các policy được ASP.NET hỗ trợ… Vì vậy nếu Mini-Web-Server cũng hỗ trợ một mô hình như vậy thì các nhà phát triển sẽ dễ dàng xây dựng các ứng dụng dựa trên “Mini MVC” thay vì ASP.NET MVC :D. Và có lẽ đây sẽ là tính năng lớn nhất mà Mini cung cấp, là một hành trình mất nhiều tháng để hoàn thành, và tôi muốn chia sẻ cùng các bạn hành trình này, từ các bước chúng ta thiết kế, cho đến việc implement, và thậm chí những sai sót khi thiết kế đã dẫn đến những vấn đề gì. A ha! Bạn nghĩ đúng rồi đó! Tôi vẫn thường xuyên sai sót khi thiết kế và cả khi code nữa!

Nhưng trước tiên chúng ta phải hiểu một cách chính xác MVC là gì và nó hoạt động như thế nào.

(hết phần 1)

Tại sao chúng ta phải vẽ ra các sơ đồ khi thiết kế ứng dụng?

Các sơ đồ (class, sequence, E-R, database…) được vẽ ra để:

– Trực quan hóa: giúp người thiết kế dễ dàng nhìn thấy các thực thể, các mối quan hệ, tìm ra các vấn đề có thể xảy ra và xây dựng bước thiết kế tiếp theo.

– Xây dựng tài liệu giúp tra cứu lại sau này, giúp các thành viên mới tham gia vào dự án có thể hiểu được.- Trao đổi thông tin giữa các thành viên trong dự án khi thiết kế.

ℹ️ Mục đích của vẽ diagram, kể cả các UML diagram là để giúp thiết kế/lập tài liệu dễ dàng hơn, không phải là một phương pháp thiết kế.

Continue reading “Tại sao chúng ta phải vẽ ra các sơ đồ khi thiết kế ứng dụng?”

Khi nào bạn bắt đầu có thể học về thiết kế?

Có một số bạn nhắn tin hỏi về công việc thiết kế, cũng như cần chuẩn bị gì để học, trong bài này tôi sẽ gom chung một số câu hỏi thường gặp nhất dành cho các bạn quan tâm.

👉 Khi nào tôi có thể bắt đầu học về phân tích thiết kế: Để bắt đầu học, bạn cần tương đối thành thạo về lập trình, đặc biệt lập trình hướng đối tượng (OOP). Hãy nhớ OOP là một cách tư duy về tổ chức chương trình, chứ không chỉ là một phương thức lập trình. Bạn thậm chí có thể bắt đầu học về phân tích thiết kế từ năm 1, năm 2 đại học, tùy vào khả năng của bạn lúc đó đến đâu.

👉 Công việc của nhà thiết kế phần mềm là gì? Một nhà thiết kế thông thường vẫn là một developer, hàng ngày anh ta vẫn phải code, test, debug… Có lẽ hiếm có nhà thiết kế nào chỉ làm mỗi công việc thiết kế, vì 2 lẽ:- Công việc thiết kế thường không chiếm nhiều thời gian so với các phần việc khác, vẽ ra một component, cùng các class bên trong nhanh hơn nhiều so với code/test/debug/release/doc nó.- Các phần việc còn lại (code/test/debug/release/doc) cũng thực sự phức tạp, thiếu hiểu biết về chúng sẽ dẫn đến việc thiết kế ra các mô hình không thực tế, cũng như không thấy được những khó khăn có thể gặp phải. Vậy nên bạn vẫn phải làm công việc của một developer để cập nhật các kỹ năng trên. Thật sự muốn trở thành một nhà thiết kế giỏi, bạn cũng phải là một nhà phát triển giỏi, nhưng không nhất thiết phải chờ đến khi lập trình giỏi thì mới bắt đầu học thiết kế – bạn hoàn toàn có thể học song song cả hai.

Continue reading “Khi nào bạn bắt đầu có thể học về thiết kế?”

LÀM QUEN VỚI PHÂN TÍCH THIẾT KẾ

Một trong những câu hỏi tôi luôn suy nghĩ trong đầu khi bắt đầu bước vào ngành phần mềm là làm thế nào để từ một bài toán thực tế ta có thiết kế ra được các thành phần bên trong một cách đúng đắn: DLL, class, property… Tôi tin rằng các bạn cũng có cùng câu hỏi như vậy, có một kiến thức tốt về thiết kế không chỉ giúp cho công việc hiện tại mà còn mở ra một chân trời mới trong con đường sự nghiệp của bạn.Loạt bài này sẽ giúp bạn có được những kiến thức vững chắc về thiết kế phần mềm, và vì có khá nhiều vấn đề liên quan đến thiết kế nên tôi sẽ viết ra thành nhiều bài theo thứ tự, các bạn chịu khó theo dõi nhé.

Trước khi bắt đầu, ta cần thống nhất với nhau vài điều:

– Kiến thức về OOP là bắt buộc, các phương pháp thiết kế ở đây đều yêu cầu một nền tảng tốt về OOP ❗️.

– Tôi sẽ không viết riêng cho một nền tảng hay ngôn ngữ nào, nhưng sẽ tập trung vào Java và .NET, cùng các ngôn ngữ là Java và C#. Đây là hai trong những nền tảng phổ biến và tốt nhất, đặc biệt cho việc xây dựng các ứng dụng lớn.

– UML: Bạn không cần biết trước về UML, nhưng nếu có kiến thức về nó sẽ rất tốt, đôi khi tôi có thể dùng nó để mô tả.

Continue reading “LÀM QUEN VỚI PHÂN TÍCH THIẾT KẾ”