Cái dự án tôi muốn quên
Năm 2019, tôi nhận một dự án platform nội bộ cho một tập đoàn bán lẻ lớn. Requirement nghe có vẻ đơn giản: "Hệ thống quản lý inventory tập trung, kết nối 50 cửa hàng."
Team tôi hào hứng. Chúng tôi họp 2 ngày để thiết kế kiến trúc - microservices, event sourcing, CQRS, Kubernetes, API gateway. Đẹp như mơ trên whiteboard.
6 tháng sau, chúng tôi deliver được 30% feature. Chi phí vượt 2x budget. Và cái hệ thống "đơn giản" đó có độ phức tạp vận hành cao đến mức team IT của khách hàng không thể tự maintain.
Nhìn lại, vấn đề không phải là team kém. Vấn đề là ngay từ đầu, chúng tôi đã không hỏi đúng câu hỏi.
Câu hỏi 1: "Scale lên bao nhiêu là đủ - và trong bao lâu?"
Đây là câu hỏi tôi hỏi đầu tiên, mọi lần, không ngoại lệ.
Khách hàng thường nói "cần scale được". Nhưng scale được nghĩa là gì? 100 users? 10,000? 1 triệu? Trong 6 tháng? 5 năm?
Con số này ảnh hưởng trực tiếp đến mọi quyết định kiến trúc: database nào, caching strategy nào, có cần queue không, có cần horizontal scale không.
Dự án inventory của tôi có 50 cửa hàng, mỗi cửa hàng 2-3 nhân viên dùng. Tối đa là 150 concurrent users. Tôi đã thiết kế hệ thống như thể cần phục vụ 50,000 concurrent users. Overkill hoàn toàn.
Công thức tôi dùng bây giờ:
Peak concurrent users × 3 (safety buffer) = capacity target
Nếu target đó một monolith .NET API + single SQL Server xử lý được - thì dùng monolith. Đơn giản luôn tốt hơn.
Câu hỏi 2: "Ai sẽ maintain hệ thống này sau khi tôi bàn giao?"
Câu hỏi này nghe có vẻ không liên quan đến kỹ thuật. Nhưng nó ảnh hưởng rất lớn đến technology choice.
Tôi từng thiết kế một hệ thống beautiful với Event-driven architecture, Kafka, separate microservices cho mỗi domain. Technically flawless. Rồi bàn giao cho team IT của khách hàng - 3 người, background chủ yếu là sysadmin, không có ai từng dùng Kafka.
6 tháng sau họ gọi lại: "Anh ơi hệ thống lag, không biết tại sao." Tôi debug 2 ngày mới tìm ra consumer group offset bị lệch - một vấn đề hoàn toàn bình thường với Kafka nhưng cần người biết Kafka để xử lý.
Câu hỏi tôi hỏi bây giờ: "Team bạn có bao nhiêu người? Background là gì? Họ đã từng dùng [technology X] chưa?"
Nếu câu trả lời là "không" - thì technology X dù tốt đến đâu cũng không phải lựa chọn đúng.
Câu hỏi 3: "Thứ gì KHÔNG THỂ sai - và thứ gì có thể down tạm thời?"
Không phải mọi thứ trong hệ thống đều quan trọng như nhau. Nhưng developer thường thiết kế như thể mọi thứ đều critical.
Trong e-commerce, tôi luôn hỏi: "Nếu tôi phải chọn, cái gì tuyệt đối không được sai?" Câu trả lời thường là: đặt đơn hàng và thanh toán. Search product có thể chậm, trang catalog có thể cache 5 phút, nhưng checkout phải luôn hoạt động.
Điều này dẫn đến quyết định kiến trúc rất cụ thể:
- Checkout service: synchronous, strong consistency, replicated database
- Search service: async, eventual consistency, có thể stale 5 phút
- Product catalog: heavily cached, CDN, acceptable nếu stale 1 tiếng
Khi bạn biết thứ gì critical, bạn đầu tư đúng chỗ. Không phải đầu tư đồng đều cho mọi thứ - điều đó vừa tốn kém vừa phức tạp không cần thiết.
Câu hỏi 4: "Data nào cần real-time, data nào có thể batch?"
Câu hỏi này tiết kiệm cho tôi rất nhiều phức tạp kiến trúc.
Ví dụ: Inventory management. Bạn có thực sự cần biết exact stock count real-time? Hay "còn hàng / hết hàng" cập nhật mỗi 5 phút là đủ?
Với 99% retailer, cập nhật mỗi 5 phút là fine. Bạn không cần event streaming pipeline phức tạp. Một batch job chạy mỗi 5 phút, read từ database, update cache là đủ.
Nhưng với flash sale trong 10 phút, bạn cần real-time. Vì 1000 người mua cùng lúc và stock chỉ còn 50 cái - thì batch 5 phút sẽ oversell.
Pattern tôi dùng:
// Xác định data category
// Category 1: Real-time required
// - Order placement
// - Payment processing
// - Stock reservation (khi flash sale)
// Category 2: Near-real-time (< 5 phút)
// - Inventory display
// - Price updates
// - Search index
// Category 3: Batch (giờ/ngày)
// - Analytics
// - Reports
// - Email notifications
Khi bạn phân loại xong, kiến trúc tự nhiên đơn giản hơn rất nhiều.
Câu hỏi 5: "Budget vận hành hàng tháng là bao nhiêu?"
Câu hỏi này thường bị bỏ qua nhất - và cũng gây ra nhiều bất ngờ nhất sau khi deploy.
Tôi đã từng thiết kế hệ thống với 5 microservices trên Kubernetes, mỗi service 2 replicas. Chi phí Azure hàng tháng: khoảng $800-1000. Khách hàng budget $200/tháng.
Bây giờ câu hỏi về budget tôi hỏi ngay trong buổi discovery đầu tiên. Và từ con số đó, tôi work backwards để chọn kiến trúc phù hợp.
$50-100/tháng: Single App Service + Azure SQL (Standard tier) - đủ cho hầu hết SMB
$200-500/tháng: 2-3 App Services + SQL + Redis Cache - đủ cho hệ thống vừa
$1000+/tháng: Kubernetes, microservices, Event Hub - chỉ khi thực sự cần scale
Kiến trúc đẹp trên whiteboard nhưng vượt budget không phải kiến trúc tốt. Kiến trúc tốt là kiến trúc phù hợp với constraints thực tế.
Bài học tôi rút ra
Sau hơn 20 năm và nhiều dự án - cả thành công lẫn thất bại - tôi nhận ra: đa số lỗi kiến trúc không phải vì thiếu kiến thức kỹ thuật, mà vì thiếu thông tin về context.
5 câu hỏi này không phải magic. Chúng chỉ giúp bạn có đủ thông tin để đưa ra quyết định phù hợp. Và đôi khi, câu trả lời cho cả 5 câu hỏi sẽ dẫn bạn đến một monolith đơn giản chạy trên một server - và đó hoàn toàn là lựa chọn đúng.
Gửi các bạn trẻ
Khi bạn được giao thiết kế một hệ thống mới, đừng vội mở IDE hay vẽ diagram. Hãy hỏi trước.
Và khi bạn hỏi, hãy lắng nghe cả những gì người ta nói lẫn những gì người ta không nói. "Hệ thống cần nhanh" có thể nghĩa là "trang load 3 giây hiện tại khó chịu quá", chứ không phải "cần sub-100ms P99 latency".
Hiểu đúng vấn đề còn quan trọng hơn giải quyết đúng vấn đề.
Bạn nghĩ sao?
Bạn có câu hỏi nào khác mà bạn luôn hỏi trước khi bắt đầu dự án mới? Tôi rất muốn nghe - vì 5 câu của tôi chắc chắn chưa đủ :)
/Son Do - believe in basic
#1percentbetter #SolutionArchitecture #SystemDesign #softwareengineering