go言語のいいところ・惜しいところ


2020年は基本的にgo言語で開発していました。
私のgo言語歴も2年を超えて少しはわかった気がするのでほかの言語と比べていいなって感じた点とちょっと残念に感じた点をまとめてみようと思います。

画像2

1. インストールが簡単

私がgo言語で何よりも気に入っている部分です。
どこでもインストールできて、Linuxならtar ballを解凍するだけ、windowsならmsiを実行するだけでインストールでき、エラーなく動くのは感動ものです。
言語によっては最新版はソースからインストールしないといけなかったり、その際環境によってはたまに失敗したりなどハードルが高いものもあるため、go言語が簡単に試せるというのは本当に最高です。
入門の入り口が低いというのは個人的にはかなり評価できる点だと思っています。

2. 公式ドキュメントが充実

go言語は非常にドキュメントが充実しています。例えば標準packageはhttps://golang.org/pkg/にまとまっています。
例えば、その中のioパッケージを見てみると、まずパッケージに含まれる関数の一覧がすべて載っており、それぞれごとに説明がついています。説明の中にはExampleという項目があるものも存在し、ここで実際に挙動を試すことができます。
さらに説明でだけではいまいちわからない場合は関数名を押すと直接goのコードに飛べるので中身をすべて追えます。
そのため、困ったときにはここを見ればいいのでコーディング中に迷う時間を節約できます。
初心者向けにはA Tour of Goというページもあり非常にチュートリアルも充実しています。このサイト内でも実際にgoのコードを試せるので、ほんとに至れり尽くせりといった感じです。

画像1

3. シングルバイナリができる

go言語ではビルドすると単一のバイナリのみが生成されます。
つまり例えばwindows環境でビルドするとexeファイルが1つだけでき、その他のファイル(例えばdllファイルなど)は一切できませんし、実行時に必要になりません。
これは作成したものを配布するときに非常に便利です。相手にexeファイル1つのみ渡せばいいため、余計な手間をかけさせることがありません。
同様に開発環境で作成したものを本番環境に適用することも非常に簡単で、リリースの際に余計なことを考えなくてすみます。
また、dockerのマルチステージビルドとの相性も非常によく、go言語の入ったビルドステージでビルドし生成された実行ファイルのみをリリース用のステージにコピーしてやることで、イメージサイズを小さくなりますしDockerfileもシンプルに保っておけます。

4. クロスコンパイルが簡単

go言語のクロスコンパイルはめちゃくちゃ簡単です。
なぜなら環境変数を1つ指定してやればいいだけですもの。
windows用のexeファイルが欲しければ環境変数でGOOSを指定してやればいいのです。
arm用のバイナリが欲しい?だったらGOARCH=armを設定してgo buildをたたけばいいのです。
あとは何も考えなくてもgoがいい感じに作ってくれます。

# 例
export GOOS=windows
export GOARCH=arm
go build

5. 周辺ツール(linterやfomatterなど)が充実

rubyのrubocopやpythonのautopep8のようにほかの言語にも素晴らしいツールはいろいろあります。
しかし、go言語の場合はインストール時にデフォルトでついてきます。フォーマットしたければgo fmtってたたけばフォーマットしてくれます。
go言語の場合は基本的にformatterやlinterの細かい設定をすることはできません。有効にするか無効にするかです。
これについて否定的な意見がある人もいるかもしれませんが私は結構好意的です。細かく設定できるということは個人によって差が出ることになります。複数人で開発する場合は誰かに合わせないといけなくて、もめる原因になります。そのため、必要のないところでもめないので設定できなくてもいいかなぁという感じです。
ちなみに普段私はvscodeで開発しているのでvscodeのプラグインを入れておけばファイル保存時に自動でフォーマットしてくれてるため、余計なことを考えずコーディングに集中できるのはうれしいですね。

6. エラーを返せる

これまではgo言語自体というより周辺環境の話だったのでここからはgo言語自体についても触れたいと思います。
ただ、個人的には言語特性はある程度慣れてしまえばどんな言語でもさほど気にならないかなぁって思います。
まずはエラーが返せるという点です。
go言語では関数の戻り値を複数設定できるので以下のように処理結果とエラーを同時に返せます。これによりエラーが返ってくることがコードからすんなりわかるので後から読んでも理解しやすいコードを書くことができます。
言語によってはtry/catchでエラーを扱うものもありますが、関数が例外を投げうる可能性があることをパッと見ただけでわからないような言語はすべてtry/catchできているか不安になるのであまり触りたくはないですね。

// 例
func div(a, b int) (result int, err error) {
  if b == 0 { 
    return 0, errors.New("zero divide")
  }
  return a/b, nil
}

7. 並列処理は書きやすい

go言語にはgoroutine, channelがあり、非常に簡単に並列処理を書けます。以下の例のようにgoを付けるだけで並列処理が書けますし、channelによってスレッド間のデータの受け渡しも簡単です。
ただし、そもそも並列処理は複雑になりやすく、バグを埋め込んでしまいがちであったり、そのバグ自体もタイミング障害のような厄介なバグになりがちなので、使用する場面は十分に考えて使わないといけないですが・・・

// マルチスレッドとチャネルの例
func thread(msg chan string) {
	fmt.Println("thread process ...")
	msg <- "thread message"
}

func main() {
	msg := make(chan string)
	go thread(msg)
	res := <-msg
	fmt.Println(res)
}


go言語の惜しいところ

go言語はいくつものいい点がありますが、すべての面で完璧というわけではありません。ここからは個人的にもうちょっと何とかなるとうれしいなという点を挙げてみようと思います。

1. サーバーサイド以外は弱い

go言語は非常に使い勝手がいいのですが2020年現在サーバーサイド以外(例えばGUIアプリやモバイルアプリなど)は非常に弱いです。
ここからは個人的にもうちょっと何とかなるとうれしいなという点を挙げてみようと思います。この辺りはJavascriptなんかに軍配が上がるのですがあんな闇の言語使わなくてもいいような世界が来るといいなぁという気がしています。

2. ifとかforに()あってもよかったのでは

go言語ではif, forに()は必要ありません。これ自体は問題ないのですが、この記法になれると、たまにほかの言語を触った時に()を忘れてしまって動かなかったので統一してほしかったなというのはあります。

3. 何の関数が実装されているかわかりにくい

go言語にはclassはありませんが、構造体に関数を追加できるためclassのような感じで書けます。ただ、構造体への追加なのであらかじめ定義しておく必要はなく、その構造体にどんな関数があるかはドキュメントなどを見ないとわからないことがあります。
この辺りはinterface型を使うといい感じに書けるのですが、必須ではないので書いて無いコード(かつドキュメントがしっかりしていないコード)に出会うと大変だったりします。


まとめ

流行りだしKubernetesみたいなOSSでも使われているからという単純な理由で始めたgo言語ですが、今ではメイン言語になるくらい使っていて使いやすいのでやってよかったなぁという感じです。
個人的にはサーバーサイドの人にとっては敷居の低い言語だと思うので割とおすすめの言語です。(逆にfrontendだと使う機会は少ないかも・・・)
とりとめのない文章ですが、この記事が誰かの役に立っていれば幸いです。


※画像: Renee French


この記事が気に入ったらサポートをしてみませんか?