🗂

google/wire がアーカイブされたけどどうすればいいの?

に公開
4

(追記: 2025/08/22)

2025年8月7日に google/wire リポジトリはアーカイブ化されましたが、その後 8月21日に例外的に PR (#432) がマージされました。これは Go 1.25 でビルドが壊れる不具合への対応で、golang.org/x/tools のバージョンを更新する最小限の修正です。2025/08/22の執筆時点でアーカイブが解除されていますが、今後再びアーカイブされる可能性はあると思います。
ユーザーとしては Wire を Go 1.25 でも安全に利用できるようになったことが大きな意味を持ちます。

https://github.com/google/wire/pull/432

背景

Go の DI ツールでおなじみの google/wire が 2025/8/7 にアーカイブされ read only となりました。

この記事の立場

  • wire がアーカイブされても、既存プロダクトが困ることは基本的にありません。
  • wire はツールとして十分に枯れており、機能拡張の要求がなければ、そのまま使い続けられます。 リポジトリ自体が消える可能性は小さいはずです。
  • どこかの組織・会社が継続開発やメンテナンスを引き継ぐ可能性もあります(フォークや移管など)。
  • 本記事は積極的な移行を促すものではありません。 類似の DI ツールを整理しておき、必要になったときの判断材料として活用できれば十分と考えます。

TL;DR(結論)

  • 既存システムは 現状維持で問題なし
  • 新規開発や大規模改修で DI を見直す必要が出た場合に備え、代表的な選択肢を把握しておく。
  • いま直ちに移行コストを負う合理性は乏しい。必要になったら検討するで十分。

DI の代表的なアプローチ

本記事では、すぐに移行しない前提で「必要になったら検討できる候補」を整理します。用途やチーム規模に応じて選択してください。

1) 手動DI (自作DI)

  • 特徴:最小依存・明示的・読みやすい。規模増大時は変更の手間が増える。
  • 向き:小〜中規模、もしくは依存の増減が緩やかなプロダクト。
// 依存を明示的に渡すだけのシンプルな構成

type Repo struct{}
func NewRepo() *Repo { return &Repo{} }

type Service struct{ R *Repo }
func NewService(r *Repo) *Service { return &Service{R: r} }

func main() {
  r := NewRepo()
  s := NewService(r) // 手動で Repo を注入
  _ = s
}

2) 軽量DI(Genericsベース): samber/do

  • 特徴:Generics により型安全・コード生成不要。学習コストが低い。
  • 向き:小〜中規模、段階的導入。

https://github.com/samber/do

サンプルコード:

package main

import (
    "fmt"

    "github.com/samber/do/v2"
)

type Service struct{}
func (s *Service) HealthCheck() error { 
    fmt.Println("HealthCheck called")
    return nil
}

func main() {
	i := do.New()
	do.Provide(i, func(inj do.Injector) (*Service, error) { return &Service{}, nil })
	_ = do.MustInvoke[*Service](i).HealthCheck()
}

3) リフレクション型: uber-go/dig

  • 特徴:実行時に依存グラフを組み立てる。柔軟だが、問題は実行時に表面化する。
  • 向き:プラガブルな構成や、差し替え頻度が高い領域。

後述する uber-go/fx の内部で利用されています。

https://github.com/uber-go/dig

4) フレームワーク型: uber-go/fx

  • 特徴:DI に加えてライフサイクル(起動/停止)・モジュール化・観測フックを提供。
  • 向き:中〜大規模。起動順序やリソース管理を明示化したい場合。

https://github.com/uber-go/fx

サンプルコード:

package main

import (
    "context"
    "net"
    "net/http"
    "go.uber.org/fx"
)

func newHTTP(lc fx.Lifecycle) *http.Server {
    s:=&http.Server{Addr:":8080"}
    lc.Append(fx.Hook{
        // アプリケーション起動時のhook
        OnStart: func(ctx context.Context) error {
            ln,err := net.Listen("tcp",s.Addr)
            if err != nil {
                return err
            }
            go s.Serve(ln)
            return nil
        },
        // アプリケーション終了時のhook
        OnStop: func(ctx context.Context) error {
            return s.Shutdown(ctx)
        },
    })
    return s
}

func main(){
    fx.New(fx.Provide(newHTTP)).Run()
}

5) フレームワーク型: alibaba/IOC-golang

  • 特徴:アノテーション風の記述でコンポーネント登録と自動注入(Autowire)。AOP による横断的関心(ログ/メトリクス/リトライ等)の適用。設定値の注入やライフサイクル管理も提供。
  • 向き:フレームワーク志向で、Spring ライクな開発体験に親和性があるチーム/中〜大規模。規約に沿って一体型の機能に乗りたい場合。

https://github.com/alibaba/IOC-golang

package main

import (
	"fmt"

	"github.com/alibaba/ioc-golang"
	"github.com/alibaba/ioc-golang/autowire"
	"github.com/alibaba/ioc-golang/autowire/singleton"
)

// +ioc:autowire=true
// +ioc:autowire:type=singleton
type App struct{}

func (a *App) Greet() {
	fmt.Println("Run")
}

func init() {
	singleton.RegisterStructDescriptor(&autowire.StructDescriptor{
		Factory: func() interface{} {
			return &App{}
		},
	})
}

func main() {
	_ = ioc.Load()
	appInterface, _ := singleton.GetImpl("main.App", nil)
	app := appInterface.(*App)
	app.Greet()
}

かんたん比較(用途の目安)

上記で紹介した各 DI ツールを表で整理してみます。あくまで筆者の主観による評価です。

観点 手動DI samber/do uber-go/dig uber-go/fx alibaba/IOC-golang
依存 なし 中〜大
学習コスト 中〜高 中〜高
型安全性 高(コンパイル時) 高(コンパイル時に概ね気づくが依存未解決は実行時) 中(実行時) 中(実行時に問題に気づく) 中(実行時に問題に気づく)
柔軟性 低〜中 高(LC/Hook) 高(AOP/Autowire)
規模適性 小〜中 小〜中 中〜大 中〜大

まとめ

  • wire のアーカイブは ただちに移行を迫る出来事ではありません。
  • 既存プロダクトは現状維持で問題なし。必要になったときのために最小限の備えと選択肢のだけ持っておく。
  • 将来の体制や要件の変化があれば、その時点で類似のDIツールと自身のプロダクトとの適合性を検討すれば十分です。

Discussion

わたなおわたなお

google/wireのアーカイブですが、解除されてません?

motchmotch

ほんとですね!教えていただいてありがとうございます!

motchmotch

提供いただいた情報を元に追記しました! 🙇