どういった背景があったのか
マイクロサービス化を導入してる都合上、gRPCを使って通信をしていました。主にprotoファイルといった通信規格を定義するファイル群を疎通を行う双方向のサーバーに配置するのが一般的だと思います。
よくあるケースとして、protoファイル群を1つのリポジトリにまとめ、そのリポジトリをシステム間で参照するといったケースを見かけると思います。
・マイクロサービス化したシステム構成になっている
・各システム間で、特定のリポジトリのスキーマを参照したかった
・GitSubModulesなどを導入して、これらを実現したかった
どういった状況だったのか
この場合、特定のリポジトリに対し、protoファイル群をまとめたものを置くことになるため、以下のような構成になるのではないでしょうか。
service_1
├── microservice_scheme // protoファイル群が入ったリポジトリ
│ ├── go.mod // go.modが複数ある状況が生まれる
│ ├── go.sum // go.sumが複数ある状況が生まれる
│ └── main.go
├── go.mod
├── go.sum
└── main.go
GitSubModulesなどを使って、こういったディレクトリ構成にするなどの手順が一般的だと思います。
このようなときに、go.modが複数ある状況が生まれてしまうんですよね。。
こうなると、go mod
系のコマンドや gopls
も正しく動作・解釈してくれません。vscodeがエラーの嵐になります。。
どうやって解決したのか
単一のリポジトリ内に複数の go.mod
を配置したとき、上述した障壁が出てきたと思います。
実は、この解決方法は、意外と簡単です。
プロジェクトのルートディレクトリに go.work
というファイルを配置し、
単一のリポジトリだけど、複数の go.mod
が存在するよっ
と伝えてあげれば解決ができます。
なので、さっきのケースを元に go.work
を追加すると以下のような構成になります。
service_1
├── microservice_scheme // protoファイル群が入ったリポジトリ
│ ├── go.mod // go.modが複数ある状況が生まれる
│ ├── go.sum // go.sumが複数ある状況が生まれる
│ └── main.go
├── go.mod
├── go.sum
├── go.work // ルートディレクトリに置く
└── main.go
あとは、 go.work
複数の go.mod
が存在するよっと伝えてあげればいいので、
go 1.21
use (
./microservice_schema
)
このような書き方をすると、うまく動作・解釈してくれると思います!
まとめると
go.work
というファイルを特定の配置場所に置いてあげることで、うまく gopls
などが反応し、解決ができました。
goでは、もっと厳密にいうと go.mod
では、インストールしたpkgをモジュールという単位で管理をしています。
このファイルを置くことによって、
単一のプロジェクト内に複数のモジュールが、枝分かれされていると解釈され、
service_1
で扱ってるモジュールと microservice_scheme
で扱ってるモジュールは、それぞれ異なるもの
とこちらが期待していた解釈になる訳です。
余談
こうした知見は、時間があるときに go.dev なんかを読み漁ると、知見が深まりそうだなーと感じました。
皆さんもぜひお時間あるときに一読してみてはいかがでしょうか!
・multi-module に関して体系的に、ハンズオンで書かれていて、面白かった
・go.workを使ったときの、複数のモジュールがどう切り分けされるか、イメージ図が添付されていて、理解が進んだ