Menu
ESC

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

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

Đang tải...

Bài 18 — Solution: User-facing behavior trước architecture

Viết PRD & Product Spec cho PM Bài 18/60

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

Có một sai lầm kinh điển mà gần như PM nào cũng từng mắc khi viết phần Solution trong PRD: vừa nghĩ ra giải pháp là lập tức nhảy vào mô tả hệ thống bên dưới. "Chúng ta sẽ tạo một bảng user_preferences, viết một cron job chạy mỗi 15 phút, gọi API của bên thứ ba, cache kết quả vào Redis…". Nghe rất kỹ thuật, rất "có chiều sâu". Nhưng khi engineer và designer đọc xong, họ vẫn không trả lời được một câu hỏi đơn giản nhất: Rốt cuộc người dùng sẽ thấy gì và làm gì?

Phần Solution của một PRD tốt phải mô tả hành vi mà người dùng nhìn thấy (user-facing behavior) TRƯỚC, kiến trúc kỹ thuật (architecture) SAU — hoặc tốt hơn nữa, không mô tả kiến trúc trong PRD chút nào mà để cho phần technical design lo. Lý do rất sâu sắc: PRD là tài liệu định nghĩa "cái gì" và "tại sao", còn "làm thế nào ở tầng hệ thống" là việc của engineer. Khi bạn vội vàng kê khai database schema và message queue, bạn đang vô tình làm hai việc tệ: (1) khoá cứng một giải pháp kỹ thuật mà có thể engineer có cách hay hơn, và (2) làm mờ đi câu hỏi quan trọng nhất — trải nghiệm người dùng đã đúng và đủ chưa.

Bài này dạy bạn cách viết phần Solution theo đúng thứ tự tư duy: bắt đầu từ high-level flow (luồng tổng thể người dùng đi qua), rồi đến key UI states (các trạng thái giao diện chính người dùng nhìn thấy), và chỉ chạm tới kiến trúc khi thật sự cần để ràng buộc quyết định. Đây là kỹ năng phân tách "behavior" khỏi "implementation" — một trong những thứ tách biệt PM giỏi với PM mới vào nghề.

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

User-facing behavior là gì, architecture là gì

User-facing behavior là tất cả những gì người dùng có thể quan sát, cảm nhận, tương tác: họ thấy màn hình nào, bấm nút gì, hệ thống phản hồi ra sao, thông báo hiện lên thế nào, trạng thái thay đổi như thế nào. Nó là "hợp đồng" giữa sản phẩm và người dùng.

Architecture là cách hệ thống được xây dựng để tạo ra hành vi đó: database nào, service nào gọi service nào, dữ liệu chảy qua đâu, đồng bộ hay bất đồng bộ. Người dùng không bao giờ nhìn thấy trực tiếp những thứ này.

Nguyên tắc vàng: Trong một PRD, behavior là bắt buộc; architecture là tuỳ chọn và thường nên để cho tài liệu technical design. Khi bạn buộc mình mô tả behavior trước, bạn ép bản thân làm rõ trải nghiệm — và đó chính là phần PM phải chịu trách nhiệm.

Vì sao thứ tự "behavior trước" lại quan trọng

Hãy nghĩ về ba nhóm người đọc PRD của bạn:

  • Designer cần biết người dùng đi qua những màn hình nào, mỗi màn hình ở trạng thái gì, để vẽ flow và mock.
  • Engineer cần hiểu rõ hành vi mong muốn để tự thiết kế hệ thống tối ưu. Nếu bạn áp đặt kiến trúc, bạn lấy mất không gian sáng tạo và trách nhiệm của họ.
  • Stakeholder (sếp, sales, support) cần hình dung trải nghiệm để đánh giá xem nó có giải quyết đúng vấn đề không.
Cả ba nhóm này đều cần behavior trước. Không một ai trong số họ cần biết bạn dùng Redis hay PostgreSQL để duyệt và phê duyệt giải pháp. Khi bạn viết kiến trúc lên trước, bạn vô tình loại bỏ designer và stakeholder khỏi cuộc thảo luận, và biến cuộc review thành một buổi tranh luận kỹ thuật quá sớm.

Hai trụ cột của phần Solution: High-level flow và Key UI states

Một phần Solution viết theo hướng user-facing sẽ luôn có hai trụ cột:

1. High-level flow — luồng tổng thể. Đây là chuỗi bước người dùng đi qua từ điểm bắt đầu đến khi đạt mục tiêu. Có thể là sơ đồ (flow diagram) hoặc các bước được đánh số. Mục tiêu là cho người đọc thấy "bức tranh đường đi" trong vòng 30 giây. Ví dụ: "(1) Người dùng mở app → (2) thấy banner gợi ý nạp tiền → (3) bấm vào, chọn gói → (4) xác nhận → (5) nhận thông báo thành công". Lưu ý: flow ở đây là flow của người dùng, không phải flow của dữ liệu trong hệ thống.

2. Key UI states — các trạng thái giao diện chính. Với mỗi bước quan trọng trong flow, người dùng nhìn thấy gì? Một màn hình không chỉ có một trạng thái "thành công" — nó có thể có trạng thái trống (empty), đang tải (loading), lỗi (error), thành công (success). Phần này mô tả cụ thể nội dung và hành vi của từng trạng thái mà người dùng có thể gặp. (Lưu ý: bài này chỉ giới thiệu khái niệm "key UI states" ở mức tổng quan trong phần Solution; việc đặc tả chi tiết empty/loading/error/success là chủ đề riêng của một bài sau, nên ở đây ta chỉ liệt kê đủ để engineer và designer hiểu phạm vi.)

Khi nào behavior cần "chạm" tới architecture

Không phải lúc nào bạn cũng được phép hoàn toàn im lặng về kỹ thuật. Có những trường hợp một ràng buộc kỹ thuật ảnh hưởng trực tiếp tới hành vi người dùng, và bạn buộc phải nêu — nhưng nêu dưới góc nhìn behavior:

  • "Vì dữ liệu cập nhật bất đồng bộ, người dùng có thể thấy số dư cũ trong tối đa 5 giây sau giao dịch — cần hiển thị trạng thái 'đang cập nhật'." → Đây là behavior, dù gốc rễ là quyết định kỹ thuật.
  • "Tính năng này phụ thuộc API của đối tác có giới hạn 100 request/phút, nên ở giờ cao điểm người dùng có thể gặp màn hình 'thử lại sau'." → Ràng buộc kỹ thuật được dịch thành hành vi.
Quy tắc: nếu một chi tiết kỹ thuật làm thay đổi những gì người dùng thấy hoặc cảm nhận, hãy đưa vào — nhưng diễn đạt bằng ngôn ngữ behavior. Nếu nó hoàn toàn vô hình với người dùng, để nó cho technical design doc.

Tình huống thực tế

Ví dụ 1: Tính năng "Gợi ý nạp tiền" của một ví điện tử Việt Nam

Giả sử bạn là PM tại một ví điện tử kiểu MoMo/ZaloPay. Đội bạn muốn làm tính năng nhắc người dùng nạp tiền khi số dư thấp, để tăng tỷ lệ giao dịch thành công.

Cách viết SAI (architecture-first):

> "Chúng ta tạo service balance-monitor lắng nghe event transaction.completed, nếu balance < ngưỡng thì ghi vào bảng low_balance_flags, một cron job mỗi 10 phút quét bảng này và đẩy notification qua FCM…"

Designer đọc xong không biết banner trông thế nào. Stakeholder không biết người dùng sẽ bị làm phiền ra sao. Engineer thì cau mày vì họ thấy ngay cron 10 phút là kiến trúc tệ nhưng giờ đã bị "chốt" trong PRD.

Cách viết ĐÚNG (behavior-first):

High-level flow:

  • Người dùng mở app trong khi số dư dưới 50.000đ.
  • Một banner màu cam xuất hiện ở đầu màn hình chính: "Số dư của bạn còn 32.000đ. Nạp thêm để không gián đoạn?".
  • Người dùng bấm "Nạp ngay" → mở màn hình chọn nguồn tiền và số tiền gợi ý (100k/200k/500k).
  • Xác nhận → thấy trạng thái xử lý → thông báo thành công, banner biến mất.
Key UI states: banner chỉ hiện tối đa 1 lần/ngày; nếu người dùng vừa nạp xong thì không hiện lại trong 24h; nếu nạp thất bại thì banner đổi sang trạng thái "Nạp tiền chưa thành công, thử lại".

Bài học: Phiên bản behavior-first khiến cả designer, engineer, lẫn sếp marketing đều đánh giá được giải pháp ngay. Engineer hoàn toàn tự do chọn dùng event-driven thay vì cron. Và quan trọng nhất: cuộc thảo luận tập trung vào câu hỏi đúng — "banner 1 lần/ngày có quá ít/quá nhiều không?" thay vì "cron 10 phút hay 5 phút?".

Ví dụ 2: Grab — tính năng "đặt lại chuyến vừa huỷ"

Một PM tại một nền tảng gọi xe (tương tự Grab/Be) muốn làm tính năng: khi tài xế huỷ chuyến, khách được đề nghị tự động tìm tài xế khác mà không phải đặt lại từ đầu.

PM đầu tiên viết: "Khi nhận event driver.cancelled, hệ thống giữ lại ride_request trong queue, re-dispatch tới pool tài xế trong bán kính 3km…". Toàn bộ review meeting biến thành tranh luận về thuật toán matching.

PM thứ hai viết lại theo behavior-first:

High-level flow: (1) Khách đang chờ → (2) tài xế huỷ → (3) thay vì màn hình "Không tìm thấy tài xế", khách thấy ngay banner "Tài xế vừa huỷ. Đang tìm tài xế khác cho bạn…" với điểm đón và điểm đến giữ nguyên → (4) tìm được → cập nhật thông tin tài xế mới → (5) nếu sau 60 giây không tìm được, hiện nút "Tiếp tục chờ" hoặc "Huỷ chuyến".

Key UI states: trạng thái "đang tìm lại" (có animation), trạng thái "tìm được tài xế mới", trạng thái "không tìm được sau 60s". Mỗi trạng thái mô tả rõ người dùng thấy gì và có nút gì.

Bài học: Bản behavior-first làm lộ ra một quyết định sản phẩm quan trọng mà bản architecture-first đã che giấu: điều gì xảy ra nếu sau 60 giây vẫn không có tài xế? Đây là câu hỏi về trải nghiệm, không phải kỹ thuật — và chỉ khi viết theo flow + states người dùng thì nó mới nổi lên để cả nhóm cùng quyết.

Ví dụ 3: Tiki — đồng bộ giỏ hàng giữa web và app

PM tại một sàn TMĐT muốn cho phép giỏ hàng đồng bộ giữa web và mobile app. Đây là một tính năng nghe rất "kỹ thuật", và đó chính là cái bẫy.

Bản nháp đầu: hai trang dày đặc về cách sync delta, conflict resolution, "last write wins"… Sếp đọc xong hỏi: "Nếu tôi thêm sản phẩm trên web rồi mở app sau 2 giây thì tôi thấy gì?". PM không trả lời ngay được — vì đã quên mất behavior.

Viết lại behavior-first, phần Solution mở đầu bằng: "Người dùng thêm sản phẩm trên web. Khi mở app (hoặc đang mở app sẵn), trong vòng tối đa 3 giây giỏ hàng app cập nhật để khớp. Nếu cùng lúc người dùng sửa giỏ trên cả hai nơi, hệ thống giữ phiên bản mới nhất và hiển thị toast 'Giỏ hàng đã được cập nhật'." Chỉ duy nhất một dòng chạm tới kỹ thuật: "Đồng bộ là bất đồng bộ nên có độ trễ tối đa ~3 giây — cần thể hiện rõ qua trạng thái loading nhỏ trên icon giỏ hàng."

Bài học: Ngay cả với tính năng bản chất là kỹ thuật, vẫn luôn có một lớp behavior người dùng cảm nhận được (độ trễ 3 giây, toast thông báo). Nhiệm vụ của PM là làm rõ lớp đó trước, rồi mới để engineer lo phần "last write wins" trong technical design.

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

Đây là quy trình bạn có thể áp dụng mỗi khi viết phần Solution:

Bước 1 — Viết một câu mô tả trạng thái cuối cùng người dùng đạt được. Bắt đầu từ kết quả: "Sau tính năng này, người dùng có thể ___ mà trước đây không thể / phải làm vất vả hơn." Câu này neo toàn bộ phần Solution vào giá trị cho người dùng.

Bước 2 — Vẽ high-level flow bằng các bước được đánh số. Liệt kê 4–8 bước người dùng đi qua, từ trigger đến mục tiêu. Mỗi bước là một hành động của người dùng hoặc một phản hồi của hệ thống mà người dùng thấy. Tránh đưa bước nội bộ hệ thống ("ghi vào DB") vào flow này.

Bước 3 — Với mỗi bước quan trọng, liệt kê các UI state người dùng có thể gặp. Tự hỏi: ở bước này, nếu dữ liệu đang tải thì sao? Nếu trống thì sao? Nếu lỗi thì sao? Nếu thành công thì sao? Không cần đặc tả chi tiết từng pixel (đó là việc của design và của bài chuyên sâu về states), chỉ cần liệt kê đủ để mọi người thấy phạm vi.

Bước 4 — Soát lại và gạch bỏ mọi câu nói về kiến trúc. Đọc lại từng dòng. Mỗi khi gặp một câu mô tả hệ thống (database, queue, service, API nội bộ), tự hỏi: "Câu này có thay đổi những gì người dùng thấy không?". Nếu KHÔNG → xoá hoặc chuyển sang technical design doc. Nếu CÓ → viết lại dưới góc nhìn behavior.

Bước 5 — Thêm một mục nhỏ "Ràng buộc kỹ thuật ảnh hưởng tới trải nghiệm" (nếu có). Đây là nơi hợp pháp duy nhất để chạm tới kỹ thuật trong phần Solution: chỉ những ràng buộc làm thay đổi behavior (độ trễ, giới hạn rate, phụ thuộc đối tác).

Bước 6 — Kiểm tra bằng "bài test người đọc". Đưa cho một người không phải kỹ thuật (designer, sales) đọc phần Solution. Nếu họ hình dung được trải nghiệm và đặt câu hỏi về trải nghiệm — bạn đã viết đúng. Nếu họ bối rối vì thuật ngữ kỹ thuật — bạn vẫn còn architecture-first.

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

Lỗi 1: Mô tả flow của dữ liệu thay vì flow của người dùng. "Request đi từ client tới gateway, qua auth service…" — đây là flow hệ thống. Người dùng không "đi qua gateway". Hãy luôn bắt đầu mỗi bước flow bằng chủ ngữ "Người dùng…".

Lỗi 2: Chỉ mô tả trạng thái thành công (happy path). Rất nhiều PRD vẽ một flow đẹp đẽ nhưng quên hỏi: lỡ lỗi thì sao, lỡ trống thì sao. Mẹo: với mỗi màn hình, ép mình viết tối thiểu hai trạng thái — một thành công và một "ngoài happy path".

Lỗi 3: Chốt cứng giải pháp kỹ thuật quá sớm. Khi bạn viết "dùng WebSocket", bạn đã quyết hộ engineer. Hãy viết "cập nhật theo thời gian thực, độ trễ cảm nhận dưới 1 giây" — đó là behavior, còn WebSocket hay polling để engineer chọn.

Lỗi 4: Dùng từ kỹ thuật để né việc mô tả trải nghiệm. "Hệ thống sẽ cache kết quả" nghe có vẻ đủ, nhưng nó né câu hỏi: người dùng có thấy dữ liệu cũ không, cũ tới mức nào, có chấp nhận được không. Mẹo: mỗi khi định viết một từ kỹ thuật, hỏi "từ này dịch ra trải nghiệm người dùng là gì?".

Mẹo lớn: Hãy hình dung bạn đang quay một đoạn video demo tính năng cho người dùng xem. Bạn sẽ quay được những cảnh nào? Đó chính là high-level flow và key UI states. Bạn không quay được cảnh "dữ liệu ghi vào Redis" — và đó là lý do nó không thuộc phần này.

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

Chọn một tính năng đơn giản: "Lưu sản phẩm yêu thích (wishlist)" cho một app TMĐT.

  • Viết một câu mô tả trạng thái cuối người dùng đạt được (Bước 1).
  • Vẽ high-level flow 5–7 bước, mỗi bước bắt đầu bằng "Người dùng…" hoặc "Hệ thống hiển thị…". Cấm dùng bất kỳ từ nào về database, API, server.
  • Với màn hình "danh sách yêu thích", liệt kê ít nhất 4 trạng thái UI (ví dụ: danh sách trống, đang tải, có sản phẩm, sản phẩm đã hết hàng).
  • Viết một mục "Ràng buộc kỹ thuật ảnh hưởng trải nghiệm" — nghĩ xem có ràng buộc nào không (ví dụ: nếu yêu thích cần đăng nhập thì người dùng chưa đăng nhập sẽ thấy gì?).
  • Đưa bản viết cho một người bạn không làm kỹ thuật đọc và hỏi họ: "Bạn hình dung được trải nghiệm không?". Ghi lại câu hỏi đầu tiên họ đặt ra — nếu đó là câu hỏi về trải nghiệm, bạn đã thành công.
Phần thưởng: thử viết thêm bản "architecture-first" cùng tính năng đó, rồi so sánh xem bản nào khiến đồng nghiệp non-tech hiểu nhanh hơn.

Tóm tắt

Phần Solution của PRD phải kể câu chuyện về những gì người dùng thấy và làm, chứ không phải bản vẽ kỹ thuật của hệ thống. Hãy luôn mở đầu bằng high-level flow — chuỗi bước người dùng đi qua — rồi tới key UI states — các trạng thái giao diện chính người dùng gặp, bao gồm cả những trạng thái ngoài happy path. Kiến trúc chỉ được phép xuất hiện khi nó trực tiếp làm thay đổi trải nghiệm người dùng, và khi đó phải được diễn đạt bằng ngôn ngữ behavior (độ trễ, giới hạn, thông báo). Mọi chi tiết hệ thống vô hình với người dùng nên để cho tài liệu technical design.

Lợi ích lớn nhất của lối viết behavior-first không chỉ là tài liệu dễ đọc, mà là nó ép đúng cuộc thảo luận đúng thời điểm: stakeholder bàn về giá trị, designer bàn về trải nghiệm, engineer được tự do thiết kế hệ thống tối ưu. Khi bạn tách được "behavior" khỏi "implementation", bạn đang làm đúng việc của một PM: định nghĩa cái gì và tại sao, và tin tưởng giao "làm thế nào" cho những người giỏi nhất việc đó.