0

Đổi địa chỉ giao hàng – Một nút bấm và kỹ năng state modeling của PM

Giả sử bạn vừa đặt một phần cơm trưa.

Thanh toán xong, nhìn lại địa chỉ mới thấy mình đã chọn văn phòng cũ. Quán cách chỗ hiện tại hai con phố, tài xế còn chưa nhận đơn. Bạn mở màn hình chi tiết đơn hàng và tìm nút Đổi địa chỉ.

Không có.

Bạn nhắn support. Support gọi cho quán. Quán gọi cho tài xế. Tài xế lại gọi cho bạn để xin địa chỉ mới. Một phần cơm giá 55.000 đồng vừa tạo ra một cuộc họp bốn bên.

Nếu đứng ở phía user, yêu cầu nghe khá đơn giản: thêm một nút cho sửa địa chỉ sau khi đặt đơn.

Nếu đứng ở phía team sản phẩm, câu hỏi khó chịu hơn là: nút ấy được phép tồn tại đến lúc nào?

Một địa chỉ, nhưng không còn là cùng một đơn hàng

Khi đơn vừa được tạo, quán chưa xác nhận và chưa bắt đầu làm món, đổi địa chỉ gần giống sửa một dòng text. Hệ thống tính lại phí giao hàng, kiểm tra địa chỉ mới có nằm trong vùng phục vụ hay không rồi cập nhật đơn.

Nhưng vài phút sau, quán đã bắt đầu nấu. Địa chỉ mới có thể khiến khoảng cách tăng từ một lên sáu cây số. Phí giao hàng cũ không còn đúng. Thời gian dự kiến không còn đúng. Tài xế được ghép cho quãng đường cũ cũng chưa chắc muốn nhận quãng đường mới.

Muộn hơn nữa, tài xế đã lấy đồ ăn và đang chạy. Bây giờ đổi địa chỉ không còn là sửa thông tin. Nó thay đổi công việc mà tài xế đã đồng ý làm.

Cùng một thao tác “đổi địa chỉ”, nhưng tác động của nó đổi theo từng thời điểm của đơn hàng.

Vì vậy, viết một user story kiểu này chưa giúp được team bao nhiêu:

Là người đặt đồ ăn, tôi muốn đổi địa chỉ giao hàng để nhận món ở đúng nơi.

User story nói được nhu cầu. Nó chưa nói được lúc nào yêu cầu đó an toàn, ai phải đồng ý, giá nào cần tính lại và hệ thống phải làm gì nếu một bước ở giữa thất bại.

Nút đổi địa chỉ nhìn có vẻ là việc của UI. Thật ra phần khó nằm dưới cái nút.

Vẽ đơn hàng thành các trạng thái

Đây là lúc state modeling có ích. Nói đơn giản, PM và team liệt kê các trạng thái mà một đối tượng có thể đi qua, rồi xác định điều kiện để nó chuyển từ trạng thái này sang trạng thái khác.

Với đơn giao đồ ăn giả định ở trên, phiên bản đầu có thể trông như thế này:

Đã tạo
↓ quán xác nhận
Đang chuẩn bị
↓ tài xế lấy món
Đang giao
↓ giao thành công
Hoàn tất

Ngoài đường thẳng đẹp đẽ đó còn có Đã hủy, Thanh toán lỗi, Không tìm được tài xế, Giao thất bại và vài trạng thái nghe chẳng vui vẻ gì. Tạm thời mình chưa kéo tất cả vào đây, không thì phần cơm trưa sẽ nguội trước khi sơ đồ vẽ xong.

Quay lại nút đổi địa chỉ.

Ở trạng thái Đã tạo, team có thể cho user tự sửa nếu địa chỉ mới vẫn nằm trong vùng phục vụ. Nếu phí thay đổi, user xác nhận mức phí mới trước khi đơn tiếp tục.

Ở trạng thái Đang chuẩn bị, quán đã bỏ nguyên liệu vào chảo. Team có thể vẫn cho đổi địa chỉ, nhưng phải kiểm tra lại vùng phục vụ và tìm tài xế theo tuyến mới. Nếu không tìm được tài xế, sản phẩm cần nói rõ địa chỉ cũ được giữ nguyên, đơn bị hủy hay yêu cầu đổi địa chỉ được chuyển cho support.

Đến Đang giao, quyết định bắt đầu dính tới tài xế. Một phương án là khóa tính năng và cho user liên hệ support. Một phương án khác là gửi đề nghị đổi tuyến cho tài xế, báo thêm quãng đường và thu nhập, rồi chỉ cập nhật khi tài xế đồng ý.

Không có một đáp án đúng cho mọi ứng dụng. Team có thể chọn chính sách khác nhau tùy mô hình vận hành, hợp đồng với tài xế, cách tính phí và tỷ lệ support có thể gánh được.

Nhưng team cần chọn.

Nếu không, mỗi bộ phận sẽ tự chốt một mảnh: designer đoán lúc nào nên ẩn nút, developer tự chặn một số API call, còn support nghĩ cách chữa cháy cho những trường hợp sản phẩm chưa quy định.

Button bị disabled thì sao ?

State modeling không dừng ở một sơ đồ để dán vào ticket. Mỗi đường chuyển trạng thái đều kéo theo một loạt câu hỏi rất cụ thể.

Ví dụ user đổi địa chỉ khi đơn đang chuẩn bị. Hệ thống kiểm tra địa chỉ mới và báo phụ thu 18.000 đồng. User đồng ý, nhưng giao dịch thu thêm tiền thất bại.

Địa chỉ trong đơn lúc này là địa chỉ nào?

Nếu hệ thống đã lưu địa chỉ mới trước khi thu tiền, tài xế có thể chạy theo tuyến mới trong khi user chưa trả phần chênh lệch. Nếu hệ thống thu tiền trước rồi mới lưu địa chỉ, user có thể bị trừ tiền nhưng đơn vẫn giữ địa chỉ cũ khi bước cập nhật lỗi.

Team phải chọn thứ tự, cách rollback và thông báo mà user nhìn thấy. Chữ “rollback” nghe hơi kỹ thuật, nhưng câu hỏi thì rất đời thường: làm nửa đường bị lỗi, sản phẩm quay về đâu?

Một transition tốt thường cần ít nhất bốn thứ:

  • Ai được quyền bắt đầu thay đổi.
  • Điều kiện nào phải đúng trước khi thay đổi.
  • Những hệ thống hoặc con người nào phải xác nhận.
  • Khi một bước thất bại, trạng thái cuối cùng là gì.

Danh sách này chưa đủ cho mọi case. Nó chỉ đủ để cuộc nói chuyện giữa PM, designer, engineer và operation bắt đầu bằng cùng một đơn hàng, thay vì mỗi người tưởng tượng một phiên bản khác nhau.

Còn phía user, đừng chỉ làm nút biến mất rồi để họ đoán.

Nếu không thể đổi vì tài xế đã lấy món, sản phẩm nên nói đúng điều đó và đưa ra lựa chọn tiếp theo: gọi tài xế, liên hệ support hay tiếp tục giao tới địa chỉ cũ. Nếu có thể đổi nhưng phát sinh thêm 18.000 đồng, con số cần xuất hiện trước khi user xác nhận.

Trạng thái bên trong hệ thống có thể phức tạp. Phần user nhìn thấy thì nên trả lời được ba chuyện: đơn đang ở đâu, vì sao họ chưa làm được điều mình muốn và còn đường nào để đi tiếp.

State Modeling trước khi vẽ wireframe

State modeling dễ bị xem là phần việc kỹ thuật vì nó có ô, mũi tên và mấy cái tên như PAYMENT_PENDING. Cơ mà PM không cần thiết kế database để dùng được nó.

PM cần làm rõ những quyết định sản phẩm mà mỗi trạng thái kéo theo.

Chẳng hạn, team có cho user đổi địa chỉ sau khi quán bắt đầu làm món không? Ai chịu phần phí tăng thêm? Tài xế có quyền từ chối tuyến mới không? Bao lâu không có phản hồi thì yêu cầu đổi địa chỉ hết hạn? Support được phép ép chuyển trạng thái nào?

Những câu đó liên quan tới trải nghiệm user, chi phí vận hành và lời hứa với tài xế. Engineer có thể chỉ ra giới hạn của hệ thống. Operation biết quy trình ngoài đời đang chạy ra sao. Designer tìm cách giải thích quyết định trên giao diện. PM gom các phần ấy lại thành một chính sách đủ rõ để team có thể xây và kiểm tra.

Đây cũng là lý do state modeling nên xuất hiện trước wireframe.

Nếu bắt đầu bằng màn hình, team rất dễ vẽ một nút Lưu địa chỉ mới rồi chỉ bàn xem đặt nó bên trái hay bên phải. Khi bắt đầu bằng trạng thái, team phải đối diện với đoạn khó hơn: bấm Lưu ở mỗi thời điểm sẽ thay đổi lời hứa với những ai.

Sau khi đã thống nhất chính sách, acceptance criteria cũng bớt mơ hồ. Thay vì ghi “user có thể đổi địa chỉ sau khi đặt đơn”, ticket có thể nói rõ:

  • Cho phép yêu cầu đổi khi đơn ở Đã tạo hoặc Đang chuẩn bị.
  • Địa chỉ mới phải nằm trong vùng phục vụ và được tính lại phí.
  • Chỉ cập nhật đơn sau khi user thanh toán thành công phần chênh lệch.
  • Nếu thanh toán thất bại, giữ địa chỉ và phí cũ.
  • Khi đơn ở Đang giao, khóa chỉnh sửa và hiển thị đường liên hệ support.

Đến đây designer biết phải thiết kế những màn hình nào. Engineer biết API cần kiểm tra gì thay vì tin trạng thái đang hiển thị trên app. QA cũng có các đường chuyển để test, gồm cả đường lỗi chứ không chỉ happy path.

Lời nhắn

Không phải sản phẩm nào cũng cần một sơ đồ trạng thái to như bản đồ tàu điện. Một form đăng ký nhận newsletter chắc chưa cần kéo cả team vào phòng họp để tranh luận về transition.

Nhưng nếu một đối tượng đi qua nhiều bước, quyền của user thay đổi theo thời gian hoặc một thao tác có thể kéo theo tiền và công việc của người khác, PM nên thử vẽ trạng thái trước khi viết requirement.

Với phần cơm ở đầu bài, chiếc nút Đổi địa chỉ chỉ nên xuất hiện khi team trả lời được chuyện gì xảy ra sau cú bấm. Còn nếu câu trả lời vẫn là “support xử lý giúp”, ít nhất hãy vẽ rõ nhánh chuyển sang support và tính luôn số cuộc gọi mà chính sách ấy sẽ tạo ra.


Bài gốc trên Substack: https://henrypham.substack.com/p/oi-ia-chi-giao-hang-mot-nut-bam-va


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí