Goにおけるパッケージの利用可能範囲と共通化の自分ベストプラクティス
なぜ調べたのか?
Goを使ったプロジェクトで以下のような問題に直面し、調査を行いました。
- ディレクトリ間でのパッケージ利用時のエラー
- 既存コードの意図を汲み取る必要性
- 他者が書いた既存コードを理解する過程で、特定のパッケージがどこまで利用可能なのかを知りたい場面がありました。
これらの背景から、Goにおけるパッケージの適用範囲や構造に関する知識を整理する必要があると感じました。
結論
調査の結果、以下の知見を得ました。
- 機能上のパッケージのスコープ
go.mod
以下に存在するすべてのディレクトリにパッケージはアクセス可能。- ただし、同じパッケージ名が複数存在すると名前衝突が発生するため、別名をつけてインポートする必要がある。
- 実務での運用ルール
- 共通機能の整理方法
以下のようなディレクトリ構造を採用すると、コードの再利用性が向上しやすい。
RootDir ├─ common/ │ ├─ utility.go // 共通機能 │ ├─ package common ├─ A/ │ ├─ middleware/ │ │ ├─ xx.go │ │ ├─ package middleware │ ├─ main.go ├─ B/ │ ├─ middleware/ │ │ ├─ xx.go │ │ ├─ package middleware │ ├─ main.go ├─ C/ │ ├─ hoge/ │ │ ├─ main.go ├─ go.mod
パッケージの適応範囲の検証内容
ケース1: go.mod
配下でのパッケージ利用
以下のディレクトリ構成では、C
ディレクトリからA
のmiddleware
パッケージの関数を呼び出せます。
RootDir/ ├─ A/ │ ├─ middleware/ │ │ ├─ xx.go (package middleware) │ │ ├─ AMiddlewareFunc ├─ B/ │ ├─ middleware/ │ │ ├─ xx.go (package middleware) │ │ ├─ BMiddlewareFunc ├─ C/ │ ├─ hoge/ │ │ ├─ main.go ├─ go.mod
検証結果:
C/hoge/main.go
内でimport "RootDir/A/middleware"
とすることで、AMiddlewareFunc
を呼び出せました。- すべてのディレクトリが同じ
go.mod
の管理下にある場合、パッケージの利用に制約は少ない。
ケース2: 各ディレクトリに独自のgo.mod
が存在する場合
以下のようにディレクトリごとに独自のgo.mod
を持たせた場合、C
ディレクトリからA
やB
のパッケージを利用できません。
RootDir/ ├─ A/ │ ├─ middleware/ │ │ ├─ xx.go (package middleware) │ │ ├─ AMiddlewareFunc │ ├─ go.mod │ ├─ main.go ├─ B/ │ ├─ middleware/ │ │ ├─ xx.go (package middleware) │ │ ├─ BMiddlewareFunc │ ├─ go.mod │ ├─ main.go ├─ C/ │ ├─ hoge/ │ │ ├─ main.go
検証結果:
C/hoge/main.go
からA/middleware
やB/middleware
を呼び出せません。- 各ディレクトリが独立した
go.mod
を持つ場合、外部パッケージとして明示的にインポートする必要があります。
共通化のためのディレクトリ構造の提案
以下の構造を採用することで、共通機能の管理が容易になります。
RootDir/ ├─ common/ │ ├─ utility.go (package common) ├─ A/ │ ├─ middleware/ │ │ ├─ xx.go (package middleware) │ ├─ main.go ├─ B/ │ ├─ middleware/ │ │ ├─ xx.go (package middleware) │ ├─ main.go ├─ C/ │ ├─ hoge/ │ │ ├─ main.go ├─ go.mod
このように、common
ディレクトリを作成して共通機能を格納すると、以下のメリットがあります。
- コードの再利用性向上
- 共通処理を一元化できるため、修正が容易。
- 名前衝突の回避
- 各パッケージが独立しているため、衝突の心配がない。
- 保守性の向上
- 共通機能が明確に分離され、開発者全員がアクセスしやすくなる。
まとめ
Goでは、go.mod
以下のディレクトリでパッケージを利用できますが、名前衝突の可能性を考慮する必要があります。実務ではディレクトリ単位でパッケージを分離し、共通機能をcommon
ディレクトリなどに集約することが推奨されます。このような構造を採用することで、コードの保守性や再利用性を高めることができます。
Goプロジェクトを設計する際の参考になれば幸いです!