Có một câu chuyện mà tôi thấy lặp đi lặp lại ở mọi team tôi từng đi qua. Đó là câu chuyện "bệnh viện quá giỏi" trong kiến trúc.
Anh em bắt đầu bằng một dự án nhỏ, Rails app 5 trang, Express server 3 endpoint. Rồi dự án lớn lên. Khách hàng thêm feature, product thêm yêu cầu, team thêm người. Và bỗng nhiên một ngày đẹp trời, ai đó trong sprint planning đề xuất: "Ta chia monolith ra microservices đi, cho dễ scale!"
Tôi đã nghe câu đó ít nhất 15 lần trong 20 năm qua. Và biết bao nhiêu dự án đã "chuyển đổi kiến trúc" xong rồi... tan vỡ. :D
Năm 2026, khi AI có thể viết code nhanh hơn cả senior dev, khi "code got cheap" nhưng "review didn't", thì câu hỏi về software architecture patterns càng trở nên quan trọng hơn bao giờ hết. Không phải vì complexity giảm đi, mà vì cost của complexity đã thay đổi.
Hãy cùng tôi mổ xẻ những mô hình kiến trúc phổ biến nhất năm 2026, từ "basic" nhất đến những pattern mới nổi lên.
1. Monolith Cổ Điển - Vẫn Là Lựa Chọn Của Đa Số?
Khi nào nên chọn Monolith?
Nghe có vẻ "lạc hậu" nhưng thực tế là: 90% dự án không cần gì hơn một monolith được viết đúng cách.
Để tôi kể các bạn nghe một câu chuyện. Năm 2019, tôi có một đàn em mới ra trường, gọi là Minh. Minh được giao xây dựng một internal tool cho công ty - một admin dashboard để quản lý đơn hàng, inventory, và customer data. Đơn giản, đúng không?
Thay vì dùng ASP.NET Core Razor Pages + EF Core (cái mà team đang dùng), Minh quyết định... xây bằng microservices. "Cho nó scalable," anh nói. "Cho nó hiện đại."
Kết quả là gì? Sau 3 tháng, team có 5 services, 3 databases, 2 message queues, và... một admin dashboard chưa chạy nổi. Test environment không bao giờ ổn định. Deployment pipeline phức tạp gấp 10 lần. Và khi khách hàng cần thêm một field "ghi chú" cho đơn hàng, phải deploy 4 services cùng lúc.
Đó là bài học đầu tiên: Đừng để cái tên "scalable" giết chết dự án của bạn.
Monolith được viết đúng cách trông như thế nào?
// Dự án Monolith được tổ chức tốt trong .NET
// Solution Structure:
/MyApp
/src
/MyApp.Api # Controllers, Middleware
/MyApp.Core # Domain entities, Interfaces, Services
/MyApp.Infrastructure # DbContext, Repositories, External services
/MyApp.Tests # Unit & Integration tests
Điểm mạnh:
- Deployment đơn giản: một file exe, một câu lệnh
dotnet publish - Debug dễ: attach debugger vào một process duy nhất
- Transaction đảm bảo: không phải lo eventual consistency
- Codebase nhất quán: refactor an toàn với IDE
Điểm yếu:
- Scale theo chiều dọc (vertical scaling) có giới hạn
- Deploy toàn bộ app cho mỗi thay đổi nhỏ
- Team lớn (50+ dev) sẽ conflict trên codebase
Áp dụng khi:
- Team nhỏ (< 10 developers)
- Dự án MVP / Idea validation
- Internal tools, administrative dashboards
- Deadline gấp, cần ship nhanh
2. Modular Monolith - Cái Tên Nhiều Người Biết Nhưng Ít Người Hiểu
Định nghĩa đơn giản
Modular Monolith = Một file deploy nhưng được chia thành các module độc lập bên trong.
Nói cách khác: các bạn vẫn deploy một app duy nhất (thuận lợi), nhưng bên trong code được tổ chức rõ ràng, có boundaries, có interface riêng cho từng domain.
// Modular Monolith trong .NET - ví dụ tổ chức theo Domain
namespace MyApp.Modules.Ordering;
public interface IOrderService
{
Task<Order> CreateOrder(CreateOrderRequest request);
Task<IEnumerable<Order>> GetOrdersByCustomer(int customerId);
// Module chỉ expose những gì cần thiết
}
namespace MyApp.Modules.Inventory;
public interface IInventoryService
{
Task<bool> CheckStock(int productId, int quantity);
Task ReserveStock(int productId, int quantity);
}
// Core module - ai có quyền gọi module nào?
namespace MyApp.Core.Abstractions;
public interface IModuleRegistry
{
void RegisterModule(IModule module);
object GetModule(string moduleName);
}
Tại sao Pattern này "hot" trở lại năm 2026?
Nhìn vào xu hướng from Dev.to article tôi vừa crawl được: Python + HTMX đang Dominate 2026. Tại sao? Vì nó simple, nó "believes in basic".
Nhưng thực ra đó là một dạng Modular Monolith, chỉ là ở mức độ web:
- Server renders HTML = một module duy nhất
- HTMX handles interactivity = swap DOM fragments
- Không có API boundary = không có network latency
- Không có serialization = không có JSON parsing errors
Đọc đoạn này từ bài viết trên Dev.to:
"What HTMX actually does is conceptually simple: it lets HTML elements make HTTP requests and swap parts of the page based on the response. No virtual DOM, no component lifecycle, no client-side routing. You write
hx-get="/search"and the results div updates. The HTML is the state."
Cái hay là: nó giải quyết vấn đề thực, không phải vấn đề tưởng tượng.
Best practices cho Modular Monolith
- Explicit module boundaries: Mỗi module có thư mục riêng, file riêng, namespace riêng
- Module không được reference trực tiếp sang module khác: phải qua interface
- Shared kernel thống nhất: Entity base class, exceptions chung
- Có integration test cho từng module: verify module chạy độc lập
// Module descriptor - định nghĩa contracts
public class OrderingModule : IModule
{
public string Name => "Ordering";
public IEnumerable<Type> Services => new[] { typeof(IOrderService) };
public void Register(IServiceCollection services)
{
services.AddScoped<IOrderService, OrderService>();
}
}
3. Macro Services - Vừa Đủ, Không Quá
Pattern mới nổi năm 2026
Macro Services = Mỗi service handle một bounded context đầy đủ, nhưng số lượng service rất ít (3-10 thay vì 50-100).
Đây là sự "hồi sinh" của kiến trúc SOA thực sự, sau "bệnh microservices" tràn lan.
Khác biệt với Microservices:
| Aspect | Microservices | Macro Services |
|---|---|---|
| Số lượng | 50-200 | 3-10 |
| Size code | 500-2000 dòng | 5000-20000 dòng |
| Team per service | 1-2 dev | 3-5 dev |
| Deployment | Từng service | Service group |
| Database | 1 per service | Shared hoặc 2-3 services/DB |
Khi nào nên chuyển từ Monolith?
Dấu hiệu cần chia:
- Team > 15 developers và commit conflict liên tục
- Deploy frequency khác nhau: module A cần deploy daily, module B quarterly
- Scaling requirements khác biệt: module A cần scale ngang, module B không
- Technology stack khác biệt: module A cần real-time (SignalR), module B là batch processing
Đừng bao giờ chia chỉ vì:
- "Microservices cool hơn"
- "Netflix làm vậy"
- "Scale được"
- "Interviewer thích nghe"
Ghi nhớ: Scale theo business, không phải theo architecture pattern.
4. Event-Driven Architecture - Nhưng Đừng Biến Nó Thành Religion
Khái niệm thực tế
Event-Driven = Các service giao tiếp qua events thay vì synchronous calls.
// Event example trong .NET với MediatR
public record OrderCreatedEvent(int OrderId, int CustomerId, decimal TotalAmount) : INotification;
// Publisher
public class OrderService
{
private readonly IMediator _mediator;
public async Task CreateOrder(Order order)
{
await _repository.AddAsync(order);
await _mediator.Publish(new OrderCreatedEvent(order.Id, order.CustomerId, order.Total));
}
}
// Subscriber - Inventory Service
public class OrderCreatedHandler : INotificationHandler<OrderCreatedEvent>
{
public async Task Handle(OrderCreatedEvent notification, CancellationToken ct)
{
// Reserve stock cho order
}
}
Cái bẫy của Event-Driven năm 2026
Đọc bài "Code Got Cheap. Review Didn't" từ Dev.to, có một insight quan trọng:
"The ratio inverted. Writing a hundred lines used to take hours... Now writing those same hundred lines can take ten minutes: the AI drafts, the engineer guides. Reviewing them still takes forty minutes."
Điều tương tự với architecture: Tạo event-driven system ngày nay dễ hơn nhờ AI, nhưng maintain và debug nó vẫn khó như xưa.
Các vấn đề thường gặp:
- Eventual consistency: user đặt hàng xong, vào xem order... không thấy. Refresh 3 lần mới thấy. :(
- Event duplication: Handler chạy 2 lần, process 2 lần payment
- Event missing: Message mất trên đường đi, không ai biết
- Debug khó: Không có stack trace, không biết event từ đâu
Khi nào dùng Event-Driven?
- Multi-step workflows: Order -> Payment -> Inventory -> Shipping -> Notification
- Long-running processes: Approval flows, batch jobs
- Cross-service notifications: Không cần immediate response
- Audit requirements: Cần replay events
Khi nào KHÔNG dùng?
- Simple CRUD: Đọc ghi đơn giản, không cần async
- Strict consistency required: Financial transactions
- Real-time UI required: User click xong cần thấy kết quả ngay
5. API-First + BFF - Xu Hướng Mới Của 2026
BFF Pattern (Backend For Frontend)
Thay vì một API chung cho mọi client (web, mobile, third-party), mỗi frontend có một BFF riêng:
/MobileApi # Mobile BFF - lightweight, optimized bandwidth
/users # Get user profile
/notifications # Push notifications
/offline-sync # Local cache sync
/WebApi # Web BFF - SSR optimized
/html # Return HTML fragments for HTMX
/stream # Server-Sent Events
/ThirdPartyApi # Partner API - full features, versioning
/v1
/v2
Tại sao pattern này hợp lý trong 2026?
Khi mà "Python + HTMX is dominating" như bài viết tôi crawl được, thì:
- Web không cần gọi API → server trả về HTML, HTMX swap vào DOM
- Mobile cần lightweight responses → BFF có thể transform data
- Third-party cần stability → BFF có version control
Ví dụ .NET Implementation
// BFF cho Mobile - ASP.NET Core
[ApiController]
[Route("api/v1/mobile/[controller]")]
public class UsersMobileController : ControllerBase
{
[HttpGet("me")]
public async Task<UserMobileResponse> GetCurrentUser()
{
// Lấy user với only fields mobile cần
var user = await _userService.GetUserAsync(CurrentUserId);
return new UserMobileResponse
{
Id = user.Id,
Name = user.Name,
AvatarUrl = _imageService.GetResizedUrl(user.Avatar, 100, 100), // Optimized
// Không gửi các field không cần thiết
};
}
}
6. So Sánh Tổng Quan
| Pattern | Độ phức tạp | Team size | Use case điển hình | AI-friendly |
|---|---|---|---|---|
| Monolith | Thấp | 1-10 | MVP, Internal tools | ✅ Viết nhanh |
| Modular Monolith | Trung bình | 5-20 | Mid-size apps | ✅ Viết + maintain dễ |
| Macro Services | Trung bình-Cao | 15-50 | Scale startup | ⚠️ Cần clear boundaries |
| Event-Driven | Cao | 20+ | Complex workflows | ❌ Debug khó |
| API-First + BFF | Trung bình | 10-30 | Multi-platform | ✅ Phù hợphybrid |
Lời Khuyên Cho Các Bạn Trẻ
- Bắt đầu từ Monolith: Đừng over-engineer từ đầu. Ship cái gì đó chạy được trước.
- "Believe in basic": KISS (Keep It Simple, Stupid) vẫn là nguyên tắc vàng. Complexity là cost, không phải feature.
- Chia khi đau, không phải khi mơ: Chia service chỉ khi team đông lên, deploy conflict, hoặc scale requirements thực sự.
- AI không thay thế architecture thinking: AI viết code nhanh, nhưng AI không biết bounded context nào cần chia, event nào cần handle. Đó vẫn là công việc của architect.
- Review cost quan trọng như code cost: Như bài "Code Got Cheap. Review Didn't" nhắc nhở: code rẻ rồi, nhưng maintainance vẫn đắt. Chọn architecture có maintenance cost thấp.
Tài Liệu Tham Khảo
- When to Choose Microservices (and When Not To) - Sam Newman
- Modular Monolith - Bill Busby's Approach
- HTMX in Production - Carson Gross
- .NET Microservices Architecture - Microsoft Learn
/Son Do - "believe in basic"
#SoftwareArchitecture #Monolith #Microservices #ModularMonolith #1percentbetter