やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

Protocol Buffers 環境構築 buf

データ構造を定義する最高の環境を整える。

成果物

Protocol Buffers

Protocol Buffersは構造化データのシリアライゼーション形式。

  • XML,JSON,YAMLよりデータサイズが小さく解析も高速
  • プログラミング言語に依存しない
  • 後方互換を保ちながらフィールド変更できる

ようするにJSON Schemaよりも良い感じのデータ構造体系。

インストール

まずはgo言語をインストールする。以下が便利。

完了したら以下でbufをインストールする。

go install github.com/bufbuild/buf/cmd/buf@latest

かなり時間かかった。

バージョン確認

$ buf --version
1.72.0

使ってみる

型定義する.protoを書いて.jsonを生成してみる。

  1. プロジェクト作成
  2. パッケージ作成
  3. .proto作成
  4. 入力用.yaml作成
  5. .json出力

1. プロジェクト作成

DIR=buf-demo
mkdir $DIR
cd $DIR
buf config init

2. パッケージ作成

PKG=demo/v1
mkdir -p $PKG
cd $PKG

3. .proto作成

vim $PKG/master.proto

./demo/v1/master.proto

syntax = "proto3";
package demo.v1;

message Master {
  repeated Human humans = 1;
  repeated Item items = 2;
}
message Human {
  optional string name = 1;
  optional int32 age = 2;
  optional bool male = 3;
  repeated int32 items = 4;
}
message ItemList {
  repeated Item items = 1;
}
message Item {
  optional int32 id = 1;
  optional string name = 2;
}

クソ仕様による破綻

buf 1.72.0 の場合、空配列は必ずプロパティごと削除される。

これは仕様である。回避不能。以下のようなゴミ仕様が重なった結果。

  • buf 1.72.0 の場合、buf convert --to=#emit-defaultsのようなコマンド引数がない!
  • optionalを付与しないと初期値の時にプロパティごと消される?!(クソ仕様)
  • repeatedoptionalは併用できない
  • repeatedが初期値[]の時はプロパティごと消される?!(不可避)

そもそもoptionalという任意を意味する語をつけることで初期値の時にプロパティ削除されることを防ぐ、という仕様が意味不明。普通optionalが付与されたほうこそ削除されるべきなのに。表記と機能が反対の意味になっている。クソ仕様すぎて反吐が出る。

バカなの?

buf lint: 構文確認

buf lint

構文エラーがないか確認する。

buf format: 書式修正

buf format -w

インデントやスペースなどを調整し.protoを上書きする。

4. 入力用.yaml作成

input.yaml

humans:
  - {name: '山田', age: 12, male: false, items: [0,1,2]}
  - {name: '鈴木', age: 24, male: true, items: []}
items:
  - {id:0, name: 'おにぎり'}
  - {id:1, name: '木刀'}
  - {id:2, name: 'ラズパイ'}
  - {id:3, name: '鏡'}

5. .json出力

$ buf convert ./demo/v1/human.proto   --type=demo.v1.Master   --from=input.yaml   --to=output.json

出力されたJSONの内容を整形して出す。

$ jq . output.json -M
{
  "humans": [
    {
      "name": "山田",
      "age": 12,
      "male": false,
      "items": [
        0,
        1,
        2
      ]
    },
    {
      "name": "鈴木",
      "age": 24,
      "male": true
    }
  ],
  "items": [
    {
      "id": 0,
      "name": "おにぎり"
    },
    {
      "id": 1,
      "name": "木刀"
    },
    {
      "id": 2,
      "name": "ラズパイ"
    },
    {
      "id": 3,
      "name": ""
    }
  ]
}

鈴木からitemsプロパティが消えた?!

空でも出してくれないと利用時に型相違でバグるから空配列を出して欲しいんだが。だからわざわざYAMLで[]と記述したんだが。

しかし、これがbufの、ひいてはProtocolBufferの仕様だ。

これがあの天下のGoogleが作った、データ・シリアライゼーション・フレームワーク業界のデファクトスタンダードであるProtocolBufferだと?!

嘘だろ?

所感

これはひどい。もう使いたくない。

  • = 1とかいう無意味な代入の必須
  • optionalとかいう意味が反対の語を記述しないと初期値の時にプロパティごと消える
  • repeatedoptionalは併用できない仕様により空配列は必ずプロパティごと消える

終わってるよProtocolBuffer。どうしたらそんな汚い構文体系が作れるんだい? 流石Go言語の産みの親。もう二度と使いたくない。こんなのが業界のデファクトスタンダードってマジ?

私が何か間違っているのでは? gRPCな用途じゃないからダメなのか? でもこういう用途でも使える奴なんでしょ? いざ出力したら破綻したんですけど。なんでプロパティ消えるんだよ。アホちゃうか。

なんか他のをインストールしたらいいとか言われてやったら訳わからないコード出されて、それを確認するための動作コードが動かないし。

ダメだこりゃ。多分gRPCでならいい感じの仕様なのだろうけど。それ以外で使うと破綻する。じゃあ要らないわ。

bufのコマンドは超便利なんだけどなぁ。lintformatconvertとか。でも大本の.proto構文がデータを構造化できない言語仕様なのだから台無し。もったいない。

結論。情弱な私には難しすぎた。