Dưới đây là bảng tóm tắt trực quan các ý chính từ bài viết “Stop Over-Engineering Your Clean Architecture” trên Stackademic, cùng với các cảnh báo & lời khuyên thực tiễn:

Chủ đề / Ý chínhNội dungVí dụ / Ghi chúKết luận rút ra
Tình huống tác giả trải quaBan đầu tác giả áp dụng Clean Architecture quá mức — chia dự án nhỏ thành nhiều module/lớp, abstractions, “project for everything”Dự án CRUD nhỏ được chia thành MyApp.Application, Domain, Infrastructure, Persistence, Contracts, CrossCutting, Startup… mỗi module có DTOs, Interfaces, MappersKhi thêm hay sửa một trường, công việc lan ra nhiều file/lớp → phản tác dụng
Nguyên nhân dẫn đến over-engineeringCác developer coi Clean Architecture như “giáo điều”, áp dụng triệt để từng pattern mà không cân nhắc“Separate everything”, “Abstract your abstractions”, tạo lớp interface cho mọi thứ ngay từ đầuCấu trúc trở nên cồng kềnh, khó hiểu, bảo trì khó
Một số anti-pattern cụ thể– Abstraction cho mọi phần, interface + implementation dù chỉ có 1 biến thể – Use-case classes cho logic CRUD đơn giản – DTO trùng cấu trúc lặp đi lặp lại – Dependency injection / DI containers dùng “mạnh tay” dù không cần thiết – Layers “kiêu căng” mà không mang lại lợi íchVí dụ: chỉ để thực thi truy vấn đơn giản nhưng tạo thêm lớp UseCase, Service, Repository, Interface, DTO, MapperMức độ abstraction + layers phải có mục đích rõ ràng, không làm cho thiết kế “lớn hơn” vì “đẹp”
Khi nào Clean Architecture / phân tầng đúng là cần thiết– Dự án với yêu cầu phức tạp, domain business logic thay đổi nhiều – Hệ thống cần mở rộng, tách rời các phần (infrastructure, DB, API, domain) – Khi có đội ngũ & tổ chức đủ lớn để giữ chuẩnTrong các dự án enterprise, domain logic rõ ràng, các module độc lậpClean Architecture là công cụ hỗ trợ, không phải mục tiêu
Khi nào nên giữ thiết kế đơn giản hơn– Dự án nhỏ, MVP, proof-of-concept – Khi logic đơn giản, không có nhiều biến thể – Khi bạn chưa rõ domain sẽ phát triển như nàoKhông cần tạo nhiều module/lớp phức tạp từ đầu — bắt đầu đơn giản, refactor khi cầnĐừng áp dụng chuẩn “toàn bộ ngay từ đầu” nếu chưa cần
Chiến lược cân bằng / thực dụng– Bắt đầu từ kiến trúc đơn giản, mở rộng khi thực tế đòi hỏi – Chỉ abstraction & layers ở nơi có complexity thực sự – Refactor dần theo nhu cầu phát triển – Ưu tiên clarity (dễ hiểu) hơn sự “đẹp kiến trúc”Ví dụ: logic CRUD đơn giản có thể gộp service + repository; chỉ domain logic phức mới tách UseCase, Aggregate Kiểm tra mỗi abstraction xem nó có đem lại giá trị thực khôngClean Architecture nên “phục vụ bạn”, không thành “trói buộc bạn”