Versioning & Evolution
API ของคุณจะอยู่นานกว่ารูปแบบแรก
หัวข้อที่มีชื่อว่า “API ของคุณจะอยู่นานกว่ารูปแบบแรก”โมดูล protobuf แสดงให้เห็นว่า wire format ทนการเปลี่ยนแปลงได้อย่างไร — field number ไม่ใช่ name เป็นตัวระบุข้อมูล บทเรียนนี้พูดถึงวินัยที่เปลี่ยนความทนระดับล่างนั้นให้กลายเป็น versioning strategy จริงที่ caller พึ่งพาได้
กฎทอง: client เก่ากับ server ใหม่ต้องยังทำงานได้ และ client ใหม่กับ server เก่าต้องยังทำงานได้ ทุกอย่างข้างล่างนี้เพื่อเป้าหมายนั้น
version อยู่ใน package
หัวข้อที่มีชื่อว่า “version อยู่ใน package”convention คือใส่ major version ไว้ใน protobuf package (และใน path ของไฟล์):
package user.v1; // user/v1/user.protoเมื่อต้องเปลี่ยนแบบ incompatible คุณไม่แก้ v1 แต่สร้าง user.v2 ขึ้นมาคู่กัน code ที่ generate ลงคนละ namespace ทำให้ v1 กับ v2 รันใน server เดียวกันพร้อมกันได้ และ caller ค่อย migrate ตามตารางของตัวเอง
additive vs breaking
หัวข้อที่มีชื่อว่า “additive vs breaking”การเปลี่ยนส่วนใหญ่ควรเป็นแบบ additive — ปลอดภัยเพราะ wire format ไม่สนสิ่งที่ไม่รู้จัก:
| ปลอดภัย (additive) | breaking (ต้องขึ้น version ใหม่) |
|---|---|
| เพิ่ม field ใหม่ด้วย number ใหม่ | เปลี่ยน number ของ field |
| เพิ่ม method ใหม่เข้า service | เปลี่ยน type ของ field |
| เพิ่ม enum value ใหม่ (ปกติ) | rename/reuse number ของ field ที่ลบไปแล้ว |
| เพิ่ม message ใหม่ | ลบ field ที่ยังใช้อยู่ |
| rename package, service หรือ method |
flowchart TB v1["user.v1"] -->|add field #7, add method| v1b["user.v1 (still compatible)"] v1 -->|change field type, remove field| v2["user.v2 (new package, runs alongside v1)"] client1["old client"] --> v1b client2["new client"] --> v2
reserve สิ่งที่เลิกใช้
หัวข้อที่มีชื่อว่า “reserve สิ่งที่เลิกใช้”เมื่อคุณลบ field จริง ๆ อย่าให้ number (หรือ name) ของตัวเองถูก reuse — field ในอนาคตที่ใช้ number เดิมจะอ่านข้อมูลเก่าผิดแบบเงียบ ๆ ให้ mark เป็น reserved:
message User { reserved 4, 7; reserved "phone_number"; int64 id = 1; string name = 2;}นี่คือ guardrail ระดับ schema ที่อยู่เบื้องหลังกฎ field number: compiler จะปฏิเสธการเอา 4, 7 หรือ phone_number ไปใช้ซ้ำ
ให้เครื่องมือบังคับใช้
หัวข้อที่มีชื่อว่า “ให้เครื่องมือบังคับใช้”คนพลาดการมองเห็น breaking change ตอน review buf breaking เทียบ .proto ของคุณกับ baseline (version ที่ release ล่าสุด, git ref หรือ registry) แล้วทำให้ CI fail ถ้า change ไหนจะทำลาย wire หรือ generated code:
buf breaking --against '.git#branch=main'การต่อสิ่งนี้เข้า CI เปลี่ยน “ช่วยจำกฎ compatibility ทั้งหมดด้วยนะ” ให้กลายเป็นด่านอัตโนมัติ — นิสัยที่ให้ leverage สูงสุดสำหรับ schema ที่หลายทีมพึ่งพา