ProgrammingGo 開発者

Go モジュールと Go における依存関係の管理はどのように機能しますか?依存関係の更新や固定化時にどのような問題が発生する可能性がありますか?

Hintsage AIアシスタントで面接を突破

回答

Go モジュールは、Go 1.11 以降で導入された標準の依存関係管理メカニズムです。主なファイルは go.mod(最小依存関係とそのバージョンを定義)と go.sum(ハッシュによって整合性を保証)です。

依存関係を追加するには次のようにします:

go get github.com/pkg/errors@v0.9.1

依存関係を更新するには:

go get -u ./... go mod tidy # 未使用のものを削除

Go はセマンティック バージョニング (semver) をサポートし、依存関係は厳密に固定されます: プロジェクトは再現可能で、ビルドは決定論的です。しかし、以下の点を考慮する必要があります:

  • replace パス(<replace github.com/pkg/errors = ../errors>)を使用すると、互換性のリスクが生じます。
  • go.mod を手動で修正する際のエラーは、バージョンの互換性や間接依存関係の競合を引き起こす可能性があります。
  • 一部の依存関係は他のシステム(dep、vendoring)を使用しているため、移行が難しくなる場合があります。

誘導的質問

go.sum ファイルを削除し、go build コマンドを実行した場合、何が起こり、なぜそれが危険なのでしょうか?

多くの人は、Go が単に依存関係をゼロから再構築すると考えています。しかし、go.sum ファイルにはすべての使用モジュールのハッシュが含まれており、置き換え(サプライチェーン攻撃)から保護されています。それを削除すると、次回ビルド時に Go は依存関係を再ダウンロードし、ファイルを再構築しますが、もしその依存関係のリポジトリが悪意のある者によって変更されていた場合 - 保護が破られます!本番環境でのコードの置き換えが可能になります。

知識不足による実際のエラーの例


逸話

大規模プロジェクトで、リポジトリが vendoring から Go モジュールに移行した際に、バージョンを固定するのを忘れました。サードパーティのパッケージが更新された1ヶ月後に互換性が壊れ、古いブランチをビルドできなくなりました - コードが再現性を失いました。


逸話

別のプロジェクトで、開発者が誤って go.sum を削除しました。再実行した際にチームは依存関係の一部が変わったことに気付き、マイナーバージョンの互換性に関連するバグが発生しました - これにより数日前にロールバックが発生しました。


逸話

ローカルディレクトリへの replace パス (replace ... = ../some/library) がデプロイ前に削除されなかったため、CI/CD パイプラインでビルドが失敗しました。外部システムがローカルファイルにアクセスできなかったため、本番環境は不正なバージョンに「固定」されました。