Go言語に新たに導入されたProtocol Buffersのバインディングは、Protocol Bufferの型システムをGoの型システムに統合して、実行時に操作可能にするためのものだ。Protocol Buffersは、ハイパフォーマンスアプリケーションにおけるJSONの代替を目的にGoogleが開発した、言語ニュートラルなデータ交換フォーマットである。
Protocol Buffersは、構造データの転送に使用されるスキーマの指定手段を提供する。このスキーマは一般的に、バインディング(binding)と呼ばれる言語固有の表現に変換されることで、より高レベルなインターフェースを使用したprotobufメッセージの操作を容易なものにしている。
新しいprotobuf
モジュールバージョンの作者であるJoe Tsai、Damien Neil、Heibie Ong氏らは、これまでのprotobuf
実装ではGo開発者の期待に応えることができないという。具体的には、リッチとは言えないGoの型システムにマップすることで、protobuf型システムのビューに制限が生じるのだ。
この結果として、例えば、Goの型システムに含まれないprotobufアノテーションが失われて、メッセージログや全機密情報の削除といった処理が不可能になる可能性があるのだ。
旧protobuf
モジュールのもうひとつの制限は静的バインディングへの依存性だ。これは、コンパイル時には完全に分からないような、動的メッセージを使う場合に障害となる。
APIv2とバージョニングされた新しいprotobuf
モジュールの開発者たちが採用したアプローチでは、protobuf
Message
はメッセージの振る舞いをすべて指定しなければならないという仮定と、リフレクションを使用して提供するprotobuf型の完全なビューに依存している。Go protobuf APIv2の基礎となっているのが、生成されるメッセージタイプすべてに共通なインターフェースとしてメッセージコンテントへのアクセス手段を提供する、新しいproto.Message
インターフェースである。このインターフェースには任意のprotobufフィールドが含むことが可能で、protoreflect.Message.Range
メソッドを使ったイテレーションを行うことができる。このアプローチにより、動的メッセージを使用した処理と、メッセージオプションへのアクセスが可能になる。以下に示すのは、事前処理として、メッセージに含まれるすべての機密情報をクリアする方法の例である。
// Redact clears every sensitive field in pb.
func Redact(pb proto.Message) {
m := pb.ProtoReflect()
m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
opts := fd.Options().(*descriptorpb.FieldOptions)
if proto.GetExtension(opts, policypb.E_NonSensitive).(bool) {
return true
}
m.Clear(fd)
return true
})
}
Go protobuf APIv2のバージョニングは、Hacker Newsのコメントでも指摘されているように、分かりにくい構造である。。事実として、寄贈のリポジトリを新バージョンで拡張してv2
のタグを付けるのではなく、特定のリポジトリに新バージョンを結び付ける方法を開発者たちは選択したのだ。このような決定を下した理由について、Damien Neil氏は次のように説明している。
新APIをv2とタグ付けした場合、
importパス内での"v1"と"v2"の区別が非常に明確になる。
google.golang.org/protobuf@v1は存在しないが、v2が存在するという混乱がある。
10年もたてば、古いgithub.com/golang/protobufを気にする人がいなくなって、混乱は解決するかも知れない。
新APIをv1とタグ付けした場合、
importパス上の視覚的な区別は失われる。
google.golang.org/protobufの最初のバージョンがv1となるため、理にかなっている。
よくないアイデアだと判断された場合、v2をv1にロールバックするよりも、v1をv2に変更するほうが容易である。
さらに、Go protobuf APIv2はバージョン1.20から開始されている。これはNeil氏が述べているように、Go protobuf APIv1はバージョン1.20まで進まないだろうという予想に基いて、オーバーラップしたバージョンに対してバグが報告される曖昧さを回避するための方策である。
最後に注意する点として、APIv2によってAPIv1が廃止されることはなく、メンテナンスも永遠に行われる。それを証明するものとして、最新の実装であるバージョン1.4は、実際にはAPIv2上に実装されている。