active: true
derived: false
groups:
- SERIAL
header: |
  プロトコルベースのシリアライザ登録
level: 1.24
links:
- ARCH005: f7IpeWL9LR7SQ3LP4FNILP4SUho1yMVkYhHP8_dKm8Y=
- REQ005: iMDbh51FT-Eu8XByvRDwGCzvXD7iYGh6c5AwH9v0RxA=
normative: true
ref: ''
reviewed: MppsiJ-qy9YDdeVsn5KS2LjzysxXS5mnkXXuc5WeDL4=
status: accepted
text: |
  # プロトコルベースのシリアライザ登録

  ## コンテキストと課題

  `beautyspot` では、`@spot.register` デコレータを使用してカスタム型を登録できます。
  当初の実装では、`Spot` クラス内でシリアライザが `MsgpackSerializer` のインスタンスであるかどうかを明示的にチェックしていました。

  ```python
  if isinstance(self.serializer, MsgpackSerializer):
      self.serializer.register(...)
  ```

  これは、高レベルの `Spot` クラスを特定の具象クラス (`MsgpackSerializer`) に結合させており、依存関係逆転の原則 (Dependency Inversion Principle) に違反していました。その結果、カスタム型登録をサポートする他のシリアライザ（将来的な `JsonSerializer` やカスタムラッパーなど）を使用することが不可能でした。

  ## 判断基準

  * **Decoupling**: `Spot` クラスを特定のライブラリ（`msgpack`）や実装から切り離すこと。
  * **Extensibility**: ユーザーが独自のシリアライザを実装し、かつカスタム型登録機能も維持できるようにすること。
  * **Interface Segregation**: 基本的なシリアライズ機能と、型登録機能という異なる責務を明確に分離すること。

  ## 検討した選択肢

  * **Option 1**: 具象クラスに対する `isinstance` チェックを維持する。
  * **Option 2**: 構造的部分型（Protocol）を導入し、インターフェースに基づくチェックに切り替える。

  ## 決定事項

  採用した選択肢: **Option 2**.

  `beautyspot.serializer` に **`TypeRegistryProtocol`** を導入します。

  1. **Define Protocol**: 型登録に必要な `register` メソッドのシグネチャを規定するプロトコルを定義します。
  2. **Decoupling**: `Spot` クラスは、具象クラスではなくこのプロトコルに対して適合性チェックを行うように変更します。
  3. **Interface Segregation**: 基本的な `SerializerProtocol` (dump/load) と `TypeRegistryProtocol` を分離し、型登録をサポートしないシリアライザも許容できるようにします。

  ## 影響・結果

  * **ポジティブ**:
      * コアロジックが `msgpack` から解放され、`TypeRegistryProtocol` に従う任意のシリアライザを使用可能になった。
      * モックを使用したテストが容易になった。
  * **ネガティブ**:
      * シリアライザの実装者は、プロトコルで定義された `register` メソッドのシグネチャを正確に遵守する必要がある。
