Go言語のDIフレームワークFx
Go言語のDIフレームワークFxの解説
Table of contents
author: oikawa-k
Go言語にもDI(Dependency Injection)をするフレームワークが存在します。それが Fx です。 この記事ではFxの紹介と評価をします。使い方は ドキュメント を読んでください。
Fxのよいところ
Uberが提供している現状ほぼ唯一のDIを行う現実解である
FxはUberという比較的大きな会社がメンテナンスをしており2026年7月現在7.6kという非常に多数のGitHubスターを獲得しています。従って安心して利用できるフレームワークと言ってよいです。 以前はwireというGoogleが作っていた静的DIを行うライブラリがありましたが、wireがアーカイブ化されてしまったため実質唯一のDIの選択肢となってしまいました。
コンストラクタベースのDIができる
基本的にDIフレームワークはコンストラクタベースのDIを提供したほうが良いとされています。FxはコンストラクタベースのDIを提供しているためこの条件を満たしています。(オプションでFx独自のコードを埋め込むことも可)
Lifecycle管理が組み込まれている
Fxは fx.Lifecycle を使ってアプリケーションのOnStart/OnStopフックを登録する仕組みを提供しています。これにより、サーバーの起動処理・終了処理をDIコンテナ側にまとめて管理できます。
fx.Invoke(func(lc fx.Lifecycle, server *http.Server) {
lc.Append(fx.Hook{
OnStart: func(ctx context.Context) error {
go server.ListenAndServe()
return nil
},
OnStop: func(ctx context.Context) error {
return server.Shutdown(ctx)
},
})
})
自前でmain関数にgoroutineの起動処理やSIGTERM待受処理を書き並べる必要がなくなり、コンポーネントごとに起動・終了処理を閉じ込められるのはFxならではの利点です。
fx.Moduleで関心を分離できる
アプリケーションの規模が大きくなるとProviderの数も膨大になりますが、fx.Module を使うことで機能単位にProviderをグルーピングできます。
var UserModule = fx.Module("user",
fx.Provide(NewUserRepository, NewUserService),
)
機能ごとにModuleを分けてmainで fx.New(UserModule, OrderModule, ...) のように組み立てられるため、DIの構成が把握しやすくなります。
起動時にDIグラフ全体を検証してくれる
Fxは fx.New() の実行時にすべての依存関係を解決しようとします。解決できない依存関係があればその時点でエラーになるため、実際にAPIを呼び出してから「DIし忘れていた」と気づく事故を防げます。実行時検証ではあるものの、アプリケーション起動直後に検出できるのは十分実用的です。
Fxの気になるところ
リフレクションベースなのでコンパイル時にエラーを検出できない
FxはGoの reflect パッケージを利用して依存関係を解決しています。そのため型の不整合やProviderの設定ミスはコンパイル時には検出できず、fx.New() を実行した瞬間に初めて表面化します。
かつてのwireはコード生成によって静的にDIコードを構築していたため、コンパイル時にエラーを検出できるという明確なメリットがありました。wireがアーカイブされてしまった今、この点はFxを使う上で受け入れざるを得ないデメリットです。
リフレクションベースなので起動が遅くなる
依存解決をリフレクションで行う都合上、Providerの数が増えるほどアプリケーションの起動時間が伸びていきます。リクエスト処理自体はDI完了後は通常のGoコードとして動くため実行時のパフォーマンスに影響はありませんが、起動時にすべての依存関係を組み立てる分だけコストがかかります。ローカル開発でホットリロードを多用する場合や、Cloud Run・Lambdaのようにコールドスタートの速さが求められる環境では、この起動コストが地味に響いてくることがあります。
エラーメッセージが読みにくい
依存解決に失敗した際のエラーメッセージは内部的な型情報がそのまま出力されるため、慣れないうちはどこが原因か読み解くのに時間がかかります。Providerの数が増えてくるほど、原因箇所の特定に苦労する場面が出てきます。
独自の記法を覚える必要がある
fx.Provide や fx.Invoke だけでなく、インターフェースと実装を紐づける fx.As、名前付き依存を扱う fx.Annotated / fx.ResultTags など、Fx独自の記法が多数存在します。これらを使いこなすにはドキュメントの読み込みが必要で、学習コストは決して低くありません。
プロジェクトの規模によってはFxを使用せず、自前でDIを実装するという手段も考えられるでしょう。特に昨今はAIの導入によりこういった単純ではあるが量の多いコードを量産するコストが下がっているので、DIフレームワークを使用しないというのも選択肢になります。
まとめ
- FxはUberがメンテナンスする信頼性の高いDIフレームワークであり、wireがアーカイブされた今、実質的にほぼ唯一の選択肢である
- コンストラクタベースのDI、Lifecycle管理、Moduleによる関心分離など、実務で使いやすい機能が揃っている
- リフレクションベースであるため、コンパイル時の型安全性という面ではwireに劣る
- 独自記法の学習コストやエラーメッセージの読みにくさは事前に把握しておくべき
Goで規模の大きいアプリケーションを開発するのであれば、導入を検討する価値のあるフレームワークだと言えます。特にLifecycle管理やModule分割による見通しの良さは、チームでの開発効率向上に寄与するでしょう。
※本記事は、ジーアイクラウド株式会社の見解を述べたものであり、必要な調査・検討は行っているものの必ずしもその正確性や真実性を保証するものではありません。
※リンクを利用する際には、必ず出典がGIC dryaki-blogであることを明記してください。
リンクの利用によりトラブルが発生した場合、リンクを設置した方ご自身の責任で対応してください。
ジーアイクラウド株式会社はユーザーによるリンクの利用につき、如何なる責任を負うものではありません。