Chương 80. Bắt đầu từ yêu cầu thật
Từ chương này, ta bước sang một phần rất quan trọng:
Quy trình thiết kế một hệ thống.
Các chương trước đã cho ta nhiều mảnh ghép:
API.
Database.
Cache.
Queue.
Microservices.
Security.
Observability.
Testing.
AI architecture.
Realtime.
Money.
Abuse prevention.
Nhưng khi thật sự phải thiết kế một hệ thống, câu hỏi đầu tiên không nên là:
Dùng Kafka hay RabbitMQ?
Dùng PostgreSQL hay MongoDB?
Dùng microservices hay monolith?
Dùng Kubernetes hay serverless?
Câu hỏi đầu tiên nên là:
Hệ thống này sinh ra để phục vụ ai, giúp họ làm việc gì, và điều gì không được sai?
Nếu bỏ qua yêu cầu thật, ta rất dễ thiết kế một hệ thống nhìn hiện đại nhưng không giải quyết đúng bài toán.
Thông điệp chính của chương:
> Thiết kế hệ thống tốt bắt đầu từ yêu cầu thật, không bắt đầu từ công nghệ. Trước khi chọn kiến trúc, hãy hiểu người dùng, hành động chính, dữ liệu quan trọng, độ trễ cần thiết, việc nào xử lý sau được, và điều gì tuyệt đối không được sai.
---
80.1. Một lỗi rất phổ biến: nhảy thẳng vào công nghệ
Khi nghe một bài toán mới, engineer rất dễ nghĩ ngay đến stack.
Ví dụ:
App có nhiều user -> microservices.
Cần realtime -> WebSocket.
Cần scale -> Kubernetes.
Cần event -> Kafka.
Cần nhanh -> Redis.
Cần AI -> vector database.
Những công nghệ này có thể đúng.
Nhưng nếu chọn quá sớm, ta đang thiết kế trong sương mù.
Ví dụ user nói:
Tôi muốn hệ thống chấm bài bằng AI.
Nếu ta nhảy ngay vào:
FastAPI + Celery + Redis + Gemini + PostgreSQL + Kubernetes.
ta vẫn chưa biết các điều quan trọng:
Ai dùng?
Chấm bài gì?
Một ngày bao nhiêu bài?
Kết quả cần ngay hay có thể chờ?
Điểm AI là chính thức hay chỉ gợi ý?
Giáo viên có duyệt lại không?
Bài nộp có được mất không?
Nếu AI provider lỗi thì sao?
Chi phí mỗi bài chấm chấp nhận bao nhiêu?
Nếu những câu hỏi này chưa rõ, công nghệ chỉ là trang trí.
Kiến trúc tốt phải đi từ bài toán thật ra công nghệ.
Không đi ngược lại.
---
80.2. Yêu cầu thật là gì?
Yêu cầu thật không chỉ là danh sách tính năng.
Ví dụ tính năng:
User có thể nộp bài.
AI chấm bài.
Giáo viên xem kết quả.
Admin xem báo cáo.
Yêu cầu thật sâu hơn:
Học sinh cần chắc chắn bài đã được nhận trước deadline.
Giáo viên cần biết bài nào cần review.
Nhà trường cần điểm không bị mất và có thể audit.
Hệ thống cần chấm đủ nhanh trong giờ cao điểm.
Chi phí AI không được vượt ngân sách.
Tính năng nói hệ thống làm gì.
Yêu cầu thật nói vì sao việc đó quan trọng, ai bị ảnh hưởng, và sai thì đau ở đâu.
Ví dụ:
Tính năng: upload file.
Yêu cầu thật: file bài làm gốc không được mất, vì đó là bằng chứng nộp bài.
Hai câu này dẫn đến kiến trúc khác nhau.
Nếu chỉ là upload file phụ, ta có thể làm đơn giản.
Nếu file là bằng chứng chính thức, ta cần:
Object storage bền.
Checksum.
Virus scan.
Audit.
Backup/versioning.
Trạng thái upload rõ.
Không báo đã nộp trước khi file lưu thành công.
Yêu cầu thật làm kiến trúc nghiêm túc đúng chỗ.
---
80.3. Người dùng là ai?
Câu hỏi đầu tiên:
Ai dùng hệ thống này?
Đừng trả lời quá chung:
User.
Hãy tách vai trò.
Với AI Judge:
Học sinh.
Giáo viên.
Admin trường.
Người vận hành hệ thống.
Support.
Tích hợp LMS.
Billing admin.
Mỗi nhóm có mục tiêu khác nhau.
Học sinh muốn:
Nộp bài chắc chắn.
Biết bài đã được nhận.
Xem feedback khi có.
Không bị mất bài vì lỗi mạng.
Giáo viên muốn:
Tạo assignment.
Xem bài nộp.
Xem điểm.
Review case AI không chắc.
Sửa điểm nếu cần.
Xuất báo cáo.
Admin trường muốn:
Quản lý user.
Quản lý lớp.
Theo dõi quota/cost.
Export dữ liệu.
Đảm bảo compliance.
Người vận hành muốn:
Biết queue có backlog không.
Biết AI provider có lỗi không.
Rollback prompt/model nếu cần.
Không bị alert nhiễu.
Nếu không phân biệt người dùng, ta sẽ thiết kế một luồng chung chung và bỏ sót quyền, dữ liệu, audit, quota, support.
---
80.4. Một user có thể có nhiều vai trò
Trong hệ thống thật, vai trò không luôn đơn giản.
Ví dụ:
Một giáo viên cũng có thể là admin trường.
Một user có thể thuộc hai trường.
Một support staff có quyền xem nhiều tenant.
Một học sinh có thể là trợ giảng trong lớp khác.
Vì vậy đừng thiết kế quyền quá ngây thơ:
users.role = "teacher"
có thể không đủ.
Tốt hơn là nghĩ theo:
User này là ai?
Trong tenant nào?
Trong resource nào?
Với role gì?
Đang thực hiện hành động gì?
Yêu cầu về user dẫn đến data model.
Data model dẫn đến permission.
Permission dẫn đến API, audit và testing.
Nếu câu hỏi "người dùng là ai" bị trả lời hời hợt, lỗi quyền sẽ xuất hiện rất sớm.
---
80.5. Hành động chính là gì?
Sau khi biết ai dùng, hãy hỏi:
Họ làm hành động chính nào?
Không phải mọi hành động quan trọng như nhau.
Với AI Judge, các hành động chính có thể là:
Học sinh nộp bài.
Worker chấm bài.
Giáo viên xem và review kết quả.
Admin quản lý lớp/user.
Hệ thống xuất điểm sang LMS.
Billing tính usage.
Trong đó, luồng sống còn có thể là:
Nộp bài trước deadline.
Không mất bài.
Chấm bài và lưu kết quả.
Giáo viên review case cần thiết.
Còn một số hành động phụ hơn:
Xuất báo cáo đẹp.
Dashboard realtime chi tiết.
Gợi ý feedback nâng cao.
Thống kê nâng cao.
Khi có sự cố, ta cần biết:
Giữ hành động nào sống trước?
Hành động nào có thể tạm hạ cấp?
Nếu không phân loại hành động, hệ thống dễ bảo vệ sai thứ.
Ví dụ report export làm database chậm, kéo theo submit bài chậm.
Đó là dấu hiệu kiến trúc không ưu tiên đúng hành động chính.
---
80.6. Mô tả hành động chính bằng câu đơn giản
Một cách rất tốt là viết hành động chính theo dạng:
Ai làm gì để đạt kết quả gì?
Ví dụ:
Học sinh nộp bài để được ghi nhận trước deadline.
Giáo viên xem bài cần review để quyết định điểm chính thức.
Admin trường xem usage để kiểm soát chi phí.
Worker chấm bài để tạo kết quả ban đầu cho giáo viên.
Câu này buộc ta nhìn vào kết quả.
Không chỉ thao tác.
Ví dụ:
Học sinh upload file.
chưa đủ.
Tốt hơn:
Học sinh nộp bài và nhận bằng chứng rằng bài đã được ghi nhận.
Câu thứ hai làm rõ:
Phải có trạng thái received.
Phải có timestamp.
Phải không báo thành công khi file chưa lưu.
Có thể cần confirmation id.
Ngôn ngữ yêu cầu tốt giúp kiến trúc tốt hơn.
---
80.7. Dữ liệu nào quan trọng?
Sau user và hành động, hãy hỏi:
Dữ liệu nào quan trọng nhất?
Với AI Judge:
Submission gốc.
File bài làm.
Deadline/timestamp nộp.
Rubric.
Prompt/model version.
AI result.
Điểm chính thức.
Feedback.
Audit log.
Usage/billing records.
Không phải dữ liệu nào cũng cùng cấp.
Ví dụ:
File bài làm gốc: cực kỳ quan trọng.
Dashboard cache: có thể tạo lại.
Search index: có thể rebuild.
Prompt metadata: quan trọng để audit.
Full prompt log: nhạy cảm, có thể retention ngắn.
Khi biết dữ liệu nào quan trọng, ta mới quyết định:
Lưu ở đâu?
Backup thế nào?
Ai được xem?
Có cần audit không?
Có cần version không?
Có thể xóa không?
Có thể rebuild không?
Dữ liệu quan trọng phải được bảo vệ trước khi ta tối ưu những thứ đẹp hơn.
---
80.8. Source of truth là gì?
Source of truth là nơi hệ thống xem là sự thật chính cho một loại dữ liệu.
Ví dụ:
Submission gốc nằm trong database + object storage.
Điểm chính thức nằm trong grading_results sau khi review.
Payment status cuối cùng lấy từ payment provider + internal payment state.
Usage billing lấy từ usage ledger.
Nếu không định nghĩa source of truth, hệ thống dễ có nhiều sự thật.
Ví dụ:
Database nói bài đã graded.
Cache nói vẫn grading.
LMS nói chưa có điểm.
Dashboard nói failed.
Cần biết:
Khi lệch, tin ai?
Làm sao reconcile?
Làm sao update bản phụ?
Một read model, cache, search index, dashboard snapshot thường không nên là source of truth.
Chúng là bản phục vụ đọc.
Source of truth nên bền, audit được, restore được.
Định nghĩa source of truth sớm giúp tránh mớ trạng thái mâu thuẫn.
---
80.9. Dữ liệu nào cần version?
Một số dữ liệu thay đổi theo thời gian và cần version.
Ví dụ:
Rubric.
Prompt.
Model.
Assignment instruction.
Policy chấm điểm.
Feedback template.
Nếu bài được chấm hôm qua bằng rubric v2, hôm nay rubric đổi sang v3, ta không được quên v2.
Khi giáo viên hỏi:
Vì sao bài này được 7 điểm?
Ta cần biết:
Bài đó dùng rubric version nào.
Prompt version nào.
Model nào.
Context nào.
AI response nào.
Ai review.
Nếu không version, hệ thống mất khả năng giải thích quá khứ.
Không phải mọi dữ liệu cần version.
Nhưng dữ liệu ảnh hưởng quyết định quan trọng nên cân nhắc version.
Đặc biệt là AI app.
Vì prompt/model thay đổi có thể làm output thay đổi.
---
80.10. Việc nào cần realtime?
Realtime hấp dẫn.
Nhưng không phải mọi thứ cần realtime.
Hỏi:
Nếu user thấy chậm 5 giây, có sao không?
Nếu chậm 30 giây, có sao không?
Nếu chậm 5 phút, có sao không?
Với AI Judge:
Typing trong chat: realtime nếu có chat.
Dashboard kỳ thi đang diễn ra: gần realtime có ích.
Trạng thái bài đang chấm: vài giây đến vài chục giây có thể đủ.
Báo cáo tổng kết ngày: không cần realtime.
Billing usage: có thể delayed.
Analytics trend: delayed được.
Nếu cần realtime thật, ta phải thiết kế:
WebSocket/SSE.
Snapshot + events.
Reconnect.
Ordering.
Permission subscription.
Backpressure.
Nếu polling đủ, đừng tự làm khó.
Ví dụ:
Export report status polling mỗi 5 giây
có thể tốt hơn WebSocket.
Realtime là chi phí kiến trúc.
Chỉ trả khi lợi ích thật.
---
80.11. Việc nào có thể xử lý sau?
Một câu hỏi cực kỳ quan trọng:
Việc nào không cần làm ngay trong request?
Với AI Judge, khi học sinh nộp bài, request submit không nên làm tất cả:
Lưu file.
Gọi AI.
Chấm bài.
Tạo feedback.
Gửi email.
Cập nhật analytics.
Đồng bộ LMS.
Xuất báo cáo.
Request submit nên làm phần tối thiểu:
Validate.
Lưu submission/file.
Ghi nhận timestamp.
Tạo job chấm.
Trả confirmation.
Các việc có thể xử lý sau:
AI grading.
Notification.
Analytics.
LMS sync.
Report update.
Search indexing.
Tách việc xử lý sau giúp request nhanh và ổn định hơn.
Nhưng cũng tạo bài toán mới:
Queue.
Retry.
Idempotency.
Status.
Observability.
User biết đang chờ.
Async không phải miễn phí.
Nhưng với việc lâu hoặc dễ lỗi, async thường là lựa chọn đúng.
---
80.12. Đừng async hóa mọi thứ
Việc xử lý sau rất hữu ích.
Nhưng không phải mọi thứ nên đưa vào queue.
Một số việc cần làm ngay để đảm bảo correctness:
Kiểm tra user có quyền nộp bài.
Kiểm tra assignment còn mở không.
Lưu submission gốc.
Lưu timestamp nộp.
Đảm bảo idempotency cho submit.
Nếu trả success trước khi lưu submission, user có thể mất bài.
Đó là sai.
Async phù hợp với:
Việc lâu.
Việc có thể retry.
Việc không cần user chờ.
Việc có trạng thái trung gian rõ.
Sync phù hợp với:
Việc cần xác nhận ngay.
Việc quyết định request có hợp lệ không.
Việc tạo source of truth ban đầu.
Câu hỏi không phải:
Dùng sync hay async?
Câu hỏi là:
Phần nào phải chắc chắn trước khi trả response?
Phần nào có thể hoàn thành sau?
---
80.13. Điều gì không được sai?
Đây là câu hỏi quan trọng nhất của chương:
Điều gì không được sai?
Với AI Judge, có thể là:
Không mất bài nộp gốc.
Không ghi nhận sai thời điểm nộp.
Không để user xem dữ liệu tenant khác.
Không chấm nhầm bài của học sinh khác.
Không tính tiền/credit hai lần.
Không công bố điểm chưa được duyệt nếu policy yêu cầu duyệt.
Không dùng rubric/prompt sai version mà không biết.
Không để AI output ngoài schema đi thẳng vào điểm chính thức.
Những điều này khác với:
Dashboard hơi chậm.
Email gửi trễ.
Report update sau vài phút.
Feedback nâng cao tạm unavailable.
Khi biết điều gì không được sai, ta biết nơi cần:
Transaction.
Constraint.
Idempotency.
Audit.
Test.
Review.
Monitoring.
Backup.
Human approval.
Không phải mọi phần cần cùng mức nghiêm ngặt.
Kiến trúc tốt nghiêm ngặt đúng chỗ.
---
80.14. Điều gì được phép chậm?
Một hệ thống không thể tối ưu mọi thứ cùng lúc.
Hãy hỏi:
Điều gì được phép chậm?
Ví dụ:
AI chấm bài có thể mất vài phút.
Report có thể update sau 10 phút.
Analytics có thể update cuối ngày.
Email có thể trễ vài phút.
Search index có thể eventual consistency.
Nếu một việc được phép chậm, ta có thể thiết kế:
Queue.
Batch.
Retry.
Rate limit.
Backpressure.
Lower priority.
Nếu một việc không được phép chậm, ta phải thiết kế khác:
Fast path.
Caching.
Precompute.
Capacity planning.
SLO nghiêm.
Fallback.
Không hỏi câu này, mọi thứ đều bị xem là cần nhanh.
Khi mọi thứ đều cần nhanh, kiến trúc vừa đắt vừa rối.
---
80.15. Điều gì được phép sai tạm thời?
Một số dữ liệu có thể eventual consistency.
Ví dụ:
Dashboard count có thể lệch vài giây.
Search result có thể chưa thấy bài mới ngay.
Analytics có thể chậm.
Notification unread count có thể update trễ.
Một số dữ liệu không được sai tạm thời theo cách ảnh hưởng quyết định:
Deadline nộp bài.
Điểm chính thức.
Quyền truy cập.
Credit balance.
Payment status.
Nếu biết phần nào được eventual consistency, ta có thể dùng cache/read model/event async.
Nếu phần nào cần strongly consistent, ta cần transaction/source of truth rõ.
Đừng nói chung chung:
Hệ thống phải consistent.
Hãy nói cụ thể:
Submission received status phải đúng ngay sau submit.
Dashboard aggregate được phép trễ 10 giây.
Billing ledger không được double charge.
Đó mới là yêu cầu thiết kế được.
---
80.16. Điều gì được phép mất?
Câu hỏi nghe hơi lạ:
Dữ liệu nào được phép mất?
Nhưng rất hữu ích.
Ví dụ có thể mất:
Typing indicator.
Temporary progress update.
Cache.
Một số debug logs không quan trọng.
Intermediate preview.
Không được mất:
Submission gốc.
Payment record.
Ledger entry.
Audit log quan trọng.
Teacher final override.
Tenant configuration.
Nếu typing event mất, không sao.
Nếu submission mất, sự cố nghiêm trọng.
Hai loại dữ liệu này không nên dùng cùng storage/guarantee.
Biết dữ liệu nào được phép mất giúp ta không over-engineer chỗ nhẹ và không under-engineer chỗ nặng.
---
80.17. Ràng buộc thực tế là gì?
Thiết kế không xảy ra trong chân không.
Cần hỏi:
Team có bao nhiêu người?
Thời gian launch là bao lâu?
Budget hạ tầng bao nhiêu?
Đội có kinh nghiệm vận hành Kafka/Kubernetes không?
Khách hàng đầu tiên cần gì?
Compliance nào bắt buộc?
Traffic hiện tại và 6 tháng tới ra sao?
Một kiến trúc rất hay trên giấy có thể không phù hợp nếu team không vận hành nổi.
Ví dụ:
5 microservices, Kafka, Kubernetes, service mesh
có thể quá nặng cho một team 3 người đang tìm product-market fit.
Ngược lại, nếu đã có khách enterprise, dữ liệu nhạy cảm, SLO nghiêm, một monolith viết vội không audit có thể quá rủi ro.
Kiến trúc tốt là kiến trúc phù hợp hoàn cảnh.
Không phải kiến trúc nghe senior nhất.
---
80.18. Yêu cầu phi chức năng
Yêu cầu phi chức năng là các yêu cầu không phải tính năng trực tiếp, nhưng quyết định kiến trúc.
Ví dụ:
Latency.
Throughput.
Availability.
Durability.
Security.
Privacy.
Compliance.
Cost.
Scalability.
Maintainability.
Observability.
Với AI Judge:
95% bài được chấm trong 5 phút.
Submission không được mất.
Tenant isolation bắt buộc.
AI cost không vượt X mỗi tháng.
Audit điểm và review phải giữ 1 năm.
Hệ thống phải chịu deadline peak.
Những câu này quan trọng hơn tên framework.
Chúng quyết định:
Có queue không.
Có backup thế nào.
Có rate limit không.
Có observability gì.
Có multi-tenancy ra sao.
Có prompt/model versioning không.
Nếu yêu cầu phi chức năng không rõ, thiết kế sẽ dựa trên cảm giác.
Mà cảm giác thường lạc quan quá mức.
---
80.19. Câu hỏi về scale nên cụ thể
Đừng hỏi:
Hệ thống có scale không?
Hỏi cụ thể hơn:
Bao nhiêu user active mỗi ngày?
Bao nhiêu request mỗi giây ở giờ cao điểm?
Bao nhiêu submission trong 10 phút trước deadline?
Mỗi submission trung bình bao nhiêu MB?
Mỗi bài chấm mất bao lâu?
Provider AI cho phép bao nhiêu RPM/concurrency?
Database dữ liệu tăng bao nhiêu mỗi tháng?
Với AI Judge, một con số rất quan trọng:
Số bài nộp trong thời gian cao điểm.
Không phải chỉ tổng số bài mỗi ngày.
Ví dụ:
100.000 bài/ngày
nghe lớn.
Nhưng nếu trải đều 24 giờ, khác với:
80.000 bài trong 10 phút trước deadline.
Peak shape quyết định kiến trúc queue, worker, rate limit, backpressure và UX.
Scale không phải một con số.
Scale là hình dạng tải.
---
80.20. Đầu vào, đầu ra và side effects
Với mỗi hành động chính, hãy xác định:
Input là gì?
Output là gì?
Side effects là gì?
Ví dụ nộp bài:
Input:
user_id.
tenant_id.
assignment_id.
file/content.
client_request_id.
Output:
submission_id.
status = received/queued.
received_at.
Side effects:
File được lưu.
Submission record được tạo.
Grading job được enqueue.
Audit log được ghi.
Notification maybe later.
Side effects cần idempotency.
Nếu request retry, không được tạo hai submission không mong muốn.
Nếu job enqueue fail sau khi submission lưu, cần outbox/retry.
Chỉ khi viết rõ input/output/side effects, ta mới thấy rủi ro.
---
80.21. Happy path và failure path
Khi lấy yêu cầu, đừng chỉ mô tả happy path.
Happy path:
Học sinh nộp bài.
AI chấm thành công.
Giáo viên xem điểm.
Failure path:
File upload fail.
User mất mạng.
Submit retry.
Assignment đã đóng.
AI provider timeout.
AI trả JSON hỏng.
Queue backlog.
Giáo viên sửa điểm trong lúc job retry.
LMS webhook fail.
Tenant hết quota.
Production sống ở failure path rất nhiều.
Mỗi failure path cần quyết định:
Retry không?
Fail rõ không?
User thấy gì?
Có alert không?
Có manual review không?
Có compensation không?
Nếu yêu cầu chỉ có happy path, thiết kế sẽ mong manh.
---
80.22. Ví dụ yêu cầu tốt cho AI Judge
Một bộ yêu cầu tốt có thể viết như sau:
Học sinh phải nộp được bài trước deadline và nhận confirmation nếu server đã lưu thành công.
Submission gốc và timestamp nộp không được mất.
AI grading có thể chạy nền, không cần trả điểm ngay trong request submit.
95% bài phải có kết quả hoặc trạng thái cần review trong 5 phút ở tải bình thường.
Nếu AI provider lỗi, bài vẫn giữ trạng thái queued/retry/needs_review rõ ràng.
Điểm AI không được trở thành điểm chính thức nếu policy của tenant yêu cầu giáo viên duyệt.
Mỗi submission attempt chỉ bị tính credit một lần.
Rubric, prompt và model version dùng để chấm phải được lưu để audit.
Giáo viên chỉ xem được dữ liệu tenant/lớp mình có quyền.
Những câu này rất giàu thông tin kiến trúc.
Từ đó ta suy ra:
Database bền.
Object storage.
Queue.
Worker.
Idempotency.
Status model.
Audit log.
Prompt versioning.
Permission.
SLO.
Observability.
Yêu cầu tốt kéo kiến trúc ra một cách tự nhiên.
---
80.23. Ví dụ yêu cầu mơ hồ
Yêu cầu mơ hồ:
Hệ thống phải nhanh.
Hệ thống phải scale.
Hệ thống phải realtime.
AI phải chấm tốt.
Dữ liệu phải an toàn.
Những câu này đúng nhưng chưa thiết kế được.
Cần hỏi tiếp:
Nhanh là bao nhiêu giây?
Scale đến bao nhiêu user/traffic?
Realtime cho màn hình nào?
AI chấm tốt đo bằng gì?
Dữ liệu nào an toàn theo nghĩa nào?
Ví dụ cụ thể hơn:
API submit p95 < 1 giây khi 500 requests/giây.
95% bài có kết quả trong 5 phút.
Dashboard assignment cập nhật trong 10 giây.
AI score lệch không quá ngưỡng trên evaluation set.
Submission file giữ 5 năm và backup cross-region.
Không phải lúc nào cũng có số chính xác từ đầu.
Nhưng phải cố biến tính từ mơ hồ thành ràng buộc kiểm tra được.
---
80.24. Đừng hỏi user muốn công nghệ gì
User thường không thật sự muốn:
Kafka.
Redis.
Microservices.
WebSocket.
Vector database.
Kubernetes.
Họ muốn:
Không mất bài.
Chấm nhanh.
Xem kết quả đúng.
Không bị lộ dữ liệu.
Tích hợp được LMS.
Chi phí trong tầm kiểm soát.
Nếu user nói:
Tôi cần realtime.
hãy hỏi:
Bạn cần thấy thay đổi trong bao lâu?
Màn hình nào?
Nếu chậm 30 giây có chấp nhận không?
Nếu mạng mất thì sao?
Nếu user nói:
Tôi cần microservices.
hãy hỏi:
Bạn đang đau vì deploy, team ownership, scale độc lập, hay chỉ nghe microservices tốt?
Công nghệ là câu trả lời sau.
Yêu cầu thật là câu hỏi trước.
---
80.25. Yêu cầu cũng có trade-off
Không phải yêu cầu nào cũng có thể đạt cùng lúc.
Ví dụ:
Rẻ nhất.
Nhanh nhất.
An toàn nhất.
Scale lớn nhất.
Linh hoạt nhất.
Ra mắt trong 2 tuần.
Không thể có tất cả.
Thiết kế hệ thống là chọn trade-off.
Ví dụ:
Muốn chấm bài ngay lập tức cho mọi submission -> cần capacity lớn, cost cao.
Muốn cost thấp -> chấp nhận queue và delay.
Muốn tenant isolation mạnh -> vận hành database riêng phức tạp hơn.
Muốn mở public API sớm -> phải giữ contract sớm hơn.
Muốn full audit -> storage và quyền truy cập phức tạp hơn.
Senior không chỉ hỏi "làm được không".
Senior hỏi:
Làm được với giá nào?
Rủi ro nào?
Đội có vận hành nổi không?
Có cần ngay bây giờ không?
---
80.26. Từ yêu cầu thật đến kiến trúc
Sau khi có yêu cầu thật, ta mới bắt đầu chọn kiến trúc.
Ví dụ yêu cầu:
Submit phải nhanh và không mất bài.
AI grading có thể chờ.
Provider có thể chậm.
Không được double charge.
Teacher cần review case không chắc.
Suy ra:
API submit lưu source of truth trước.
AI grading chạy qua queue.
Job có idempotency.
Submission có status rõ.
AI result có validation.
Credit charge có ledger/idempotency.
Teacher review là state riêng.
Observability theo queue/provider/cost.
Kiến trúc không còn là tranh luận trừu tượng.
Nó trở thành phản ứng với yêu cầu.
Đây là cách thiết kế bớt cảm tính.
---
80.27. Một canvas yêu cầu đơn giản
Khi bắt đầu thiết kế, có thể dùng một canvas ngắn:
1. Người dùng chính là ai?
2. Hành động chính là gì?
3. Dữ liệu nào quan trọng nhất?
4. Điều gì không được sai?
5. Điều gì cần nhanh?
6. Điều gì có thể xử lý sau?
7. Điều gì cần realtime?
8. Điều gì có thể eventual consistency?
9. Peak traffic trông như thế nào?
10. Ràng buộc bảo mật/privacy/compliance là gì?
11. Chi phí nào cần kiểm soát?
12. Nếu dependency ngoài lỗi thì user thấy gì?
Canvas này không thay thế thiết kế chi tiết.
Nó giúp không bỏ qua nền tảng.
Nếu trả lời tốt 12 câu này, ta đã đi xa hơn rất nhiều so với việc mở đầu bằng:
Dùng database nào?
---
80.28. AI Judge: trả lời canvas nhanh
Ví dụ:
Người dùng:
Học sinh, giáo viên, admin trường, ops, LMS partner.
Hành động chính:
Nộp bài, chấm bài, review điểm, xuất/sync kết quả.
Dữ liệu quan trọng:
Submission gốc, timestamp, rubric, result, official score, audit, usage ledger.
Không được sai:
Mất bài, sai quyền, double charge, sai deadline, sai tenant, mất audit.
Cần nhanh:
Submit confirmation.
Dashboard kỳ thi ở mức vài giây đến vài chục giây.
Có thể xử lý sau:
AI grading, notification, analytics, LMS sync, report.
Realtime:
Dashboard đang thi, progress quan trọng.
Không cần realtime:
Billing report, analytics dài hạn.
Ràng buộc:
Privacy học sinh, tenant isolation, AI cost, provider rate limit.
Chỉ từ vài dòng này, kiến trúc đã bắt đầu hiện ra.
---
80.29. Những sai lầm phổ biến
Sai lầm thứ nhất:
Bắt đầu bằng công nghệ.
Chưa hiểu bài toán đã chọn Kafka, Kubernetes, microservices.
Sai lầm thứ hai:
Không phân biệt người dùng.
Học sinh, giáo viên, admin, ops, partner có nhu cầu và quyền khác nhau.
Sai lầm thứ ba:
Không biết dữ liệu nào quan trọng.
Cache và submission gốc bị đối xử như nhau.
Sai lầm thứ tư:
Realtime hóa mọi thứ.
Polling hoặc async status có thể đủ.
Sai lầm thứ năm:
Async hóa cả việc phải chắc chắn ngay.
Trả success trước khi lưu source of truth.
Sai lầm thứ sáu:
Không hỏi điều gì không được sai.
Dẫn đến thiếu idempotency, audit, transaction, backup ở nơi cần.
Sai lầm thứ bảy:
Yêu cầu phi chức năng quá mơ hồ.
"Nhanh", "scale", "an toàn" nhưng không có ngưỡng.
Sai lầm thứ tám:
Không nói trade-off.
Hứa mọi thứ cùng lúc rồi kiến trúc phình và vẫn không đúng trọng tâm.
---
80.30. Checklist bắt đầu thiết kế
Trước khi chọn kiến trúc, hãy hỏi:
- Người dùng chính là ai?
- Có những vai trò nào?
- Một user có thể thuộc nhiều tenant/role không?
- Hành động chính của từng vai trò là gì?
- Luồng nào là sống còn?
- Dữ liệu nào là source of truth?
- Dữ liệu nào có thể rebuild?
- Dữ liệu nào cần version?
- Dữ liệu nào không được mất?
- Điều gì không được sai?
- Điều gì được phép chậm?
- Điều gì được phép eventual consistency?
- Việc nào phải làm trong request?
- Việc nào có thể xử lý sau?
- Màn hình nào thật sự cần realtime?
- Peak traffic xảy ra lúc nào?
- Dependency ngoài nào có thể lỗi?
- Ràng buộc privacy/compliance là gì?
- Chi phí nào cần kiểm soát?
- Team có vận hành nổi kiến trúc đề xuất không?
Nếu chưa trả lời được nhiều câu trong danh sách này, đừng vội chọn công nghệ.
---
80.31. Bảng nhìn nhanh
| Câu hỏi | Vì sao quan trọng | |---|---| | Người dùng là ai? | Quyết định role, permission, UX | | Hành động chính là gì? | Quyết định luồng cốt lõi cần bảo vệ | | Dữ liệu nào quan trọng? | Quyết định storage, backup, audit | | Điều gì không được sai? | Quyết định transaction, idempotency, test | | Việc nào cần realtime? | Quyết định WebSocket/SSE/polling | | Việc nào xử lý sau được? | Quyết định queue, worker, status | | Peak traffic ra sao? | Quyết định capacity và backpressure | | Dependency nào có thể lỗi? | Quyết định timeout, retry, fallback | | Ràng buộc privacy là gì? | Quyết định data governance | | Cost nào cần kiểm soát? | Quyết định quota, budget, monitoring |
---
80.32. Kết luận của chương
Thiết kế hệ thống không nên bắt đầu bằng công nghệ.
Nó nên bắt đầu bằng yêu cầu thật:
Ai dùng?
Họ làm gì?
Dữ liệu nào quan trọng?
Điều gì cần nhanh?
Điều gì có thể chờ?
Điều gì không được sai?
Khi trả lời tốt các câu hỏi này, lựa chọn kiến trúc trở nên rõ hơn.
Ta biết chỗ nào cần transaction.
Chỗ nào cần queue.
Chỗ nào cần realtime.
Chỗ nào chỉ cần polling.
Chỗ nào cần audit.
Chỗ nào phải kiểm soát cost.
Chỗ nào có thể đơn giản.
Thông điệp cần nhớ:
> Công nghệ là câu trả lời. Yêu cầu thật mới là câu hỏi. Nếu hỏi sai câu hỏi, kiến trúc dù hiện đại đến đâu cũng có thể giải quyết sai vấn đề.
Ở chương tiếp theo, ta sẽ nói về ước lượng nhanh trước khi thiết kế: cách ước lượng traffic, dữ liệu, throughput, latency, chi phí và điểm nghẽn trước khi chọn kiến trúc chi tiết.