Proto 필드 번호 관리 규칙
와이어 형식은 필드를 번호로만 식별하므로, 한번 사용한 번호는 변경하거나 재사용하지 않고 reserved로 차단한다.
필드 번호의 역할
protobuf의 와이어 형식(wire format, 직렬화된 바이트)에는 필드 이름과 선언 타입이 포함되지 않는다. 각 값 앞에는 필드 번호와 와이어 타입을 결합한 tag만 붙는다. 수신 측은 자신의 .proto에서 해당 번호를 찾아 값을 해석하므로, 이름은 변경할 수 있으나 한번 사용한 번호는 변경할 수 없다.
번호·타입 변경의 영향
| 변경 내용 | 결과 |
|---|---|
| 번호 변경 | 필드를 삭제하고 새 필드를 추가한 것과 같다. 이전 버전 프로그램은 그 값을 읽지 못한다. |
| 삭제한 번호 재사용 | 이전 정의로 기록한 값을 새 정의로 읽는다. 파싱 오류가 발생하면 문제를 감지할 수 있으나, 오류 없이 값이 잘못 해석될 수도 있다. |
| 타입 변경 | 번호를 재사용한 경우와 같은 문제가 발생한다. int32·int64·uint32·uint64·bool처럼 서로 호환되는 타입 집합 내의 변경만 예외이다. |
삭제 필드의 reserved 지정
필드를 삭제할 때는 해당 번호를 reserved에 등록한다. 등록된 번호를 재사용하면 protoc가 오류로 처리한다. JSON에는 필드 이름이 포함되므로 이름도 함께 등록한다.
syntax = "proto3";
message DeviceStatus {
// 지운 필드의 번호와 이름을 막아 둔다
reserved 3, 6 to 8;
reserved "battery", "error_text";
string device_id = 1;
double speed = 2;
// 새 필드는 쓴 적 없는 번호를 받는다
uint32 battery_percent = 9;
}
번호와 이름은 한 reserved 줄에 혼용할 수 없다.
번호 선택 기준
1~15: tag가 한 바이트이므로 자주 설정되는 필드에 할당한다.16~2047은 두 바이트이다.19000~19999: protobuf 구현이 사용하는 번호이므로 사용할 수 없다.- 새 필드: 항상 새 번호를 할당한다. 이전 버전 프로그램은 알지 못하는 번호를 무시한다.