Nguyên tắc: thay đổi tương thích ngược thì không cần version mới; thay đổi phá vỡ thì phải chạy song song hai phiên bản một thời gian.
Thay đổi an toàn (thêm, không bỏ): thêm trường mới, thêm giá trị enum có xử lý mặc định, thêm endpoint. Điều kiện là consumer viết theo kiểu tolerant reader — chỉ đọc trường mình cần, bỏ qua trường lạ thay vì fail khi gặp field không biết. Nếu consumer dùng deserializer strict (lỗi khi có field thừa), thì việc thêm trường cũng thành breaking change. Đây là thứ phải thống nhất từ đầu.
Thay đổi phá vỡ: bỏ/đổi tên trường, đổi kiểu dữ liệu, đổi ngữ nghĩa (amount từ đồng sang xu), siết validation. Quy trình:
1. Expand — thêm cái mới, giữ nguyên cái cũ, ghi cả hai (total và total_cents).
2. Publish v2 (/v2/orders hoặc header version), thông báo lịch ngừng hỗ trợ.
3. Theo dõi metric theo phiên bản để biết ai còn dùng v1 — không dựa vào trí nhớ.
4. Contract — khi lưu lượng v1 về 0 mới xoá.
Điểm hay bị hỏi thêm: deploy không bao giờ đồng thời, nên trong lúc rollout luôn có phiên bản cũ và mới chạy cùng lúc → mọi thay đổi phải sống được ở trạng thái trộn. Với event/message cũng vậy: schema event là hợp đồng công khai, dùng schema registry và quy tắc tương thích thay vì sửa tại chỗ.