Go_依存性の注入
date
Jun 10, 2020
slug
dependencyInjection
status
Published
tags
Golang
summary
Golang DI触ってみた、まあまあな感じ
type
Post
ubar-go/dig
は、依存性の注入(Dependency Injection)を実現するためのGo言語のパッケージです。 結論から言うこと
ubar-go/dig
を使用することで、依存性の注入を効果的に活用し、柔軟でテスト可能なコードを構築することができます。私利用したくない理由としては、以下のような点が挙げられます:
- 学習コスト:
ubar-go/dig
は依存性の注入を扱うための高度な機能を提供していますが、そのため学習コストがかかる場合があります。特にDIのコンセプトやパッケージの使用方法に慣れていない場合、導入や適切な使用に時間がかかる可能性があります。(JavaSpringのDIみたいなら利用します。)
- プロジェクトの規模: 小規模なプロジェクトや単純な依存関係を持つ場合、
ubar-go/dig
の使用は過剰な複雑さをもたらす可能性があります。
- リフレクションを使用しない:
ubar-go/dig
はリフレクションを使用しないDIを提供しますが、リフレクションを使用しないために一部の動的な機能が制限される場合があります。一部の特定のケースで柔軟性が必要な場合、別のDIパッケージの方が適しているかもしれません。(動的な依存関係の解決、動的なコンポーネントの追加など利用出来ない)
- 既存の依存性の注入フレームワークの使用: 既にプロジェクトで利用している別の依存性の注入フレームワークがあり、
ubar-go/dig
に切り替える必要性がない場合、既存のフレームワークを継続して使用する方がシームレスな選択肢になるでしょう。
使い方
インストール
まずは、
ubar-go/dig
をインストールしましょう。ターミナルで以下のコマンドを実行します:go get github.com/uber-go/dig
サンプルコード
以下のサンプルコードでは、構造体の注入方法を示しています。
package main import ( "fmt" "go.uber.org/dig" ) type DatabaseConfig struct { Host string Port int Username string Password string } type DatabaseConnection struct { Config DatabaseConfig } type UserRepository struct { DatabaseConnection DatabaseConnection } type UserService struct { UserRepository UserRepository } type UserController struct { UserService UserService } func NewDatabaseConfig() DatabaseConfig { return DatabaseConfig{ Host: "localhost", Port: 5432, Username: "admin", Password: "password", } } func NewDatabaseConnection(config DatabaseConfig) DatabaseConnection { return DatabaseConnection{ Config: config, } } func NewUserRepository(connection DatabaseConnection) UserRepository { return UserRepository{ DatabaseConnection: connection, } } func NewUserService(repository UserRepository) UserService { return UserService{ UserRepository: repository, } } func NewUserController(service UserService) UserController { return UserController{ UserService: service, } } func main() { container := dig.New() // Greeterの依存関係を登録 err := container.Provide( func() DatabaseConfig { return NewDatabaseConfig() }, func(config DatabaseConfig) DatabaseConnection { return NewDatabaseConnection(config) }, func(connection DatabaseConnection) UserRepository { return NewUserRepository(connection) }, func(repository UserRepository) UserService { return NewUserService(repository) }, func(service UserService) UserController { return NewUserController(service) }, ) if err != nil { panic(err) } // 依存関係の解決 err = container.Invoke(func(controller UserController) { // コントローラーの処理を実行 }) if err != nil { panic(err) } fmt.Println("Injection successful!") }
上記のコードでは、
DatabaseConfig
、DatabaseConnection
、UserRepository
、UserService
、UserController
といった複数の構造体を定義しています。それぞれの構造体は依存関係を持っており、NewXxx
関数で依存関係を解決します。main()
関数では、dig.New()
で新しいコンテナを作成し、各構造体の依存関係を登録します。そして、Invoke()
関数を使用してUserController
のインスタンスを取得し、コントローラーの処理を実行します。実行
上記のコードを実行するには、ターミナルで以下のコマンドを実行します:
go run main.go
出力結果は以下のようになります:
Injection successful!
ubar-go/dig
メリット
- 柔軟な依存性の注入:
ubar-go/dig
パッケージは依存関係を簡単に管理できる依存性の注入(DI)フレームワークです。依存関係を自動的に解決し、テスト容易性を向上させます。
- リフレクションを使用しない:
ubar-go/dig
はリフレクションを使用せずに注入を行うため、パフォーマンスが向上します。
- コンテナによる依存関係の管理:
ubar-go/dig
はコンテナを使用して依存関係を管理します。コンテナは依存関係を保持し、必要に応じて注入を行います。
ubar-go/dig
デメリット
- 学習コスト:
ubar-go/dig
パッケージは比較的高度な概念である依存性の注入を扱うため、学習コストがかかる場合があります。
- 依存関係の定義の煩雑さ: 大規模なプロジェクトでは、依存関係の定義や注入のセットアップに苦労することがあります。
競合するパッケージとの比較
- Google Wire: Googleが開発した依存性の注入パッケージ。コード生成による静的解決を行うため、パフォーマンスが向上する場合があります。また、
wire
コマンドを使用して自動的に依存関係の注入コードを生成することができます。
- Facebook Inject: Facebookが開発した依存性の注入フレームワークです。構造体のフィールドタグを使用して依存関係を定義し、注入を行います。ビルド時に依存関係を解決し、リフレクションを使用せずに注入を行うため、パフォーマンスが向上する特徴があります。
これらの競合パッケージと
ubar-go/dig
の選択は、プロジェクトの要件や個人の好みに依存します。重要な点は、依存性の注入を使用することで、柔軟性とテスト容易性を向上させることができることです。