web-dev-qa-db-ja.com

APIの変更に対する下位互換性を処理する

デバイスとの通信を可能にするAPIを持っています。通信プロトコルはJSONファイルに保存されます。デバイスが発生させることができるイベント、機能、フレーム形式などをリストします。

しかし、このJSONファイルは頻繁に変更されるため、APIをすべてのJSONファイルと下位互換性を保つ必要があります。

私はいくつかの解決策を想像しました(私はPythonを使用しています):

  1. 私の関数(@ api_1、@ api_2 ...)でデコレータを使用しますが、api 5以上に到達すると重すぎます

  2. APIの変更ごとにフォルダーを作成する

    1. /API
      1. API_1
        1. frame_translation.py ...
      2. API_2
        1. frame_translation.py ...
  3. 戦略パターン?

2番目の解決策は、最初の解決策よりも優れているようですが、おそらく最善ではありません。

どうしますか?

1
PyNico

これは セマンティックバージョニング のバリエーションです(これもお読みください):

  1. メジャー番号とマイナー番号を別々にして、APIのバージョン番号を確立します。これを明示的にJSONファイルに含め、(可能であれば)プロトコルハンドシェイクに含めます。バージョン1.0(major.minor)から始めます。
  2. 下位互換性のあるAPIを変更する場合は、マイナー番号を増やします。
  3. 下位互換性のないAPIの変更を行う場合は、メジャー番号を増分し、マイナー番号を0にリセットします。
  4. 接続を確立するときに、メジャー番号が一致しない場合、ハンドシェイクに失敗するか、可能であれば古いバージョンのコードにフォールバックします。
  5. 下位互換性のない変更を軽く(またはまったく)行わないでください。

APIの詳細はわかりませんが、下位互換性のある変更の例をいくつか示します。

  • 新しいメッセージタイプの紹介。*
  • 既存のメッセージにオプションのフィールドを追加します。デフォルトの動作(フィールドが指定されていない場合)は、以前の動作と同じです。
  • 前提条件を弱める。
  • 事後条件の強化。
  • メッセージタイプを削除または変更せずに、非推奨としてマークします。

次に、互換性のない変更の例をいくつか示します。

  • メッセージタイプの削除。
  • メッセージタイプからフィールドを削除する。
  • メッセージタイプに必須フィールドを追加します。
  • APIの反対側が合理的に気付くような方法でメッセージの動作を変更する(たとえば、キャッシングレイヤーを導入しても問題ありませんが、異なる結果を返すことはできません)。
  • 前提条件を強化する。
  • 事後条件を弱める。

技術的には、マイナー番号はまったく必要ありません。この情報を追跡するために、バージョン管理に頼ることができます。ただし、バージョン番号はコミットハッシュよりもユーザーフレンドリーであり、マイナー番号を使用して機能の検出を行うことができます。

後方互換性を壊さないのであれば、メジャー番号も必要ありません。ただし、重大な変更を行う必要がある場合に備えて、これを用意することをお勧めします。このような変更はまれです。

一方、APIがまだ公開されておらず、下位互換性の影響を受ける可能性のあるクライアントコードがない場合は、メジャー番号を1ではなく0から開始して、APIが暫定的であることを示すことができます。次に、メジャー番号を変更せずに、下位互換性のない変更を加えることができます。「ゴールドにする」準備ができたら、バージョン1.0に進みます。

*メッセージの受信者が送信者よりも古い可能性がある場合は、送信者と受信者の両方が、受信者がメッセージを認識しない場合、またはメッセージの特定のフィールドを処理できることを確認する必要があります。通常のサーバークライアントWeb APIでは、これが問題になることはほとんどありませんが、ハードウェアAPIの場合は状況がまったく異なる場合があります。これを重大な変更と見なさなければならない可能性があります。これにより、このアドバイスの一部を実行するのがかなり難しくなります。

2
Kevin

場合によっては、異なるプログラムバージョンを実行している複数のシステム間で構造を共有する必要があります。各プログラムバージョンに一致する複数のデータ構造を持つこと(上記で提案)は1つのソリューションですが、ソリューションによっては、データのクローン作成と同期、追加のストレージ、追加のメンテナンスと複雑さなど、複数の問題が発生する可能性もあります。

別の解決策は、すべてのデータバージョンを1つの共通の構造に結合し、各プログラムバージョンを変更して、理解できる情報のみを処理し、残りを無視することです。ミームまたはバージョン管理プロトコルは、不明なデータ構造内のデータ項目であり、上位のリリースの機能に関連するデータと見なされ、このプログラムバージョンには必要ありません(データは無視されます)。以下の例。

新しいバージョンのデータはすべて、データ構造の最後に追加する必要があります。つまり、v1.0は最初の10バイトのみを処理します。 v1.1は最初の20バイトを処理します。 v1.3は最初の40バイトを処理します。この方法では、プログラムv1.0で必要な最初の10バイトが変更されないようにし、v1.0は最初の10バイトを解析して残りを無視するようにプログラムされています。最初の10バイトがIDで、v1.3が10ではなく20バイトである必要がある場合、例として新しい20バイトのIDを追加できます。

General Markup言語GMLを実装します。 HTMLプロトコルは、このメソッドを使用して、すべてのバージョンのHTMLブラウザーに同じWebページを提供します。各ブラウザは、タグのサポート機能と無視機能を備えたブラウザを処理するようにプログラムされています。

別のアプローチは、各バージョンデータに共有構造でインデックスを実装することです。これは上記のappendメソッドに似ていますが、[offset、length]のインデックスを使用してデータバージョンセグメントを見つけます。すべてのプログラムバージョンは、インデックス作成を理解し、それを使用して必要なデータを見つけます。データの重複を減らすために、データアイテムはそれを導入したバージョンセグメントにのみ配置されます。つまり、新しいプログラムバージョンは、以前のバージョンフィールドの取得方法を変更する必要はありません。具体的には、file_idを抽出するv1.0のコードメソッドはコードv1.4では変更されておらず、file_idは引き続きv1.0データセグメントから抽出されます。

2
Nella N.

現在のアプローチを考えると、通信プロトコルの変更がAPIの変更につながるべきではありません。通信プロトコルはJSONファイルに格納されているため、通信プロトコルを効果的に説明できるようになるとすぐに、API構造はすべてのデバイスで同じままです。 JSON。

特定のデバイスと通信する場合、APIの呼び出し元は、JSONを指定するか、APIが対応するJSONを見つけることができる場合は、実際のデバイスIDやバージョンを使用して、通信プロトコルのバージョンを指定するだけです。 。

APIのバージョンを実際に変更する必要があるのは、特定のJSONをどのように変更しても、新しいデバイスが以前のAPIでサポートされていない機能を使用している場合です。

比較として、USB標準のしくみを見てください。新しいUSBデバイスがリリースされるたびに、オペレーティングシステムを更新する必要はありません(幸い)。ただし、デバイスとの通信方法をオペレーティングシステムに指示するデバイスのドライバーをインストールする必要があります。これはJSONファイルに似ています。ただし、USB 2はUSB 3に取って代わられ、高速化やその他の多くの拡張機能が提供されました。これは、ドライバーを追加するだけでは実現できないことです。

2