覚えたら書く

IT関係のデベロッパとして日々覚えたことを書き残したいです。twitter: @yyoshikaw

Go言語LT大会! 「最近、Go言語始めました」の会に行ってきた #golangjp

Go言語LT大会! 「最近、Go言語始めました」の会に参加してきました。

以下自分用のメモです。


概要

Go言語入門者のLT大会&懇親会

  • 開催日: 2017/6/5
  • 場所: レバレジーズ株式会社


おススメ・標準・準標準パッケージ20選

上田拓也 氏 (メルカリ/ソウゾウ)

  • Go標準のパッケージ
    • 様々な機能が提供されている
      • HTTPサーバ/クライアント
      • 文字列処理
      • 暗号化
      • 画像処理
    • 160パッケージぐらいある
  • Go標準のパッケージ
    • golang.org/xで提供されるパッケージ
    • 450パッケージ以上ある
  • fmtパッケージ
    • 書式付きプリント機能を提供する
    • %T, %q %vあたりが便利
    • %[1]d, %[2]dとかでN番目の値が出せる。引数の順番を指定できる。引数を使いまわすこともできる
    • fmt.Stringerが便利
      • JavaのtoString的な役割のインターフェース
  • ioパッケージ
    • IO関係の基本的な型が定義されている
      • io.Readerとio.Writerが強力
        • インターフェースの良い例
      • io.TeeReaderとかもあり便利
        • UNIXのteeコマンド的なもの
  • io/ioutilパッケージ
    • IO関係の便利関数がある
    • NopCloserが便利
    • ReadAllhあんまり使わない
      • ストリームのままやろう
  • stringsパッケージ
    • 文字列に関する処理を提供
    • strings.Readerが便利
      • 文字列をio.Readerに変換してくれる
    • strings.Fieldsが便利
      • ホワイトスペースでいい感じに区切ってくれる
  • bytesパッケージ
    • strringsにあるものはだいたいある
    • bytes.Readerが便利
      • []byteをio.Readerに変換できる
    • bytes.Bufferが便利
      • ゼロ値で扱える
  • bufioパッケージ
    • bufio.Scannerが便利
    • bufio.SplitFuncでカスタマイズ
  • encoding/binaryパッケージ
    • 構造体とバイト列をマッピングできる
    • Go1.9でmath/bitsが入る
  • x/textパッケージ
    • 日本語の文字コードに対応(EUCJO,Shift-JIS,ISO2022JPに対応)
    • 多言語化の機能を提供
    • transform.TransFormerが便利
      • ストリームのまま変換できる
      • 実際の例を何回か読まないと理解が難しい
  • flagパッケージ
    • コマンドライン引数に関する機能を提供
      • オプションパースが便利
      • flag.Argsでオプション以外の引数が取れる
      • ポインタの使用例としてGood
  • path/filepathパッケージ
    • ファイルパスに関係する処理を提供する
      • \や/を意識しなくてよい
    • filepath.Walkが便利
      • 再帰的にディレクトリを読んでいく
  • text/templateパッケージ
    • html/templateはHTML特化版
    • コマンドライン引数に使うと便利
    • コードジェネレーションにも利用できる
  • testingパッケージ
    • go testでユニットテストが実行できる
    • Go1.7からサブテストが可能
    • テストを並列で実行可能
      • t.Paralellを使う
    • カバレッジが取れる
      • -cover
  • net/httpパッケージ
    • HTTPサーバ.\/クライアントを提供する
      • http.Handlerを実装すればよい
      • インターフェース実装の良い例
      • 重量なWebフレームワークは必要ない
      • テストしやすい
  • net/http/httptestパッケージ
    • HTTPサーバのテストで使える機能を提供
      • ハンドラのテストが便利
      • httpdocも便利
  • syncパッケージ
    • ロックなどの機能を提供
      • sync.WaitGroupが便利
      • sync.Onceが便利
        • 1回だけ実行したい場合に楽
  • contextパッケージ
    • 複数のGoルーチンをまたいだキャンセル機能などに使える
    • context.Contextが強力
      • インターフェースなので拡張しやすい
    • errgroupパッケージも便利
  • imageパッケージ
    • 画像処理を提供するパッケージ
      • image.Imageがインターフェース
        • 実装すればなんでも画像として扱える
      • pngやjpeg,gifなどに対応している
  • x/imageパッケージ
    • 標準パッケージでは足りていない機能を提供
    • x/image/drawが描画機能を提供してくれる
    • フォントに関する機能も提供している
  • reflectパッケージ
    • リフレクションの機能を提供する
      • structタグにアクセスする唯一の方法
      • 使いどころを間違えなければ便利。遅いので乱用はNG
      • 食わず嫌いは良くない
      • パニックが起こりなくるのでちゃんとチェックを行うこと
  • goパッケージ
    • 静的解析の機能を提供する
      • 抽象構文木(AST)が取得できる
      • 式単位でもパースできる
      • 型チェックもできる
      • 自作開発ツールも作ることができる


Go開発合宿2017

@n0bisuke 氏

  • Goを書く合宿
    • いろんな人が集まってわいわいやるコミュニティ
  • 合宿場所にした土善旅館は開発合宿プランを用意している
    • 過去の合宿者の要望をもとにした優れた設備等がある


初心者がGoでCLIツールを作ってみて学んだこと

@syossan27 氏

  • 作ったOSS
    • kirimori
    • torisetsu
  • 初心者ならではの様々な失敗
    • packageで分ける粒度が分からず1つのファイルにすべて突っ込む
    • エラーハンドリング時に適当にpanicを使ったために自分がpani
    • 構造体メソッドンに対してポインタレシーバを使わない
    • やたら変数名を長くしてしまう


作って学ぶミニマムgolint

@minamijoyo 氏

  • golint
    • Goっぽくないコーディングスタイルを指摘してくれる
    • どうやって検出しているのか?
      • ただの辞書だった
  • よくわからないのでgolint作ってみた
    • 標準のgoパッケージを使う


j2hの紹介

@kanga333 氏

  • j2hを作った
    • JSONからHiveのDDLを出力してくれる
  • gjson
    • goでJSONを取り扱うライブラリの一つ
    • result.TypeでJSONのタイプを取得できる
    • ForReachで子要素に対して反復処理ができる


GoとLintのおいしい関係

@wata727 氏

GoとLintのおいしい関係 Go言語LT大会

  • Lint
    • コンパイラより詳細かつ厳密なチェック
  • Golint
    • Goのスタイルチェッカー
    • (個人的に)Golintの良いところ:行の長さを制限しない
  • Govet
    • コンパイラよりも詳しい検査を行う
  • Go Meta Linter
    • セキュリティとかtypoのチェックとか
  • goは標準パーサがある
    • 新しいシンタックスにも追従してくれる
  • Linterを作りやすい
  • GoではLintを使おう。Linterを作るならGoでやろう


Golangちゃんと始めてから1カ月経ちました

@nntsugu 氏

  • Datadog
    • デザインファーストなFWのgoaで書く
  • プチ合宿やりませんか?


We "Go" fast

@taison124 氏

  • Goで開発
    • 環境や作法が決まっていて迷いどころない
      • 暗黙知が排除されている
    • 標準のやり方でできる
  • 本質的な問題解決に時間や情報を集中できる

個人的にこのLTが一番ためになりました!!


コネクションプールをGoでどう作ろうか調べた話

Jumpei Mano 氏

  • golibmc
    • 1つのコネクションをロックしながら使いまわしている
    • ボトルネックになる
  • memcached用コネクションプールを実装するためにdatabase/sqlの実装を読んだ
    • 非常にいい勉強になった
    • Go特有のchannelを使うことで実装がすっきりしている


ずっとRubyをやっていたエンジニアがGoに入門して挫折して再挑戦した話

@suzan2go 氏

https://speakerdeck.com/suzan2go/zututorubywoyatuteitaenziniagagoniru-men-sitecuo-zhe-sitezai-tiao-zhan-sitahua

  • 敗因
    • Go言語でRubyのようなオブジェクト指向をやろうとしてしまった
    • Rubyのように楽に書く方法がないか探し求めてしまった
  • 再挑戦
    • GitHubでGo言語のアプリケーションを色々見てみる
    • Go言語の設計についての記事を色々読んでみる
    • Goに従ってみると楽しくなってきた
  • GoDocが凄い
  • Goに入ればGoに従え



関連エントリ

golang.tokyo #6 に行ってきたよ #golangtokyo

golang.tokyo #6 に参加してきました。

以下自分用のメモです。


概要

  • 開催日: 2017/6/1
  • 場所: 株式会社ディー・エヌ・エー


Gopher Fest 2017 参加レポート

上田拓也 氏 (メルカリ/ソウゾウ)

  • Gopher Festとは?
    • Google I/O に合わせて開催されるイベント
    • 5/15にサンフランシスコで開催
  • The State of Go
    • Goの開発状況
      • Go1.8は2/16にリリース済
      • Go1.9は5月1日にコードフリーズ済
    • 言語仕様の変更
      • 型のエイリアスを定義できるようになる
        • 完全に同じ型
        • キャスト不要
        • エイリアスの方でメソッドは定義できない
    • 標準ライブラリの変更
      • math/bits
        • ビット演算に便利なライブラリ
      • sync.Map
        • スレッドセーフなマップ
      • html/templateがより安全に
      • os.Exec
        • 重複する環境変数を削除するように、一番後ろのものを優先するようになった(直感的になった)
    • ツール類の変更
      • コンパイラのエラーメッセージの改善(少し優しくなった笑)
    • コンパイラの速度改善
    • go testの改善
      • 複数パッケージの場合にvendorを無視
    • go doc
      • フィールドにリンクが貼れるようになった


初めてGolangで大規模Microservicesを作り得た教訓

Yuichi MURATA (DeNA)

  • Golangで大規模なMicroservices構成のAndAppを作ったときに得た教訓
  • AndAppの基本構成/アーキテクチャ
    • Google App Engine / Go 1.6
    • Gin / Echo
  • 教訓1:フレームワークにこだわらない
    • Ginで始めた開発
      • シンプルで使いやすかった
      • App Engineとのインテグレーションもサンプルにあった
      • Framework Context vs App Engine Context 問題
        • gin,ContextからApp Engine Contextを派生させ回避  * Echo
      • ワイルドカードパスを共有したルーティングが可能
      • Webアプリ系のコンポーネント開発が捗る
      • 設計がガリガリ書き換わる
      • Version3でコンテキストの派生が不可能に
    • そもそもGoでフレームワークにこだわらない
      • 洗練されたnet/httpパッケージがある
      • Golangは言語仕様がシンプルかつgofmtがある
  • 教訓2: interfaceを尊重する
    • 独自のエラー型を定義して利用することに
    • Nilには型があるの罠
      • errorインターフェースと独自エラー型を混在した時に発生
    • 素直に他の関数にならってerrorインt-フェースに統一すればよかった
    • interfaceの定義されたものを積極的に使った方が標準ライブラリとの連携がシンプルになる
  • 教訓3: regex compile / reflection は遅い
    • 複数スキーマを読み込むためにgojsonchemaを選択
    • パフォーマンステストで問題が発覚
      • バリデーションの有無でパフォーマンスに顕著な差が出ることがわかった
      • パースの度にRegexコンパイルしていた
      • 動的にスキーマを解析する部分でrefletionを多用していた
    • そもそもgo-jsvalで頑張ればさらに段違いに良い結果になった・・
    • regex / reflection などのコスト高の操作を意識する
  • 教訓4: 非対称暗号は遅い
    • Microservicesにおいて肝となる認証・認可
      • JSON Web Token / Json Web Signatureを活用している
    • 非対称鍵の署名が重い
      • opensslと比べgoのcrypto/rsaが貧弱
      • 対象会議の署名:0.37msec, 非対称鍵の署名:486msec
    • cgoを使ったopensslのバインディングも存在する
  • まとめ
    • 困ったときにGoの哲学に帰りシンプルなアプローチをとる
    • Goを過信せずにパフォーマンスに気を配る


ゲーム開発には欠かせない?!あれをシュッと見る

Ryosuke Yabuki (カヤック)

  • CSV
    • CSVは視認性が悪い
    • カラムとデータの関係性が見づらい
  • csviewer
    • CSVをいい感じに表示するコマンドラインツール
    • CSVをテーブル形式で表示してくれる
    • 絞り込みなどもできる
  • 実装で使った便利だったライブラリ
    • sliceflag
      • 複数の値を肝がんに受け取ることができる
      • flagの普段の使い方と大きく変わらない
    • tablewriter]
      • CSVを表示するだけなら相当少ないコード量で済む


Go Code Review Comment を翻訳した話

鎌田健史 氏 (KLab)

  • Go Code Review Commentsとは
    • コードレビューする際にます見るべき箇所をまとめたもの
    • Effective Goを簡単にしたもの
  • 幾つかのカテゴリに分かれている
    • コードの見た目を改善
      • golintめっちゃ優秀
    • コメントや文章の体裁
    • tips系
    • 設計の指針になるようなもの
      • レシーバをポインタにするかどうか迷ったら読もう


ScalaからGo

James (エウレカ)

  • Scala
    • 経験者は関数型っぽく書く
  • 関数型開発はGoでできますか?

  • No!
  • 関数型開発のコンセプトはGoで使える?
    • Yes!
  • 関数型開発とは?
    • 副作用がない開発
  • コードレベル
    • 部分適用はGoでもできる
  • ScalaとGoどっちが好き?
    • Scalaが好き
    • 企業としてはGoがいいかも。Goの方が初心者でも綺麗なコードが書ける


Crypto in Go

Kengo Suzuki (マネーフォワード)

  • Goにおける暗号アルゴリズムを利用する
    • ECBモード
    • パディングとHMACの実装面倒くさい
    • ASE + GCM
      • とてもシンプル



関連エントリ・リンク

Go言語 - 日時のフォーマット処理

本エントリでは、Go言語で日時を特定の書式にフォーマットする処理を実行してみます。

基本的にはtimeパッケージのTime.Format関数を利用することになります。


例えばJavaなら、LocalDateTime#format やら SimpleDateFormat#format 等を利用してフォーマットを行いますが、
その時に与える書式は例えばyyyy/MM/dd HH:mm:ssという文字列になります。

で、これと同じことをGoでやろうとした場合、指定する書式は

2006/01/02 15:04:05

です。具体的な上記の日時を書式として与える必要があります。

慣れの問題なんでしょうけど、具体的な値を指定するというのは私には違和感がありました。

一応典型的な書式はtimeパッケージでconstとして提供されています。(が、日本人好みのスラッシュが入った書式は無いです・・)

const (
        ANSIC       = "Mon Jan _2 15:04:05 2006"
        UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
        RubyDate    = "Mon Jan 02 15:04:05 -0700 2006"
        RFC822      = "02 Jan 06 15:04 MST"
        RFC822Z     = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
        RFC850      = "Monday, 02-Jan-06 15:04:05 MST"
        RFC1123     = "Mon, 02 Jan 2006 15:04:05 MST"
        RFC1123Z    = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
        RFC3339     = "2006-01-02T15:04:05Z07:00"
        RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
        Kitchen     = "3:04PM"
        // Handy time stamps.
        Stamp      = "Jan _2 15:04:05"
        StampMilli = "Jan _2 15:04:05.000"
        StampMicro = "Jan _2 15:04:05.000000"
        StampNano  = "Jan _2 15:04:05.000000000"
)

ちなみに、与えられる日時は上記の値(2006年1月2日 15:04:05)に固定されていて、例えば年部分を 2017 にしたり、月部分を 12 にしたり とかはできません。(やると結果がおかしなことになります)

ただし、12時間表記にするために時間部分の 15 を 03 にしたり、 ゼロ埋めしないように 秒部分の 05 を 5 にしたり等はOKです。


以下で現在日時を色々な書式でフォーマットして出力してみました。

■サンプルコード

package main

import (
    "fmt"
    "time"
)

func main() {
    nowTime := time.Now()

    const format1 = "2006/01/02 15:04:05" // 24h表現、0埋めあり
    fmt.Printf("now -> %s\n", nowTime.Format(format1))

    const format2 = "2006/1/2 3:4:5" // 12h表現、0埋め無し
    fmt.Printf("now -> %s\n", nowTime.Format(format2))

    const DateFormat = "2006/01/02"
    const TimeFormat = "15:04:05"
    const MilliFormat = "2006/01/02 15:04:05.000"
    const MicroFormat = "2006/01/02 15:04:05.000000"
    const NanoFormat = "2006/01/02 15:04:05.000000000"

    fmt.Printf("yyyy/MM/dd -> %s\n", nowTime.Format(DateFormat))
    fmt.Printf("HH:mm:ss   -> %s\n", nowTime.Format(TimeFormat))

    // ミリ秒まで出力
    fmt.Printf("Milli -> %s\n", nowTime.Format(MilliFormat))

    // マイクロ秒まで出力
    fmt.Printf("Micro -> %s\n", nowTime.Format(MicroFormat))

    // ナノ秒まで出力
    fmt.Printf("Nano  -> %s\n", nowTime.Format(NanoFormat))

    // Unixtimeに変換
    unixTime := nowTime.Unix()
    fmt.Printf("unixTime -> %d\n", unixTime)
}


■実行結果

now -> 2017/05/24 19:21:04
now -> 2017/5/24 7:21:4
yyyy/MM/dd -> 2017/05/24
HH:mm:ss   -> 19:21:04
Milli -> 2017/05/24 19:21:04.135
Micro -> 2017/05/24 19:21:04.135562
Nano  -> 2017/05/24 19:21:04.135562200
unixTime -> 1495621264


というわけで無事に日時のフォーマット処理ができました。(2006/01/02 15:04:05を頭に入れとこう。)



関連記事

Go言語 - melodyを利用してWebSocketサーバを立てる

melodyGinを使ってWebSocketサーバを立てて、簡易的なチャット画面を作ってみました。

実際には、melody Exampleを、ほぼそのまま流用しているだけです。


準備

以下を実行してmelodyを利用可能な状態にしておきます

go get gopkg.in/olahol/melody.v1


プログラムとhtml

WebSocketサーバと動作確認用チャット画面のindex.htmlとして以下を用意しました。

■WebSocketサーバ(Goプログラム)

package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/gin-gonic/gin"
    "gopkg.in/olahol/melody.v1"
)

func main() {
    log.Println("Websocket App start.")

    router := gin.Default()
    m := melody.New()

    rg := router.Group("/sampleapp")
    rg.GET("/", func(ctx *gin.Context) {
        http.ServeFile(ctx.Writer, ctx.Request, "index.html")
    })

    rg.GET("/ws", func(ctx *gin.Context) {
        m.HandleRequest(ctx.Writer, ctx.Request)
    })

    m.HandleMessage(func(s *melody.Session, msg []byte) {
        m.Broadcast(msg)
    })

    m.HandleConnect(func(s *melody.Session) {
        log.Printf("websocket connection open. [session: %#v]\n", s)
    })

    m.HandleDisconnect(func(s *melody.Session) {
        log.Printf("websocket connection close. [session: %#v]\n", s)
    })

    // Listen and server on 0.0.0.0:8989
    router.Run(":8989")

    fmt.Println("Websocket App End.")
}


■index.html

<html>
  <head>
    <title>Chat powered by Melody</title>
  </head>

  <style>
    #chat {
      text-align: left;
      color:#ffffff;
      background: #113131;
      width: 400px;
      min-height: 300px;
      padding: 10px;
      font-family: 'Lucida Grande', 'Hiragino Kaku Gothic ProN', 'ヒラギノ角ゴ ProN W3', 'Meiryo', 'メイリオ', sans-serif;
      font-size: small;
    }
  </style>

  <body>

    <center>
      <h3>Sample Chat</h3>
      <pre id="chat"></pre>
      <label id="title"></label>
      <input placeholder="say something" id="text" type="text">
    </center>

    <script>
      var url = "ws://" + window.location.host + "/sampleapp/ws";
      var ws = new WebSocket(url);
      var name = "Guest-" + Math.floor(Math.random() * 1000);
      var chat = document.getElementById("chat");
      document.getElementById("title").innerText = name + ": ";
      
      var text = document.getElementById("text");
      var now = function () {
        return new Date().toLocaleString();
      };

      ws.onmessage = function (msg) {
        var line =  now() + " : " + msg.data + "\n";
        chat.innerText += line;
      };

      text.onkeydown = function (e) {
        if (e.keyCode === 13 && text.value !== "") {
          ws.send("[" + name + "] > " + text.value);
          text.value = "";
        }
      };
    </script>

  </body>
</html>


実行してみた

対象のアプリを実行します。実行すると以下のようなログがコンソールに出力されます

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET    /sampleapp/               --> main.main.func1 (3 handlers)
[GIN-debug] GET    /sampleapp/ws             --> main.main.func2 (3 handlers)
[GIN-debug] Listening and serving HTTP on :8989


http://localhost:8989/sampleapp/にアクセスすることでチャット画面が利用できました


f:id:nini_y:20170523160815g:plain


というわけで、お遊び程度ですがかなりコード量少なくWebSocketのサーバサイドを実装することができました。



関連エントリ

Go言語 - Goの特徴

Go言語(Golang)の特徴(メリット)として以下のようなものが一般的に挙げられています


高パフォーマンス

一般的に軽量言語(LL)ではメモリ管理のコストなどに注意してコードを構成しなければパフォーマンスが極端に悪くなることがあります。
それに対して、Goは細部を気にせずにコードを書いても比較的パフォーマンスを引き出しやすい傾向があります。


メモリ管理からの解放

C/C++等はメモリ管理を手動で行う必要がありますが、Goではメモリ管理をGoランライムに任せることができます


コンパイル速度の速さ

C/C++等に比べてGoのコンパイル速度は極端に早いです。
コンパイル速度が速いので、コードを修正してビルド・実行という開発の流れを気軽に何度も実行することができます


スタイルやコード整形

プログラムをチーム開発している際に、どの書式スタイルに統一するかという議論がなされることがあります。
Goではスタイルの規定が最初からしっかりしていて、かつ、そのスタイルをサポートするためのコード整形ツールも揃っています。
このことにより、Goではコードのスタイルに関して質を簡単に保つことができます。


シンプルな言語仕様

Goは機能の割にとてもシンプルな仕様で作られています。
人によっては1日程度で言語仕様を理解することもできます。


シングルバイナリ

Goで書かれたプログラムは基本的には単体で実行可能なシングルバイナリとして生成されます。
一旦コンパイルしてしまえばLL系言語で必要なランタイムや依存関係の管理は必要なくなります。
アプリのインストール・デプロイといった作業も非常に簡単になります。



関連エントリ