











Preview text:
  lOMoAR cPSD| 58833082
3. Triển khai (Implementation/Coding) 
3.1. Viết mã nguồn 
3.1.1. Tại sao cần thiết kế trước khi viết mã nguồn? 
Việc thiết kế trước khi lập trình giúp:  • 
Xác định rõ ràng yêu cầu hệ thống, tránh sai sót.  • 
Đảm bảo mã nguồn có kiến trúc tốt, dễ mở rộng và bảo trì.  • 
Hỗ trợ quá trình kiểm thử, giúp phát hiện lỗi sớm.  • 
Giúp các thành viên trong nhóm hiểu rõ nhiệm vụ của mình. 
 Ví dụ thực tế với hệ thống gợi ý sản phẩm Trong dự án, trước khi lập trình, chúng ta đã có 
một thiết kế rõ ràng, bao gồm: API Backend với Spring Boot (Java). Giao tiếp với AI Model 
thông qua REST API. Database MongoDB để lưu lịch sử gợi ý. 
3.1.2. Cách tiếp cận  • 
Tạo các RESTful API sử dụng Spring Boot.  • 
Tích hợp MongoDB để lưu dữ liệu lịch sử gợi ý.  • 
Gọi API AI thông qua một service riêng biệt. 
Gọi API AI thông qua một service riêng biệt thay vì gọi trực tiếp từ client hoặc từ nhiều phần 
khác nhau trong hệ thống có nhiều lợi ích, đặc biệt khi bạn triển khai trong một kiến trúc 
EventDriven Architecture (EDA) hoặc microservices. Dưới đây là một số lý do chính: 
1. Tách biệt trách nhiệm (Separation of Concerns)  • 
Nếu gọi trực tiếp API AI từ nhiều phần khác nhau trong hệ thống, mã nguồn sẽ bị rải rác,  khó quản lý.  • 
Một service riêng biệt giúp đóng gói toàn bộ logic xử lý liên quan đến AI (như tiền xử lý 
dữ liệu, caching, logging, thống kê, bảo mật, v.v.).   
2. Tăng hiệu suất và giảm chi phí API (Caching & Throttling)  • 
API AI (như OpenAI, Google Gemini, Claude…) thường tốn phí và có giới hạn gọi API.  • 
Một service trung gian có thể caching kết quả, giúp giảm số lần gọi API không cần thiết.  • 
Có thể rate limiting để tránh vượt quá quota của API.        lOMoAR cPSD| 58833082
3. Bảo mật & Quản lý API Key  • 
Tránh để API Key xuất hiện trên client, giảm nguy cơ bị lộ hoặc lạm dụng.  • 
Service trung gian có thể kiểm soát ai được phép gọi API AI, tránh bị spam hoặc tấn  công.   
4. Dễ dàng thay đổi hoặc nâng cấp AI model  • 
Nếu sau này muốn đổi từ OpenAI sang Claude hoặc Google Gemini, chỉ cần thay đổi 
trong service mà không ảnh hưởng đến toàn bộ hệ thống.  • 
Có thể tạo abstraction layer để hỗ trợ nhiều mô hình AI cùng lúc. 
3.1.3. Đạt các tiêu chuẩn nào thì có thể thực hiện viết mã nguồn?  • 
Đảm bảo tính đúng đắn: API trả về dữ liệu chính xác theo đầu vào, không phát sinh lỗi  runtime.  • 
Đảm bảo hiệu suất: API phản hồi nhanh, không làm chậm hệ thống. 
Sử Dụng Caching – Giảm Số Lần Gọi API 
Thay vì tính toán lại mỗi lần request, ta có thể cache dữ liệu để trả về kết quả nhanh hơn. 
🔥 Redis Cache – Lưu Kết Quả API 
Lưu dữ liệu thường truy vấn nhiều (ví dụ: danh sách sản phẩm hot). 
Lưu kết quả từ API AI (nếu câu hỏi đã từng được xử lý). 
Xử Lý Bất Đồng Bộ – Không Chờ Đợi Quá Lâu 
Thay vì chặn API chờ xử lý, ta có thể xử lý request bất đồng bộ, giúp API phản hồi nhanh hơn. 
 Bảo mật dữ liệu: Không để lộ thông tin khách hàng, sử dụng JWT Authentication cho API.  Spring Security  • 
Framework bảo mật mạnh mẽ giúp xác thực và phân quyền trong Spring Boot.      lOMoAR cPSD| 58833082 • 
Hỗ trợ authentication (xác thực) và authorization (phân quyền).  • 
Dễ dàng tích hợp với JWT, OAuth2, LDAP, Database, API Key,... 
✅ JWT (JSON Web Token)  • 
Token-based authentication – không cần lưu session trên server.  • 
Token chứa thông tin user, quyền hạn (roles), thời gian hết hạn.  • 
Dùng để xác thực API request mà không cần gửi lại username/password mỗi lần. 
✅ OAuth2 (Open Authorization 2.0)  • 
Chuẩn mở cho xác thực và ủy quyền.  • 
Cho phép ứng dụng xác thực thông qua Google, Facebook, GitHub,... mà không cần  lưu password.  • 
Kết hợp với JWT để cấp quyền cho API nhanh chóng. 
3.1.4. Các nguyên tắc  • 
SOLID Principles: Ví dụ: S (Single Responsibility) - API chỉ xử lý yêu cầu gợi ý sản 
phẩm, không kiêm nhiệm quá nhiều logic.  • 
Clean Code: Đặt tên biến, method có ý nghĩa (getRecommendedProducts() thay vì 
getData()),Viết code không lặp lại, giúp dễ bảo trì, Chỉ Viết Code Khi Cần, Code càng đơn giản 
càng tốt, tránh code phức tạp không cần thiết.  • 
Logging rõ ràng: Sử dụng @Slf4j để ghi log khi gọi API AI. 
Nếu tiêu chuẩn được đảm bảo, Unit Test sẽ dễ dàng kiểm tra logic của hệ thống. 
3.1.5. Công nghệ mã hóa và chuẩn mực mã hóa áp dụng cho phần mềm này  • 
Công nghệ sử dụng: SpringBoot(Viết RESTful API,MongoDB(Lưu lịch sử gợi ý), Feign 
Client / WebClient(Gọi API AI), Lombok(Giảm boilerplate code), MapStruct(Chuyển đổi  DTO).  • 
Chuẩn mực mã hóa: RESTful API chuẩn (sử dụng GET, POST đúng quy tắc), Spring 
Security để bảo mật API, Swagger để tài liệu hóa API.  • 
Nếu tuân theo chuẩn RESTful, việc viết API Test sẽ dễ dàng hơn, Security Test cần được 
thực hiện để đảm bảo API không bị lộ thông tin. 
3.1.6. Công nghệ mã hóa và chuẩn mực mã hóa áp dụng cho phần mềm này  • 
GitHub/GitLab/Bitbucket để quản lý mã nguồn  • 
GitFlow để kiểm soát phiên bản      lOMoAR cPSD| 58833082 • 
Khi phát hiện ra lỗi, có thể dùng Git để có thể quay lại phiên bản cũ 
3.2. Tích hợp liên tục (Continuous Integration - CI) 
3.2.1. Thực hiện tích hợp mã nguồn thường xuyên   Mục đích:  • 
Giúp phát hiện xung đột mã nguồn giữa các thành viên khi làm việc nhóm.   Phát 
hiện lỗi tích hợp sớm, giảm thời gian sửa lỗi sau này.   Cách thực hiện:  • 
Quy trình commit thường xuyên: Mỗi thành viên push code lên Git ít nhất 1 lần/ngày.  • 
Merge vào branch develop thường xuyên để tránh xung đột lớn.  • 
Sử dụng Pull Request (PR) với Code Review trước khi merge code vào main.  Chạy 
test tự động sau mỗi lần merge để đảm bảo không làm hỏng hệ thống. 
 Liên hệ với dự án gợi ý sản phẩm:  • 
Khi cập nhật API gọi AI model, cần kiểm tra xem có ảnh hưởng đến các API khác hay  không.  • 
Khi thay đổi cách lưu lịch sử gợi ý vào database, cần kiểm tra có làm hỏng truy vấn  dữ liệu cũ không. 
3.2.2. Sử dụng hệ thống CI để tự động hóa quá trình build, kiểm thử đơn vị, và 
kiểm tra chất lượng mã 
 Công cụ CI/CD phổ biến:  •  GitHub Actions  •  GitLab CI/CD  •  Jenkins  •  CircleCI 
 Quy trình CI trong dự án: 
Khi có commit mới vào Git, hệ thống CI sẽ tự động thực hiện: 
1. Build ứng dụng: Kiểm tra xem mã nguồn có thể biên dịch không. 
2. Chạy kiểm thử đơn vị (Unit Test): Kiểm tra từng chức năng nhỏ có hoạt động đúng  không. 
3. Chạy kiểm thử tích hợp (Integration Test): Kiểm tra các API hoạt động đúng khi gọi  lẫn nhau. 
4. Phân tích mã nguồn (Code Quality Check): Sử dụng SonarQube để kiểm tra lỗi code.      lOMoAR cPSD| 58833082
 Liên hệ với dự án gợi ý sản phẩm:  • 
Kiểm thử API gợi ý sản phẩm có trả về kết quả đúng không?  • 
Nếu thay đổi thuật toán gợi ý, CI cần kiểm tra có gợi ý sai sản phẩm không?  • 
Nếu cập nhật database, kiểm tra có ảnh hưởng đến dữ liệu lịch sử không? 
3.2.3. CI/CD trong dự án này nằm ở đâu?  • 
CI (Continuous Integration - Tích hợp liên tục): 
o Khi developer push code lên Git, CI sẽ tự động kiểm tra lỗi. o Nếu lỗi Unit Test hoặc 
Integration Test → Cảnh báo ngay lập tức để sửa lỗi trước khi merge.  • 
CD (Continuous Deployment - Triển khai liên tục): o Khi tất cả bài test đều đạt → hệ 
thống tự động triển khai lên môi trường staging. o Sau khi kiểm tra trên staging → có thể triển 
khai lên production một cách an toàn.  • 
Ứng dụng CI/CD vào dự án gợi ý sản phẩm: 
o CI giúp kiểm tra API AI Model: Đảm bảo API luôn trả về kết quả đúng. o CI giúp 
kiểm tra database: Tránh lỗi khi thay đổi schema của MongoDB. 
o CD giúp triển khai nhanh: Khi có cập nhật mới, có thể đẩy lên môi trường thực tế  ngay lập tức.  Kết luận  • 
CI giúp phát hiện lỗi sớm, đảm bảo code luôn ổn định.  • 
CD giúp triển khai nhanh chóng, không bị gián đoạn khi cập nhật hệ thống.  • 
Dự án gợi ý sản phẩm cần CI/CD để đảm bảo hệ thống luôn hoạt động chính xác khi cập nhật 
dữ liệu và thuật toán AI.   
4. Kiểm thử (Testing) 
4.1. Kiểm thử đơn vị (Unit Testing) 
Unit Testing (Kiểm thử đơn vị) là một kỹ thuật kiểm thử phần mềm, trong đó từng đơn vị nhỏ 
nhất của mã nguồn (thường là một hàm, phương thức hoặc lớp) được kiểm tra độc lập để đảm 
bảo rằng nó hoạt động chính xác.  4.1.1. Mục đích  • 
Kiểm tra xem mô hình AI trả về kết quả dự đoán có đúng với mong đợi không (dựa trên  dữ liệu mẫu).  • 
Đánh giá logic tiền xử lý dữ liệu đầu vào của AI trước khi đưa vào mô hình.  • 
Kiểm tra API có gửi đúng dữ liệu đầu vào cho mô hình không.  • 
Kiểm tra API có nhận và xử lý đúng dữ liệu đầu ra từ mô hình không.      lOMoAR cPSD| 58833082 • 
Đảm bảo hệ thống không bị sai lệch khi thêm tính năng mới hoặc cập nhật thuật toán dự  đoán.  • 
Giảm thiểu lỗi logic trong xử lý dữ liệu (ví dụ: lấy sản phẩm từ database, tính toán điểm  đánh giá…).  • 
Khi có thay đổi trong mô hình AI hoặc thuật toán, Unit Test giúp nhanh chóng phát hiện 
lỗi mà không cần kiểm tra toàn bộ hệ thống.  4.1.2. Đặc điểm  • 
Độc lập: Mỗi test chỉ kiểm tra một thành phần cụ thể như hàm tiền xử lý dữ liệu, hàm dự  đoán AI.  • 
Tự động hóa: Sử dụng các framework như JUnit (Java), xUnit (.NET).  • 
Chạy nhanh: Giúp phát hiện lỗi trong quá trình phát triển mà không làm chậm quá trình  CI/CD.  • 
Kiểm tra trên dữ liệu giả lập (Mock Data): Sử dụng Mockito (Java) hoặc Moq (.NET) 
để tạo dữ liệu giả.   
Hàm recommendProducts() sẽ gọi API của mô hình AI để lấy danh sách sản phẩm được gợi ý.      lOMoAR cPSD| 58833082    
4.2. Kiểm thử tích hợp (Integration Testing) 
Kiểm thử tích hợp (Integration Testing) là quá trình kiểm thử sự tương tác giữa các thành phần 
của hệ thống để đảm bảo chúng hoạt động cùng nhau một cách chính xác. 
4.2.1. Khác với Unit Testing  • 
Unit Testing chỉ kiểm tra từng đơn vị riêng lẻ (class, function).      lOMoAR cPSD| 58833082    
Mock API AI: Tránh gọi API thực, chỉ kiểm tra xem service có gọi đúng API không.      lOMoAR cPSD| 58833082 • 
Integration Testing kiểm tra sự phối hợp giữa các thành phần (services, database, API,  message queue...).   
Gửi HTTP Request đến Controller để kiểm tra: 
o Controller nhận request → Gọi service → Nhận phản hồi từ API AI → Trả kết  quả về frontend.  Kiểm tra database: 
o Sau khi gọi API, kiểm tra xem lịch sử gợi ý có được lưu đúng không.   
4.3. Kiểm thử hệ thống (System Testing) 
Kiểm thử toàn bộ hệ thống hoặc phần chức năng được xây dựng để đảm bảo đáp ứng các yêu 
cầu chức năng và phi chức năng.      lOMoAR cPSD| 58833082
4.3.1. Khác với Integration Test  • 
Integration Testing: Kiểm tra sự kết hợp giữa Service và Repository hoặc API kết nối  với nhau đúng không.    • 
System Testing: Cho phép người dùng kiểm thử sản phẩm để xác nhận rằng nó đáp ứng 
các tiêu chí chấp nhận và nhu cầu của họ.   
4.3.2. Ví dụ về System Testing  •  Mở trang web.  •  Tìm kiếm sản phẩm.  • 
Thêm sản phẩm vào giỏ hàng.  •  Thanh toán.      lOMoAR cPSD| 58833082 • 
Kiểm tra email xác nhận đơn hàng. 
💡 Test này kiểm tra mọi thành phần cùng nhau: UI, API, database, thanh toán, email. 
4.4. Kiểm thử mô hình (ML Testing) 
So sánh hai mô hình:    • 
LightGBM có ưu thế hơn một chút về Precision, điều này có thể quan trọng vì chúng 
tôi muốn tối ưu việc gợi ý sản phẩm với độ chính xác cao hơn.  • 
Random Forest có kết quả gần tương đương, điều này cho thấy dữ liệu đã được xử lý 
khá tốt và cả hai mô hình đều hoạt động ổn định,nhưng mà nhóm sẽ ưu tiên cho 
LightGBM hơn vì độ chính xác cao hơn 
LightGBM bị bias mạnh vào một sản phẩm  • 
LightGBM dự đoán "Dress Skirt T-shirt" với xác suất 95%, trong khi các sản phẩm  khác gần như 0%.  • 
Điều này có thể là do: 
o Dữ liệu bị mất cân bằng → Kiểm tra lại tập huấn luyện sau khi dùng SMOTE.        lOMoAR cPSD| 58833082
Random Forest có kết quả rời rạc  • 
Xác suất của Random Forest khá đồng đều (~0.12, 0.11, 0.09), cho thấy mô hình chưa 
phân biệt rõ giữa các lựa chọn.  • 
Sản phẩm gợi ý "Blouse T-shirt Socks Blouse Blouse Jeans Blouse Sweater" có thể 
do lỗi trong Label Encoding hoặc cách gộp dữ liệu.   
Từ các điều trên, ta cần:  • 
Kiểm tra lại phân phối dữ liệu sau khi dùng SMOTE.  • 
Xử lý lại các nhãn sản phẩm bị lỗi trong Label Encoding  • 
Xử lý lại các nhãn sản phẩm bị lỗi trong Label Encoding o Vấn đề: LightGBM bias mạnh vào một 
sản phẩm → Điều chỉnh tham số để giảm overfitting. 
o Vấn đề: Random Forest có kết quả không rõ ràng, xác suất các nhãn gần nhau.