Khách hàng muốn "hệ thống nhanh" - làm thế nào để biết nhanh là bao nhiêu
Năm ngoái, tôi ngồi trong cuộc họp với khách hàng lớn - một công ty bán lẻ, họ muốn xây một hệ thống mua sắm online mới. Khách hàng nói: "Anh em, chúng tôi cần một hệ thống nhanh. Rất nhanh. Cạnh tranh không chịu nổi nếu khách hàng chất hành động chậm."
Tôi ghi chú lại: "nhanh". Và rồi tôi im lặng.
Không phải vì tôi lạnh lùng. Mà vì tôi biết lời nói "nhanh" đó là cái bẫy lớn nhất của bất kỳ dự án nào. Ba năm lại, hệ thống được xây xong, khách hàng nói "không như kỳ vọng", chúng tôi nói "nhưng chúng tôi build đúng y như bạn muốn". Ai cũng tức.
Lý do? Vì chúng ta chưa bao giờ dịch "nhanh" từ lời nói của khách hàng sang con số cụ thể mà architect có thể dùng để thiết kế.
Những cái bẫy của "non-functional requirements" mơ hồ
Các bạn trẻ, khi nghe "hệ thống phải nhanh", có thể cảm thấy dễ dàng. Bạn code nhanh, database được index đầy đủ, API response trong 100ms, là done rồi đúng không?
Sai.
Vì "nhanh" không phải là một non-functional requirement (NFR). Nó chỉ là một tâm lý. Một cảm nhận.
Non-functional requirements là yêu cầu về chất lượng - hiệu suất, độ tin cậy, bảo mật, khả năng mở rộng, v.v. Nhưng chúng phải đo được. Phải kiểm chứng được. Phải định lượng được.
Như thế nào là "nhanh" cơ chứ?
- Nhanh so với competitor?
- Nhanh trong điều kiện bình thường hay điều kiện peak traffic?
- Nhanh cho tất cả người dùng hay chỉ cần 90%?
- Nhanh ở home page hay cả product search?
- Nhanh bao nhiêu ms? 100ms? 500ms? 2 giây?
Bạn thấy chưa? Từ một từ "nhanh", nó nổ tung thành 10 câu hỏi. Và mỗi câu hỏi dẫn tới một kiến trúc khác nhau.
Bài học 1: Từ tâm lý sang metric - cách đặt câu hỏi đúng
Khi khách hàng nói "nhanh", tôi bây giờ không bao giờ ghi "nhanh". Tôi ghi:
"Nhanh là bao nhiêu?"
Và sau đó, tôi có một cái checklist. Nó hơi clinical, nhưng nó hiệu quả:
1. Response time cụ thể - Hiểu họ muốn gì thực sự
Tôi hỏi: "Khi khách hàng vào website và tìm kiếm sản phẩm, anh muốn search result hiển thị trong bao lâu?"
Thường họ sẽ nói: "Vài giây?"
Tôi kéo tiếp: "2 giây? 3 giây? Hay ngay lập tức?"
Và đây là insight quan trọng: Theo nghiên cứu từ Google và các công ty e-commerce lớn, người dùng chỉ chịu đợi 2-3 giây trước khi bỏ cuộc. Từ 2-3 giây, tỷ lệ bounce rate tăng 50%. Từ 3 giây trở lên, bạn mất khách hàng.
Vậy requirement là: Response time cho product search phải < 200ms (p95).
Nếu khách hàng muốn nhanh hơn nữa (150ms, 100ms), tôi sẽ cảnh báo: "Nhanh như vậy sẽ tốn 3x budget infrastructure và tăng complexity 5 lần. Có chắc chưa?"
2. Tải trọng (load) - Khách hàng muốn nhanh khi nào?
Tôi hỏi tiếp: "Bạn muốn hệ thống nhanh thế nào lúc normal traffic? Hay lúc Black Friday?"
Đây là crucial. Vì lúc normal traffic, bạn có thể xây rất nhanh. Nhưng lúc peak (Black Friday, sale campaign), có khi 100x traffic bất ngờ. Nếu bạn thiết kế cho peak từ đầu, chi phí sẽ khủng khiếp.
Thường tôi sẽ giới thiệu khái niệm error budget:
"Nếu bạn muốn 99.99% uptime (0.01% downtime = ~4 phút/tháng), tôi có thể thiết kế để xử lý 10,000 user đồng thời. Nhưng nếu Black Friday có 50,000 user, một số người sẽ bị slow. Có được không?"
Khách hàng sẽ rõ ràng hơn: "Vậy thì 99.9% uptime (43 phút downtime/tháng) được, nhưng phải xử lý 30,000 user."
Khi đó, con số là rõ ràng. Architecture có thể thiết kế.
3. Transaction type - Không phải tất cả mọi thứ cần nhanh nhất
Tôi hỏi: "Anh muốn fast response cho việc gì? Search? Add to cart? Payment?"
Bởi vì:
- Search: Phải < 200ms (p95). Nếu chậm, khách hàng bỏ.
- Add to cart: Phải < 500ms (p95). Chậm chút xíu cũng chấp nhận được.
- Payment: Phải < 3 giây (p95). Chủ yếu là chờ gateway bên thứ 3.
Nếu bạn thiết kế tất cả < 200ms, bạn sẽ tốn kém quá. Nhưng nếu bạn smart, bạn chỉ "quá fast" cho critical path, còn lại là "fast enough".
Bài học 2: Dịch Requirements sang SLA, SLO, SLI - Ngôn ngữ của kiến trúc
Khi tôi đã có các con số cụ thể từ khách hàng, tôi không dừng ở đó. Tôi dịch chúng sang:
SLI (Service Level Indicator) = Cái bạn đo được thực tế
- Ví dụ: P95 response time của search API = 150ms
SLO (Service Level Objective) = Cái bạn cam kết nội bộ
- Ví dụ: Search API response time p95 phải < 150ms, 99.9% thời gian
SLA (Service Level Agreement) = Cái bạn cam kết với khách hàng
- Ví dụ: "System uptime 99.9% tính theo tháng"
Error Budget = "Bạn có thể fail bao nhiêu?"
- Nếu SLA là 99.9%, error budget là 0.1% = ~43 phút fail/tháng
- Bạn dùng error budget này để thử nghiệm, deploy, maintenance mà không vi phạm SLA
Cái hay ở error budget là: nó giúp team biết được khi nào được fail, khi nào không được fail. Thay vì "phải 100% uptime" (impossible), bạn có một con số. Từ con số đó, bạn có thể planning được.
Bài học 3: Những trade-off mà bạn phải nói thẳng
Trong 7 năm làm solution architect, tôi học được: Không có hệ thống "nhanh hơn" mà không có giá.
Khi bạn muốn:
- Performance cao hơn → Chi phí infrastructure cao hơn, complexity cao hơn
- Scalability cao hơn → Cần distributed architecture (MySQL → Elasticsearch, sharding, v.v.), tăng operational burden
- Availability cao hơn → Cần redundancy, failover, multi-region, tăng gấp đôi chi phí
- Security cao hơn → Tăng latency (encryption, rate limiting, v.v.), user experience chậm hơn
Bạn phải nói thẳng với khách hàng: "Chúng tôi có thể build 99.99% uptime + 100ms response time + xử lý 100,000 concurrent users. Nhưng sẽ tốn $500K/tháng infrastructure, và 3-4 tháng để build. Hay là chúng tôi compromise: 99.9% uptime, 300ms response time, 30,000 concurrent users, $50K/tháng, 2 tháng build?"
Khi khách hàng nghe con số, họ sẽ rationale hơn. Vì "nhanh" bây giờ có giá.
Bài học 4: Tài liệu hóa requirements - Để sau này không có ai nói "chúng tôi chưa bao giờ nói vậy"
Một lần, tôi quên tài liệu hóa performance requirements. Sau 2 năm, hệ thống live, khách hàng nói: "Sao response time còn 1 giây vậy? Chúng tôi không bao giờ nói được 1 giây."
Tôi hối hận. Vì tôi có ghi chú "nhanh", nhưng không ghi "nhanh < 200ms". Sau đó, tôi bắt đầu viết NFR document:
Performance Requirement:
- Product Search API: < 200ms (p95), p99 < 500ms
- Add to Cart: < 500ms (p95)
- Checkout: < 3000ms (p95)
Scalability Requirement:
- Peak load: 30,000 concurrent users
- 10,000 requests/second
Availability Requirement:
- SLA: 99.9% uptime (43 minutes downtime/month acceptable)
- RTO (Recovery Time Objective): 5 minutes
- RPO (Recovery Point Objective): 1 minute
Reason:
- Performance: Bounce rate increases 50% after 3 seconds
- Scalability: Expected 10x growth in next 2 years
- Availability: Business allows 43 min/month downtime for maintenance
Một cái document simple như vậy, nhưng nó cứu tôi nhiều lần từ tranh cãi sau này.
Bài học 5: Non-functional requirements ảnh hưởng kiến trúc lớn lắm
Đây là cái mà junior dev hay bỏ qua: NFRs là cái quyết định kiến trúc, không phải functional requirements.
Khi khách hàng nói "chúng tôi cần quản lý sản phẩm, đơn hàng, thanh toán" → Đó là functional requirements. Bất kỳ developer nào cũng code được.
Nhưng khi họ nói "chúng tôi cần 30,000 concurrent users" → Đó là non-functional requirement. Và nó sẽ thay đổi hoàn toàn kiến trúc của bạn:
- Single database → Database sharding
- Monolith → Microservices
- Synchronous → Asynchronous with message queue
- In-memory cache → Distributed cache (Redis)
Vậy nên, NFRs phải được gather ở giai đoạn inception, không phải elaboration hay construction. Nếu bạn gather sau, bạn sẽ refactor kiến trúc, lãng phí thời gian và tiền.
Một ví dụ thực tế từ e-commerce
Hồi đó, tôi làm project cho một công ty e-commerce. Khách hàng nói "hệ thống phải nhanh". Tôi hỏi:
- Response time target: "< 500ms"
- Peak load: "200 requests/second, during sale"
- Concurrent users: "10,000 concurrent"
- Acceptable downtime/month: "2 hours (99.7% uptime)"
Từ 4 con số đó, tôi thiết kế:
- Frontend: React SPA + CloudFront CDN (global edge caching)
- Backend: .NET Core + load balancer, 3 instances
- Database: SQL Server + read replica cho search queries
- Cache: Redis cho product catalog (99% cache hit rate)
- Search: Elasticsearch cho product search (200ms p95)
Architecture không phức tạp. Nhưng rõ ràng, measurable, defensible.
Kinh nghiệm của tôi: 3 câu hỏi tiêu chuẩn tôi luôn luôn hỏi khách hàng
- Response time: "Bạn muốn response time nào cho critical operation?" (SMART requirement)
- Load at peak: "Traffic peak year là bao nhiêu (requests/second, concurrent users)?"
- Downtime tolerance: "Bạn chịu được downtime bao lâu per month?" (Từ đó tôi sẽ tính SLA)
3 câu hỏi đó, 80% của architecture decision đã rõ.
Lời khuyên cho junior architect
Các bạn trẻ, nếu bạn làm architect (hoặc muốn trở thành architect):
- Đừng bao giờ accept "nhanh" như một requirement. Bắt buộc khách hàng phải cho con số.
- Phải hiểu trade-off. Nhanh hơn = chi phí cao hơn. Bạn phải nói thẳng điều này.
- Tài liệu hóa NFRs ngay từ đầu. Giúp bạn và team sau này biết design decision của bạn tại sao.
- Dùng lingo chuyên môn: SLA, SLO, SLI, error budget. Chúng giúp communication rõ ràng hơn.
- Kiểm chứng lại sau 1 năm. Requirement có còn đúng không? Có cần adjust không?
Cuối cùng, solution architecture là art and science. Nhưng nếu bạn có con số, nó trở thành science. Và science thì bạn có thể defend, có thể measure, có thể improve.
Các bạn, anh mắc lỗi "chỉ ghi 'nhanh'" bao nhiêu lần rồi? Share với anh, có khi câu chuyện của bạn giúp junior thật hiểu requirement gathering.
/Son Do - believe in basic
#1percentbetter #solutionarchitecture #systemdesign #nonfunctionalrequirements #perfengineering