Blog
Clean Architecture + Modular Monolith: Xây hệ thống vẫn rõ khi lớn
Hướng dẫn trực quan về Clean Architecture để bảo vệ quy tắc nghiệp vụ, và Modular Monolith để mở rộng team trước khi nhảy sang microservices.

Hầu hết sản phẩm không thất bại vì chọn sai framework ban đầu. Chúng thất bại vì cấu trúc tan dần khi hệ thống lớn: module lẫn vào nhau, quy tắc nghiệp vụ chảy vào controller, và mỗi thay đổi đều rủi ro.
Clean Architecture và Modular Monolith không đối đầu nhau. Dùng cùng lúc, chúng cho một mặc định thực tế: bảo vệ phần lõi nghiệp vụ, chia hệ thống theo mảng nghiệp vụ rõ ràng, và hoãn độ phức tạp của hệ thống phân tán cho đến khi thật sự cần.
Clean Architecture bảo vệ điều gì
Clean Architecture nói về quy tắc phụ thuộc hơn là thư mục: phụ thuộc trong mã nguồn luôn hướng vào trong. Vòng ngoài được biết vòng trong, còn vòng trong không được biết framework, cơ sở dữ liệu hay cách giao tiếp.
Domain
Quy tắc nghiệp vụ nằm ở đây
Frameworks & Drivers
UI · DB · APIs · Messaging
Interface Adapters
Controllers · Presenters · Gateways
Application
Use cases · Ports · Điều phối
Domain
Entities · Rules · Policies
Ở trung tâm là các thực thể và chính sách tạo nên giá trị sản phẩm. Bao quanh là các use case, rồi các adapter kết nối với thế giới bên ngoài, và ngoài cùng là framework, giao diện, cơ sở dữ liệu. Nếu ngày mai đổi Postgres sang nơi lưu trữ khác, hoặc REST sang gRPC, phần nghiệp vụ gần như không cần biết.
Ba câu hỏi giúp kiểm tra nhanh:
- Bạn giải thích được quy tắc nghiệp vụ mà không nhắc đến NestJS, Laravel, Spring hay React không?
- Bạn kiểm thử được use case bằng dữ liệu giả, không cần cơ sở dữ liệu thật không?
- Đổi tên bảng có làm hỏng ngôn ngữ nghiệp vụ, hay chỉ ảnh hưởng adapter?
Nếu câu trả lời là không, kiến trúc đang nói quá nhiều về hạ tầng.
Modular Monolith trông ra sao
Modular monolith vẫn là một ứng dụng triển khai được, nhưng bên trong được tổ chức theo năng lực nghiệp vụ, không chỉ theo tầng kỹ thuật. Mỗi module sở hữu API, luồng xử lý, mô hình nghiệp vụ và phần lưu trữ của riêng nó. Các module nói chuyện qua hợp đồng rõ ràng, không xem bảng dữ liệu của nhau.
Modular Monolith
Một process · hạ tầng dùng chung · ranh giới theo module
Identity
- API / Controllers
- Application services
- Domain model
- Persistence adapter
Catalog
- API / Controllers
- Application services
- Domain model
- Persistence adapter
Ordering
- API / Controllers
- Application services
- Domain model
- Persistence adapter
Billing
- API / Controllers
- Application services
- Domain model
- Persistence adapter
Fulfillment
- API / Controllers
- Application services
- Domain model
- Persistence adapter
Reporting
- API / Controllers
- Application services
- Domain model
- Persistence adapter
Nền tảng dùng chung
Auth middleware · observability · messaging bus · helper truy cập DB, không chia sẻ domain logic giữa các module.
Với nhiều sản phẩm Việt Nam, đây là điểm cân bằng tốt: đủ cấu trúc để nhiều người cùng làm, mà chưa phải trả chi phí của hàng chục service, độ trễ mạng và pipeline triển khai ngay từ ngày đầu. Mỗi module có thể tự tổ chức như một hệ thống Clean nhỏ:
ordering/
domain/ entities, value objects, domain services
application/ use cases / ports
adapters/ http, persistence, messaging
ordering.module.ts
Gọi giữa các module đi qua API của tầng application hoặc thông điệp trong cùng tiến trình, không dùng chung một mô hình cơ sở dữ liệu lớn.
Giữ monolith hay tách service
Bạn không cần microservices để trông “hiện đại”. Bạn cần ranh giới đủ đáng tin.
Nên giữ modular monolith khi:
- Một sản phẩm, vài đội, phát hành thường xuyên và mỗi thay đổi thường chạm nhiều phần của hệ thống.
- Cần nhất quán mạnh giữa các luồng (thanh toán, hóa đơn, tồn kho).
- Muốn phát triển cục bộ nhanh và vận hành đơn giản.
Cân nhắc tách service khi:
- Một module cần mở rộng riêng hoặc chạy trong môi trường hoàn toàn khác.
- Nhịp phát hành phải tách hẳn khỏi phần còn lại.
- Cô lập lỗi đáng giá hơn chi phí mạng và giám sát.
Checklist cho buổi review thiết kế tiếp theo
- Đặt tên module theo nghiệp vụ, không theo framework (ví dụ
billing, không phảicontrollers-v2). - Giữ ngôn ngữ nghiệp vụ thuần, không đưa ORM, DTO của HTTP hay trạng thái giao diện vào phần lõi.
- Định nghĩa API công khai của module và coi các package bên trong là riêng tư.
- Cấm join cơ sở dữ liệu giữa các module trừ khi chấp nhận sự ràng buộc có ý thức.
- Đặt giám sát ở biên module để biết module nào phụ trách gì trên môi trường thật.
Kết luận: Clean Architecture giữ cho quy tắc đúng, Modular Monolith giữ cho tổ chức đúng. Cùng nhau, chúng tạo ra hệ thống vẫn đọc được sau ba tháng và vẫn phát triển được sau ba năm.
Đang thiết kế nền tảng mới, hoặc cần gỡ rối một codebase đang phình to? MinTech có thể giúp chọn ranh giới khớp với sản phẩm. Trao đổi cùng MinTech.