絶品ゆどうふのタレ

ふと気づいたことを綴るだけのメモ

Go Conference 2014 autumn に参加してきた

GoCon2014秋にいってきたよ! とりあえず、まとめと見つけられた分のスライド載せました。

先にまとめ

  • 朝から全開で実用的な話が多く、ためになる話多かった。
  • Goの哲学をRob Pike先生本人から聞けるなんてなかなか無いですよね。
  • 8時間ハードだった
  • ケツ痛い
  • 英語力磨かねば。。。
  • スタッフの皆さん、発表者のみなさま、会場+協賛をしてくださった楽天さん、Klabさん。素晴らしいイベントを有難うございました!

Keynote

  • Rob Pike

Goはなぜ成功したか

  • シンプルさ、こそが本質
    • 他の様々な言語は、複雑すぎる
  • 各言語は、他の言語のいいところを吸収しあうことで大きくなり、複雑化して発展してきた

  • Goはそれをしない

  • Go1の時点で言語機能は固定化された。

    • 色々な機能を追加してほしい、という声がある、が、それは追加しない。
  • もちろん、いくつかの機能は必要

    • 正しい機能を実装する!

可読性

  • プログラミングにおいて非常に重要

  • 言語が難しいことによって、様々なやり方が生まれてしまい、あとで何故コレが動くのかわからなくなる。

  • 言語がシンプルなら、書き方は絞られる。

  • 可読性は信頼性

  • 表現力が高いからといって、可読性が高いとは限らない。

  • 実装コストが高くなったり、パフォーマンスも予測しづらくなる。

正しい言語機能

  • 機能のための機能ではない
  • 目的を正しく認識し、必要な機能を

Goの目的

  • サーバソフトウェアを強力に作るためのもの
  • 各要素がそれぞれ単純に組み合わさっている

  • Gopherってシンプルだよね!(笑

単純さ

  • Goは実際には複雑だけど、シンプルにする仕組みがある
    • GC
    • goroutines
    • constant
    • interface
    • package

GC

  • 複雑さを隠す最たるもの
    • コレのお陰で、コードがシンプルに書ける
  • メモリの管理や、データのやり取りの厄介なことを隠蔽してくれる

並列性

  • プログラムを独立実行しているようにかける

    • goroutine
    • channel
    • select
  • goroutine

    • go function(arg)とかくだけ。シンプル
    • プログラマの考えることをぐっと減らしてくれる
      • スタックサイズがない
      • return, exit statusがない
      • 管理機構がない
      • IDを持っていない
    • スタック管理はGCに依存

定数

  • ただの数!!
    • 無限の精度整数型
    • 無限の浮動小数点型
    • etc...
  • 完璧にできてるわけではないが、かなり普通の数字のようになってる
  • こうすうるのはややこしかったけど、その代わりGoはシンプルになった

interface

  • メソッドの集合体
    • 想像以上に複雑
  • アサーションと型switchは本来の予定にはなかった

  • Goの最も特徴的な機能

    • io.Reader / io.Writerなどは、パイプのように扱えて、複雑さを隠蔽した

package

  • ライブラリ構成の設計
  • これの設計には非常に時間がかかった

まとめ

  • 単純さは設計が難しい
  • コレのために戦う価値がある

Goに入ってはGoに従え

  • うかいさん
  • Goの可読性について

Go Readability Approver

  • Go言語のReadabilityをレビューするチーム
    • より良いGo言語の書き方を教える
    • メインのプロジェクトではないコードを見る

Readabilityスキルとは

  • プログラミング言語リテラシ
  • 言語ごとに作法が違う

    • C++ではプロジェクトごとに作法が違う。。。
  • 他の言語で考えると「この機能が足りない、書きにくい」となってしまう。

Goのコード

  • 明瞭・簡潔
  • 使いやすいAPI
  • 適切なコメント
  • 素直なコードフロー
    • goroutineなどのお陰で、コードの流れが読みやすくなる。
  • コードの実装を読むのに、Goの実装を読むのが一番理解しやすい。

優れたツール

  • ツールによるサポートを常に適用するカルチャー
    • go fmt
    • go vet
    • golint
    • godoc

ツールだけでは十分ではない

  • 読みやすいコード == 情報が認識しやすい/脳に負担がかからない
  • Goはシンプル

Readability Reviews

  • ミス・バグチェック
  • 見やすくレイアウトされているか
  • コードフローはわかりやすいか
  • APIはわかりやすいか

  • 気になってきた点を紹介

ミス/バグ

errorチェック

  • regex.Compileのerrorチェックを飛ばす人がいる
  • regex.MustCompileでエラーチェック

    • やっていいのは、初期化の時(varかinit())のみ
  • deferを使ったcloseのチェック

    • close自体もエラーチェックする
  • 値自体で-1がエラーみたいな判定をさせるのではなく、値とエラーを分ける。

    • error毎のデータを定義して、それを判定する
  • errorの設計

    • エラー処理の区別が不要なら、fmt.Errorfかerrors.Newで作って返す
      • err != nilでチェック
    • 色々情報を含めたい場合
      • structにエラー情報を含めて処理
    • panicは使わない
      • どうしても使いたいなら、packageの中にとどめて、recoverした上で外部にはerrorで返す
  • nil error

    • 値と型が共にnilの場合
    • 間違えやすいので注意
  • interface実装の型チェックには、structにinterfaceを実装するのではなく。。。

    • _ scan.Write =などのようにすることで、型チェックだけできる

見やすく

  • structフィールドのレイアアウト
    • 関連が深いものをブロックに分ける
  • 長い行
    • 長さ制限はないので、1行に
    • なので、名前は簡潔に
      • 与えられたコンテキストのなかで、わかり易い名前にする
      • 長い名前がわかりやすいわけじゃない
    • 冗長な名前をさける
      • レシーバ変数は数文字で良い

素直なコードフロー

  • 基本のコードパスのインデントは最小に

    • errorの分岐もシンプルに
    • funcを分割したり
    • if else並べるぐらいならswitch
  • time.Duration

    • constは型を持たないので、time.Durationにする型変換は不要
  • chanを使えば、sync.Mutex, sync.Condが不要な時がある

  • 型がわかっているようなときにreflectを使わない

テストコード

  • わかりやすいテストメセージ
  • 独自アサート関数を定義するより、言語の機能を使う
  • コメントにAPIの使い方を書くくらいなら、Exampleテスト

コメント

  • packageコメントを書く
    • mainパッケージは、コマンドのコメント
    • Exportしている名前にはコメントつける
    • 対象の名前を先頭に
  • コメントがわかりにくかったり書きにくい場合は、API設計を考えなおした方がいい

  • APIデザイン

    • 適切な名前のpackageを作る
  • APIをシンプルにする
    • 返り値は複数使えるので、出力変数としてポインタを使わない
    • Cとかでよくある
  • 非同期APIより同期API
    • chanをpackageを超えて使わない
    • 非同期化は使う側がgoroutine + chanで制御

読みやすいコードを書くには

  • 明瞭に表現すること

質問

  • 名前付き戻り値について、いつ使うか
    • コメントで補足しないとわからなくなるような場合(string, string, intなどのようになって、1つめ2つなんだっけ?としまう場合)
    • deferの中で、返り値を弄りたい場合などは、名前がついていないとそもそもいじれない

Gardner & Go

  • Tシャツ作ったよ
  • とあるゲームの色を。。。w
  • FreeGuhoでEC販売してるよ
    • 1500 + 160だよ
  • Golang Tシャツもあるよ
    • 2500 + 160

App Engine for Golang Preformance

  • 普段はApp EngineでJava書いてる

App Engine for Go

  • 最初の呼び出し部分はmain()じゃない
  • init() -> http.HandleFunc("/", handler)とかしていく

App Engine for Goの微妙な所

  • Version upが遅い
  • GOMAXPROCS = 1限定
  • Goが本気出せない

Managed VMとは

  • Google Compute Engine上でApp Engineのコンテナを動かす事ができる
    • dockerで動いてる
  • GOMAXPROCSも挙げたりできる

    • 本気出せる
  • 微妙な点

    • deployが遅い
    • autoscaleの最小値が1
      • 常時課金発生

Performance

  • GAE
    • golang
      • 時間が経つと、何故か遅くなったのでちょっと要調査
    • Java
      • 最初からぐっと遅い
      • goの方がおねだん半分ぐらいで済みそう
  • Managed VM
    • 比較側のJavaがほぼ死んでる。。。
    • Betaなので。

Golang@ISUCON

なんでGo?

  • 改善効率の高さ

取り組んだこと

  • プロセスキャッシュ
  • タスク分散処理

プロセスキャッシュ

  • データをプロセス上に全て保持しておく
  • 永続化は適度なタイミングでRedisに保存したりする

  • グローバルに変数置いて。。。とかやると、Goroutine複数作ると整合性の保証が必要になる

  • Race Condition

  • syncパッケージ

    • 各種ロックを使う
    • sync.RWMutek
    • sync/atmic
  • atomic.Value

    • golang 1.4
    • プロセス上にatomicにデータ更新できるストア
    • シンプルにかける

タスクの分散処理

  • 画像・動画などは重複処理したくない
  • Task Queueing

    • goroutineとchannelでそのまま使える
    • goroutineの本数で調整できる
  • 重複処理

    • 1台の場合
      • sync.Cond
    • 複数台の場合
      • sync.Condを複数
      • mcondつくった
  • 処理先を振り分ける

    • consistent hashライブラリ
    • stathat/consistent

mackerel-agent徹底解説

Mackerel

  • サーバ監視・管理ツール
  • エージェントがGo

mackerel-agentとは

ソースコード解説

  • 外部への依存: tomlを利用
  • windowsで動かなくなるオチを防ぐため、シグナルハンドルではos.Interruptを使う

  • chan chan

    • チャンネルでチャンネルを渡す
    • 複雑なので、シグナルハンドルもメイン処理に入れたほうがいいんじゃないか?というのはある
  • loopの状態管理

    • enumっぽくtype作って処理
  • なんか色々改善点あればご指摘ください

Why my Go program is slow?

  • methaneさん
  • CPUプロファイラの話

runtime/pprof

  • サンプリングプロファイラ
    • モンテカルロ法に似てるやり方だよ
    • 計測方法として、実行時のサンプルを大量にとって、重い箇所を特定する
  • net/http/pprofなんかがHTTPではおすすめ

  • 解析するプログラムもpprofという名前

  • Go 1.3からCLIにbundle(Perl版)

  • Go 1.4からはGo版になってる
    • ぐっと便利になってるので、ここだけでも1.4にするといいよ

デモ

  • webで展開できたり、アセンブリ単位で見れたりしてすごい

どこが重いか

  • GC
  • memory copy
  • function call

GC

  • GOGC=400とかすると、急激な負荷に唐突に突っ込むとGC頑張っちゃって負荷が高くなってしまうので、それを遅くする

memory copy

  • 文字列便利だからってコピーしまくると大変
  • []byteとか使おう

function call

Golang JP Community

  • 日本のGolang JPのコミュニティの紹介

Go at Gengo

  • Gengoの中の人
  • 中でめっちゃ使ってる

the early days

  • GoShip

    • Goベースのデプロイメントツール
    • なぜGoを使った?
      • productionに入れる前に、試しに作ってみるのに調度良かった
  • Go API

    • シンプルなPHP(CodeIgniter)のエンドポイントを持っていたが、これをGOに移植した
    • 500 ms -> 10ms になった
    • 今では78%のAPIがGoに置き換わった
  • どこから入れるべきか

    • まず、クリティカルじゃない所から入れよう
    • 全てを一度にrewriteしようとしないほうがいいよ

Dive in

  • Managing dependencies

    • まず試したのはここら
      • go get
      • gom
      • godep
    • 結局シンプルなshellscriptになった
      • godepが標準ぽいけど。
  • Test Fixtures

    • reflectをつかって頑張ってる
    • Gorpの`Insertable`を使うと簡単にできる
    • LoadFisturesみたいなの定義して使ってる
    • ただ、fixtureテストが並列化できないよね
      • go test -p 1してる。。
  • Quick Wins

    • graceful shutdownの例
    • gofmt -s / gofmt -w は走らせよう
    • go test -race / go importsしよう
    • go vet 大事

One Year Down

  • 抱えてる問題
    • logging
    • slow build times
    • test fixtures

NSQ-Centric Archtecture

chatサーバをGoで

  • Go + webview + websocket

NSQ

  • message queue
  • SPOFなしでスケーラブル
  • プッシュ型のメッセージ通知

    • データフォーマットはなんでも良い
  • 問題点

    • メッセージが1回以上とどく
    • 順序保証がない
  • NSQのアーキテクチャの話

  • 自作したChatアプリのアーキテクチャの話

  • 面白そうだけど。。。話が飛んじゃって流れがわかんなくなった。。。

Hacking Go Compiler Internals

  • moriyoshi

対象の人

  • Go に拡張いれたいなー、コンパイラーどうなってんのかなーって人

Lexer

  • Goのコードをより抽象的なデータ構造に変換する

  • どういう時にLexerを弄りたいか

  • UTF-8の関数怒られた(寿司)

  • これを追加したい!
  • なんてことをやってみた

Parser

  • Lexerが作ったTokenを抽象構文木(AST)に変換する
  • yaccで作られてるよ

  • Braket operator overloadの例

  • print()関数はdebugの時に便利だよ

    • printfっぽいやつ

Roll-up

  • 一見大変そうだけど、中身は凄くシンプルでhackしやすいよ!

nginx-build

  • bokkoさん
  • mercariのひと

本題

  • Go製のnginxビルドツール

  • nginxのビルドするのがつかれたので、作った

  • nginxのビルドは、現実的にはいろいろなものをダウンロードしてきたりしないといけない

  • configure optionsを大量に追加しないといけない
  • しかもそのビルドスクリプトをメンテしないといけない

  • これらまとめて解決してくれる

使い方

  • binary を持ってきて、mkdir work -> nginx-build -d work みたいにする
  • 3rd partyモジュールを、iniファイルに指定しておくと、まとめてダウンロードしてくれる

なんでGoで?

  • Go好きなので
    • 並列ダウンロードが楽
    • CLIツールを書くのにすごく適してる

Terraformで始めるGo言語

楽天のInfrastracture as Code

  • サービスいっぱい = サーバの種類が多い
  • 最下部のインフラ層に向いてそうなterraformがリリースされたので使ってみた

Terraform

TerraformとGo

  • Terraform Plugin開発
  • v2.0からフレームワーク機能をサポート

  • やりやすいから、このへんから始めてみては。

Goでビルドパイプラインツールを書いた話

なんでGo?

  • ジョブの実行をgoroutineで
  • データの受け渡しをするのにchannel
  • このへんが扱いやすそうだったので

その他Tips

  • プロジェクト構成について

    • coreos/etcd を参考にした
    • テスト、ビルドはshell
  • package管理

    • submoduleでやってたけど辛かった
    • Godep
  • ログ出力

    • どこも軒並み自前で用意してた
    • golang/glogを利用

Goの所感

  • Object指向的な書き方をしてしまって、ぎこちない感じになった
  • channelをつかってみた、厳しくなったらsync.Mutex

go/parser go/astの話

I/Oに依存したテスト

I/Oに依存したテストをどうするか

  • RubyだとStringIO
  • Goでは、bytes.Buffer がある

bytes.Buffer

  • []byteにいろいろメソッドが生えた感じ
  • io.ReadWriter

  • テストコードの実践

ポイント

  • I/O依存部分を切り出す
  • インターフェースに依存して書く

  • ここまでー

Destributed system

  • marioさん
  • 分散システムの話

Consul

  • 実装の例の話