設問とコンテキスト
Go 1.25 を使用しているマルチモジュールの Go モノレポがあります。チームは Go 1.26 のツールとランタイムの改善を望んでいますが、開発者マシンのバージョンは Go 1.23 から 1.26 まで幅があり、CI には Linux、macOS、Windows ランナーが存在し、ダウンストリームユーザーは古い Go バージョンとのライブラリ互換性を必要としています。
go ディレクティブ、ツールチェーンの選択、Go 1.26 のブートストラップ要件、モジュールのリリース境界、CI マトリックス、およびロールバックゲートを網羅する移行を設計してください。
面接官がテストするポイント
- コンパイラバージョン、
go.mod内の言語バージョン、自動ツールチェーンダウンロードを区別できているか。 - Go 1.26 のブートストラップ要件がビルドイメージやセルフホスティングチェーンにどのように影響するかを特定できるか。
- マルチモジュールリポジトリ、生成コード、ダウンストリームコンシューマーに明確な互換性境界があるか。
- ローカルの Go を単に更新するだけでなく、再現性のある CI、チェックサム、アーティファクトによって安全性を証明できるか。
確認すべき質問
- 複数の
go.modファイル、ツールモジュール、生成コードディレクトリが存在しますか? - バイナリ、ライブラリ、あるいはその両方をリリースしていますか?ダウンストリームの最小 Go バージョンは何ですか?
- CI でツールチェーンを自動ダウンロードすることは許可されていますか?また、オフラインビルドはどのように動作しますか?
- cgo、プラットフォーム固有のツール、古いコンパイラ、またはベンダーのビルドイメージが関係していますか?
30秒の回答
各モジュールの最小サポートバージョン、ジェネレーター、ランナーを棚卸しした上で、Go 1.26 コンパイラ、go ディレクティブ、ツールチェーン選択を個別に管理します。Go 1.26 のブートストラップには Go 1.24.6 以降が必要なため、まずビルドイメージとセルフホスティングチェーンをアップグレードします。モジュールは、実際に新しい言語機能やライブラリ機能を使用するまで、ダウンストリームに約束された go バージョンを維持します。CI では、Linux、macOS、Windows 全体でツールチェーン、チェックサム、オフラインキャッシュを固定し、2バージョンテスト、アーティファクト比較、カナリアテストを実施します。ロールバック時は、イメージ、ロックファイル、モジュールディレクティブをセットで元に戻します。
ステップごとの詳細解説
バージョンと境界の棚卸し
各モジュールの go、toolchain、replace ディレクティブ、ジェネレーター、cgo 設定、プラットフォーム制約をリストアップします。モノレポ全体を一括で引き上げるのではなく、古い Go で引き続き利用可能でなければならないライブラリと、新しいコンパイラでビルドすべき内部ツールを分離します。
最初にブートストラップチェーンを修正
Go 1.26 はブートストラップに Go 1.24.6 以降を必要とします。ビルダーイメージ、クロスコンパイル環境、セルフホスティングスクリプトを検証します。
bootstrap Go >= 1.24.6
build Go = 1.26.x
module go = lowest promised language version共有ランナーを置き換える前に、隔離されたイメージでコンパイルとテストを実行します。ホストの Go が暗黙的に使用されないよう、ダウンロード元とチェックサムを記録します。
go.mod とツールチェーンポリシーの設計
go ディレクティブはモジュールの言語バージョンを表し、toolchain は推奨されるビルドツールチェーンを表すことができます。ライブラリは、CI ツールがアップグレードされたという理由だけで go ディレクティブを引き上げるべきではありません。Go 1.26 の機能を使用する場合は、モジュールバージョンを引き上げて最小要件をドキュメント化します。自動ダウンロードにはプロキシ、キャッシュ、オフライン失敗ポリシーが必要です。
マルチモジュールと生成コードの処理
プロダクトモジュールが言語保証を維持する一方で、ツールモジュールを先にアップグレードします。ジェネレーターの Go バージョン、入力スキーマ、出力を固定し、移行の前後でフォーマット、エクスポートされた API、バイナリの動作、ソースメタデータを比較します。ジェネレーターが開発者マシンの異なるツールチェーンを勝手に使用しないようにします。
CI 互換性マトリックスの構築
サポート対象の OS 上で Go 1.25 および 1.26 のコンパイル、ユニットテスト、競合検出(race)、静的チェック、パッケージングをテストします。ライブラリについては最小バージョンのコンシューマーテストを実行し、内部バイナリには 1.26 を固定します。バージョン間のキャッシュの使い回しを防ぐため、キャッシュキーには Go バージョン、モジュールグラフ、プラットフォームを含める必要があります。
カナリア、可観測性、ロールバック
まずは1つのモジュールと1つのランナーカナリアから開始します。コンパイル時間、テスト結果、race レポート、アーティファクトハッシュ、起動時の動作、依存関係の解決を比較します。ブートストラップ、cgo、プラットフォーム、またはダウンストリームの互換性に問題が発生した場合は、古いイメージ、go.mod/toolchain、キャッシュキーを復元します。PATH を変更するだけではロールバックとは言えません。
模範回答
この移行では、コンパイラ、言語バージョン、ブートストラップチェーンを明確に分離する必要があります。Go 1.26 のブートストラップには Go 1.24.6 以降が必要なため、まずビルダーイメージとクロスコンパイルをアップグレードします。ライブラリは、新しい言語機能やライブラリ機能を実際に必要とするまで、約束された最小の go ディレクティブを維持し、内部ツールは先行して移行できます。ツールチェーン、プロキシ、チェックサム、キャッシュを固定し、Go 1.25/1.26、サポート対象プラットフォーム、race、ダウンストリームの最小バージョンをテストします。ジェネレーターのバージョンを固定してアーティファクトを比較します。カナリア指標に基づいて対象を拡大し、再現可能なビルドのためにイメージ、モジュールディレクティブ、ツールチェーン、キャッシュをまとめてロールバックできるようにします。
よくある間違い
- ブートストラップコンパイラとビルドイメージを無視して開発者の Go だけをアップグレードすること。
goディレクティブ、ツールチェーン、コンパイラバージョンを同一の概念として扱うこと。- 新しい CI ツールを使用するためだけに、ライブラリの最小 Go バージョンを引き上げること。
- ジェネレーターやビルダーがホストの PATH に依存し、再現性のない出力を生成してしまうこと。
- キャッシュキーから Go バージョンとプラットフォームを除外してしまい、互換性のないキャッシュを再利用すること。
go.mod、イメージ、サプライチェーンのチェックサムを復元せず、PATH のみをロールバックすること。
フォローアップの質問
なぜ Go 1.26 のブートストラップバージョンを個別に検証するのですか?
セルフホスティングチェーンでは、新しい Go をコンパイルするために古い Go を使用します。イメージが 1.24.6 未満の場合、アプリケーションソースの互換性に関係なく、コンパイラの構築時にアップグレードが失敗します。
ライブラリはいつ go ディレクティブを引き上げるべきですか?
そのソースコードや標準ライブラリ API が真に新しいバージョンを必要とし、その最小要件がリリースコントラクトに明記されるタイミングです。CI や内部ツールのアップグレードだけでは、ダウンストリームへの保証を変更すべきではありません。
ツールチェーンの自動ダウンロードはすべてのバージョン問題を解決しますか?
いいえ。ネットワークアクセス、信頼できるプロキシ、キャッシュ、オフラインポリシーが依然として必要です。また、cgo、プラットフォームツール、ブートストラップの依存関係は個別に固定する必要があります。
ロールバックが機能することをどのように証明しますか?
バージョン文字列を確認するだけでなく、カナリア環境で古いイメージ、モジュールディレクティブ、ツールチェーン、キャッシュを実際に復元し、リビルドしてテスト、アーティファクトハッシュ、ダウンストリームでのインストールを比較します。