Khi API không làm gì cả, hãy không làm gì cho đúng cách
- Khi API không được phép làm gì cả, điều quan trọng là phải bảo đảm nó “không làm gì” theo đúng cách.
- Ví dụ, Windows có một hạ tầng in ấn rất đồ sộ, nhưng Xbox thì không có hạ tầng như vậy.
- Khi ứng dụng cố in trên Xbox, việc ném ra
NotSupportedException là cách làm sai.
- Vì ứng dụng chủ yếu được kiểm thử trên PC, nên khi chạy trên Xbox có thể không xử lý ngoại lệ này và bị sập.
- Một thiết kế tốt hơn để “hỗ trợ” tính năng in trên Xbox là để hàm in vẫn thành công nhưng báo rằng không có máy in nào được cài đặt.
- Khi người dùng thử in, hệ thống yêu cầu chọn máy in nhưng danh sách trống, nên người dùng sẽ nhận ra rằng “à, không có máy in” và hủy yêu cầu in.
- Với các ứng dụng cố cài máy in, hàm cài đặt máy in có thể trả về ngay với mã kết quả “người dùng đã hủy thao tác”.
- Mục tiêu là hành xử như thể tính năng in được hỗ trợ đầy đủ, nhưng trên thực tế thì như thể không có máy in nào.
- Trên các hệ thống mà việc in hoàn toàn không hoạt động, có thể thêm một hàm kiểm tra khả năng in để ẩn nút in khỏi UI.
- Kiểu hành vi này được gọi là “vô hiệu” (
inert).
- Bề mặt API vẫn tồn tại và vẫn hoạt động theo đặc tả, nhưng trên thực tế không làm gì cả.
- Điều quan trọng là nó phải “không làm gì” một cách nhất quán với tài liệu, để giảm thiểu vấn đề với mã hiện có.
Ví dụ về vô hiệu hóa API
- Có một ví dụ về việc vô hiệu hóa một API bao gồm nhiều hàm tạo widget handle, các hàm nhận widget handle và một hàm đóng widget handle.
- Ban đầu, nhóm đề xuất vô hiệu hóa API bằng cách để
CreateWidget thành công nhưng trả về con trỏ null.
- Tuy nhiên, cách này có thể khiến ứng dụng bối rối. “Lời gọi thành công nhưng lại không nhận được handle hợp lệ sao?”
- Việc để
EnableWidget trả về “handle không hợp lệ” cũng có thể gây nhầm lẫn.
- Họ đã tìm thấy trong tài liệu hiện có một giá trị trả về
ERROR_CANCELLED, nghĩa là việc tạo widget đã bị người dùng hủy.
- Vì vậy, mỗi khi ứng dụng cố tạo widget, có thể trả lời rằng “không, người dùng đã hủy”.
Ý kiến của GN⁺
- Điều quan trọng nhất trong bài viết này là khi API không làm gì cả, nó vẫn phải “không làm gì” theo cách không làm tổn hại trải nghiệm người dùng và vẫn giữ được khả năng tương thích với mã hiện có.
- Cách tiếp cận này nhấn mạnh với các lập trình viên tầm quan trọng của thiết kế API, đồng thời góp phần mang lại trải nghiệm phần mềm thân thiện hơn với người dùng.
- Bài viết cho thấy một khía cạnh tinh tế của kỹ nghệ phần mềm, và đưa ra một ví dụ thú vị về cách ứng dụng có thể thất bại một cách duyên dáng ngay cả trong những môi trường không ngờ tới.
2 bình luận
Ý kiến Hacker News
Ý kiến về việc "nuốt lỗi":
paniccủa Go là một cách tốt để làm nổi bật sai lầm của lập trình viên trong quá trình kiểm thử.Ý kiến về khả năng tương thích ngược:
Phàn nàn về thiết kế UI:
Chỉ ra việc Microsoft không rút kinh nghiệm:
Ý kiến về việc Xbox không hỗ trợ in:
Lời khuyên về việc sử dụng API:
NotSupportedExceptionkhông phải là sai.Cảm nhận về "tuân thủ ác ý":
Ý kiến tích cực về bảo mật:
Hồi tưởng về chiến lược trình duyệt:
Điều các nhà phê bình về xử lý ngoại lệ đang hiểu sai:
Ý kiến trên Lobste.rs
Nói đùa vậy thôi, tôi không đồng ý với kiểu lập trình và trải nghiệm người dùng phòng thủ quá mức như thế này. Làm vậy thì phần mềm sẽ không làm đúng việc của nó mà người dùng cũng không biết vì sao, lại càng không có cách nào để tìm ra. Ứng dụng nên bắt lỗi và nếu có thể thì tạo thông báo thân thiện với người dùng, nếu không thì ít nhất cũng phải hiển thị thông báo lỗi gốc cho người dùng. Nếu là tác vụ nền thì phải có nhật ký lỗi
Tôi công nhận bài này được viết từ góc nhìn của nhà phát triển API chứ không phải nhà phát triển ứng dụng. Vậy thì cần tài liệu hóa lỗi API và cung cấp thông báo lỗi để phía gọi có thể xử lý
Tôi cũng không thích việc ẩn nút trong UI chỉ vì không có quyền truy cập. Nếu không gian cho phép thì tốt hơn nên hiện nút nhưng vô hiệu hóa nó, và khi người dùng rê chuột vào thì hiển thị thông điệp cho biết làm thế nào để kích hoạt nó
Nhìn chung, yêu cầu tính chính xác vẫn tốt hơn. Tuy nhiên, nếu bạn đã có 1 tỷ người dùng hiện hữu thì việc tránh làm hỏng họ nhiều nhất có thể là lựa chọn rất khôn ngoan, và từ góc nhìn người dùng thì cứ chạy được là tạo ra giá trị thực ở cấp hệ thống. Cuối cùng, thái độ nên là thất bại sớm, nhưng đừng để thất bại hàng loạt
Chuyện này gần với độ ổn định ABI hơn là API. Trên Windows, phần mềm được build từ 15 năm trước vẫn phải tiếp tục chạy được trên hệ điều hành mới càng nhiều càng tốt. Bạn không thể thay đổi chữ ký hàm, nên nếu muốn những API không còn ý nghĩa nữa vẫn tiếp tục hoạt động thì phải dùng những lời nói dối thiện ý
Ví dụ, API vẫn giả vờ như Active Desktop còn tồn tại, vì lựa chọn khác là làm hỏng hàng loạt phần mềm cũ đang tồn tại
Khi đó bạn không thể biết là tính năng ấy đã biến mất hay chỉ bị chôn ở một màn hình khác trong lúc đó
Nhưng nếu ứng dụng không làm vậy, thì người dùng ứng dụng đó sẽ đổ lỗi cho Windows. Họ đổ lỗi cho Windows chứ không phải cho ứng dụng, và ngay cả khi ứng dụng bị crash cũng thế
Vì vậy Microsoft mới tạo ra các giải pháp vòng vo. Cứ để tác vụ in tự biến mất thì dễ hơn nhiều, và rồi người dùng sẽ nghĩ một lát rồi chấp nhận rằng “à đúng rồi, mình đâu có máy in”
ifđể kiểm tra null. Mỗi lần thấy vậy tôi lại nhớ đến bài nàyVì thế tôi đã bảo agent đừng lặp đi lặp lại kiểm tra null, mà hãy dùng các hàm vô hại và chỉ xác nhận một lần tại thời điểm khai báo rằng giá trị chắc chắn không bao giờ là null