32
1 id ObjectId Mã nhận dạng
2 name String Tên cách nấu ăn
Hình 3.6: Mô tả CookMethod
3.4. Kết chương
Chương này trình bày các phân tích và thiết kế hệ thống với các sơ đồ chức năng và sơ đồ lớp. Ở chương sau chúng tôi sẽ trình bày về quá trình hiện thực hệ thống, xây dựng kiến trúc hệ thống và xây dựng các API, ứng dụng mobile và chatbot.
33 Chương 4. HIỆN THỰC HỆ THỐNG 4.1. Mở đầu
Sau khi đã phân tích và thiết kế hệ thống, đưa ra được các chức năng cần thực hiện bước tiếp theo cần hiện thực các chức năng đó. Trong chương này sẽ trình bày về kiến trúc của hệ thống và cách xây dựng các API, giao diện ứng dụng và chatbot.
4.2. Kiến trúc hệ thống
Hình 4.1: Kiến trúc hệ thống
Mobile(Client): thể hiện giao diện nơi người dùng tương tác với hệ thống.
Client giao tiếp với Server thông qua Request/Response để yêu cầu xử lý thông tin và nhận kết quả hiển thị lên cho người dùng. Mobile (client) được hiện thực hóa sử dụng Flutter.
Server (Nodejs): Nhận và xử lý request từ Client. Có thể tương tác với
Database (MongoDB) để tương tác dữ liệu và trả kết quả về cho Client thông qua Response. Server được hiện thực hóa sử dụng ExpressJS.
34
Chatbot(Rasa): Mobile sẽ kết nối trực tiếp tới Restful api chatbot nhằm xử
lý các hành vi chat/tương tác của người dùng, để đưa ra mẫu câu/hành động phù hợp.
Api-Database(Edamam, Cooky): Chatbot sẽ kết nối trực tiếp với dữ liệu
APi ( để tìm kiếm công thức nấu ăn, thực đơn,...)
Database (MongoDB): lưu trữ các dữ liệu người dùng (bài viết, video,
ảnh,...).
4.3. Xây dựng Server
4.3.1. Mô hình ba lớp
Để xây dựng server công việc đầu tiên là lựa kiến trúc lập trình. Lợi ích của việc này là giúp source code rõ ràng hơn, dễ dàng quản lý, phát triển và bảo trì khi có thay đổi và mô hình nhóm lựa chọn là mô hình ba lớp. Mô hình này sẽ tách biệt hoàn toàn logic nghiệp vụ cũng như truy vấn database ra khỏi API route và chuyển chúng đến các layer tương ứng.
35
• Controller layer (API routes and endpoints) Đây là module code cho phép
định nghĩa các API route trong ứng dụng. Nhiệm vụ module này là xác thực data và chuyển đến Service Layer để xử lý.
• Service layer (for business logic) Module này cho phép tạo ra lớp tách biệt
ra khỏi các API Router. Mỗi một service tương ứng với một nhiệm vụ riêng biệt (Nên tuân theo nguyên tắc SOLID). Việc chuyển logic nghiệp vụ vào module này cho phép các thể tái sử dụng ở các API khác nhau một cách hiệu quả.
• Data access layer (for working with a database) Module này đảm nhận trách
nhiệm giao tiếp với database với các công việc truy vấn như get, update, create,.... Ngoài ra các công việc như định nghĩa model, ORM, connect database đều được thực hiện tại đây.
4.3.2. Cấu trúc thư mục
Sau khi đã chọn được kiến trúc lập trình công việc tiếp theo là áp dụng kiến trúc này để xây dựng cấu trúc thư mục cho phần source code để chia nhỏ các phần công việc và quản lý chúng hiệu quả, dưới dây là cấu trúc mà nhóm đã xây dựng
Hình 4.3: Cấu trúc thư mục của Server Theo cấu trúc này source sẽ được chia thành 10 folder, trong đó:
36
• Config: Chứa các cài đặt cơ bản để xử lý các vấn đề chung của mỗi request
nhằm giảm bớt công việc khi xây dựng các api.
• Utils: Sẽ chưa các hàm tiện ích chung sẽ được tái sử dụng ở nhiều nơi.
• Routes: Chưa các api routes.
• Middlewares: Nó đóng vai trò trung gian giữa request/response và các xử lý
logic bên trong server. sẽ là các hàm được dùng để tiền xử lý, lọc các request trước khi đưa vào xử lý logic hoặc điều chỉnh các response trước khi gửi về cho người dùng.
• Permissions: Đây là nơi chứa các hàm kiểm tra quyền và cho phép sử dụng
api này hay không.
• Validations: Khi một request gửi đến sẽ bao gồm các dữ liệu kèm theo,
validation sẽ kiểm xem các dữ liệu này có hợp lệ hay không trước khi được đưa đến phần controller để xử lý. Validations sẽ chứa các object để lưu cấu trúc kiểm tra cho các request.
• Controllers: Chứa các module với nhiệm vụ chuyển các data đến services.
• Services: Đại diện cho service layer, nơi đây chưa các module với logic nghiệp
vụ và tương tác với Data access layer. Các module này cho phép tái sử dụng các api khác.
• Models: Đây là nơi chưa các schema cho các collection tương ứng được lưu
trữ trên MongoDB.
4.3.3. Xây dựng các thành phần
Theo kết quả của phần thiết kế dữ liệu và chức năng chúng tôi đã xây dựng chúng tôi chia chia các collection thành 3 nhóm như sau
Data access: có 18 collection với:
• 5 collection chính (Users, Posts, comments, Recipes, Products)
• 5 collection chi tiết (RecipeLikes, RecipeCooks, Ratings, CommentReactions,
37
• 8 collection tra cứu (Ingredients, Units, SpecialGoals, MenuTypes, Cuisines,
DishTypes, CookMethods, ProductTypes)
Sau khi đã chia các collection thành các nhóm chúng tôi xây dựng Mongo Schema dựa trên phần thiết kế cho tất cả các collection. Với dữ liệu trên một ứng dụng mạng xã hội, dữ liệu sẽ lớn dần theo thời gian. Đối với các dữ liệu tương đối lớn, hàng chục ngàn record trở lên việc quan tâm tới thời gian thực thi là cực kì quan trọng. Nó giúp tăng hiệu năng của ứng dụng, giúp trải nghiệm của người dùng được tốt hơn. Nó giúp tăng hiệu năng của ứng dụng, giúp trải nghiệm của người dùng được tốt hơn. Trong MongoDb, Indexes nó hỗ trợ việc thực thi những câu lệnh query một cách hiệu quả. Index trong database cũng giống như mục lục của một cuốn sách. Thay vì tìm từng trang của cuốn sách Database tạo một mục lục, và nó chỉ việc tìm nội dung của cuốn sách qua mục lục đó. Qua đó giúp cho câu lệnh truy vấn nhanh hơn. Một câu truy vấn không có index được gọi là table scan. Nghĩa là Database phải xem qua toàn bộ các Document để tìm được kết quả truy vấn, và đối với các collection lớn, câu truy vấn sẽ rất chậm. Do đó sau khi xây dựng schema chúng tôi thiết lập các indexes cho các collection để phục vụ các chức năng truy vấn và tìm kiếm. Sau đó là gắn thêm các plugin cho chúng, ở đây chúng tôi sử dựng 2 plugin là toJson và pagination.
Service: Sau khi đã có các collection chúng tôi xây dựng có các service để tương
tác với chúng theo thứ tự như sau:
• Mỗi collection chính có 6 service gồm Create, Query, GetById, UpdateById,
DeleteById, TextSearch.
• Recipe xây dựng thêm các service Like, Dislike, Mark Cooked, Unmark
Cooked, Vote, Unvote
• Post và comment thêm service React và Delete Reaction
• User có follow và unfollow
38
• Mỗi collection tra cứu có 5 service Create, Query, GetById, UpdateById, DeleteById.
• Với media bao gồm image và video xây dựng service upload, download, và
getList.
Với các service của các collection chính, cần xây dựng các câu lệnh truy vấn để trả về các thông tin cần thiết cho service đó, các dữ liệu từ collection khác. Để làm điều này với MongoDb chúng tôi sử dụng Aggregate và xây dựng các pipeline phù hợp với từng collection.
Controller: Tương ứng với mỗi service sẽ xây dựng một validate để kiểm tra dữ
liệu đầu vào từ request và một controller để chuyển dữ liệu cho service sau đó xây dựng route và gắn các thành phần vào. Sau khi đã có các route chúng tôi chia thành các cụm và kiểm thử với Postman với kết quả như sau
39
Hình 4.4: Kết quả xây dựng các API route
4.4. Xây dựng ứng dụng mobile
4.4.1. BLoC Pattern
Cũng như việc xây dựng server, khi xây dựng ứng dụng mobile cũng cần lựa chọn một kiến trúc phù hợp để dễ dàng phát triển và phát hiện các bug dễ dàng hơn. Xây dựng một ứng dụng Flutter thì lựa chọn phổ biến nhất là BLOC pattern. Pattern này tách code business logic ra khỏi UI. Code business logic được tách ra đó người ta đặt tên là BLoC (Business Logic Component). BLoC là 1 hệ thống quản
lý state cho Fultter được đề nghị bởi Google developers. Nó giúp lập trình viên quản lý state và luồng dữ liệu trong ứng dụng của 1 màn hình tốt hơn vì các state sẽ được quản ở Bloc tách biệt với UI. Chính vì vậy, mỗi màn hình trong app flutter
40
nên tạo ra 1 bloc để xử lý logic của màn hình đó và quản lý state của cả màn hình đó.
Hình 4.5: BLOC pattern cho flutter
4.4.2. Cấu trúc thư mục
Từ sơ đồ BLOC pattern và kiến thức lập trình Flutter chúng tôi ứng dụng vào source code và xây dựng cấu trúc thư mục như sau:
41
Hình 4.6: Cấu trúc thư mục trong ứng dụng Flutter • Core: Đây là nơi chứa các class cơ sở để kế thừa sau này.
• Blocs: Nơi chứa tất cả các bloc của ứng dụng
• Local services: Tương tác với các dữ liệu được lưu ở máy
• Remote services: Tương tác với các dữ liệu lưu trữ ở nơi khác
• Responses: Các class với hàm chuyển dữ liệu trả về từ response sang dạng
model tương ứng.
42
• Repositories: Làm trung gian giữa Bloc và service, xử lý các dữ liệu và
chuyển đến tầng tiếp theo.
• Pages: Nơi hiện thực các giao diện của ứng dụng.
• Widgets: Chứa các widget nhỏ có thể tái sử dụng ở nhiều nơi
• Utils: Chứa các module có thể được tái sử dụng.
• Các folder khác: Style của ứng dụng như asset, color, constant, language, … 4.4.3. Xây dựng các thành phần
Dựa trên phần thiết kế usecase và thiết kế giao diện, chúng tôi đã xây dựng các giao diện và chức năng theo cấu trúc source code trên. Cụ thể như sau:
Công việc đầu tiên là xây dựng và kiểm tra xem các request tới api bằng cách xây dựng các remote service tương ứng với các api và các repositories để quản lý chúng. Sau đó chúng tôi xây dựng một page để kiểm trả tất cả api này.
Để sử dụng kết quả api trả về là các json, cần xây dựng các lớp để chuyển đổi chúng, tương ứng chúng tôi xây dựng các response và model file theo cấu trúc từ đoạn json trả về.
Sau khi đã chuẩn bị xong phần dữ liệu cho ứng dụng chúng tôi sẽ xây dựng các Page và các Bloc tương ứng cho mỗi Page như sau:
4.4.3.1. Màn hình đăng nhập
Đây là màn hình đầu tiên khi mở ứng dụng. Nhập thông tin và nhấn nút đăng nhập.
43
Hình 4.7: Màn hình đăng nhập
4.4.3.2. Màn hình chính
Màn hình hiển thị danh sách các bài viết
• Nhấn vào dấu cộng ở góc phải màn hình để mở màn hình thêm bài viết
• Tương tự, nhấn nút kính lúp kế bên để tìm kiếm
• Ở mỗi bài viết trong danh sách:
o Nhấn giữ nút reaction để chọn loại react
o Nhấn comment để mở màn hình bình luận
44
45