Menu
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Đang tải...

Bài 7 — NFR (Non-Functional Requirements) — Định nghĩa

Architecture Decision-Making Bài 7/60

Mở đầu — vì sao bài này quan trọng

Hãy tưởng tượng bạn vừa hoàn thành một hệ thống đặt vé xem phim. Người dùng đăng nhập được, chọn ghế được, thanh toán được — mọi thứ "chạy đúng". Nhưng đến tối thứ Sáu khi bom tấn ra rạp, 50.000 người cùng vào đặt vé trong 10 phút. Trang web treo. Người dùng bấm thanh toán hai lần vì thấy màn hình quay vòng, và có người bị trừ tiền hai lần. Đội kỹ thuật thức trắng đêm.

Câu hỏi đau đớn ở đây là: hệ thống có "sai" không? Về mặt chức năng, không. Nó làm đúng mọi việc bạn yêu cầu nó làm. Vấn đề nằm ở chỗ nó làm những việc đó không đủ tốt dưới áp lực thực tế. Đây chính là địa hạt của Non-Functional Requirements (NFR) — Yêu cầu Phi chức năng.

Trong vai trò một người ra quyết định kiến trúc, phần lớn những sai lầm đắt giá nhất mà bạn sẽ chứng kiến không đến từ việc viết sai logic nghiệp vụ, mà đến từ việc bỏ quên hoặc định lượng sai các NFR. Một tính năng viết sai thì sửa được trong một buổi chiều. Nhưng một hệ thống được thiết kế cho 1.000 người dùng mà thực tế cần phục vụ 1 triệu người thì thường phải viết lại từ đầu. Bài học hôm nay đặt nền móng cho toàn bộ phần còn lại của khóa học: trước khi bàn về scalability, reliability, security hay performance ở các bài sau, bạn cần hiểu chính xác NFR là gì, khác gì với yêu cầu chức năng, và tại sao việc định nghĩa chúng cho tử tế lại là kỹ năng cốt lõi của một kiến trúc sư.

Khái niệm cốt lõi

Functional vs Non-functional — sự khác biệt nền tảng

Cách phân biệt đơn giản nhất, dễ nhớ nhất mà tôi muốn bạn khắc cốt ghi tâm:

  • Functional requirement (Yêu cầu chức năng): mô tả hệ thống làm gìwhat the system does. Nó là những hành vi cụ thể, những chức năng người dùng có thể quan sát được. Ví dụ: "Người dùng có thể đặt đơn hàng", "Hệ thống gửi email xác nhận sau khi thanh toán", "Admin có thể xuất báo cáo doanh thu theo tháng".
  • Non-functional requirement (Yêu cầu phi chức năng): mô tả hệ thống làm việc đó tốt đến mức nàohow well the system does it. Nó không thêm chức năng mới, mà đặt ra các thuộc tính chất lượng cho những chức năng đã có. Ví dụ: "Đơn hàng phải được xử lý trong dưới 2 giây ở phân vị 95", "Hệ thống phải chịu được 10.000 người dùng đồng thời", "Dữ liệu thanh toán phải được mã hóa khi lưu trữ".
Một mẹo kiểm tra nhanh: nếu bạn có thể viết yêu cầu dưới dạng "Người dùng có thể..." hoặc "Hệ thống sẽ..." kèm một hành động — đó thường là functional. Nếu yêu cầu đó cần một tính từ hoặc trạng từ đo lường được — nhanh, an toàn, ổn định, chịu tải, khả dụng — đó thường là non-functional.

NFR là thuộc tính, không phải là tính năng

Điểm mấu chốt khiến nhiều bạn hiểu sai: NFR không tồn tại độc lập. Bạn không thể "làm xong tính năng performance" như làm xong tính năng đăng nhập. NFR là thuộc tính bao trùm (cross-cutting) áp lên toàn bộ hoặc một phần lớn hệ thống.

Ví dụ, yêu cầu "thời gian phản hồi dưới 200ms" không thuộc về riêng màn hình nào — nó áp cho tất cả các API. Yêu cầu "khả dụng 99,9%" không phải là một dòng code — nó là kết quả của hàng loạt quyết định về hạ tầng, redundancy, monitoring và quy trình vận hành. Đây là lý do NFR khó và tốn kém: chúng thấm vào mọi ngóc ngách của kiến trúc.

Các nhóm NFR quan trọng (các "-ilities")

Trong ngành, NFR thường được gọi là các "-ilities" vì phần lớn tên tiếng Anh kết thúc bằng đuôi này. Bạn không cần thuộc lòng danh sách, nhưng cần nhận diện được các nhóm lớn — mỗi nhóm sẽ có một bài riêng phía sau trong khóa học:

  • Performance (Hiệu năng): tốc độ, độ trễ (latency), thông lượng (throughput). Bài 11 sẽ đi sâu.
  • Scalability (Khả năng mở rộng): khả năng phục vụ nhiều tải hơn khi thêm tài nguyên. Bài 8.
  • Availability & Reliability (Tính khả dụng & Độ tin cậy): hệ thống có sẵn sàng phục vụ không, và có chạy đúng liên tục không. Bài 9.
  • Security (Bảo mật): bảo vệ dữ liệu và chống truy cập trái phép. Bài 10.
  • Maintainability (Khả năng bảo trì): dễ sửa đổi, dễ hiểu, dễ mở rộng code.
  • Usability (Khả năng sử dụng): trải nghiệm người dùng, độ dễ dùng.
  • Portability, Observability, Compliance... và nhiều nhóm khác tùy bối cảnh.
Ở bài này, mục tiêu của chúng ta không phải đi sâu từng nhóm — mà là học cách định nghĩa một NFR cho đúng chuẩn, bất kể nó thuộc nhóm nào.

Một NFR "tốt" trông như thế nào — công thức đo lường được

Đây là phần quan trọng nhất của bài. Một NFR chỉ có giá trị khi nó đo lường được và kiểm chứng được. So sánh hai cách viết:

  • ❌ "Hệ thống phải nhanh." — Vô nghĩa. Nhanh là bao nhiêu? Cho ai? Trong điều kiện nào?
  • ✅ "95% các request tra cứu sản phẩm phải trả về trong dưới 300ms, khi hệ thống chịu tải 5.000 request/giây, đo tại server."
NFR tốt cần trả lời được bốn câu hỏi: Chỉ số gì (metric), Ngưỡng bao nhiêu (target), Trong điều kiện nào (context/load), và Đo ở đâu (measurement point). Thiếu bất kỳ vế nào, NFR sẽ biến thành một lời hứa mơ hồ mà không ai kiểm tra được — và những gì không kiểm tra được thì không tồn tại trong thực tế kỹ thuật.

Tình huống thực tế

Ví dụ 1: Sàn thương mại điện tử và ngày sale 12/12

Một sàn thương mại điện tử tại Việt Nam (gọi là ShopViet cho dễ hình dung) chuẩn bị cho ngày sale 12/12. Đội sản phẩm đưa yêu cầu chức năng rất đầy đủ: người dùng săn deal, áp voucher, thanh toán qua ví điện tử. Mọi tính năng đều hoạt động hoàn hảo trong môi trường test với vài chục người.

Ngày sale, lúc 0h00, lượng truy cập tăng vọt lên gấp 40 lần bình thường. Trang chủ tải mất 15 giây. Nút "áp voucher" quay vòng rồi báo lỗi. Đến 0h20, hệ thống thanh toán ngừng phản hồi hoàn toàn. Doanh thu giờ vàng gần như bằng không.

Diễn giải: Đội kỹ thuật đã làm đúng 100% functional requirements nhưng chưa từng định nghĩa NFR một cách nghiêm túc. Không ai viết ra câu hỏi: "Đêm 12/12, cao điểm dự kiến bao nhiêu request/giây? Latency chấp nhận được là bao nhiêu? Nếu tải vượt ngưỡng thì hệ thống suy giảm mượt hay sập hẳn?" Vì không có con số mục tiêu, đội hạ tầng không biết cần bao nhiêu server, không biết đặt ngưỡng cảnh báo ở đâu, không có kịch bản chịu tải để test trước.

Bài học rút ra: NFR về scalability và performance phải được định nghĩa bằng con số cụ thể, gắn với sự kiện kinh doanh thực tế. Với thương mại điện tử ở Việt Nam, các mốc sale 9/9, 11/11, 12/12 là những bài toán tải có thể dự đoán trước hàng tháng. Một NFR đúng chuẩn cho tình huống này sẽ là: "Trong khung 0h00–1h00 ngày sale, hệ thống phục vụ được 20.000 request/giây với P95 latency dưới 800ms, và khi vượt ngưỡng phải xếp hàng người dùng thay vì trả lỗi."

Ví dụ 2: Ứng dụng ngân hàng số và yêu cầu về tính khả dụng

Một ngân hàng số ở Đông Nam Á đặt mục tiêu marketing: "App luôn sẵn sàng, giao dịch tức thì". Nghe rất hay, nhưng đây là một NFR tồi vì nó không đo lường được. Khi đội kiến trúc ngồi lại, họ chuyển nó thành các con số cụ thể.

Họ xác định mục tiêu availability là 99,95%. Nghe có vẻ nhỏ chênh lệch so với 99,9%, nhưng hãy nhìn con số thật: 99,9% cho phép hệ thống chết khoảng 8,76 giờ/năm, còn 99,95% chỉ cho phép 4,38 giờ/năm — giảm một nửa thời gian chết, và chi phí hạ tầng để đạt được điều đó tăng lên đáng kể. Với performance, họ định nghĩa: "99% giao dịch chuyển khoản nội bộ hoàn tất trong dưới 3 giây."

Diễn giải: Chính việc gắn con số đã buộc mọi bên phải đối mặt với cái giá của NFR. Khi bộ phận kinh doanh đòi 99,99% (tức chỉ ~52 phút chết/năm), đội kiến trúc trình bày rằng để đạt mức đó cần triển khai multi-region, database replication đồng bộ, và ngân sách hạ tầng tăng gấp ba. Cuộc trò chuyện lập tức trở nên thực tế: NFR không còn là khẩu hiệu, mà là một quyết định đánh đổi có giá tiền cụ thể.

Bài học rút ra: NFR về availability phải được biểu diễn bằng phần trăm và quy đổi ra thời gian chết cho phép để mọi người hiểu ý nghĩa thật của nó. Và quan trọng hơn — mỗi con số 9 thêm vào đều có cái giá tăng theo cấp số, nên đừng bao giờ mặc định "càng cao càng tốt".

Ví dụ 3: Startup logistics và cái bẫy "over-engineering" NFR

Một startup giao đồ ăn giai đoạn đầu, chỉ có khoảng 2.000 người dùng ở một thành phố. Đội kỹ thuật vốn từ công ty lớn, quen tư duy "phải chịu tải triệu người", nên họ dựng kiến trúc phân tán phức tạp, đặt mục tiêu NFR "chịu 100.000 request/giây, availability 99,99%".

Sáu tháng sau, họ đốt gần hết vốn cho hạ tầng và nhân sự vận hành hệ thống phức tạp đó, trong khi lượng người dùng thực tế chưa bao giờ chạm ngưỡng cần đến 1% năng lực đã xây. Đối thủ dùng kiến trúc đơn giản hơn thì ra tính năng mới nhanh gấp đôi.

Diễn giải: NFR sai không chỉ là NFR đặt quá thấp — mà còn là NFR đặt quá cao so với thực tế kinh doanh ở giai đoạn hiện tại. Việc định nghĩa NFR luôn phải gắn với bối cảnh và giai đoạn của sản phẩm. Một startup 2.000 người dùng cần NFR kiểu "phục vụ 200 đơn/giờ giờ cao điểm, latency dưới 2 giây" — vừa đủ để trải nghiệm tốt, vừa để dồn tiền cho tăng trưởng.

Bài học rút ra: Định nghĩa NFR là bài toán cân bằng, không phải cuộc đua tối đa hóa. Con số mục tiêu phải phản ánh nhu cầu thực và khả năng chi trả thực, không phải tham vọng hay nỗi sợ.

Hướng dẫn từng bước

Đây là quy trình bạn có thể áp dụng ngay để định nghĩa một bộ NFR cho hệ thống của mình.

Bước 1 — Liệt kê các functional requirement chính trước. Bạn không thể định nghĩa "tốt đến mức nào" nếu chưa biết "làm gì". Viết ra các luồng nghiệp vụ quan trọng nhất: đăng nhập, tìm kiếm, đặt hàng, thanh toán.

Bước 2 — Gắn mỗi luồng quan trọng với các thuộc tính chất lượng liên quan. Với luồng "thanh toán", các thuộc tính đáng quan tâm là: performance (nhanh), reliability (không mất giao dịch), security (bảo vệ dữ liệu thẻ), availability (luôn sẵn sàng). Không phải luồng nào cũng cần mọi NFR — hãy chọn thứ thực sự quan trọng với luồng đó.

Bước 3 — Chuyển mỗi thuộc tính thành một câu đo lường được. Áp dụng công thức bốn vế: chỉ số + ngưỡng + điều kiện + điểm đo. Ví dụ: "Latency API thanh toán (chỉ số) dưới 500ms ở P95 (ngưỡng) khi có 3.000 giao dịch/phút (điều kiện), đo tại API gateway (điểm đo)."

Bước 4 — Xác định nguồn của con số. Đừng bịa số. Con số nên đến từ: dữ liệu lịch sử (log của hệ thống cũ), benchmark ngành, ước lượng kinh doanh (dự báo người dùng), hoặc ràng buộc bên ngoài (SLA với đối tác, quy định pháp lý). Nếu thật sự chưa có dữ liệu, hãy ghi rõ đây là giả định cần kiểm chứng.

Bước 5 — Ước lượng cái giá của mỗi NFR. Với mỗi mục tiêu, tự hỏi: "Nâng ngưỡng này lên một bậc tốn thêm bao nhiêu?" Việc này giúp bạn và bên kinh doanh ưu tiên đúng, thay vì đòi mọi thứ đều hoàn hảo.

Bước 6 — Ghi lại và làm cho NFR kiểm chứng được. Đưa NFR vào tài liệu kiến trúc (và ở khóa này, bạn sẽ thấy nó gắn chặt với ADR ở các bài trước). Mỗi NFR nên đi kèm cách kiểm chứng: load test cho performance, chaos test cho reliability, pen-test cho security.

Lỗi thường gặp & mẹo

Lỗi 1 — Viết NFR bằng tính từ suông. "Hệ thống phải nhanh, ổn định, an toàn." Đây là loại NFR phổ biến nhất và vô dụng nhất. Mẹo: mỗi lần bạn viết một tính từ, hãy tự ép mình thêm ngay một con số và một đơn vị đo đằng sau. Không có con số thì gạch bỏ.

Lỗi 2 — Bỏ quên NFR cho đến cuối dự án. Nhiều đội coi NFR là "chuyện tối ưu về sau". Nhưng scalability hay security không thể "gắn thêm" vào một kiến trúc đã hoàn thiện — chúng phải được nhắm tới từ đầu. Mẹo: đưa NFR vào ngay từ giai đoạn thiết kế, cùng lúc với functional requirement.

Lỗi 3 — Dùng con số trung bình (average) thay vì phân vị (percentile). "Latency trung bình 200ms" nghe êm tai nhưng che giấu sự thật: có thể 5% người dùng đang chịu 5 giây. Trải nghiệm tệ của thiểu số này chính là những khách hàng bỏ đi. Mẹo: luôn ưu tiên P95, P99 thay vì average. Bài 11 sẽ giải thích sâu vì sao percentile phản ánh trải nghiệm thật tốt hơn.

Lỗi 4 — Đặt mọi NFR ở mức tối đa. Đòi availability 99,999% cho một blog nội bộ là lãng phí. Mẹo: mỗi NFR phải trả lời câu hỏi "nếu không đạt thì hậu quả kinh doanh là gì?" — hậu quả càng nghiêm trọng, ngưỡng mới càng cần cao.

Lỗi 5 — Không tính đến sự đánh đổi giữa các NFR. Tăng consistency có thể giảm availability; tăng security có thể tăng latency. Các NFR thường xung đột nhau. Mẹo: đừng định nghĩa NFR trong ốc đảo — luôn xem xét chúng như một tập hợp có mâu thuẫn, và bài về Trade-off Analysis (Bài 6) chính là công cụ để cân.

Mẹo tổng quát: Hãy tập thói quen đọc mỗi NFR to lên và hỏi "Ai sẽ kiểm tra điều này, bằng cách nào, và khi nào?". Nếu bạn không trả lời được, NFR đó chưa hoàn chỉnh.

Bài tập thực hành

Bài 1 — Phân loại. Cho các yêu cầu sau, hãy đánh dấu đâu là Functional (F) và đâu là Non-functional (NF):

  • Người dùng có thể đặt lại mật khẩu qua email.
  • Trang kết quả tìm kiếm phải hiển thị trong dưới 1 giây.
  • Hệ thống hỗ trợ đăng nhập bằng Google.
  • Dữ liệu cá nhân phải được mã hóa khi lưu trữ.
  • Admin có thể khóa tài khoản vi phạm.
  • Hệ thống chịu được 5.000 người dùng đồng thời.
Bài 2 — Viết lại cho đo lường được. Ba NFR dưới đây được viết tồi. Hãy viết lại mỗi câu theo công thức bốn vế (chỉ số + ngưỡng + điều kiện + điểm đo):
  • "App phải chạy nhanh."
  • "Hệ thống phải luôn hoạt động."
  • "Dữ liệu phải an toàn."
Bài 3 — Tình huống của bạn. Chọn một hệ thống bạn đang làm hoặc quen thuộc (ví dụ: một website bán hàng nhỏ). Viết ra 5 NFR đầy đủ cho nó, mỗi cái kèm: con số mục tiêu, nguồn của con số đó, và cách bạn sẽ kiểm chứng. Sau đó tự hỏi: NFR nào đắt nhất để đạt được, và có đáng không?

Gợi ý đáp án Bài 1: F = 1, 3, 5; NF = 2, 4, 6.

Tóm tắt

Trong bài này, chúng ta đã đặt nền móng cho toàn bộ tư duy về chất lượng hệ thống. Những điểm cốt lõi cần mang theo:

  • Functional requirement mô tả hệ thống làm gì; Non-functional requirement (NFR) mô tả hệ thống làm việc đó tốt đến mức nào. Cả hai đều bắt buộc, nhưng NFR thường bị bỏ quên và chính là nguồn của những thất bại kiến trúc đắt giá nhất.
  • NFR là thuộc tính bao trùm, không phải tính năng rời rạc — chúng thấm vào mọi quyết định thiết kế, nên phải được nhắm tới từ đầu chứ không gắn thêm về sau.
  • Một NFR chỉ có giá trị khi đo lường được: chỉ số + ngưỡng + điều kiện + điểm đo. Tính từ suông như "nhanh", "an toàn" là NFR chết.
  • Con số mục tiêu phải đến từ dữ liệu và bối cảnh kinh doanh thực, không phải tham vọng hay nỗi sợ. Đặt NFR quá cao gây lãng phí; đặt quá thấp gây sập hệ thống.
  • Mỗi NFR đều có cái giá, và các NFR thường xung đột nhau — đây là lý do định nghĩa NFR luôn gắn liền với phân tích đánh đổi.
Từ nền tảng này, các bài tiếp theo sẽ đi sâu vào từng nhóm NFR: scalability, reliability, security, performance. Nhưng dù đi vào nhóm nào, hãy luôn quay lại nguyên tắc gốc của bài hôm nay — nếu bạn không thể đo nó, bạn không thể đảm bảo nó.