WEBSITE ĐANG PHÁT TRIỂN

Khách hàng muốn 'hệ thống nhanh' - làm thế nào để biết nhanh là bao nhiêu

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 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:

  1. Response time target: "< 500ms"
  2. Peak load: "200 requests/second, during sale"
  3. Concurrent users: "10,000 concurrent"
  4. 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

  1. Response time: "Bạn muốn response time nào cho critical operation?" (SMART requirement)
  2. Load at peak: "Traffic peak year là bao nhiêu (requests/second, concurrent users)?"
  3. 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


Bài viết liên quan

Xem thêm
Solution Architecture & System Design

PostgreSQL vs SQL Server - quyết định tôi đã đưa ra và tại sao

Không có database "tốt hơn". Có database phù hợp hơn với context của bạn. Tôi dùng SQL Server 20 năm và PostgreSQL 5 năm - cả hai đều excellent, nhưng chúng khác nhau ở những trade-off quan trọng mà architect cần hiểu rõ. Năm 2019, tôi nhận một project mới - một startup fintech đang xây MVP. Họ hỏi tôi: "Anh Son, chúng tôi nên dùng database gì?" Câu hỏi đơn giản. Nhưng tôi không trả lời ngay. Thay vào đó, tôi hỏi lại: "Tech stack của team là gì? Ai sẽ maintain database này sau khi tôi đi? Infrastructure của các bạn là on-premise hay cloud? Budget cho licensing là bao nhiêu?" Họ nhìn tôi hơi ngớ ngẩn. Họ expected một câu trả lời technical - benchmark performance, feature comparison. Tôi lại hỏi về organization và budget. Vì đó mới là thứ thực sự quyết định.

Solution Architecture & System Design

Conway's Law - tại sao architecture của bạn trông giống org chart

Conway's Law nói rằng hệ thống bạn build sẽ phản chiếu cấu trúc tổ chức của team. Đây không phải lý thuyết học thuật - đây là lý do tại sao microservices nhiều dự án VN thất bại, và tại sao đôi khi cần thay đổi org chart trước khi thay đổi architecture. Năm 2021, tôi bắt đầu làm tư vấn cho một công ty fintech. Họ muốn chuyển từ monolith sang microservices - xu hướng lúc đó ai cũng nói về. Tôi vào, review codebase, rồi nhìn sang org chart. Và tôi thấy ngay. Monolith của họ có 3 module lớn: Accounting, Lending, và Customer Management. Org chart của họ cũng có 3 team tương ứng: Team Kế toán, Team Tín dụng, và Team Khách hàng. Ba team này không nói chuyện với nhau nhiều - mỗi team có lead riêng, backlog riêng, sprint riêng. Tôi đoán trước microservices của họ sẽ trông như thế nào nếu họ tự migrate: đúng 3 service, tương ứng với 3 team. Không nhiều hơn, không ít hơn. Và đó chính xác là điều xảy ra sau 6 tháng họ tự làm trước khi gọi tôi vào. 3 services, ranh giới business không đúng, coupling vẫn còn đầy, chỉ là coupling giờ đi qua HTTP thay vì function call. Distributed monolith - thứ tệ nhất của cả hai thế giới. Conway's Law đã xảy ra, nhưng không ai để ý.

Solution Architecture & System Design

Read replica vs sharding - chọn sai thì refactor rất đau

Read replica và sharding đều là cách scale database - nhưng giải quyết hai vấn đề hoàn toàn khác nhau. Chọn nhầm thì sau này migrate cực kỳ đau. Đây là cách tôi quyết định, dựa trên kinh nghiệm thực tế.