🛠️

Goのmonorepoで共通処理を利用する方法

2022/02/26に公開
4

はじめに

平下CTO@sweeepです。Go言語でのmicroservicesにおけるmonorepo構成と共通処理を利用する方法を解説します。monorepo構成での共通処理の利用を目的としています。
本記事の内容です。

  • monorepoフォルダー構成
  • utilsで共通処理
  • 各microservice側での利用方法
  • 実行結果

monorepoフォルダー構成

monorepo直下にutilsとsrc、src下に各microserviceを配置します。GCP/AWSのデプロイ関連フォルダーもmonorepo直下に置くことが多いと思います。monorepo直下で一括管理し各microserviceのバージョン管理やデプロイの管理がラクになります。

.
└─ utils
|  ├── file
|  |   ├── file.go
|  |   └─ go.mod
...
└─ src
|  ├── aservice
|  |   ├── main.go
|  |   └─ go.mod
...

utilsで共通処理の実装

共通処理をutils下にパッケージ名のフォルダー/パッケージ名.goで実装します(以下はfileパッケージのサンプル)。

utils/file/file.go
package file
...
func CheckFileSize(size int64) (int64, error) {
	if size > MaxSize { // MaxSizeより大きい場合はエラー
		return size, fmt.Errorf("size: %v error: %w", size, ErrFileSize)
	}
	return size, nil
}

以下のコマンドでパッケージフォルダー下へ移動し、モジュール化実施します。

$ cd /utils/file
$ go mod init
$ go mod tidy

各microservice側での利用方法

以下のコマンドで各microservice下へ移動し、モジュール初期化実施します。service下にmain.go配置が必要です。

$ cd /src/service
$ go mod init

すると、以下のようなgo.modファイルが作成されます。

src/service/go.mod
module github.com/hirac1220/go/go-monorepo/src/service

go 1.17

privateリポジトリのfileパッケージをインポートして利用するために、以下のように相対パスでreplace実施をgo.modに記述します。

src/service/go.mod
replace github.com/hirac1220/go/go-monorepo/utils/file => ../../utils/file

以下のコマンドを実行します。

$ go mod tidy

これでgo.modにfileパッケージを利用するための記述が追加され、準備ができました。

src/service/go.mod
module github.com/hirac1220/go/go-monorepo/src/service

go 1.17

replace github.com/hirac1220/go/go-monorepo/utils/file => ../../utils/file

require github.com/hirac1220/go/go-monorepo/utils/file v0.0.0-00010101000000-000000000000

利用する箇所でfileパッケージをインポートし、file.関数名で利用します。

src/service/main.go
package main

import (
	"log"
	"os"

	"github.com/hirac1220/go/go-monorepo/utils/file"
)

func main() {
	// ファイルサイズチェック
	f, _ := os.Open("../../sample/image.jpg") // ファイルオープン
	defer func() {
		_ = f.Close()
	}()

	fi, _ := f.Stat()
	size, err := file.CheckFileSize(fi.Size()) // ファイルサイズチェック
	if err != nil {
		log.Println(err)
	}
	log.Printf("size: %d", size)

}

実行結果

以下コマンドで各microservice下へ移動し、実行するとmain.goからfileパッケージ呼び出して結果が表示されました。

$ cd /src/service
$ go run main.go
2022/02/26 18:30:16 size: 2604

まとめ

今回はGo言語でのmicroservicesにおけるmonorepo構成と共通処理を利用する方法を解説しました。
monorepoを利用することで、各microserviceのバージョン組合せを気にせず管理でき、またデプロイも各microservice毎ではなくmonorepo下を一括デプロイできます。そして、共通処理をutilsへまとめてパッケージ化することで、各microserviceで利用可能となります。

使用したサンプルはこちらのGitHubレポジトリにあります。
https://github.com/hirac1220/go-monorepo

GitHubで編集を提案

Discussion

TakaTaka

utilsで共通処理を実装されているとのことですが、 utilsを更新したら各マイクロサービスをデプロイし直す必要があると思います。
切り出し方やデプロイに関して気をつけていることはありますか?

hirachirac

基本的にmonorepoなので一括CICDでビルド&テストを通すのであまり問題はないかと思っています。切り出し方はDRY原則で、同じことをやっている箇所をリファクタして切り出し、または再利用可能性が高いものをあらかじめ切り出す2パターンが多いでしょうか。

TakaTaka

ご返信ありがとうございます!それであればバグになってしまうことはなさそうですね。
チームの規模やデプロイの頻度・方法 によって ソースコードDryにするか、完全に独立させるか
議論の余地がありそうですね。

hirachirac

そうですね、そもそもサービスやチーム規模が小さいうちはmicroserviceを採用するかどうか議論した方がよいかな、と思います(最初はMVCとかでさくっと作ってPMF優先など)。コメントありがとうございます!