【Go】脱Go初心者のためにGoでオンライン交流会に役立つツールを制作してみた

# はじめに
Go案件に携わりたいなと思い、お勉強のがてらこんなツールを作りました。
制作過程をまとめようと思っていたんですけど、つまづいたポイントをまとめただけになりました。。
合間を見てどんどん機能を追加していこうと思います！

・デモGIF
![gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113263/927f2061-54bd-c89d-d27c-b2b0567e5930.gif)

・URL
https://group-shuffle-app.herokuapp.com/

・Github
https://github.com/yagi-eng/group_shuffle_gui

# ツールの説明
以下の問題解決を目的としたツールです。

- 交流会などで、複数回参加者をシャッフルしてグループ分けする
- なるべく重複しないようにする

## おおまかな流れ
1. 参加者の組み分けをランダムに生成し、以下の評価方法に基づき評価
2. 1.を複数回繰り返し、一番評価が良い組み分けを最良の組み分けとする

## 評価方法
- 組み分けに対して、参加者毎のスコアを以下のように定義
    - 各回で同席した人との同席回数の合計を、全ての回で合計した値
- 全参加者のスコアの標準偏差が最も小さい組み分けを最良の組み合わせとする

例えば、1さんが1回目に[2,3,4]、2回目に[4,5,6]の人と同席になった場合。
1回目では、いずれも初同席なので同席回数はそれぞれ1となり、1さんのスコアは `1+1+1=3`
2回目では、4とは2回目の同席なので同席回数は2となり、1さんのスコアは `2+1+1=4`

## 使用技術
- Go 1.14
- echo v3.3.10
- Heroku
- Vue.js

# Goでつまづいたこと
## ディレクトリ構成のベストプラクティスがわからない
以下の記事を参考にしました。

- [Goのパッケージ構成の失敗遍歴と現状確認](https://medium.com/@timakin/go%E3%81%AE%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E6%A7%8B%E6%88%90%E3%81%AE%E5%A4%B1%E6%95%97%E9%81%8D%E6%AD%B4%E3%81%A8%E7%8F%BE%E7%8A%B6%E7%A2%BA%E8%AA%8D-fc6a4369337)
- [Standard Go Project Layout](https://qiita.com/sueken/items/87093e5941bfbc09bea8)


## package分割がうまくできない
以下の記事を参考にしました。
[Go Modules でインターネット上のレポジトリにはないローカルパッケージを import する方法](https://qiita.com/hnishi/items/a9217249d7832ed2c035)


go moduleを使うと実現できます。
import文に相対パスを指定する方法もありますが、現在では非推奨なようです。

package化したメソッドの呼び出しは `(package名).(メソッド名)`である必要があります。
当たり前のことなんですけど、これをうっかり見落としていて少し時間をかけてしまいました。

## go module導入したらechoがimportされなくなった
以下の記事を参考にしました。
[GolangとEchoでお手軽にAPIサーバを立てる](https://ken-aio.github.io/post/2019/01/30/golang-echo/)

```
$ go mod init
```
した後に

```
$ go get github.com/labstack/echo/v4
```
すると、いい感じに解消してくれます。
自分の場合は順番が逆でした。

ちなみに、以下のコマンドで、 `go.mod`ファイルから不要なモジュールを削除してくれます。

```
$ go mod tidy
```

## 型が違うだけの処理を共通化できない
具体的に、 `util/slice/slice.go` の以下2つのメソッドを1つにまとめたかったができなかった。

```go:slice.go
// DevideArr スライスを分割する
func DevideArr(arr []int, lenOfEachSlice int) [][]int {
	arrs := [][]int{}
	len := len(arr)

	for i := 0; i < len; i += lenOfEachSlice {
		end := i + lenOfEachSlice
		if len < end {
			end = len
		}
		arrs = append(arrs, arr[i:end])
	}

	return arrs
}

// DevideArrStr スライスを分割する
func DevideArrStr(arr []string, lenOfEachSlice int) [][]string {
	arrs := [][]string{}
	len := len(arr)

	for i := 0; i < len; i += lenOfEachSlice {
		end := i + lenOfEachSlice
		if len < end {
			end = len
		}
		arrs = append(arrs, arr[i:end])
	}

	return arrs
}
```

`interface{}` を使えばできるかもと思ったが、`[]interface{}` を引数として、`[]int` を受け取ろうとしたらコンパイルエラーになった。

参考
[Go言語の型とreflect](https://qiita.com/atsaki/items/3554f5a0609c59a3e10d)

## Herokuにデプロイはできるが動作しない
以下のコミットのようにポート番号を環境変数から取得するように修正します。
https://github.com/yagi-eng/group_shuffle_gui/pull/4/commits/6ad3ee022d4990b8459c0141b2905278c3259eef

```go:server.go
-	e.Logger.Fatal(e.Start(":1323"))
+	e.Logger.Fatal(e.Start(":" + os.Getenv("PORT")))
```

# Vueでチャレンジしたこと
## formのvalidation
以下の記事を参考にしました。
[これでわかるvue.jsのフォームバリデーションVuelidate](https://reffect.co.jp/vue/vue-js-validation-vuelidate)
段階的に実装していくのでわかりやすかったです。

## axiosを使ったAPI通信
以下の記事を参考にしました。
[axiosの使い方まとめ (GET/POST/例外処理)](https://www.sukerou.com/2019/05/axios.html)
Vueではないけど、初めて使いました。