# OpenTelemetryにおけるアップグレードの考え方

> Source: https://www.ymotongpoo.com/works/otel-specs-ja/spec/upgrading/


大規模に広く分散されたソフトウェアを管理するには、後方互換性・バージョニング・アップグレードに関する慎重な設計が必要です。OpenTelemetryのアプローチは以下の通りです。OpenTelemetryを使う予定があるなら、この問題に対する私たちの取り組み方を理解しておくと役立ちます。

## コンポーネントの概要

スムーズなアップグレードと長期的なサポートを実現するため、OpenTelemetryクライアントは複数のコンポーネントに分解されています。この文書の以下の部分では、次の用語を使います。

**パッケージ**とは、何らかの依存関係管理の仕組みを介して互いを参照するコード単位を指す一般的な用語です。プログラミング言語ごとに依存関係管理へのアプローチは異なり、この概念を表すためにモジュールやライブラリなど別の用語が使われることに注意してください。

**API**とは、OpenTelemetryの計装を書くために必要なすべてのインターフェースと定数を含むソフトウェアパッケージの集合を指します。APIの実装は、アプリケーションの起動時に登録できます。他の実装が登録されない場合、APIはデフォルトでno-opの実装を登録します。

**SDK**とは、OpenTelemetryプロジェクトによって提供される、APIを実装するフレームワークを指します。特殊なケースに対応するために代替のAPI実装が書かれることもありますが、OpenTelemetryを使うほとんどのユーザーはSDKをインストールすることを想定しています。

**プラグインインターフェース**とは、SDKによって提供される拡張ポイントを指します。これには、サンプリングの制御・データのエクスポート・その他さまざまなライフサイクルフックのためのインターフェースが含まれます。これらのインターフェースはAPIの一部ではなく、SDKの一部であることに注意してください。

**計装**とは、APIを呼び出すすべてのコードを指します。これには、OpenTelemetryプロジェクトによって提供される計装、サードパーティの計装、さらに自らを計装するアプリケーションコードやライブラリが含まれます。

**プラグイン**とは、SDKのプラグインインターフェースを実装するすべてのパッケージを指します。これには、OpenTelemetryプロジェクトによって提供されるプラグインと、サードパーティのプラグインが含まれます。

プラグインと計装の間には重要な区別があります。プラグインはプラグインインターフェースを実装します。計装はAPIを呼び出します。この違いは、OpenTelemetryのアップグレードへのアプローチに関係します。

## 依存関係の管理

OpenTelemetryのユーザーと実装者が、OpenTelemetry APIの最新バージョンに追随することは非常に重要です。OpenTelemetryは後方互換性に関して厳格なルールに従っています。OpenTelemetryパッケージの最新のマイナーバージョンへは常に安全にアップグレードできます。

### アプリケーション開発者

アプリケーションにOpenTelemetry SDKをインストールする予定の開発者は、すべてのマイナーバージョンのアップグレードを受け入れることが推奨されます。これにより、アプリケーションが常に最新の最適化とセキュリティパッチを適用してビルドされるようになります。

同様に、アプリケーション開発者は、現在のメジャーバージョンにおけるOpenTelemetry APIの将来のすべてのバージョンに依存することが推奨されます。これにより、計装が将来のマイナーバージョンの新機能を使うようにアップグレードされた際にも、バージョンの衝突が発生しないようになります。

### ライブラリのメンテナー

OSSライブラリをメンテナンスする開発者は、OpenTelemetry APIを使って自分のライブラリコードに直接計装を追加することが推奨されます。このアプローチを「ネイティブ計装」と呼びます。

OpenTelemetry APIをライブラリの依存関係として追加する際は、現在のメジャーバージョンの***将来のすべてのバージョン***に依存することが非常に重要です。

特定のマイナーバージョンに依存すると、後のマイナーバージョンで追加されたAPI機能を使う他のライブラリとの***バージョン衝突を引き起こす可能性があります***。APIのマイナーバージョンのバンプは、既存の計装との互換性の問題を決して引き起こしません。APIの将来のバージョンに依存することは完全に安全です。

### SDK実装者

公式のOpenTelemetry SDKのメンテナーおよび代替SDKのメンテナーは、自分たちの実装を最新バージョンのOpenTelemetry APIと常に最新かつ互換性のある状態に保たなければなりません（MUST）。

OpenTelemetry APIの新しいマイナーバージョンがリリースされると、新しい機能が含まれます。これには新しいインターフェースや、既存インターフェースへの新しいメソッドが含まれます。SDKのメンテナーは、これらの機能を実装した新しいバージョンを適時にリリースすることが期待されます。

このような形で実装を継続的にメンテナンスできないと考える場合は、代替SDKを実装しないことを強く推奨します。OpenTelemetryが新機能をリリースし、アプリケーション開発者やライブラリのメンテナーがこれらの機能を利用することは避けられません。

## OpenTelemetryのアップグレードパス

設計要件に入る前に、実際のアップグレードがどのように機能するかを説明します。OpenTelemetryのすべてのコンポーネント（API、SDK、プラグイン、計装）が、それぞれ別々のバージョン番号を持つことに注意してください。

### APIの変更

OpenTelemetry APIに新しい機能が追加されると、APIの新しいマイナーバージョンがリリースされます。これらのAPIの変更は常に追加的であり、以前のバージョンをインポート・呼び出す既存の計装パッケージの観点から見て後方互換性があります。すべての以前のマイナーバージョンのAPIに対して書かれた計装は動作し続け、依存関係の衝突を発生させることなく同じアプリケーション内に組み合わせて使えます。

API実装は、常にAPIの最新バージョンをターゲットにすることが期待されます。APIの新しいバージョンがリリースされると、そのAPIをサポートするSDKのバージョンも同時にリリースされます。SDKの古いバージョンは、APIの新しいバージョンをサポートすることを期待されていません。

### SDKの変更

バグ修正・セキュリティパッチ・パフォーマンス改善は、SDKのパッチバージョンとしてリリースされます。APIの新しいバージョンへのサポートは、マイナーバージョンとしてリリースされます。新しいプラグインインターフェースは、SDKのマイナーバージョンのバンプとしてリリースされます。

プラグインインターフェースへの破壊的変更は、非推奨化を通じて扱われます。プラグインインターフェースを破壊する代わりに、新しいインターフェースが作成され、既存のインターフェースは非推奨として印付けられます。非推奨のインターフェースを対象とするプラグインは動作し続け、SDKは不足している機能のデフォルト実装を提供します。1年後、非推奨のプラグインインターフェースは、SDKのメジャーバージョンリリースで削除されることがあります。

## 設計要件とその説明

このアップグレードへのアプローチは、レガシーコードに関連するメンテナンスの負担を最小限に抑えながら、2つの重要な設計要件を解決します。

* APIの呼び出し元は決して壊れない。
* SDKのユーザーは最新バージョンへ容易にアップグレードできる。

既存の計装を無期限にサポートすることは、OpenTelemetryの重要な機能です。APIに対して数百万行のコードが書かれることが想定されます。これには、統合されたOpenTelemetry計装を備えて出荷される共有ライブラリも含まれます。これらのライブラリは、OpenTelemetryが依存関係の衝突を発生させることなく、アプリケーション内に組み合わせられなければなりません。一部の計装（OpenTelemetryプロジェクトが提供するものなど）はAPIの最新バージョンへ更新されますが、他の計装は決して更新されないこともあります。

新しい計装を利用するには、ユーザーがSDKの最新バージョンへアップグレードする必要が生じる場合があります。このアップグレードが容易でなければ、OpenTelemetryプロジェクトは古いバージョンのSDKと、計装エコシステム全体の古いバージョンをサポートし続けることを強いられるでしょう。

これは、うまくいってもとてつもないメンテナンス負担になりますし、OpenTelemetryプロジェクトがそのエコシステムの一部しか管理していないことを考えると、そもそも実現不可能です。OpenTelemetryは、ネイティブ計装を持つライブラリに対して、APIの複数バージョンをサポートすることを要求できません。アプリケーションの所有者やオペレーターがSDKの最新バージョンへアップグレードできるようにすることで、この問題は解決されます。

SDKのアップグレードを妨げる主な要因は、古くなったプラグインです。新しいバージョンのSDKが既存のプラグインインターフェースを破壊すれば、依存しているプラグインがアップグレードされるまで、どのユーザーもSDKをアップグレードできなくなります。ユーザーは、依存する計装がSDKと互換性のないバージョンのAPIを要求する一方で、そのSDKが自分たちの使うプラグインをサポートしているバージョンとは異なる、という板挟みの状況に陥る可能性があります。

プラグインインターフェースに関して非推奨化のパターンに従うことで、新しいSDKがリリースされた後にプラグインエコシステムがアップグレードできる1年間の期間を作り出します。これは、積極的にメンテナンスされているプラグインがアップグレードするために十分な時間であり、また使われなくなったプラグインを識別して置き換えるためにも十分な時間だと考えています。

SDKを容易にアップグレードできるようにすることで、アプリケーションの所有者やオペレーターが、多数の以前のSDKバージョンにわたってパッチをバックポートする必要なく、重要なバグ修正やセキュリティパッチを迅速に取り込むための道も提供します。

