🦊
AWS SAMにGo言語で取り組む際のディレクトリ構成
要約
- SAMで複数のLambda関数を作りたいが、その中で使う自作パッケージは共通化したいときに、どのようなディレクトリ構成にしておけば良いか、調べた&試した結果を残します。
- また
go.mod
はどこに置いて、各.go
ファイルから自作パッケージを参照するにはどうしたら良いのかについてもまとめます。 - 以下のフォルダ構成が良いのかな、という結論に至りました。
project.root/
├─ go.mod
├─ go.sum
├─ cmd/
│ ├─ SAM_project1/
│ │ ├─ lambda1/
│ │ │ ├─ main.go
│ │ │
│ │ ├─ lambda2/
│ │
│ ├─ SAM_project2/
│
├─ pkg/
├─ package1/
├─ package2/
はじめに
- 趣味でAWSを触り始め早一ヶ月、SAM(Serverless Application Model)を使って、ちまちまとLambdaを作っていました。
- 開発規模が徐々に大きくなってきたところで、自作パッケージが循環参照に陥る等、見切り発車でディレクトリ構成を考えていたツケが回ってきました。こりゃいかんということでリファクタリングを始めたところで、「あれ、そもそもGo言語のディレクトリ構造とか、モジュール管理(go.mod)はどうするべきなんだっけ…?」と悩んでしまいました。
やりたいこと
- 複数のLambdaで繰り返し使用する関数はパッケージにまとめて再利用したい。
- 1つのSAM Projectの中で複数のLambdaを置きたい。
- SAM Projectを複数持ちたい(用途毎に切り分けておきたい)。ただしパッケージは共通で使いたい。
要は、1つのプロジェクト内で、共通パッケージを持つ複数のアプリケーションを開発するケースと同じです。
何が私を迷わせたか
-
sam init
でAWSテンプレートを使用すると下記のフォルダ構成が生成されると思います。この時、1つのLambda関数に相当するhello-world
ディレクトリ内にgo.mod
が置かれているので、「あれ?Lambda関数毎に用意しておかないといけないのかな?」と考えてしまいました。
SAM-Root
│ Makefile
│ README.md
│ samconfig.toml
│ template.yaml
│
└─hello-world
go.mod
go.sum
main.go
main_test.go
しかしgo.mod
はプロジェクトのモジュール環境を整えるものなので、もっと大きな括りで用意すれば良いことが、四苦八苦してわかりました。
どうしたか
- 冒頭に記載したように、ルートディレクトリ直下に
go.mod
ファイルを置き、アプリケーションを収めるcmd
ディレクトリと、パッケージを収めるpkg
ディレクトリを配置しました。 - その上で
go.mod
ファイル、各.go
ファイル中で以下のような記述を行い、必要なパッケージを参照します。なお、プロジェクト全体を非公開で運用する予定のため、モジュール名はgithub.com/~~
の形式を取らないようにしました。- モジュール名の中で宣言するルートディレクトリ名にドットを含んでいないと怒られるので、今回は
project.root
という名前にしています。(前提としてモジュール名とディレクトリ名は一致させています)
- モジュール名の中で宣言するルートディレクトリ名にドットを含んでいないと怒られるので、今回は
go.mod
module project.root
project.root/cmd/SAM_project1/lambda1/main.go
package main
import (
"project.root/pkg/package1"
"project.root/pkg/package2"
)
func main(){
package1.hoge()
package2.fuga()
}
- 自分が分からなかったのは、同じモジュール配下であれば、例えローカルにしかないパッケージであっても、モジュール内の絶対パスを記述することでインポートできるということでした。
- それまではたくさんの
go.mod
を作り=たくさんのモジュールを作り、他のローカルモジュールを参照するために、それぞれのgo.mod
ファイル内でreplace
ディレクティブを使ってパスを指定していました。
- それまではたくさんの
おわりに
- 移行作業は面倒でしたが、おかげでプロジェクト全体がスッキリとしました。
Discussion