필드 번호를 바꿨더니 옛 클라이언트가 조용히 틀린 값을 읽었다 · 계약 검사는 리뷰어가 아니라 스크립트가 한다 · 실습
계약 검사기를 만든다
목표
두 .proto 를 비교해 와이어 호환성 위반을 한 줄씩 출력하는 protocheck.py 를
만듭니다. 규칙을 하나씩 더해 가며 픽스처 8쌍과 채점기가 숨겨 둔 쌍을 통과시키고,
마지막에는 디렉터리 단위로 돌리는 check-all.sh 를 만들어 CI 에 넣을 수 있는
형태로 마무리합니다.
왜 중요한가
앞 실습에서 번호 하나를 바꾸면 옛 클라이언트가 오류 없이 틀린 값을 읽는 것을
봤습니다. 그 변경은 코드 리뷰에서 눈에 잘 띄지 않습니다 — diff 에는 숫자 두 개가
바뀐 것뿐이고, 컴파일도 테스트도 통과합니다. 사람이 매번 잡아낼 수 있는 종류의
실수가 아닙니다. 그래서 계약 검사는 리뷰어가 아니라 스크립트가 해야 합니다.
검사기의 규칙은 전부 공식 문서의 "안전한 변경·안전하지 않은 변경" 목록에서
나오며, 여러분이 만드는 것은 그 목록을 기계가 읽게 옮긴 것입니다.
단계
1. /root/grpc/compat/protocheck.py 를 만들고 python3 protocheck.py --dump <file.proto> 가 메시지별 필드를 <메시지> <번호> <타입> <이름> 으로, 예약을 <메시지> reserved <번호> 와 <메시지> reserved "<이름>" 으로 한 줄씩 출력하게 하세요. 주석(//, /* */)·공백·옵션([deprecated=true])은 무시하고, 9 to 11 은 세 번호로 펴고, 중첩 메시지는 Outer.Inner 로 부릅니다.
2. python3 protocheck.py <old.proto> <new.proto> 에 첫 규칙을 넣으세요 — 옛 번호가 새 파일에 없고 reserved 도 아니면 REMOVED_NOT_RESERVED <메시지>.<이름>=<번호>. 위반이 있으면 exit 1, 없으면 마지막 줄에 OK 를 찍고 exit 0.
3. 같은 이름이 다른 번호로 옮겨 갔으면 RENUMBERED <메시지>.<이름> <옛번호>-><새번호>.
4. 같은 번호·같은 이름에 타입이 다르면 TYPE_CHANGED <메시지>.<이름>=<번호> <옛타입>-><새타입>, 같은 번호에 이름도 타입도 다르면 NUMBER_REUSED <메시지>#<번호> <옛이름>:<옛타입>-><새이름>:<새타입>.
5. 옛 파일이 reserved 한 번호(범위 포함)를 새 파일이 필드로 쓰면 REUSED_RESERVED <메시지>#<번호> <이름>.
6. 같은 번호·같은 타입에 이름만 다르면 WARN RENAMED <메시지>#<번호> <옛이름>-><새이름> 을 찍되 exit 코드에는 영향을 주지 마세요(경고만 있으면 OK · exit 0).
7. /opt/app/grpc/compat/ 의 8쌍을 모두 돌려 /root/grpc/compat/07-report.txt 에 <case> OK 또는 <case> FAIL 을 한 줄씩 적으세요.
8. /root/grpc/compat/check-all.sh <디렉터리> 를 쓰세요 — 그 아래 old.proto 와 new.proto 가 있는 하위 디렉터리마다 검사기를 돌려 <case>: OK / <case>: FAIL 을 찍고, FAIL 이 하나라도 있으면 exit 1.
참고
- 규칙의 원본: [proto3 — 메시지 타입 갱신](https://protobuf.dev/programming-guides/proto3/#updating), [Proto 모범 사례](https://protobuf.dev/best-practices/dos-donts/).
- 픽스처:
safe_addremove_no_reservedrenumbertype_changereuse_reservedrename_onlynestedsafe_reserved. 각 디렉터리의new.proto주석에 무엇을 바꿨는지 적혀 있습니다. - 채점기는 픽스처 말고도 지시문에 없는 .proto 쌍을 임시로 만들어 여러분의 스크립트에 넣습니다. 픽스처 이름이나 결과를 박아 두면 그 자리에서 떨어집니다. 판정은 종료 코드와 출력만으로 합니다.
- 규칙의 우선순위: 이름이 새 파일 어딘가에 다른 번호로 있으면 RENUMBERED 로 보고하고 그 번호는 더 보지 않습니다. 번호가 새 파일에 남아 있으면 REMOVED 가 아닙니다.
- 파서는 앞 실습의 채점기처럼 관대해야 합니다 —
syntax = "proto3" ;도 읽혀야 합니다.
단계 8개
- .proto 를 읽는 파서를 만든다
- 예약 없이 지운 번호를 잡는다
- 번호가 옮겨 간 것을 잡는다
- 타입 변경과 번호 재사용을 잡는다
- 예약된 번호를 꺼내 쓴 것을 잡는다
- 이름 변경은 경고만
- 픽스처 8쌍을 전부 돌린다
- 디렉터리 단위 검사 스크립트