Go

Goでwebサーバー作るときに考えたこと

More than 1 year has passed since last update.

Goでwebサーバーを作るときに考えたことをまとめておきます。
dockerコンテナで動かす場合を少し考慮してます。

フルスタックフレームワークか軽量系フレームワークか

最初に突きつけられる問題です。

どんなフレームワークもそうですが、フルスタックなフレームワークならば、
その道に乗っかることで余計なことを考えずにすみます。
だけどその道から外れることをする場合に苦労が伴います。

golangの場合、Go初心者ならばフルスタックでもいいけれど、
ある程度Goに慣れてくると標準のライブラリといくつかのライブラリを使うだけで
webサーバーを作る場合、十分な場合があります。

前にrevelを使っていたときは、最初はrevelの機能を使っていたけれど、途中で他のライブラリを使ったほうが楽なんじゃないかとなり、少しずつrevelの機能から離れていったことがあります。

今なら自分は、gojiが一番手っ取り早いと思ってます。

なので、ここからは軽量系フレームワークを使った場合の話になります。

Command Line

flagは標準で用意されているライブラリ。
kingpinやcliだとそれに加えて、サブコマンドの設定まで一括で設定することができます。

考慮するべきは

  • flagのように1つ1つ設定するか、codegangsta/cliのように一括で設定するか
  • 環境変数で設定できるか

dockerを使おうとするとIII. Config - The Twelve-Factor Appにある通り、環境変数で切り替えしたくなってきます。その場合、flagでは無理なので、os.Getenvの選択肢がでてきます。codegangsta/clialecthomas/kingpinは指定すれば環境変数の値を使うことができます。

--helpとかで、何が使えるか出てきたほうが便利だよね、と。

alecthomas/kingpinのほうが1行ずつ確認できるので個人的には好みです。

タスクランナー

  • Makefile

Goは有能なタスクランナーはないので、Makefileが一番手っ取り早い気がします。gulpでもnpmでもrakeでも他に乗っかるとかはご自由に。

webフレームワーク

ウェブフレームワークを選ぶ上で、必要となったのは大きく4つあります。

  • http.Handler をサポートしているか
  • ServeMux (いわゆるルーティング)
  • context
  • Graceful

gojiの場合、一通りサポートしてくれているので楽です。
ただ、contextを使うときにweb.Cにロックインされるのが少しネックです。
それが嫌なら golang.org/x/net/contextを使えるように考えたほうがいいです。

その場合ルーティング処理とhttp.Handlerを分けるためにgithub.com/julienschmidt/httproutergorilla/muxなどのrouterまわりのライブラリの検討が必要になります。

もしくは kami などの検討になりそうです。(さわったことない)

Context

golang.org/x/net/contextのほうがよく見かける印象があります。

Gracefull shutdown

両方とも、コード量多くないのでお好きなほうをって感じです。

Logger

ポイントは、エラーレベルの制御とか、log rotationできるかとか、パフォーマンス問題ないかあたりでしょうか。

siupsen/logrusはlogrotateをアプリケーションレベルでやるべきではないって方針。
cihub/seelogはlogrotate機能が含まれています。

dockerコンテナで動かす場合、stdout/stderrに流し続けることになりそうなので、あんまり深く考えなくても良いかもです。(参考:Collecting Docker Container stdout/stderr Logs)

Template

golangの標準は html/template

テンプレート内で演算ができないため、複雑な演算系の関数はあらかじめ作成して登録しておく必要があります。

あまりどれも使い勝手が良くないので、マークアップエンジニアと呼ばれる人が書くイメージがつかないです。なので、GoはAPIサーバー作るのは良いけど、ウェブサーバー作るのにはツラいこと多そうな気がしてます。

テストアサーション

go testの補助くらいで testify。

Config

上でも書きましたが、Dockerコンテナの場合、環境変数で細かく切り替えできたほうが良さそうなので、コンテナで動かさないときだけ使います。

1回読み込んだら、それを使いまわせるようにするだけなので、configファイルをどの形式で読み込むようにするかの問題になると思います。

DB Client

DBのクライアントは、

の2つは必須で、あとはORマッパーやらSQLビルダーを使ったり使わなかったりする選択をしていきます。

上の2つだけだと、ORマッパー的な使い方ができないのもそうですが、結果を取り出してそれを値に詰めるところが面倒だったりします。

参考 golangでSQLを叩くライブラリまとめ[基本/クエリビルダ/ORM]

例えばPostgreSQLを使う場合、こんな風にいろいろ組み合わせを考えることになります。

よく見かけるgorpは、他のORMとは若干使い勝手が違っていて、
プライマリキーの指定以外でデータ取得したい場合、SQLを書く必要があります。

また、selectのカラムが指定した構造体に無いとエラーになるので、SELECT *は利用側で禁止みたいなローカルルールを立てる必要がありそうです。

ORMも、go-xorm/xormだったら、int8使えないとか、正しくタグを設定しないとincrement後のidが取得できないなど、中身を読まないとハマるポイントがあるので、大きいものを使うならば、それなりの覚悟が必要な気がします。

大きいORMを使わなければ、こんな組み合わせになると思います。

  • database/sql (DBアクセス)
  • lib/pq (PostgreSQL Driver)
  • lann/squirrel (クエリビルダー)
  • gorp (結果のScan + Insert, Update, Delete, PK使った処理とか)

migration

あんまり良いのないんです。ほんと。
(参考 Go製マイグレーションツールの現状確認)

Redis Client

redis公式にいろいろある(http://redis.io/clients#go)ので、好きなのどうぞと。

Debug

debugger

  • mailgun/godebug 最近出てきた。breakpoint打てる。それなりに使えるかも。

pretty printer

pp が色つき。

まとめ

まだ書いていないものが、いろいろありそうな気がするので、また何か思いついたら追記していきます。