1. 序章

このチュートリアルでは、APIとABIがソフトウェアに関係していること、それらが他の消費者や私たちにとって何を意味するか、そしてそれらを変更するたびに考慮する必要があることを探ります。

2. What Is an API?

API、または「アプリケーションプログラミングインターフェイス」は、あるソフトウェアが別のソフトウェアとどのように相互作用できるかを定義します。

これは、インターネットを介して相互作用する2つの異なるアプリケーション間で発生する可能性があります。 たとえば、HTTP APIは、 OpenAPI を使用して文書化される場合があります。これにより、他のアプリケーションが一貫してHTTPAPIと対話できるようになります。 これにより、サーバーに送信されるHTTPメッセージと、受信が予想される応答が定義されます。

または、ソフトウェアライブラリにもAPIがあります。 これらは、アプリケーションがライブラリと対話する方法の説明です。 たとえば、ライブラリのアクセス可能なインターフェイスを構成するクラスとメソッドはAPIと見なされます。 次に、これにより、アプリケーション(または実際には他のライブラリ)がアプリケーションと正しく対話する方法が定義されます。

アプリケーションのすべてのレベルにAPIがあり、常にそれらが表示されるとは限りません。たとえば、データベースドライバーがデータベースとの通信に使用するAPIを公開していることは比較的明らかです。

ただし、データベーススキーマはAPIでもあります。これは、データベースに入れることができるものとできないものを記述し、データの一貫性と有効性を維持することを保証します。 スキーマを変更すると、ドライバーを変更した場合と同じように、スキーマにアクセスするソフトウェアを変更する必要があります。

APIも常に同期している必要はありません。 メッセージキューに入れられたメッセージまたは電子メールを介して送信されたファイルの内容は、コードの関数定義と同じようにAPIを構成できます。 これらはすべて考慮する必要があり、それらを変更した場合の結果は、アプリケーションまたはそれらに依存するアプリケーションで予期しない副作用を引き起こす可能性があるため、重要視されます。

3. What Is an ABI?

ABI、つまり「アプリケーションバイナリインターフェイス」はAPIに似ていますが、ソースコードではなくコンパイル済みコードで表現されます。

たとえば、Javaアプリケーションでは、ライブラリのAPIはライブラリのソースコードであり、ABIはアプリケーションが機能するクラスファイルです。

多くの場合、ソフトウェアのABIはAPIに直接リンクされています。 ABIは単なるAPIであり、代わりにコンパイルされた形式で表現されるため、これは驚くべきことではありません。 ただし、2つの正確な性質は、一方を変更しても他方が変更されない場合があることを意味します。

たとえば、Javaの type erasure は、特定の変更がコンパイルされたクラスファイルで表現されないことを意味します。 次の2つの関数定義は、ソースコードでは異なって見えますが、クラスファイルでは同じように表現されています。たとえば、次のとおりです。

public List<String> getStrings() {}

public List<Integer> getInts() {}

どちらの場合も、実際のクラスファイルは次のようになります。

public List getStrings() {}

public List getInts() {}

したがって、戻り値のジェネリック型を変更することはAPIの重要な詳細ですが、ABIにはまったく反映されていないことがわかります。

逆に、APIをまったく変更せずに、ABIに影響を与える変更を加えることができます。 これは非常にまれな発生ですが、注意しないと発生する可能性があります。 重要な例の1つは、同じソースコードを別のコンパイラでコンパイルすることです。 同じクラスをJava8またはJava17バイトコードに組み込む場合、入力APIが同一であっても、ABIは異なります。

3.1. ABIのないAPI

すべてのAPIに対応するABIがあるわけではないことに注意してください。 たとえば、 JavaScriptやPythonなどの純粋に解釈された言語には、ABIと見なすコンパイル済み出力がありません。

同様に、すべてのABIが明らかであるとは限りません。 HTTPで表現されたAPIにはABI(マシン間で送信される文字通りのバイト)がありますが、これは、リモートシステムとの対話方法を説明するときに重要な詳細とは見なされないことがよくあります。

この場合、他のソフトウェアレイヤーを使用して対話を実行するため、正確な詳細が隠されていることがよくあります。 リモートシステムに電話をかけるときに、TCP/IPパケットやSSL暗号化について気にする必要はありません。 私たちはHTTPクライアントのAPIに依存しており、それがすべて私たちのために行います。 これは、リモートサービスの正確なABIがアプリケーションにとってそれほど重要ではないことを意味します。

4. APIとABIの互換性

依存ソフトウェアのAPIまたはABIが変更された場合、これを考慮してソフトウェアを変更する必要がある場合があります。必要な変更は、依存ソフトウェアで何が変更されたかによって異なります。

依存ライブラリのABIが変更されていないか、重要でない方法でのみ変更されている場合は、変更を処理するためにアプリケーションを再コンパイルする必要はありません。 ABIが同じままであるということは、変更を直接の置き換えとして使用できることを意味します。

依存ライブラリのABIが変更されたが、APIは変更されていない場合は、アプリケーションを変更せずに再コンパイルする必要があります。 APIが同じままであることは、変更が機能的に同じであることを意味しますが、ABIが異なることは、一部の低レベルの詳細が変更されたことを意味します-たとえば、一部の構造の正確なメモリレイアウトやの正確な値いくつかの定数。

APIが重大な方法で変更された場合は、さらに進んで、新しいAPIで動作するようにソフトウェアを変更する必要があります。 たとえば、メソッドにパラメータが追加または削除されている場合です。

4.1. セマンティックバージョニング

ソフトウェアの利用者が変更の結果を理解するためには、一貫したバージョン管理戦略を立てることが重要です。 セマンティックバージョニングは、非常に人気のある戦略の1つです。

上記で説明したように、APIとABIを互いに独立してバージョン管理する必要がある場合があることに注意してください。 ただし、多くの場合、APIのみをバージョン管理し、コンシューマーがABIの互換性を推測できるようにするだけで十分です。

セマンティックバージョニングを使用する場合、バージョン番号には、メジャー、マイナー、パッチの3つの主要コンポーネントがあります。

メジャーバージョンが変更された場合、これはAPIまたはABIへの互換性のない変更を示します。これは、コンシューマーがこの新しいバージョンに移行するためにコードを変更する必要があることを意味します。

たとえば、メソッドを削除したり、メソッドにパラメータを追加または削除したりすると、バージョンが大幅に変更されたと見なされます。 このメソッドに依存するコードは、コンパイルまたは機能しなくなるため、変更する必要があります。

メジャーバージョンは変更されていないがマイナーバージョンが変更されている場合、これは機能が変更されているが、下位互換性がないことを示します。これは通常、新しい機能がAPIに追加されているが、既存の機能は変更されていないことを意味します。 多くの場合、常にではありませんが、これはABIが変更されたことを意味しますが、APIは古いバージョンと完全に互換性があります。

たとえば、Beanに新しいオプションのフィールドを追加すると、バージョンのマイナーな変更としてカウントされます。 それに依存するコードは変更する必要はありませんが、メモリ内のBeanのレイアウトが変更されているため、動作を継続するにはコードを再コンパイルする必要がある場合があります。

パッチバージョンのみが変更された場合、これはAPIが変更されていないことを示します。これは通常、APIの実装にわずかな変更があるが、API自体には変更がないことを意味します。 これはおそらく、常にではありませんが、ABIも変更されていないことを意味します。

たとえば、フィールドをnullにすることができるルールを緩和すると、パッチの変更としてカウントされる場合があります。 APIとABIのどちらも変更されておらず、古いコードはすべて、変更を加えることなく同じように機能し続けます。

5. 結論

ここでは、APIとABIを構成するものの概要と、それらの変更について考える必要がある場合 –自分で行った変更、または依存しているライブラリやアプリケーションの変更について説明しました。の上。

また、賢明なバージョニング戦略を通じて、これらの変更を他の人にどのように表現できるかについても見てきました。