Skip to main content
堀内 晨彦
@hico_horiuchi
  による
Webアプリ開発のキホン
Go
16/02/27 2
よろしくお願いします
まずは自己紹介から
自己紹介
Akihiko Horiuchi
香川大学 修士2年
bit.ly/hiconyan
Emacs / Ruby / Rails / Golang
Hubot / Sensu / Ansible
研究室のインフラと掃除担当
github.com/sai-lab/mouryou
github.com/sai-lab/mouryou-web
16/02/27 3
こんなことやってます
●  Sensu Deep Talks(東京)
●  Hubot×ChatOps勉強会(大阪、神戸)
16/02/27 4
16/02/27 5
   でWebアプリを
開発するメリットは?
Go
GoでWebアプリを開発する メリット
●  インタプリタと比較して 高速・軽量
○  Railsより50倍の速度と10倍の省メモリという話も[1]
●  並列処理 が簡単
○  goroutine(スレッド)と channel(メッセージパッシング)
○  go func() のように go を使うだけ
●  シングルバイナリ でデプロイ
○  コンパイルしたバイナリをアップロードするだけ
○  ライブラリのインストールなどが不要
○  コンテナ や マイクロサービス との親和性が高そう
16/02/27 6
[1] https://plus.google.com/+MattAimonetti/posts/PeZk8FY3PWY
GoでWebアプリを開発する メリット
●  コーディング規約 を統一
○  gofmt(goimports)で強制的に直される
○  可読性が上がる、チーム開発がスムーズになる
●  標準でテストをサポート
○  関数をテストする関数を *_test.go に書く
○  あとは go test で実行するだけ
16/02/27 7
func TestSum(t *testing.T) {
actual := Sum(10, 20)
expected := 30
if actual != expected {
t.Fatal("want", expected, "got", actual)
}
}
Goの採用事例
●  犬猫10秒動画共有アプリ「mofur」
○  「Sleipnir」のフェンリルが開発
○  アプリとWebのバックエンドでGoを採用
●  Webサイト無料製作サービス「Ownd」
○  「Ameba」のCyberAgentが開発
○  決め手は 可読性 、フレームワークとして Revel を採用
16/02/27 8
16/02/27 9
Webアプリの開発で
必要なコト、考えるコト
Goの 動物図鑑 が出ました
○  チャットアプリの作成
○  WebSocket、OAuth
○  コマンドラインツールの作成
○  ミドルウェアとの連携
○  Twitter、Googleとの連携
○  REST APIの公開
○  Goの開発環境構築
などなど
基本を押えた内容で
これからGoでWebアプリを
開発する人にオススメ
16/02/27 10
必要な コト 、考える コト
●  Webアプリケーションフレームワーク
○  RubyならRails、PythonならDjango、Goは?
○  デザインパターンは Model・View・Controller ?
●  データベース周りのコト
○  マイグレーションツールは?( rake db:migrate とか)
○  ORマッパーは?(ActiveRecordとか)
●  Viewは? テンプレートエンジンは?
○  標準で "text/template" と "html/template" が付属
○  でも Slim とか Haml とか使いたい
16/02/27 11
16/02/27 12
今日は    による
「Webアプリ開発の基礎」
「オススメのパッケージ」
をご紹介します
Go
16/02/27 13
ココカラが本題です
"net/http" のキホン
●  シンプルなWebサーバを作る
○  http.HandleFunc でルーティングを定義
(ただし "/users/:id" のようにパラメタは取れない)
○  http.ListenAndServe でWebサーバを起動
○  ログ出力は "log" を使って自分で書く
16/02/27 14
func main() {
http.HandleFunc("/",
func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, World!")
log.Printf("%+vn", r)
}
)
http.ListenAndServe(":8080", nil)
}
Webアプリフレームワーク
●  GoのWebアプリフレームワークは 戦国時代
○  まだデファクトスタンダードが決まってない
○  シンプル なモノから フルスタック なモノまで[2]
○  "net/http" をベースに機能を拡張したものが多い
16/02/27 15
シンプル
(ルーティングのみ)
フルスタック
(セッションなど)
github.com/zenazn/goji
github.com/gin-gonic/gin
github.com/gorilla/mux
github.com/revel/revel
[2] http://qiita.com/najeira/items/bdc988c4e93b3b5ccf2f
Webアプリフレームワーク
●  Goji( github.com/zenazn/goji )
●  Gorilla( github.com/gorilla/mux )
16/02/27 16
router := goji.New()
router.Get("/:name", handler)

func handler(c goji.C, w http.ResponseWriter, r ...) {
name := c.URLParams["name"]
fmt.Fprintf(w, "Hello, %s!n", name)
}
router := gorilla.NewRouter()
router.HandleFunc("/{name}", handler)

func handler(w http.ResponseWriter, r *http.Request) {
name := gorilla.Vars(r)["name"]
fmt.Fprintf(w, "Hello, %s!n", name)
}
GoでDBのマイグレーション
●  goose( bitbucket.org/liamstask/goose )
○  マイグレーション:DBのバージョン管理のこと
(テーブルの作成、カラムの追加、ロールバックなど)
○  マイグレーションのスクリプトは SQL かGoで書く
○  create 、up 、down コマンドを使って管理
16/02/27 17
$ goose create create_posts
goose: created db/migrations/20160226202023_create_posts.sql

$ goose up
goose: migrating db environment 'development', ...
OK 20160226202023_create_posts.sql

$ goose down
goose: migrating db environment 'development', ...
OK 20160226202023_create_posts.sql
gooseのマイグレーションファイル
●  マイグレーションファイルのサンプル
○  up・down に対応するSQLスクリプトを書く
○  Goで書く場合は sql.Tx.Exec でSQLを実行
○  IDの AUTO_INCREMENT や PRIMARY KEY の設定を忘れずに
16/02/27 18
-- +goose Up
-- SQL in section 'Up' is executed when this migration is ...
CREATE TABLE IF NOT EXISTS `posts` (
`id` INT NOT NULL AUTO_INCREMENT,
`title` VARCHAR(255) NOT NULL,
`body` TEXT NOT NULL,
PRIMARY KEY (`id`)
);

-- +goose Down
-- SQL section 'Down' is executed when this migration is ...
DROP TABLE `posts`;
DBから構造体にマッピング
●  ORM(Object-Relation Mapping)
○  DBのタプルをGoの 構造体 に変換するもの
○  WAFと同じく シンプル なモノと フルスタック なモノ
○  マイグレーションもできるものが多い
16/02/27 19
type Model struct {
ID uint `gorm:"primary_key"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt *time.Time
}

type User struct {
gorm.Model
Name string
}
ORマッパーのサンプル
●  GORM( github.com/jinzhu/gorm )
○  かなり 高機能 でActiveRecordに近い使用感
○  First などの便利な関数、クエリの連鎖も可能
●  genmai( github.com/naoina/genmai )
○  機能はシンプルでクエリビルダに近い
16/02/27 20
db.CreateTable(&User{})
user := User{Name: "Kagawa"}
db.Create(user)
db.Where(&User{Name: "Kagawa"}).First(&user)
db.CreateTable(&User{})
user := User{Name: "Kagawa"}
db.Insert(&user)
db.Select(&users, db.Where("name", "=", "Kagawa"))
"html/template" のキホン
●  テンプレートを使うハンドラーを作る
○  構造体 をテンプレートに渡して {{}} で展開
○  template.ParseFiles でファイル読み込みも可能
type Page struct {
Name string
}

func handler(w http.ResponseWriter, r *http.Request) {
tmpl, _ := template.New("tmpl").Parse("Hello, {{.Name}}!")
tmpl.Execute(w, Page{Name: "Golang"})
}

func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
16/02/27 21
テンプレエンジン Ace を使う
●  Ace( github.com/yosssi/ace )
○  SlimやJadeにインスパイアされてる
○  ace.Load すると *template.Template が返ってくる
○  部分テンプレートにも対応( render partial 的な)
16/02/27 22
= doctype html
html lang=en
head
title Hello Ace
= css
.blue { color: blue; }
body
h1.blue {{.Msg}}
p..
Ace is an HTML template engine for Go.
= javascript
console.log('Welcome to Ace');
Goのパッケージマネージャ
●  Godep( github.com/tools/godep )
○  Godeps.json に従って Godeps/_workspace に保存
○  Herokuなどでも採用され、ほぼスタンダード?
●  gom( github.com/mattn/gom )
○  使い勝手はほぼ Bundler + Gemfile と同じ
○  gom install 、gom exec 、gom build 、など
16/02/27 23
{
"Deps": [{
"ImportPath": "code.google.com/p/go-netrc/netrc",
"Rev": "28676070ab99"
}]
}
gom の使い方
●  Rubyist なのでgom推し
○  Gomfile を書いて gom install するだけ
○  パッケージをtag、branch、commit で指定可能
○  _vendor ディレクトリにパッケージが保存される
16/02/27 24
gom 'github.com/yosssi/ace'
gom 'github.com/zenazn/goji'

group :development do
gom 'github.com/pilu/fresh'
gom 'golang.org/x/tools/cmd/goimports'
end
$ gom install
downloading github.com/google/go-github/github
downloading github.com/yosssi/ace
...
ビルドツールで快適に開発
●  Fresh( github.com/pilu/fresh )
○  ソースコードの変更を検知してリビルド
○  変更の反映にコンパイルが必要なGoの強い味方
○  JavaScriptだとGrantとかgulpみたいな感じ?
○  監視する拡張子と間隔を設定できる
16/01/23 25
$ gom exec fresh -c runner.conf
Loading settings from runner.conf
22:7:30 runner | InitFolders
22:7:30 runner | mkdir ./tmp
22:7:30 runner | mkdir ./tmp: file exists
22:7:30 watcher | Watching .
22:7:30 watcher | Watching app
22:7:30 watcher | Watching app/controllers
22:7:30 watcher | Watching app/views
16/02/27 26
デモンストレーション
今回のポイント・工夫
●  GojiでMVCデザインのAPIサーバを作成
○  これまでRails + Grapeで開発していたので
○  Viewはヘッダー・ナビゲーションバー・フッターのみ
●  フロントエンドはMithril.jsで作成
○  MVCデザインのJavaScriptフレームワーク
○  仮想DOM 採用で、Reactよりも 高速・軽量
○  モデルはAPIから返ってきたJSONをそのまま使う
○  ソースコードはバイナリ化してGinで配信
バックエンドはGoで最速のフレームワーク
フロントエンドもJavaScriptで最軽量のフレームワーク
16/01/23 27
シェルスクリプトマガジン
●  「香川大学SLPからお届け!」シリーズ
○  Vol. 33 Go言語とMithril.jsでWebアプリ開発 バックエンド編
○  Vol. 34 Go言語とMithril.jsでWebアプリ開発 フロントエンド編
○  (Amazonで著者セントラル作りたい…)
16/02/27 28
GoでJSONなRESTful API
●  GoでJSONを使うのはカンタン
○  雛形になる 構造体 を定義してエンコード・デコード
○  HTTPハンドラのBodyでJSONを書き込めばOK
○  GojiとGORMを使った場合のイメージ
16/02/27 29
router := goji.New()
router.Get("/api/users/:name", handler)

func handler(c goji.C, w http.ResponseWriter, r ...) {
var user User
name := c.URLParams["name"]
db.Where(&User{Name: name}).First(&user)
bytes, _ := json.Marshal(user)
fmt.Println(w, string(bytes))
w.Header.Set("Content-Type", "application/json")
}
kakuzuke
GitHub current streak runking of your followees
http://kakuzuke.hiconyan.com/
https://github.com/hico-horiuchi/kakuzuke
16/01/23 30
yosage
Web application of LGTM gif generator
http://yosage.hiconyan.com/
https://github.com/hico-horiuchi/yosage
16/01/23 31
16/02/27 32
まとめ
まとめ
●  GoでWebアプリを開発するメリット
○  高速・軽量、並列処理、デプロイ、規約、テスト
○  バックエンド( API )での採用が多い
●  MVCデザインで考える
○  Model :Goの 構造体 と ORマッパー で定義
○  View :標準の "html/template" で十分、Aceも
○  Controller:HTTPのハンドラとして実装
●  完成までに必要なこと
○  認証( OAuth など)、セッション(Cookie)
○  セキュリティ対策(CSRF、SQLインジェクション)
16/02/27 33