Clean Architecture và VIPER – iOS
Clean Architecture
Khái niệm này được phổ biến bởi Robert C. Martin (Uncle Bob) trong cuốn sách Clean Architecture: A Craftsman’s Guide to Software Structure and Design (Kiến trúc sạch: Hướng dẫn của người thợ lành nghề về cấu trúc và thiết kế phần mềm).
Clean Architecture (CA) là một triết lý thiết kế phần mềm và phong cách kiến trúc nhằm tạo ra các hệ thống có khả năng bảo trì, mở rộng và kiểm thử dễ dàng bằng cách tách biệt các mối quan tâm thành các lớp riêng biệt. Cách tiếp cận này nhấn mạnh vào việc giữ cho logic nghiệp vụ độc lập, giúp nó không bị ảnh hưởng bởi những thay đổi từ framework, giao diện người dùng (UI), cơ sở dữ liệu và các thành phần phụ thuộc bên ngoài.
Chi tiết về các nguyên tắc chính và cấu trúc các lớp được mô tả rõ trên trang blog Clean Coder của Uncle Bob

VIPER
VIPER là một mẫu thiết kế kiến trúc được sử dụng chủ yếu trong phát triển iOS. VIPER là viết tắt của View, Interactor, Presenter, Entity, và Router. Mô hình này thúc đẩy việc tách biệt rõ ràng các mối quan tâm bằng cách chia chức năng thành các lớp hoặc thành phần riêng biệt. Điều này giúp mã nguồn trở nên có tính mô-đun, dễ kiểm thử và dễ bảo trì hơn.

View:
- Chịu trách nhiệm cho giao diện người dùng (UI) và hiển thị thông tin cho người dùng.
- Chuyển các tương tác của người dùng (như thao tác nhấn nút) tới Presenter.
- Không chứa logic nghiệp vụ hay mã lấy dữ liệu.
- Ví dụ: Một
UIViewControllerhoặcViewtrong SwiftUI.
Interactor:
- Chứa logic nghiệp vụ cho các trường hợp sử dụng (use case).
- Chịu trách nhiệm lấy dữ liệu (ví dụ: từ mạng hoặc cơ sở dữ liệu) và xử lý dữ liệu.
- Trả kết quả về cho Presenter.
- Hoàn toàn độc lập với View và các thành phần giao diện người dùng khác.
Presenter:
- Đóng vai trò trung gian giữa View và Interactor.
- Nhận đầu vào từ View và chuyển tới Interactor.
- Xử lý dữ liệu từ Interactor và định dạng lại để hiển thị lên View.
- Xử lý logic giao diện (ví dụ: quyết định hiển thị hoặc ẩn thành phần), nhưng không làm việc trực tiếp với lớp dữ liệu.
Entity:
- Đại diện cho các mô hình dữ liệu hoặc các cấu trúc dữ liệu đơn giản.
- Chứa các thuộc tính và phương thức liên quan đến dữ liệu nhưng không có logic nghiệp vụ.
- Ví dụ: Một đối tượng
Userhoặc cấu trúc dữ liệu lấy từ phản hồi API.
Router:
- Xử lý điều hướng và chuyển màn hình.
- Quản lý logic điều hướng, đảm bảo luồng hoạt động của ứng dụng được xác định rõ ràng.
- Ví dụ: Tạo và hiển thị các
ViewControllermới.
Đặc điểm của VIPER
Tính mô-đun (Modularity)
- VIPER tổ chức ứng dụng thành các thành phần nhỏ, có tính mô-đun (module), mỗi module tương ứng với một tính năng hoặc một màn hình.
- Mỗi module độc lập và tự chứa, giúp việc cập nhật, thay thế hoặc tái sử dụng trở nên dễ dàng mà không ảnh hưởng đến các phần khác của ứng dụng.
Nguyên tắc đảo ngược phụ thuộc (Dependency Inversion Principle – DIP)
- VIPER tuân theo nguyên tắc đảo ngược phụ thuộc bằng cách đảm bảo các thành phần phụ thuộc vào các lớp trừu tượng (protocol) thay vì các triển khai cụ thể.
- Cách tiếp cận này giúp việc tạo mock cho các thành phần khi kiểm thử đơn vị trở nên dễ dàng và cho phép thay đổi triển khai nếu cần.
Khả năng kiểm thử (Testability)
- View -> Presenter: Các hành động của người dùng gọi các phương thức trong Presenter.
- Presenter -> Interactor: Các yêu cầu logic nghiệp vụ được giao cho Interactor xử lý.
- Interactor -> Presenter: Kết quả được gửi lại cho Presenter.
- Presenter -> View: Các cập nhật giao diện được gửi từ Presenter tới View.
- Presenter -> Router: Các sự kiện điều hướng được Router xử lý.
Thiết kế hướng giao thức (Protocol-Oriented Design)
- VIPER dựa nhiều vào các giao thức (protocol) để định nghĩa cách các thành phần tương tác với nhau.
- Việc trừu tượng hóa này giúp tăng tính linh hoạt, giảm sự phụ thuộc giữa các thành phần và giúp dễ dàng thay thế các thành phần khi cần.
