blog
この記事はRecruit Engineers Advent Calendar 2017 12日目の記事です.
2017年度入社の與那城です,今はリクルートテクノロジーズのAPソリューショングループで見習いプログラマをしています.
この5ヶ月くらいgolangのコードを書いていたのでその記録を振り返るための記事です.
7月にslackのpostをbacklogに投稿し, postについたコメントをbacklogにも投稿するものを作ることに.
当時のスキルセットとしてはPythonでやるのが一番速かった気がしますが, golangをやっていきたかったのでgolangで作ることにしました.
この時はとりあえず書くぞと言いながらライブラリの調査もろくにせずに走りはじめました.
http://deeeet.com/writing/2016/11/01/go-api-client/
この記事を見ながらbacklogのAPI Clientを作り始めました.
見よう見まねでコードを書いてなんとなく動くようになり, 必要なエンドポイントだけ実装してとりあえず終わりました.
READMEからもやる気の無さが伺えます.
deeeetさんの記事にも書いてありますが, 公式で提供されている場合にむやみに作るべきではありません.
この時, 理解せず記事に書いてある通りcontext.Context
対応のコードを書いていました.
実際に使うとcontext.Background()
しか渡さないし使いづらいと思い,デフォルトではcontext.Background()
を内部で渡すようにし,明示的に指定したい場合はWithContext
が末尾についた関数を使ってもらう感じにしました.
しかし, コードを修正しシグネチャが変わった時に毎回WithContext
版のシグネチャも修正しないといけなくなり「これは辛いなぁ」と思いました.
人間がやるべき仕事ではない!自動化しよう!ということで作りました.
golangのastが意外と簡単に扱えるところ,goimportsのソースコードからの呼びやすいところなどがあり,
ソースコード生成系のツールなどが非常に作りやすいなと思いました.
結局作りはしましたが, ほとんど使うことはありませんでした.
github.com/nlopes/slack
を使い簡単に作りました.
mainの制御系とslackとのやり取りをするgoroutine, slackのpostをdownloadするgoroutine, backlogに投稿するgoroutineに別けて実装しました.
ここで困ったこととして
がありました. 前者はただ変換が面倒くさいだけでしたが, 後者に関してはこの時点で勉強不足というだけでした.
いろいろ遠回りをしましたが, Slack Botを作るというTaskが終わりました.
Azure Media Serviceを使いたいという話になり,
https://docs.microsoft.com/en-us/rest/api/media/operations/azure-media-services-rest-api-reference
とにらめっこしながらAPI Clientを作り始めました.
ODataを知らず, どういうレスポンスが返ってくるかも知らず, どうやって認証したら良いのかもわからず, TenantIDとは何か, ClientIDとは何か, どのエンドポイントにアクセスすれば良いのかわからず手間取ったの覚えています.
とりあえず認証ができないと話にならないので調査をはじめました.
https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-authentication-libraries をみて, ADAL(Active Directory Authentication Library)というライブラリを使うのが良いということがわかりましたが公式にはgolangのライブラリはなく, 仕方なくNode.js実装をgolangに移植しました.
認証ができるようになったので, 実際にリクエストを送りどのようなレスポンスが返ってくるのか確認し必要な機能の実装を始めることが出来ました.
ある程度機能が実装できたあたりから, 技術顧問である@t_wadaさんからテストのレビューをしてもらいました.
その際に調べて出てきた記事, 教えて貰った記事を共有しておきます.
以下のようなコードで,最終的にmain
まで返ってきたerr
をlog.Fatal
するパターンを良く書いていました.
foo, err := Bar()
if err != nil {
return err
}
しかしこのようなやり方だとlog.Fatalがどういう文脈で起きたエラーかわからず調査に時間がかかることがあり困っていました.
これをきっかけにgolangのエラーハンドリングについて調査しました.以下の2つが日本語で読める良質なものでした.
jxckさんの記事に書いてある方法は同じような例外を簡潔に処理できる.bufio
の内部も同様な実装になっています.
deeeetさんが紹介していた方法は自分でstack traceを書くようなものですが,github.com/pkg/errors
を使い始めてからどこで起きたerrorなのかすぐわかる様になりました.
またgo-amsの機能で並列アップロードする部分があり, 並列で走らせたときのerrorってどうするんだっけと調べたところ,
で紹介されているgolang.org/x/sync/errgroup
が良さそうだと言うことがわかりました.
2つめのAPI Clientを作っていてこういう機能が共通, こういう機能があると嬉しいみたいなことを思ってきたのでライブラリ化しました.
これも作った後に気がついたのですが, github.com/dghubble/sling
やgithub.com/go-resty/resty
がやりたいこととしては同じでした.
せっかく作ったgithub.com/orisano/httpc
はgo-amsで使うようにしました.
4月に@t_wadaさんの講義を聞いてからwrite code every day
を実践していていろんなコードを趣味で書いてきたので紹介させてください.
車輪の再発明ですが, リトライポリシーに則ってリトライしてくれるライブラリ
orisano/go-retry
socket.io-clientのgolang実装
orisano/gomasio
DAMMアルゴリズムのgolang実装
orisano/go-damm
ただこれまでのことを垂れ流すだけの記事になってしまいました.
この5ヶ月で少しはgolangが書けるようになったかと思います.
書いてみてすごくシンプルな言語で,変数名やpackage名以外で悩むことがあまりないなと感じています.
formatで悩まなくてもいいところや, python2,3のような悩むところもないのが非常に良いです.
とはいえちゃんと学ばずにやってきたので,
今はプログラミング言語Goを読み進めつつ,標準ライブラリの実装なども読みながら勉強しています.
これからもgolangやっていきます.
ありがとうございました.