Goプロジェクトのはじめかたとおすすめライブラリ8.5選。ひな形にも使えるサンプルもあるよ。

# はじめに
最近イケイケなGo！
でもベターなGoプロジェクトのはじめかたっていまいち調べてもわからないですよね。
自分は最初色々迷いました。。

まずパッケージ管理ツール。
godepだったりGo Modulesだったり、少し情報がとっちらかっている印象です。

後はどのディレクトリにプロジェクトを配置した方がいいのかもわかりづらい。
importの仕方も相対と絶対のどちらがいいのか迷う。

というわけで以下の4点に絞って解説していきたいと思います！

- パッケージ管理ツール
- プロジェクトの配置場所
- 自作パッケージのimportの仕方
- おすすめライブラリ

この記事を読めば正しくGoプロジェクトが作成できます！（たぶん）

【追記】
インストール方法とVSCodeの設定に関しても簡潔にまとめたので、良かったら参考にしてください。
[【超簡単】GoのインストールとVSCode設定方法](https://qiita.com/yagi_eng/items/69cb75cd3062a24888ac)

# いきなりまとめ
## プロジェクト作成
新規にGoプロジェクトを作成したい場合は以下の通りにコマンドを実行すればOKです。

```
$ cd (任意のディレクトリ)
$ mkdir (YOUR_PROJECT)
$ cd (YOUR_PROJECT)
$ go mod init github.com/(GitHubユーザ名)/(GitHubリポジトリ名)
# 後はどんどこファイル作成！
$ vim main.go
# あるいは必要なパッケージをインストール
$ go get ~~~~~
...
```

## おすすめライブラリインストール
`go mod init`後に必要に応じて実行。
あるいは各ソースコードのimport文にライブラリのパスを記載しておくと、`go run`の時に自動でインストールしてくれます。

```
go get -u github.com/labstack/echo/v4
go get -u github.com/joho/godotenv
go get -u github.com/sirupsen/logrus
go get -u github.com/valyala/fasthttp
go get -u github.com/golang/mock/gomock
go install github.com/golang/mock/mockgen
go get -u github.com/google/wire/cmd/wire
go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql # mysqlを使う場合
go get -u github.com/oxequa/realize
```

【2021/4/21追記】
Go1.16より`go install`を使ったインストールもできるようになっています。
直近では上記インストール方法で問題ありませんが、詳細は各ライブラリのREADMEをご確認ください。

また、`go install`については、以下の記事がわかりやすかったです。

[Go1.16からの go get と go install について](https://qiita.com/eihigh/items/9fe52804610a8c4b7e41)

## サンプル
あくまでも簡易的なものです。。
[こちら(GitHub)](https://github.com/yagi-eng/go-pj-template)です。

# パッケージ管理ツール
## 簡単に説明
現在はGo Modulesが標準なのでこちらの機能を使いましょう。
Go Modulesが標準で使えるようになる前は、godepなどが使われていたらしいです。

[Go言語の依存モジュール管理ツール Modules の使い方](https://blog.mmmcorp.co.jp/blog/2019/10/10/go-mod/)

> Modules は、依存モジュール管理ツールです。
Go言語 1.11 から標準で使えるようになりました。
以下のような機能を持っています。

> ・依存モジュールの自動検知
・依存モジュールのバージョン固定、バージョンアップ検知
・依存モジュールの情報は go.mod と go.sum という名前のファイルに記載されます。

## 使い方
新規にディレクトリを作成し、`go mod init`と打つだけで、Go Modulesを使えるようになります。

```
$ mkdir (YOUR_PROJECT)
$ cd (YOUR_PROJECT)
$ go mod init github.com/(GitHubユーザ名)/(GitHubリポジトリ名)
go: creating new go.mod: module
```

そうすると、`go.mod`ファイルが`(YOUR_PROJECT)`直下に作成されます。

```go:go.mod
module github.com/(GitHubユーザ名)/(GitHubリポジトリ名)

go 1.17
```

ライブラリをインストールすると、そのファイル内にパッケージの依存情報が記載されます。
かんたん便利！

### モジュール名
`go mod init`でモジュール名（プロジェクト名）を指定する時は、慣習的にgitリポジトリのドメインから記載するようです。
色々漁ってみたんですけどソースはいまいちわかりませんでした。。
ただ、[The Go Blog - Using Go Modules](https://blog.golang.org/using-go-modules)でもそのように紹介されていました。

例えば私だと以下の通りです。

```
$ go mod init github.com/yagi-eng/go-pj-template
```

リポジトリURLはこちら。
https://github.com/yagi-eng/go-pj-template

GitHub以外、例えばCodeCommitだとこうなるらしい。

```
$ go mod init git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/hello.git
```

【参考】[Go で Lambda 書いたときの覚え書き](https://tkaaad97.hatenablog.com/entry/2019/06/16/171923)

# プロジェクトの配置場所
## 簡単に説明
Go Modulesの登場により、どこでも配置できるようになりました。
以上です。

## 以前は
Go Modulesの登場以前は`$GOPATH/src`(※)配下に配置する必要がありました。
他言語からくると、置く場所が決まっている点に少し戸惑いますが、解消されたようです。

※`$GOPATH`はデフォルトだと`$HOME/go`

どこでも配置できるようになったけど、なんかGoっぽいので自分は以下の例の通りに配置しています。

### 具体例

```
$GOPATH
├─ bin/
├─ pkg/
└─ src/
  └─ github.com/
    └─ GitHubユーザ名/
      └─ GitHubリポジトリ名/
        ├─ main.go
        └─ などなど。気の向くままに配置。
```

自分の場合はこんな感じです。

```
$GOPATH
├─ bin/
├─ pkg/
└─ src/
  └─ github.com/
    └─ yagi-eng/
      └─ go-pj-template/
        ├─ main.go
        └─ などなど。気の向くままに配置。
```

```
$GOPATH/src/github.com/yagi-eng/go-pj-templete
```

# 自作パッケージのimportの仕方
## 簡単に説明

```go
import "(モジュール名)/(自作パッケージ名)"
```

相対パスではなく、モジュール名から始まる絶対パスで指定します。
具体例は次の通りです。

## 具体例

モジュール名： `github.com/yagi-eng/hoge-pj`
自作パッケージ名: `hoge`

```:ディレクトリ構成
hoge-pj/
├─ hoge/ #自作パッケージ
| └─ hoge.go
├─ main.go
└─ go.mod
```

```go:go.mod
module github.com/yagi-eng/hoge-pj

go 1.17
```

```go:hoge.go
package hoge // 自作パッケージ

import "fmt"

func PrintHoge() {
	fmt.Println("hogehoge")
}

```

```go:main.go
package main

import "github.com/yagi-eng/hoge-pj/hoge" // こんな感じでimport！

func main() {
	hoge.PrintHoge()
}

```

こんな感じでimportすれば実行できます。

```
$ go run main.go
hogehoge
```

# linter
staticcheckというlinterがおすすめです。
詳細はこちら。

https://qiita.com/yagi_eng/items/1c34f9691128c51846e7

# おすすめパッケージ
インストールしておくと捗りそうなパッケージを紹介します。

## パッケージのインストール方法
以下のコマンドを実行するだけです。Go Modulesがいい感じにインストールしてくれます。

```
$ go get -u (インストールしたいパッケージ名)

# 例 echoフレームワークをインストールする場合
$ go get -u github.com/labstack/echo/...
```

## echo
Goの軽量フレームワーク。
簡単にルーティングやサーバ実行、ロギング、CORS設定などをすることができます。

公式HPは[こちら](https://echo.labstack.com/guide)。

```
$ go get -u github.com/labstack/echo/v4
```

## godotenv
`.env`ファイルを使用するためのライブラリ。

使い方は以下の記事が参考になります。
[【Go】.envファイルをGolangでも使用するためのライブラリ「godotenv」](https://qiita.com/sola-msr/items/fb7d6889d7bd7a6705d0)

```
$ go get -u github.com/joho/godotenv
```

## logrus
logの外部パッケージ。
Go標準パッケージの`log`はシンプル過ぎるので、ログレベルなど使いたい時に便利です。

[【Go×ログ】logrusの使い方を簡単に分かりやすくまとめてみた](https://qiita.com/gold-kou/items/3143ab4622acacd33f8d)

```
$ go get -u github.com/sirupsen/logrus
```

## 【追記】zap
こちらもlogの外部パッケージ。
記事を読んで頂いた方に紹介頂きました！

`logrus`より高速なようです。
こっちを使った方が良さそうですね。

- [uber-go/zap](https://github.com/uber-go/zap)
    - README.mdにパフォーマンスに関して言及されています。
- [golangの高速な構造化ログライブラリ「zap」の使い方](https://qiita.com/emonuh/items/28dbee9bf2fe51d28153)

```
$ go get -u go.uber.org/zap
```

## fasthttp
[net/httpとfasthttpの対応表](https://qiita.com/satto_sann/items/576fb45981d17ae56f9f)

> go言語でHTTP通信を行うためのライブラリです．

> go言語の標準パッケージではnet/httpがすでに用意されているのですが，
fasthttpでは標準パッケージを凌駕する処理の速さで一時期有名になりました．
公式のベンチマークでは，従来に比べ10倍の差がでたようです．

```
$ go get -u github.com/valyala/fasthttp
```

## gomock
mock生成ライブラリ。
簡単にモックを作成できるので、テストを実装する時などに便利です。

[Goでメソッドを簡単にモック化する【gomock】](https://qiita.com/gold-kou/items/81562f9142323b364a60)

```
$ go get -u github.com/golang/mock/gomock
$ go install github.com/golang/mock/mockgen
```

## wire
DIライブラリ。いい感じにDIできます。

[GoのDIライブラリgoogle/wireの使い方](https://user-first.ikyu.co.jp/entry/google-wire)

```
$ go get -u github.com/google/wire/cmd/wire
```

## gorm
GoのORマッパー。
2020年8月にVersion2.0がリリースされて、使い勝手が向上したみたいです。

- [GORMガイド](https://gorm.io/ja_JP/docs/index.html)
- [GOのORMを分かりやすくまとめてみた【GORM公式ドキュメントの焼き回し】](https://qiita.com/gold-kou/items/45a95d61d253184b0f33)

```
$ go get -u gorm.io/gorm
$ go get -u gorm.io/driver/mysql # mysqlを使う場合
```

## realize
hot reloadライブラリ。
Goはコンパイル言語なので、PHPのように変更が即反映されず、変更のたびにプロセスをキルして`go run`し直す必要があります。
その点を解消してくれます。

ただし、Go Modulesを使っている場合はそのままだと動作しません。
ワークアラウンドをあてる必要があります。

- [[Go] Realizeが便利なので、もう少し仲良くなってみる](https://qiita.com/enta0701/items/9f60ad18600acab8c93d)
- [Cannot do `--run` with go1.11 using go mod under windows. ](https://github.com/oxequa/realize/issues/217#issuecomment-459198990)
    - ワークアラウンドはこちら。

```
$ go get -u github.com/oxequa/realize
```

### 補足
realizeはファイルが更新された際に、今動いているアプリを停止しないまま更新後のアプリを起動させようとします。
そのため、ポート番号を指定してGoサーバを起動していると、以下のようなエラーが出てうまくhot reloadされません。

```
{"time":"2020-09-04T15:29:06.6074496+09:00",
"level":"FATAL","prefix":"echo","file":"server.go","line":"41",
"message":"listen tcp :8080: bind: Only one usage of each socket address (protocol/network address/port) is normally permitted."}
```

こちらもワークアラウンドが出てます。
[Realize is not killing the current app](https://github.com/oxequa/realize/issues/247#issuecomment-532152142)


## reflex
こちらもhot reloadライブラリ。
2つ目のhotreloadライブラリなので0.5扱いです。
realizeがダメだったら試してみるといいかも。
ただし、Windowsには対応していません。

[goのhot reloadingにはreflexが便利だった](https://qiita.com/_mkazutaka/items/fcefea6081c16a383be4)

```
$ go get -u github.com/cespare/reflex
```

## 【追記】air
こちらもhot reloadライブラリ。
記事を読んで頂いた方に紹介頂きました！
自分は`realize`も`reflex`も使えなかったので結局こちらを使っています。

[cosmtrek/air](https://github.com/cosmtrek/air)

```
$ go get -u github.com/cosmtrek/air
```

# サンプル
[こちら(GitHub)](https://github.com/yagi-eng/go-pj-template)です。

## はじめかた

```
# MySQL準備
$ docker-compose up -d
# migration実行
$ go run tools/migrate.go
# アプリ実行
$ go run server.go
```

## 説明
Goをいい感じに始められるサンプル・ひな形です。
Goがインストールしてあることを前提としています。
簡単なAPIサーバを立てる時や、Goを始めたばかりでどうプロジェクトを作成していけばいいかわからない時に有効だと思います。

本格的なGoプロジェクトを作る時には不向きです。
コードを読むとおわかり頂けるのですが、`db *gorm.DB`を引きずりまわしているのでその点が辛みです。
本格的なプロジェクトを作成する際は、`wire`などのDIライブラリを使うと捗ると思います。

`go.mod`に記載されているライブラリに関しては、以下のQiitaを参照ください。
`wire`や`gomock`などはインポートはしましたが、サンプルでは使っていません。
記念に入れておいただけなので、`go mod tidy`すると消えます。

## サンプルに含まれる内容
- `gorm`を使ったMySQL接続
- `gorm`を使ったDB migrationのサンプル
- `gorm`を使ったDB Read/Writeのサンプル
- `echo`を使ったルーティング、ロギング、CORS設定
- `godotenv`を使った`.env`ファイルの読み込み

# 本格的なGoプロジェクトに興味のある方は。。
手前みそですが、こちらの記事が参考になるかと思います。
[Goとクリーンアーキテクチャで飲食店検索ができるLINE BOT作ってみた](https://qiita.com/yagi_eng/items/983a7cd36b63a2f0ffac)

以下のように、結構ゴリゴリつくりました笑

```javascript
|--.env
|--docker-compose.yml
|--go.mod // Goのバージョン管理
|--Procfile // Herokuデプロイ
|--server.go // main関数
|--wire.go // DI用
|--domain
|  |--model
|  |--repository // databaseのinterface
|--infrastructure
|  |--database
|  |--mysql.go
|  |--router.go // Routing
|--interfaces
|  |--controllers
|  |--gateway // 外部API通信
|  |--presenter // LINE BOT出力
|--mock // 各層のmock
|  |--gateway
|  |--presenter
|  |--repository
|--tools // DBマイグレーション
|--usecases
|  |--dto // usecase用のDTO
|  |  |--favoritedto
|  |  |--googlemapdto
|  |  |--searchdto
|  |--igateway // interfaces/gatewayのinterface
|  |--interactor
|  |  |--usecase // usecases/interactorのinterface
|  |--ipresenter // interfaces/presenterのinterface
```

# さいごに
Twitterの方でも、モダンな技術習得やサービス開発の様子を発信したりしているので良かったらチェックしてみてください！

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Goのプロジェクトのはじめ方や、おすすめのライブラリをQiitaにまとめました😊<br>Goのこの辺りの情報ってあまりまとまっていないので、Goに興味のある方やGo初心者の方には参考になると思います😌<br>特にパッケージ管理やディレクトリ配置などは最初は「ん？」ってなりがち😇<a href="https://t.co/gLNPlPLzbU">https://t.co/gLNPlPLzbU</a></p>&mdash; やぎぬ😇行動力エンジニア (@yagi_eng) <a href="https://twitter.com/yagi_eng/status/1302741394356756480?ref_src=twsrc%5Etfw">September 6, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

また、BOT開発を通じてGoとLINE BOTにまとめて入門する記事をZennに掲載していますので、良かったらそちらもご覧ください！

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ZennでGoとLINE BOTの記事を書いてみました<br><br>⬇️BOT開発を通じてGoとLINE BOTにまとめて入門する<a href="https://t.co/QqsEESJMKa">https://t.co/QqsEESJMKa</a><br><br>5ステップに分け、「Hello Worldから始めて、飲食店検索ができるLINE BOTの実装まで」を解説しています<br>GoやLINE BOTに興味のある人は是非読んでみてください😇<br>24,000字超え😇</p>&mdash; やぎぬ😇行動力エンジニア (@yagi_eng) <a href="https://twitter.com/yagi_eng/status/1325027213784326152?ref_src=twsrc%5Etfw">November 7, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 参考記事
- [他言語から来た人がGoを使い始めてすぐハマったこととその答え](https://qiita.com/mumoshu/items/0d2f2a13c6e9fc8da2a4)