Golang運用で最初につまづいた点、採用した方針等をまとめてみました。
最初にやっておけばよかった事
- エディタにgoimport + golint + govetチェックを入れておく。
- エディタ比較は以下参照
- https://qiita.com/croquette0212/items/3ef6003c6bb621b59b97
- 個人的にはVSCodeを使っている
- formatOnSaveでgo vet, golint, goimportチェックさせると快適
- linter比較は以下参照
- golintの出力メッセージと対応方針
値レシーバとポインタレシーバの違い
- https://qiita.com/tikidunpon/items/2d9598f33817a6e99860
- https://skatsuta.github.io/2015/12/29/value-receiver-pointer-receiver/
ORMは何を使うか
- GORMを使っている。 (CRUD、トランザクション、ロガー等 基本機能が一通り揃っているため)
- GORM運用上の注意点
- クエリチェックはdb.LogMode(true)で行う。
- Bulkinsertが2019.03時点だと見つからないので以下ライブラリや生クエリを使っている
- トランザクション制御は以下のようなラッパ関数を用意する。
アプリ実装上の考慮点
- microservice用途の場合は12-factor-appに準拠する
- https://www.slideshare.net/masatoshitada7/twelvefactor-app
- ログは標準出力
- 状態を保つ場合は、S3等の外部ストレージ、DB, KVS等に外出しする。
設定の管理方法
- godotenvで.envに環境変数情報を持たせる (1ファイルで管理しやすい、コンテナ化する際に何を渡すか明確であるため)
タスクランナーは何を使うか
- 用途
- Dockerコンテナビルド、Dockerレジストリへのpush等
- 基本はMakefile
Dockerコンテナ化したい時はどうするか
MultiStageビルドを行う。
最終的にGoランタイムを含めずに
ビルド済バイナリのみ配布するので実行用コンテナが軽量になる
->コンテナ起動が早くなる
- Step1: ビルド専用コンテナでビルド処理
- ビルド専用の使い捨てコンテナ
- DockerfileでFROMに指定するイメージはGoランタイムを含む軽量イメージにする(golang:1.13-alpine等)
- ビルド時にCGO_ENABLED=0オプションを付ける。staticLinkでビルドされないため。
- 本番運用の際はビルド時に「-ldflags '-s -w'」オプションを付ける。
- sオプションはシンボルテーブル等(デバッグ)が含まれなくなる
- wオプションはデバッグ情報が含まれなくなる
- 必要なファイルしか入れない。必要なら.dockerignore使う
- Step2: 実行コンテナ用コンテナの起動
- DockerfileでFROMに指定するイメージは、Goランタイム含まない低サイズイメージにする(scratch等)
- Step1のコンテナからビルド済バイナリだけADD
- 外部APIコール等のためにTLSリクエスト行う場合はca証明書もADDする
PHPのvar_dump, jsのconsole.log的なものはある?
- ある。go-spewを使う。
ログの扱い方
- logパッケージを使う
- log.SetPrefix("[TEST]")でログ接頭辞追加ができる
- log.println, log.Fatalln, log.Panicln, fmt.printlnの違いは何?
- デフォルトの出力場所がfmtは標準出力, logは標準エラー出力
- 動作上の違い
- log.Println = fmt.Println + 書き出し時刻
- log.Fatalln = log.Println + os.Exit(1)
- log.Panicln = log.Println + panic()
文字列長の求め方
- unicode/utf8パッケージのutf8.RuneCountInString(str)を使う len(str)だとバイト長しかわからない
- https://blog.sarabande.jp/post/61104546593
通常の関数とレシーバ関数の使い分け
構造体-JSON間の変換はどうするか
- encoding/jsonパッケージのmarshal, unmarshalを使う
- http://blog.restartr.com/2014/08/13/golang-json-marshal-unmarshal/
例外処理はどう表現するか
- いわゆるtry-catch系の構文は今の所は無し
- 多値返却で値とエラーを返して、エラーの有無で判定
- deferで後処理を記述
- https://text.baldanders.info/golang/error-handling/
時刻、日付の扱い方
- time.Parseを使う
- 日付ならAddDate、時間ならAddTimeを使う
- 日付
- t := time.Now()
- 日付
- t.Date()
- 年
- t.Year()
- 月
- t.Month()
- 日付
- t.Day()
- 日付の増減
- 1日後
- t.AddDate(0,0,1)
- 1日前
- t.AddDate(0,0,-1)
- 1ヶ月後
- t.AddDate(0,1,0)
- 1ヶ月後
- t.AddDate(0,-1,0)
- https://ashitani.jp/golangtips/tips_time.html#time_Parse
APIクライアントの作り方
- わかりやすいチュートリアルがあるので参照