1. 導入
Go言語での開発において、プロジェクトが肥大化するにつれ「どのパッケージがどの外部ライブラリに依存しているか」を把握することが困難になります。特に、特定のレイヤー(例えばドメイン層)から外部ライブラリや特定のインフラ層が直接呼び出されることを防ぎたい、といったアーキテクチャの制約を維持する際に、手動での確認は限界があります。本稿では、Go標準の go list コマンドを使い、依存関係を自動抽出・検証する方法を解説します。
2. 基礎知識
go list は、Goのパッケージに関する情報を出力するためのツールです。通常はパッケージのパスを表示する程度に使われがちですが、-f(フォーマット)オプションを組み合わせることで、パッケージの内部構造(インポートパス、依存関係、テストファイルなど)を詳細に取得できます。
今回活用する {{.Imports}} は、そのパッケージが直接インポートしているパッケージのリストを抽出するためのテンプレート変数です。これを利用することで、CI/CDパイプラインに「特定のパッケージは特定のライブラリをインポートしてはならない」というテストを組み込むことが可能になります。
3. 実装/解決策
依存関係を特定するには、ターミナルで対象のパッケージを指定して以下のように実行します。
go list -f ‘{{.Imports}}’ ./…
これにより、プロジェクト内の各パッケージがどのライブラリをインポートしているかがリスト形式で出力されます。実務では、この出力をさらに grep や awk で加工し、禁止されているインポートが含まれていないかを確認するシェルスクリプトをCIに組み込むのが定石です。
4. サンプルプログラム
以下は、特定のパッケージ内から「禁止されたライブラリ(例:データベース関連のライブラリ)」がインポートされていないかを検証する、簡易的なGoプログラムの例です。
// main.go
package main
import (
“fmt”
“os/exec”
“strings”
)
func main() {
// 検証したいターゲットパッケージ
targetPackage := “./internal/domain/…”
// 禁止したい依存先
forbiddenImport := “github.com/lib/pq”
// go listコマンドを実行して依存パッケージを取得
cmd := exec.Command(“go”, “list”, “-f”, “{{.Imports}}”, targetPackage)
out, err := cmd.Output()
if err != nil {
panic(err)
}
// 出力結果([pkg1 pkg2] の形式)を解析
imports := string(out)
if strings.Contains(imports, forbiddenImport) {
fmt.Printf(“エラー: %s 内で禁止されたパッケージ %s が見つかりました\n”, targetPackage, forbiddenImport)
// CI環境であればここで終了コード1を返して失敗させる
} else {
fmt.Println(“検証成功: 依存関係に問題はありません”)
}
}
5. 応用・注意点
注意点1: 再帰的な依存関係
{{.Imports}} は「直接のインポート」のみを返します。間接的な依存(依存先の依存先)まで追跡したい場合は、{{.Deps}} を使用してください。ただし、DepsはGoの標準ライブラリを含む全依存を取得するため、結果が非常に長くなります。
注意点2: アーキテクチャテストの自動化
現場で導入する際は、自前でスクリプトを書く代わりに “github.com/matthewmcnew/archunit-go” や “github.com/feinberg/go-check-imports” のような、この go list を内部的に活用した既存のライブラリを利用することを推奨します。これにより、テストコードとして依存関係のルールを宣言的に記述でき、保守性が飛躍的に向上します。
まとめ
go list は単なる情報表示ツールではなく、コードの品質を担保するアーキテクチャガードレールの基盤となります。ぜひ、プロジェクトのルールをコード化する第一歩として活用してみてください。

コメント