Upgrade to Pro — share decks privately, control downloads, hide ads and more …

2019-13 実践 Go 言語/2019-13 golang

2019-13 実践 Go 言語/2019-13 golang

Cybozu
PRO

July 04, 2019
Tweet

More Decks by Cybozu

Other Decks in Programming

Transcript

  1. 実践GO言語
    2019/07/04
    開発本部
    深谷敏邦

    View Slide

  2. 対象者
    ■ A Tour of Go を読んだ
    ■ プロダクションコードは書いたことがない
    ■ Go で HTTP client/server を書きたい

    View Slide

  3. アジェンダ
    ■ はじめに
    ■ 準備
    ■ HTTP Server
    ■ HTTP Client
    ■ テスト
    ■ json 処理
    ■ エラー処理
    ■ context
    ■ go modules
    ■ Go 関連のツール

    View Slide

  4. はじめに
    ■ はじめに
    ■ 準備
    ■ HTTP Server
    ■ HTTP Client
    ■ テスト
    ■ json 処理
    ■ エラー処理
    ■ context
    ■ go modules
    ■ Go 関連のツール

    View Slide

  5. はじめに
    ■ この講義では簡単なHTTPサーバを例にGoを書く際のエッセンスを学びます
    ■ サードパーティライブラリは扱いません
    ■ Goは言語機能が少なく、ライブラリよりもイディオムを駆使する言語です
    – もっと良い書き方、機能がないかと思っても本当にないです
    – イディオムを覚えて筋力でプログラムしましょう

    View Slide

  6. 準備
    ■ はじめに
    ■ 準備
    ■ HTTP Server
    ■ HTTP Client
    ■ テスト
    ■ json 処理
    ■ エラー処理
    ■ context
    ■ go modules
    ■ Go 関連のツール

    View Slide

  7. 準備
    ■ 講義で使用するコンパイラをダウンロードしてください
    – go (1.12 くらい)

    View Slide

  8. HTTP Server
    ■ はじめに
    ■ 準備
    ■ HTTP Server
    ■ HTTP Client
    ■ テスト
    ■ json 処理
    ■ エラー処理
    ■ context
    ■ go modules
    ■ Go 関連のツール

    View Slide

  9. HTTP Server
    ■ Go は HTTP Server に関する機能は標準ライブラリに含んでいる
    – net/http
    ■ 重要な型
    – Handler
    – ResponseWriter
    – Request
    – Server

    View Slide

  10. Handler型
    ■ net.httpがユーザーリクエストに反応するためのコールバックインターフェース
    ■ ユーザーリクエストはReqeust型に入っている
    ■ ReponseWriter型を通してレスポンスする
    type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
    }

    View Slide

  11. Request型
    ■ https://golang.org/pkg/net/http/#Request
    – Method
    – URL
    – Header
    – Body
    ■ この型はClientで使うものと共通
    ■ Bodyがio.ReadCloserインターフェースを満たしているので、ioutil.ReadAllなどで中身
    を取り出す
    ■ 中身を取り出すのはコードを書く人の責任
    ■ 読んでいる最中にエラーが起きたら、それを処理するのも書く人の責任

    View Slide

  12. ResponseWriter型
    ■ https://golang.org/pkg/net/http/#ResponseWriter
    – Header().Add()/Header().Set()でヘッダを設定する
    – WriteHeader でステータスコードを設定する
    – Writeでレスポンスを返す
    ■ この型はio.Write型をみたすのでfmt.Fprintとかが使える
    ■ Writeを呼ぶと自動的にWriteHeader(http.StatusOK)がよばれる
    – エラーステータス返すなら必ずWriteHeaderを先に呼ぶ
    ■ エラーを返すならhttp.Errorが便利

    View Slide

  13. ルーティング
    ■ リクエストルーティングは簡単なパスベースならhttp.ServeMuxがつかえる
    – これ自体もHandler
    ■ メソッドとか正規表現とか使いたいんですが
    ■ 適当なライブラリを探して使う
    – 決定版はない印象
    ■ 筋力で自前でルーティング
    – 細かいバリデーションが必要なエンドユーザー相手でなければあり
    – ルータライブラリが必要になるようなサーバをGoで書きたいですか?

    View Slide

  14. Server型
    ■ https://golang.org/pkg/net/http/#Server
    ■ 実際にコネクションを受け付けてHandlerを起動してくれる型
    ■ フィールドはおおよそオプションだが、Timeoutは設定すべき
    – 後述する Context を使うとさらに細かいTimeoutが設定可能
    ■ ListenAndServerを呼べばサーバが起動する

    View Slide

  15. HTTP Client
    ■ はじめに
    ■ 準備
    ■ HTTP Server
    ■ HTTP Client
    ■ テスト
    ■ json 処理
    ■ エラー処理
    ■ context
    ■ go modules
    ■ Go 関連のツール

    View Slide

  16. HTTP Client
    ■ Go は HTTP Client に関する機能は標準ライブラリに含んでいる
    – net/http
    ■ 重要な型
    – Client
    – Request
    – Response

    View Slide

  17. Client型
    ■ https://golang.org/pkg/net/http/#Client
    ■ HTTPリクエストを行うための型
    ■ フィールドはオプションでおおよそ何も指定しなくても良い
    ■ http.DefaultClientは使わない方が良い
    – 設定がグローバル
    – テストで差し替えれない
    ■ 基本的にはDoメソッドだけを使えばよい
    – Getなどの専用メソッドがあるが、後述するContextが使えない

    View Slide

  18. Request型
    ■ https://golang.org/pkg/net/http/#Request
    ■ 見間違いではなくサーバで見たものと同じ
    ■ フィールドが多くてびっくりするが、http.NewRequestで生成する

    View Slide

  19. Response型
    ■ https://golang.org/pkg/net/http/#Response
    ■ StatusCode にステータスコードが入っている
    ■ Body は io.ReadCloser で ioutil.ReadAll などを使って自分でコンテンツを読む必
    要がある
    ■ HTTP keep-aliveを利用するにはプログラマが自前でCloseする必要がある
    – 忘れがちなので注意

    View Slide

  20. テスト
    ■ はじめに
    ■ 準備
    ■ HTTP Server
    ■ HTTP Client
    ■ テスト
    ■ json 処理
    ■ エラー処理
    ■ context
    ■ go modules
    ■ Go 関連のツール

    View Slide

  21. テスト
    ■ HTTP関連のテストならhttptest.Serverを使うのがらく
    – 使い終わったらCloseすること
    ■ table driven testが便利

    View Slide

  22. json 処理
    ■ はじめに
    ■ 準備
    ■ HTTP Server
    ■ HTTP Client
    ■ テスト
    ■ json 処理
    ■ エラー処理
    ■ context
    ■ go modules
    ■ Go 関連のツール

    View Slide

  23. JSON処理
    ■ Go は JSONに関する機能は標準ライブラリに含んでいる
    – encoding/json
    ■ 基本型や一部の標準ライブラリに含まれる型を相互変換することができる
    ■ 自分で定義した型も変換できるがここでは扱わない

    View Slide

  24. Marshal
    ■ Goの型からJSONバイト列に変換すること
    ■ json.Marshalかjson.Encoderを使う
    – json.Encoderはio.Writerを使えるのでhttp.ResponseWriterと相性が良い
    – と思わせておいて、エラーが起きるとWriteHeaderとの順番で難しいことに
    なるのでjson.Marshalを使うのが良い気がする

    View Slide

  25. Unmarshal
    ■ バイト列をGoの型に変換すること
    ■ json.Unmarshalかjson.Decoderを使う
    – json.Decoderがio.Readerを使えるのでhttp.Responseと相性が良い

    View Slide

  26. JSONと型のマッピング
    ■ Goのstructはフィールドにタグがかける
    – どう使うかは言語側は規定していないので好きに使える
    ■ jsonパッケージはこの機能を活用する

    View Slide

  27. タグ付け
    ■ タグでフィールドにマッピングされるJSONのキーを指定する
    ■ マッピングするフィールドは公開する必要がある
    ■ 実はタグがなくても公開メンバが自動的にマップされるがわかりにくいのでつ
    けた方が良い
    ■ JSONにキーが現れない場合はそのフィールドは空になる
    – キーの存在を判定するならポインタを使うと良い
    type Foo struct {
    ID int `json:"id"`
    Data string `json:"data"`
    }

    View Slide

  28. エラー処理
    ■ はじめに
    ■ 準備
    ■ HTTP Server
    ■ HTTP Client
    ■ テスト
    ■ json 処理
    ■ エラー処理
    ■ context
    ■ go modules
    ■ Go 関連のツール

    View Slide

  29. エラー処理
    ■ Goはいわゆる例外を持たない
    ■ "エラー"の扱いはコンベンションによる

    View Slide

  30. エラーを返す
    ■ エラーを返す関数は戻り値の最後にerror型を書く
    ■ 戻り値は次の性質を満たすようにする
    – もしエラーが起きていないならerror型はnilにする
    – もしエラーが起きているならerror型はnon-nilである
    – もしエラーが起きているならtypeN達は何らかの無効な値である
    ■ 大抵ゼロ値が使われる
    func foo() (int, string, error) {
    if some error is happened {
    return 0, "", errors.New("error");
    }
    return 1, "ok", nil
    }

    View Slide

  31. エラーを判定する
    ■ 関数がコンベンションを満たしているなら次のように書ける
    ■ エラーを返す関数ではerror型を最初にifでチェック
    ■ nilでないなら上位に返す
    ■ nilなら処理を継続する
    func bar() error {
    n, s, err := foo()
    if err != nil {
    return err
    }
    // use n and str
    return nil
    }

    View Slide

  32. error型
    ■ 組み込みのインターフェース
    – error
    ■ errors.Newやfmt.Errorfを使って生成する
    ■ 特定のエラーであることを伝えたり、付加情報をつけるために自前で定義する
    場合もある

    View Slide

  33. プラクティス
    ■ Goのerrorはいわゆる例外とは異なりスタックトレースを持たない
    ■ そのため雑にerrorを上位に伝播するだけだと何が起こったかわかりにくい
    – 深いロジックで起こったioエラーがmain関数でログされても意味がない
    ■ エラーが起きた時は次のことを行うのが良い
    – エラーが起きた箇所でのロギング
    – エラーをfmt.Errorfなどで付加情報をつけて投げ直す
    ■ xerrorsを使うとスタックトレースも手に入る

    View Slide

  34. context
    ■ はじめに
    ■ 準備
    ■ HTTP Server
    ■ HTTP Client
    ■ テスト
    ■ json 処理
    ■ エラー処理
    ■ context
    ■ go modules
    ■ Go 関連のツール

    View Slide

  35. context
    ■ 処理を止めるための仕組み
    – リクエスト単位のkvsとしても使えるがここでは扱わない
    ■ 例えば
    – HTTPリクエストをタイムアウトさせたい
    – 外部コマンド呼び出しをタイムアウトさせたい
    – goroutineの実行を途中で止めたい

    View Slide

  36. contextパッケージ
    ■ contextは標準のcontextパッケージとコンベンションで実現する
    ■ contextを扱う関数は第一引数にcontext型を受け取る
    – 引数名はctx
    ■ context.Doneはchannelで、closeされるとそのcontextが終了したことを示す
    ■ context生成関数がCancelFuncを返すなら必ずその関数を呼び出す

    View Slide

  37. HTTPサーバでのContext
    ■ HTTPハンドラーのrequest構造体が持つContext()からcontextを取得できる
    ■ このcontextはユーザーのコネクションがクローズされると終了する
    – すなわちcontext.Doneがcloseされる
    ■ クライアントのコネクションが閉じた時、ハンドラーの処理を停止できる

    View Slide

  38. HTTPクライアントのContext
    ■ http.Clientはcontextのコンベンションを守っていない
    – contextが後で追加されたため
    ■ 引数で直接contextを渡す代わりに、http.Requestに対してcontextを乗せる
    – WithContext
    ■ context.WithTimeoutなどと組み合わせて使う

    View Slide

  39. go modules
    ■ はじめに
    ■ 準備
    ■ HTTP Server
    ■ HTTP Client
    ■ テスト
    ■ json 処理
    ■ エラー処理
    ■ context
    ■ go modules
    ■ Go 関連のツール

    View Slide

  40. Go modules
    ■ 最近標準で用意されるようになった依存管理方法
    – npm, maven, gradle的な
    ■ Go modulesを使うとGOPATHは不要
    – GOPATHを使っているとmodulesが誤作動するので注意
    ■ 依存パッケージのバージョンが指定できるのでvendoringが不要になる

    View Slide

  41. 使い方
    ■ 初期化
    – go.mod が生成される
    ■ 依存の追加・削除
    – import文から依存がgo.modに追加される
    – ベリファイファイルのgo.sumも生成される
    ■ ビルド
    – 自動的に依存がダウンロードされる
    $ go mod init github.com/foo/bar
    $ go get github.com/hoge/fuga
    $ go mod tidy
    $ go build

    View Slide

  42. Go 関連のツール
    ■ はじめに
    ■ 準備
    ■ HTTP Server
    ■ HTTP Client
    ■ テスト
    ■ json 処理
    ■ エラー処理
    ■ context
    ■ go modules
    ■ Go 関連のツール

    View Slide

  43. Go 関連のツール
    ■ formatter
    – go fmt
    – goimports
    ■ 不要なimportを消してくれるのでgoimportsを使うのがオススメ
    ■ checker/linter
    – go vet
    ■ コーディングミスっぽいものを探してくれる
    – golint
    ■ コードスタイルをチェックしてくれる

    View Slide