Protocol Buffer地獄からの脱出:「暗号化じゃないよ!」と叫んだ3週間の戦い

「Protocol Bufferって暗号化でしょ?」という誤解から始まった、バイナリエンコーディングの真実を探る血と汗の調査記録。gRPCとtRPCの選択で3週間悩んだ実体験談。

Protocol Buffer地獄からの脱出:「暗号化じゃないよ!」と叫んだ3週間の戦い

「えっ、これ暗号化じゃないの?」- 最初の誤解

新しいマイクロサービスプロジェクトが始まった時、チームリーダーから「Protocol Buffer使ってgRPCで行こう」と言われて、内心「やばい、暗号化技術なんて分からない…」と青ざめました。

最初の大誤解:「Protocol Buffer = 暗号化技術」

実際にProtocol Bufferのバイナリデータを見たとき:

1
0A 05 41 6C 69 63 65 10 1A

「うわ、完全に暗号化されてる!これ解読できるの?」

そんな私の3週間に渡る調査と失敗の記録をお話しします。

第1週:「なぜJSONが9バイトになるんだ!?」事件

失敗体験:最初の衝撃

プロジェクト開始2日目。先輩が「Protocol BufferってJSONより3倍効率いいよ」と言うので、実際に試してみました。

元データ(JSON):

1
{"name": "Alice", "age": 26}

サイズ: 26バイト

Protocol Bufferバイナリ:

1
0A 05 41 6C 69 63 65 10 1A

サイズ: 9バイト

「マジで?本当に3分の1?でも、これ何語?宇宙人の文字?」

調査開始:バイナリの謎を解く

完全にパニックになった私は、深夜まで調査開始。

最初の失敗:Googleで「Protocol Buffer 暗号化」で検索 → 見つからない、というかそもそも暗号化じゃない

次の失敗:バイナリエディタで開いて眺める → 「41 6C 69 63 65って何?ASCII?でも0A 05って何?」

ついに発見:ASCIIコード表を引いてみる

  • 41 = 65 = ‘A’
  • 6C = 108 = ’l'
  • 69 = 105 = ‘i’
  • 63 = 99 = ‘c’
  • 65 = 101 = ’e'

「あ!“Alice"だ!暗号化じゃなくて、ただのエンコーディングじゃん!」

第2週:「フィールド番号システム」の衝撃的発見

失敗体験:.protoファイルの謎

1
2
3
4
5
message User {
  int64 id = 1;      // この「= 1」って何?
  string name = 2;   // 「= 2」も?初期値?
  int32 age = 3;     // 「= 3」も?
}

「え?idのデフォルトが1で、nameのデフォルトが2?意味不明…」

真実の発見:衝撃的な事実

3日間悩んだ末、公式ドキュメントを読んで愕然。

衝撃の事実

  • フィールド名は送信されない!
  • フィールド番号だけが送信される!
  • = 2は初期値じゃなくて識別番号!
1
2
3
4
5
0A 05 41 6C 69 63 65 10 1A
0A 05: フィールド2(name)、長さ5
41 6C 69 63 65: "Alice"
10 1A: フィールド3(age)= 26

「フィールド名送らないから小さいのか!天才的じゃん!」

実証実験:本当に3倍効率的?

JSON vs Protocol Buffer 対決

データ JSON Protocol Buffer 効率化
単純データ 26バイト 9バイト 2.9倍
ユーザー配列100件 2,600バイト 900バイト 2.9倍
複雑なオブジェクト 1,200バイト 420バイト 2.9倍

「本当だ…どのデータでも約3倍効率的!」

第3週:「gRPCとtRPC、結局どっち?」地獄の選択

失敗体験:RPC技術選択の迷宮

プロジェクトも佳境に入り、「結局、gRPCとtRPCどっち使うの?」問題が勃発。

最初の浅い理解

  • gRPC = 古い技術?
  • tRPC = 新しい技術だから良い?

実際に両方試してみた結果

gRPC実装体験:「なんで型安全じゃないの?」

1
2
3
4
5
6
7
8
// gRPCクライアント
const client = new UserServiceClient('localhost:50051');
const request = new GetUserRequest();
request.setId(123);

client.getUser(request, (err, response) => {
  // response.getName() ← これ、型チェックされない!
});

「え?TypeScriptなのに型安全じゃない?何のためのgRPC?」

tRPC実装体験:「これは快適すぎる…」

1
2
3
// tRPCクライアント
const user = await trpc.getUser.query({id: 123});
// ↑ 完全に型安全!IDEで補完も効く!

「これはやばい…開発体験が天と地の差!」

現実の壁:「でも、マイクロサービス間通信は?」

tRPCの罠に気づいたのは実装後。

tRPCの制限発見

  • TypeScript専用(他言語との連携不可)
  • サーバー間通信でJSONを使う = データ転送量が大きい
  • Protocol Bufferの恩恵を受けられない

「あー、マイクロサービスでGoやPythonも使うのに…」

最終決戦:技術選択の真実

血と汗の比較表

3週間の調査結果をまとめた、私の血と汗の結晶:

技術 データ形式 転送効率 開発体験 多言語対応 学習コスト 適用場面
gRPC Protocol Buffer ⭐⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐ マイクロサービス間
tRPC JSON ⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ フロント↔バック(TS統一環境)
REST JSON ⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ 汎用Web API

最終判断:「適材適所」の重要性

プロジェクトでの最終選択

  • マイクロサービス間通信: gRPC + Protocol Buffer
    • 理由:転送効率とパフォーマンスを最重視
  • フロントエンド↔API: tRPC
    • 理由:開発体験とタイプセーフティを最重視

「結局、銀の弾丸はないんだ…」

学んだこと:3週間の格闘から得た教訓

教訓1:「暗号化」vs「エンコーディング」

最大の誤解:Protocol Bufferを暗号化技術だと思っていた 真実:ただの効率的なバイナリエンコーディング技術

違いを理解

  • 暗号化:セキュリティ目的、復号化キーが必要
  • エンコーディング:効率化目的、ルールさえ分かれば復号可能

教訓2:「新しい = 良い」の罠

最初の思考:tRPCは新しいから良いはず 現実:用途によっては古いgRPCの方が適している

技術選択の真理

  • 要件を明確にする
  • トレードオフを理解する
  • 適材適所で選択する

教訓3:バイナリエンコーディングの威力

Protocol Bufferの真の価値

  • フィールド名を送らない = データサイズ削減
  • 型情報をスキーマで管理 = 型安全性
  • 多言語対応 = エコシステムの広さ

実測データ

1
2
3
4
5
6
7
通常のREST API:1回あたり2.6KB
gRPCでの同じデータ:1回あたり0.9KB

月間100万リクエスト時:
- REST: 2.6GB
- gRPC: 0.9GB
- 削減効果: 1.7GB(65%削減)

まとめ:「Protocol Bufferは暗号化じゃない」という当たり前の結論

3週間の格闘を通して学んだことは:

  1. Protocol Bufferは暗号化技術ではない(当たり前だった…)
  2. バイナリエンコーディングは本当に効率的(実測で証明)
  3. RPC技術は適材適所(銀の弾丸はない)
  4. 読める技術記事より、実際に手を動かす方が理解が深まる

最初の「Protocol Bufferって暗号化でしょ?」という誤解から始まった調査でしたが、結果として現代のRPC技術の全貌を理解することができました。

次に同じような技術調査をする時は

  • 公式ドキュメントを最初に読む
  • 実際にコードを書いて試す
  • 思い込みを疑う
  • 複数の技術を比較して理解する

「Protocol Bufferって暗号化?」と聞かれたら、今度は自信を持って「違うよ!効率的なバイナリエンコーディングだよ!」と答えられます。

皆さんも新しい技術に出会ったら、恐れずに手を動かして調査してみてください。きっと予想以上の発見があるはずです。

技術ネタ、趣味や備忘録などを書いているブログです
Hugo で構築されています。
テーマ StackJimmy によって設計されています。