Goland上でのディレクトリ構成はこうしている


はじめに

前まではrailsで仕事をしていて、railsだと既に決まったディレクトリ構造があって、問題なく仕事はできていました。
最近、golangを触り始めていて、ディレクトリ構造のベストプラクティスってあんまり記事がないなあと思うところがあり、
「自分はこうしてますよ」という物を残そうと思います。

ツッコミ大歓迎。

追記 2018/12/10

最近はModulesの方をよく使っています。
Depでやりたかったpackageの細かいバージョン管理は実現できています。
各ディレクトリに冗長的にファイルを作るよりはGOPATH以下に一括して管理できているのでいい感じです。

Modulesを導入すると必然的にこの記事に書いてあるディレクトリ作成は不要になります。

みんなModules使いましょう。

本題

golangって、何も考えずに開発しようと思えば、おもむろに任意のディレクトリにmain.goとかを書けば動くので、
チュートリアル的なもんであれば、特に

~/hoge/
  `- main.go

こんな感じで全然動くと思います。

でも、glideやらdepやらで管理したいとなったり、rubyでいうところのbundler or home管理下のgemの
使い分けをしたいとかなると、ちょっとこれだけじゃ困ります。

そうなると、こんな感じになります。

~/go
path/to/project/
  |- vendor/
  |- GoPkg.yml
  |- GoPkg.lock
  `- main.go

実はこれでだいたい話としてはFAです。

goenvとの併用

自分は、golangのバージョンを切り替える目的で(まだ必要に迫られてないですが)
goenv(anyenv)を使っています。

goenvは下記のlocalコマンドでディレクトリ毎に使用するバージョンをいい感じに切り替えてくれます。

$ goenv local 1.9
$ cat .go-version
1.9

つまり.go-version記載のバージョンでgo実行されることになります。

プロジェクトごとの環境切り分け

goバージョンを切り替えたりする理由はズバリ「プロジェクト毎に違う物を使う」からです。
本来なら、何も気にせず最新バージョンだけ使いたいですが、実運用だとそうは行かないです。

自分はJetBrains製のGolandを使っています。
Golandって、プロジェクト毎にGOROOT,GOPATHを切り替えることができますので、基本的にはそれを使います。

でも、これだけだと GOBIN が設定されません。
GOBINはgo get -ugo installGOPATH/binにインストールしたツールにアクセスするためのパスです。

go generateなどで使うコマンドはここに格納しておく感じです。

私はローカル上での確認はGolandのDebugやdelveやgo runを使うので、
デバッグのためにプロジェクトのバイナリをbin以下にインストールとかはやりません。

direnvを使います。

$ cd path/to/project
$ direnv edit
export GOBIN=path/to/bin/ #絶対パスを指定すること

そうすると、ディレクトリ以下に.envrcができるので、次からはそれが適用されます。

golangって$GOPATH/src/github.com/name/projectってやんなきゃいけない

多分、やんなきゃってことではないんですが、そう推奨されてるっぽいです。

なので、こんな感じです。

GOPATH/
  |- bin/
  |- pkg/
  `- src/
      `- github.com/path/to/project

色々まとめるとこんな感じです。

# GOPATH=任意のディレクトリ
# GOROOT=goenv配下のgoディレクトリ
# GOBIN=$GOBIN/bin の絶対パス

# ディレクトリ構造
GOPATH(任意でOK) # Golandではここからプロジェクトとして開く。
  |- .envrc # GOBINを指定(direnv)
  |- bin/ # go install したツールとか
  |- pkg/ # 中間ファイルとかここ(あんまり意識しなくていい)
  `- src/ # 自分のパッケージとツール用のパッケージのソースはここで管理
            `- github.com
          `- junpayment/
                `- project/
                    |- GoPkg.toml
                    |- GoPkg.lock
                    |- vendor/  # dep ensure で生成、基本気にしなくていい
                    |- lib/ # パッケージのファイルはここでコーディング
                    `- main.go

注意点

vendor以下にまだインストールしてないパッケージに依存してるのに、プロジェクトがビルドできてしてしまうことがある。
それは、 GOPATH/src直下に既にインストールしている可能性があるので超注意。

追記

ディレクトリ構造を作るスクリプトを作りました

よかったら使ってください。
https://github.com/junpayment/go-dir-maker

以上