Trong video này mình chủ yếu chia sẻ về ý tưởng, triết lý và các đặc tính quan trọng của Clean Architecture. Một lỗi sai mình thường thấy nhất là các bạn hiểu sai cái Dependency Rule nên phần nào gây nhầm lẫn và khó triển khai.
1. Triết lý của Clean Architecture giống với Hexagonal và Onion Architecture: cô lập và lấy business logic làm trọng tâm (có thể gọi là Domain). Bên ngoài giao tiếp thông qua các Ports: Input và Output.
2. Các vòng tròn ở ngoài cùng là chi tiết nhất (low-level/details), trong cùng là high level (trừu tượng).
3. Cái “mũi tên” trong ảnh Clean Architecture không phải là “call direction” mà là “dependency direction”. Bởi vì:
4. Clean Architecture sử dụng Dependency Inversion (DI) – chữ D trong SOLID.
– High level không phụ thuộc vào low level, chúng lệ thuộc abstraction.
– Abstraction không lệ thuộc vào implements/details của nó.
Từ đó các thay đổi từ các tầng low-level (chi tiết) không gây ảnh hưởng gì đến Domain ở trong. Và domain dễ dàng test, maintain một cách độc lập.
Khi implement Clean Architecture thì cấu trúc thư mục, cách phân chia package sao cũng được, miễn thoả các đặc tính trên.
Thường để đảm bảo DI, các SE kinh nghiệm thường khai báo các interfaces cần thiết ở trong domain, sau đó viết business logic, mocktesting các kiểu xong hết mới đi xử các tầng details bên ngoài: Như DB, HTTP Handlers,…
Cách này có thể gọi là Use Case first hoặc Doman Driven. Tuy nhiên để gọi là DDD và làm đúng và đủ thì còn khá nhiều thứ nữa.
Có thời gian mình sẽ nói DDD sau!!!
Clip hướng dẫn implement Clean Architecture: https://www.youtube.com/watch?v=Y_Te5Q3gxMI
A ơi! em bị yếu về mấy thứ kiến trúc này. Em xem nhiều mà không hiểu rõ. Em nghĩ là em nên học lại cho chắc phần kiến trúc. Anh cho em lời khuyên em nên bắt đầu từ đâu ạ
Mình đọc nhiều về các loại architecture rồi, nhưng khi xem clip này mới thấy thực sự ưng ý.
Khi mình implement ở layer usercase mình sẽ define IRepository và IUserCase, còn data layer ở tầng low level nó phải import interface repo từ usercase phải k vậy?
anh ơi! giải thích thêm về domain driven design đi ak.
Cám ơn những kiến thức bổ ích mà anh đã chia sẻ.
Nice voice, nice content. I respect you. By the way, I've subcribed and I think that I'll follow you in the future.
Tôi xác nhận bạn giải thích đúng, vì tôi cũng đang làm kiến trúc này trong dự án Mobile. Bổ sung thêm phần presentation sẽ là MVVM, MVP hay MVC. Và nó gọi vào class Usecase implement kế thừa IUsecase.
Em chào Anh, Anh có thể giải thích giúp em Presenters layer implement cái gì được không ạ?
+, Flow từ: UI -> presenters -> use case
Em không biết presenters có chức năng gì trong flow này.
Cùng với đó là flow of control ở sơ đồ góc dưới dùng bên phải với ạ:
+, Controller -> use case interactor -> presenters.
Vì theo dependence rule thì low level sẽ depend vào high level nên em không hiểu cái flow này đi như nào cả.
Em mới tìm hiểu về clean nên mong Anh thông cảm vì ngôn từ có thể không được chuẩn chỉnh ạ.
Em cảm ơn Anh nhiều.
cảm ơn bạn
cho e hỏi thêm với ạ, ở phút 9:00 em thấy ý tưởng đặt `IRepository` ở tầng usecase của a rất hay. nhưng nếu làm theo cách này thì tầng data ở dưới phải import ngược lên module usecase => data layer nó phụ thuộc vào usecase layer rồi đúng k ạ, theo e ĐÚNG phải là tầng usecase phụ thuộc vào tầng data ạ. Có cách nào giải quyết vấn đề này không ạ?
dạ cho e hỏi ạ. cái dialog 4:40 . trường hợp trong project chỉ có duy nhất một 1 implementation của contract `IUseCase` và tầng Data cũng chỉ có duy nhất 1 implementation của `IRepository` thì có nhất thiết phải áp dụng DI, tạo ra 2 interface chỗ này không ạ? em thấy đang phức tạp hoá 1 vấn đề đơn giản ạ. Vì theo em hiểu mình dùng Interface để có thể thay đổi một cách dynamic at runtime mà trong project chỉ có duy nhất 1 implementation của contract đó thì "WITHOUT DI" chỗ này cũng giải quyết tốt vấn đề ạ!
Em vẫn đang chưa hiểu chút ở đoạn 6:30 phần business logic implements IUsecase như nào anh ạ? Tức là IUsecase sẽ defind những function rồi Business logic sẽ implments IUsecase đó phải không anh?
Nói xuông vậy thì em xem nhiều rồi. Chưa thấy ai bắt tay xây dựng một cái project giống y như vậy cho dễ hiểu đó anh @@
interface IRepositoryPlayer {
getAllPlayer: () => Promise<string[]>;
}
class RepositoryPlayer implements IRepositoryPlayer {
getAllPlayer() {
// get from DB
return Promise.resolve(["thuong"]);
}
}
class PlayerService {
constructor(private repository: IRepositoryPlayer) {}
}
const repoPlayer = new RepositoryPlayer();
const player = new PlayerService(repoPlayer);
Theo em hiểu cái đoạn 9:11 sẽ là ntn đúng k a ạ ?.
Cảm giác nghe nó hơi bị trừu tượng sao ấy anh Việt. Em nghĩ nếu có example demo thì sẽ tường minh hơn về kiến trúc ạ