🐱 うさねこ教室 Python と可観測性の教室

エンコーディングとスキーマ進化

🐱 この章の目次

エンコーディング形式の比較

データをネットワーク越しに送信したりディスクに保存したりするには、メモリ上のオブジェクトをバイト列に変換するエンコーディング(シリアライゼーション) が必要です。 『データ指向アプリケーションデザイン』第 4 章では、代表的な形式の特性を比較しています。

形式スキーマ人間可読サイズスキーマ進化
JSON暗黙的(任意構造)大きいフィールド追加は容易
Protocol Buffers明示的(.proto)×小さいフィールド番号で互換性管理
Avro明示的(.avsc)×最小ライター/リーダースキーマの照合

JSON は手軽ですが、型情報が乏しく、数値の精度問題(整数が浮動小数点に丸められる)もあります。 バイナリ形式はサイズ効率と型安全性に優れ、大規模システムで好まれます。

スキーマ進化と互換性

システムが稼働し続ける限り、スキーマは変化します。 安全にスキーマを変更するためには、後方互換性(backward compatibility)前方互換性(forward compatibility) の両方を意識する必要があります。

  • 後方互換性: 新しいコードが古いデータを読める
  • 前方互換性: 古いコードが新しいデータを読める
// Protocol Buffers でのスキーマ進化例
syntax = "proto3";

message UserEvent {
  string user_id = 1;
  string event_type = 2;
  int64 timestamp_ms = 3;

  // v2 で追加: 古いリーダーは未知フィールドとして無視する(前方互換性)
  string source_ip = 4;

  // v3 で追加: デフォルト値があるため古いデータでも読める(後方互換性)
  int32 priority = 5;
}

フィールド番号を再利用しない、required フィールドを後から追加しないといったルールを守ることが互換性維持の鍵です。

API バージョニングとの関係

Part 2(API 設計)で学んだバージョニング戦略は、エンコーディングの互換性と密接に関係します。 REST API で JSON を使う場合、レスポンスに新しいフィールドを追加しても古いクライアントが壊れないようにする設計は、まさに前方互換性の実践です。 gRPC のように Protocol Buffers を使う場合は、.proto ファイルのフィールド番号規則がそのまま API の互換性ルールになります。

データフローのパターン

データが異なるプロセス間を流れる経路は、大きく 3 つに分類できます。

パターン互換性の考慮点
データベース経由書き込みプロセスと読み取りプロセスが異なるバージョン古い行を新しいコードが読む(後方互換性)
サービス経由(REST / RPC)マイクロサービス間の API 呼び出しクライアントとサーバーが独立デプロイ
メッセージ経由Kafka、RabbitMQ などのメッセージブローカープロデューサーとコンシューマーが独立デプロイ

いずれのパターンでも、送信側と受信側が異なるバージョンのスキーマで動く可能性を前提に設計します。 エンコーディング形式の選択は、このデータフロー全体の進化戦略を決定づける重要な設計判断です。