20161004 dmm/エウレカ/インテリジェンス合同勉強会

21
Golang こんな時どうする? Yusuke Komatsu 2016-10-04. DMM.comラボ & eureka & インテリジェンス合同 Go言語勉強会

Upload: yusuke-komatsu

Post on 14-Apr-2017

1.564 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: 20161004 DMM/エウレカ/インテリジェンス合同勉強会

Golang こんな時どうする?

Yusuke Komatsu

2016-10-04.DMM.comラボ & eureka & インテリジェンス合同 Go言語勉強会

Page 2: 20161004 DMM/エウレカ/インテリジェンス合同勉強会

NULLを許容するDBやJSONって どうしよう?

• ポインタを使う

• sqlパッケージの型を使う(sql.NullString とか)

• NULLなにそれ?おいしいの?

Page 3: 20161004 DMM/エウレカ/インテリジェンス合同勉強会

sql.Null** を使った場合

• sqlパッケージの中で実装されている

• Nil判定もできるし、実態となる型はそのまま(Int64ならInt64で値が格納されている)

• Scanを通せばある程度ゆるく解釈してくれる

• 1変数内(構造体)に2つのパラメータが格納されていて、両方見ないと値を取得できない

利点

欠点

Page 4: 20161004 DMM/エウレカ/インテリジェンス合同勉強会

ポインタを使った場合

• 数値や文字列などと一緒にNilを使える

• Nilを区別しないで使うことができる

• 通常の型として扱うには元に戻す必要がある

• JsonなどをDecodeする時にゆるい解釈ができない(IntをStringとして解釈するなど)

利点

欠点

Page 5: 20161004 DMM/エウレカ/インテリジェンス合同勉強会

NULLを許容問題はRDBだけじゃない

• 他のデータベースやキャッシュする際も考慮が必要

• jsonやXMLなどでも使う(特にAPI)

• 他言語のプログラムと通信する場合も考える必要がある

Page 6: 20161004 DMM/エウレカ/インテリジェンス合同勉強会

便利な独自型つくりました

Page 7: 20161004 DMM/エウレカ/インテリジェンス合同勉強会

JSONのEncode/Decodeが直感的

Page 8: 20161004 DMM/エウレカ/インテリジェンス合同勉強会

同じ値でもsetする型によって柔軟に解釈

Page 9: 20161004 DMM/エウレカ/インテリジェンス合同勉強会

実は某社のAPIのレスポンスで事故ったので作った• 複数のサービスのデータを取りまとめられていて、サービスごとに型が

バラバラ • int型のパラメータにstring型が混ざっていたりする • APIもPHPで、型やハッシュor配列判定を勝手に吸収して出力されている • 静的言語にとっては死亡フラグ

こんな感じだったので またこんなことが起きても対処できるように作りました

Page 10: 20161004 DMM/エウレカ/インテリジェンス合同勉強会

genericはいろんな方のいいとこ取り• Scanが定義されているのでsqlパッケージでも意識せず使える • MarshalJSON / UnmarshalJSONを定義してるのでEncode/Decode時のNULL

は自動的に考慮される • Set関数をつかえば、Nilを考えずに変数に値をセットできる • Value関数を使えば、1つだけ値が返ってくる(Nilの場合はNilが返ってくる) • 型判定の柔軟さはPHP並 • reflectはエラー時のみしか使ってない • sql.Null**型でやっているようなNULL判定も可能

Page 11: 20161004 DMM/エウレカ/インテリジェンス合同勉強会

実はGo 2系でGenericsが実装されるかも

Page 12: 20161004 DMM/エウレカ/インテリジェンス合同勉強会

http.Response.Body 消失問題しってますか?

• http.Response.Bodyを使いまわそうとしても1度使うと空のio.ReadCloserになってしまう

• 変数に入れ直しても変数も消える

Page 13: 20161004 DMM/エウレカ/インテリジェンス合同勉強会

こんなことはできません

Page 14: 20161004 DMM/エウレカ/インテリジェンス合同勉強会

こうしたら解決できる

Page 15: 20161004 DMM/エウレカ/インテリジェンス合同勉強会

みなさんテストってどうしてます?

• とりあえずgo test?カバレッジとってる?

• ソースの品質管理(担保)ってどうしてます?

• そもそもテストしてますか?

Page 16: 20161004 DMM/エウレカ/インテリジェンス合同勉強会

リポジトリ内の全パッケージをテストしたい

• リポジトリのルートディレクトリから再帰的にテスト

• vendorディレクトリ配下はテストしたくない(glide nv)

• 品質管理のためにカバレッジも取りたい(coverprofile)

go test $(glide nv) -coverprofile=coverage.out

ERROR:

cannot use test profile flag

with multiple packages

Page 17: 20161004 DMM/エウレカ/インテリジェンス合同勉強会

リポジトリ内の全パッケージをテストしたいROOT_PATH="$GOPATH/src/seeds.rickcloud.jp/bitbucket/scm/hm/wage" COV_PARTIAL_FILE=profile.cov.out COV_FILE=profile-all.cov.out COV_MODE=count HEADER="mode: $COV_MODE"

cd $ROOT_PATH; \ # テスト用DBのマイグレーション

goose -env testing up; \

echo "mode: count" > $COV_FILE # ひつようのないディレクトリを除いたディレクトリを再帰的にチェック

for dir in $(find . -maxdepth 10 -not -path './.git*' \ -not -path '*/_*' -not -path './cmd' -not -path './release*' \ -not -path './vendor*' -type d) do if ls $dir/*.go &> /dev/null; then # 個々にテストをして一時保存用プロフィールに保存

go test -v -covermode=count -coverprofile=$dir/$COV_PARTIAL_FILE $dir if [ -f $dir/$COV_PARTIAL_FILE ]; then # 一時保存されたものを出力用プロファイルに転記

cat $dir/$COV_PARTIAL_FILE | tail -n +2 >> $COV_FILE rm $dir/$COV_PARTIAL_FILE fi fi done # テスト用DBのロールバック

goose -env testing down; \

Page 18: 20161004 DMM/エウレカ/インテリジェンス合同勉強会

ソースコードの品質管理• gofmt (インストール不要)

ソースコードを整形する

• go_vet (インストール不要)コンパイルエラーにならないヒューリスティックな問題を検出する

• gocyclo (https://github.com/fzipp/gocyclo)循環的複雑度(コードの複雑性)の検証をする

• glint (https://github.com/golang/lint)Golangのlinter

• ineffassign (https://github.com/gordonklaus/ineffassign)無駄な割当を検出する

• misspell (https://github.com/client9/misspell)スペルミスを検出する

Page 19: 20161004 DMM/エウレカ/インテリジェンス合同勉強会

ソースコードの品質管理

Page 20: 20161004 DMM/エウレカ/インテリジェンス合同勉強会

ソースコードの品質管理

Page 21: 20161004 DMM/エウレカ/インテリジェンス合同勉強会

THANK YOU!![generics]

• usk81/generic https://github.com/usk81/generic

• proposal: generic programming facilities https://github.com/golang/go/issues/15292

[test] • Go Report Card

https://goreportcard.com