知識0からGo言語でCTF用スコアサーバを構築した結果、最高だった話

# ※追記
06/28：ソースコードにてのご指摘がありました。あくまでコロナ自粛から始めたので、拙いコードですので温かい目で見てもらえると嬉しいです。今後、Goについてもっと勉強していきたいと思いました。

# はじめに

どうも、テスト前で何もしたくないMarnyです。
今回は、**Qiita夏祭り2020_パソナテック**というイベントがやっていたので記事を書いていこうかなと思います。

テーマ：〇〇（言語）のみを使って、今△△（アプリ）を作るとしたら

コードの詳細を解説するより、どういったメリットがあるのか、デメリットがあるのか。そういった点に注目していきます。


# 開発経緯

そもそもなんでCTF用のスコアサーバを構築したかというと、同級生３人で通っている高専の
**低学年用にLinuxリテラシー等を学習できる環境を作ろうぜ！**

という話があり、CTFを構築することになりました。
で、使用言語なんですけど、先生から

**「DjangoかGo使いなよ」**

と言われて、僕はGoを選びました。　~~今じゃGo信者です~~


# Go言語とは

**シンプル、高速、メモリ効率が良い、メモリ破壊が無い、並行処理が得意などの特徴を備えている**

これが一番の特徴かなと思います。
とりあえず早くて、見やすいってのがいいところですね

#### 今回はGoがすでに実行できる環境を想定しています。Goの環境を作りたい方は、Dockerなり、他の人の記事を参考にしてください。


## 開発環境
```
 go version go1.13.7
 mysql  Ver 15.1 Distrib 10.4.11-MariaDB, for Win64 (AMD64)
```

# 実際のコード

とりあえず、雑なCSSですがgithubに上げときました。
URL:https://github.com/marnysan111/SMOTY
~~特にログインするページは生のhtmlです~~

例として、`main.go`と`userDB.go`を表示します

```go:main.go
package main

import (
	"net/http"
	"sort"
	"strconv"

	"github.com/gin-contrib/sessions"
	"github.com/gin-contrib/sessions/cookie"
	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	r.LoadHTMLGlob("templates/*.html")
	r.Static("/pictures", "./pictures")
	store := cookie.NewStore([]byte("secret"))
	r.Use(sessions.Sessions("user", store))

	dbInit_users()
	dbInit_linux()
	dbInit_server()
	dbInit_router()

	//ログインページ
	r.GET("/", func(c *gin.Context) {
		c.HTML(http.StatusOK, "login.html", gin.H{})
	})

	//サインアップの処理
	r.POST("/signup", func(c *gin.Context) {
		name := c.PostForm("name")
		password := c.PostForm("password")
		dbSignup(name, password)
		c.HTML(http.StatusOK, "signup.html", gin.H{"name": name, "password": password})
	})

	//ログインの処理
	r.POST("/login", func(c *gin.Context) {
		name := c.PostForm("name")
		password := c.PostForm("password")
		session := sessions.Default(c)
		dblogin(name, password)
		session.Set("user_name", name)
		session.Save()
		c.Redirect(302, "/smoty")
	})

	//SMOTYトップページ
	r.GET("/smoty", func(c *gin.Context) {
		session := sessions.Default(c)
		if session.Get("user_name") == nil {
			panic("ログインしてない")
		}
		c.HTML(200, "smoty.html", gin.H{"user_name": session.Get("user_name")})
	})

～～～～以下略～～～～

	r.Run(":80")
}
```

```go:userDB.go
package main

import (
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

type Users struct {
	gorm.Model
	Name     string //頭文字を大文字にしないと、DBにマイグレーションできない
	Password string
	Score    int
}

// DB接続
func dbInit_users() {
	db, err := gorm.Open("mysql", "root:password@/database_name?charset=utf8&parseTime=True&loc=Local")
	if err != nil {
		panic("Init失敗")
	}
	db.AutoMigrate(&Users{})
	defer db.Close()
}

//サインアップ
func dbSignup(name string, password string) {
	db, err := gorm.Open("mysql", "root:password@/database_name?charset=utf8&parseTime=True&loc=Local")
	if err != nil {
		panic("Signup失敗")
	}
	var users Users
	if err := db.Where("name = ?", name).First(&users).Error; err == nil {
		panic("すでに同じ名前が使われています")
	} else {
		db.Create(&Users{Name: name, Password: password})

	}
	defer db.Close()
}
～～～～以下略～～～～
```

## 解説

- DBとの接続には[**gorm**](https://gorm.io/ja_JP/docs/index.html)というのを使っています。日本語のドキュメントもしっかりとあったので、非常にわかりやすかったです。
- ルーティングのは[**gin**](https://github.com/gin-gonic/gin)というのを使っています。すごく単純に見やすくルーティングができて、標準パッケージが理解できなかった僕からしたら最高でした。

`main.go`というのはルーティング、`userDB.go`というのはユーザのログイン関係について書かれています。

# Goのいいところ
ここからはGoで開発してみた結果、感じたこと,良かったと思う点について話していきます。

- エラーが見やすい
- 戻り値の使い方がおもしろい
- とりあえず早い
- いろんな書き方がある
- 自動でインデント整理してくれる(VScode)
- いろんな機能をgithubより追加できる
- 自分好みのファイル構造にできる

パッと出てきたのはこのくらいですね。

Goではエラーハンドリングをif文で`err := 処理`みたいに定義した`err`を`err != nil`とエラーがあるかないかで判断します。
これを忘れるから嫌という人もいるらしいですが、基本的にエラーが出るので大丈夫かと思います。

# Goの悪いところ

- 書き方が無限過ぎて、参考にならないページが多い(と思う)
- 書いている人が少ない

振り絞ってこのくらいだと思います。

Goには色々なパッケージがあるので、ルーティングだけでも何個もやり方があります。そういったことから、同じようなコードというのはほぼほぼないのかなと思います。
あと、実装している企業さんも少ないようなのでそれも悲しい点です。


# 感想
とにかくGoに出会えてよかったなと思います。この前Laravelを触りましたが、ファイル構造も自分の好みにできなくて少し面倒でした。
これを気にGoを使ってもらう人が増えてもらえればなと思います。

気が向いたらコードの完全解説やDocker環境構築とかもしたいですね

ではではー