Họ đang đo gì
Bạn có nghĩ tới client mà bạn không kiểm soát được không — ứng dụng di động đã cài, tích hợp của đối tác.
Trả lời ngắn~30 giây
Ba cách: trong URL (/v2/orders), trong header (Accept: application/vnd.acme.v2+json), hoặc theo ngày như Stripe (Stripe-Version: 2026-08-16). URL dễ debug và dễ cache nhất nên phổ biến nhất; header thì “thuần REST” hơn nhưng khó thử bằng curl và dễ bị proxy làm rơi. Phá vỡ tương thích là: bỏ hoặc đổi tên trường, siết kiểu, thêm trường bắt buộc vào input, hoặc đổi ý nghĩa của một giá trị. Thêm trường mới vào output thì KHÔNG phá vỡ, miễn là client bỏ qua trường lạ.
Giải thích sâu
Điều đáng nói nhất là chi phí thật của phiên bản hoá không nằm ở việc phát hành v2 — nó nằm ở việc BẢO TRÌ v1 song song trong nhiều năm. Mỗi bản vá bảo mật phải áp cho cả hai, mỗi thay đổi database phải tương thích với cả hai, và đội của bạn phải nhớ cả hai hoạt động thế nào. Vì vậy chiến lược tốt nhất thường là tránh cần v2: thiết kế để mở rộng được, và coi mỗi lần buộc phải lên phiên bản là một thất bại nhỏ của thiết kế trước đó.
Cách tiếp cận của Stripe đáng học vì nó tách hai thứ mà mọi người hay gộp: phiên bản là của TÀI KHOẢN chứ không của lời gọi. Client được ghim vào phiên bản tại thời điểm họ tích hợp, và server chạy một chuỗi hàm chuyển đổi để hạ cấp phản hồi mới về hình dạng cũ. Nhờ vậy chỉ có một đường code nghiệp vụ, phần tương thích nằm gọn ở biên. Đắt để dựng, nhưng nó là cách duy nhất mình biết để duy trì hàng chục phiên bản mà không phát điên.
Về “thêm trường không phá vỡ”: điều này chỉ đúng nếu client thật sự bỏ qua trường lạ, và nhiều client thì không — bộ giải mã nghiêm ngặt sẽ ném lỗi. Vì thế nên ghi rõ trong tài liệu rằng client PHẢI chấp nhận trường chưa biết, và tốt hơn nữa là kiểm chứng điều đó bằng test tương thích chứ không chỉ bằng lời hứa.
Câu hỏi tiếp theo họ sẽ hỏi
?Làm sao biết ai còn dùng v1 để tắt được?
Đo theo client id chứ không chỉ theo lưu lượng: bao nhiêu tài khoản, đường nào, và lần cuối gọi là khi nào. Rồi thông báo, đặt hạn, và làm brownout — tắt v1 vài phút vào giờ thấp điểm để những client còn sót phát hiện ra trước ngày tắt thật.
?GraphQL giải quyết phiên bản thế nào?
Nó thay phiên bản bằng đánh dấu @deprecated cho từng trường: schema tiến hoá liên tục, trường cũ ở lại và bạn theo dõi ai còn dùng. Nghe hay hơn, nhưng đổi lại schema chỉ lớn dần và việc xoá trường vẫn cần chính xác quy trình đo–thông báo–tắt như trên.
Trả lời thế này là mất điểm
- Lên v2 vì một thay đổi nhỏ. Mỗi phiên bản là một gánh nặng bảo trì dài hạn, không phải một nhãn.
- Không có kế hoạch khai tử. Phiên bản nào cũng cần biết trước mình sẽ chết thế nào.