blog.syfm

徒然なるままに考えていることなどを書いていくブログ

より気軽に、簡単にテストができる gRPC クライアントをつくった

先日の A(izu)LT 0x09 で「Evans: more expressive universal gRPC client」 というタイトルで発表してきました。
タイトルの通り、gRPC クライアントをつくった話です 🙌

atnd.org

ALT は、会津大学の有志によって年に二回ほど開催されている LT (Lightning Talk) 会で、次回でついに 0x0a 回目を迎えます!めでたい 🎉

発表したスライドはアップロードしています。大体のことは以下に載っているけど、ちょっと補足をしておきたいと思います。

speakerdeck.com

つくったもの

github.com

Evans の目指したもの

Evans は既存の gRPC クライアントより簡単に扱えることを第一目標に作っています。
(gRPC に限らずですが、) gRPC を使っているプロダクト自体の品質を保ちたければ、gRPC を使ったテストも書いて CI で回せばいい話なので、gRPC クライアントはそれ以外のユースケースを補うためにあるべきだと思っています。

では補うべき部分とは一体なんなのかというと、

  • スクリプトによって何かのタスクを自動化したい
  • API を手動で検証したい

この二つだと思っています。
そして、この二つはそれぞれ以下の二つのモードと対応しています。

🖥️ コマンドラインモード

コマンドラインモードは、その名の通り一回のコマンドのみで完結するステートレスなモードで、既存の gRPC クライアントの Polyglot が採用している方式でもあります。

github.com

コマンドラインモードは、単なるコマンドなので、UNIX 哲学に則ってつくっています。
例えば、stdin から入力を受け取ることでフィルターとしての役割を果たすことができますし、その一方で出力は stdout へ JSON 形式で行われます。そのため、jq コマンドなどで適当に加工したりすることが可能です。

$ echo '{ "name": "ktr" }' | evans --package hello --service Greeter --call SayHello hello.proto | jq -r '.message'
# hello, ktr!

また、ファイルへ入力の JSON を保存して、何度も使いたい場合などのケースのために --file (-f) オプションを用意しており、こちらでも同じような動作ができます。

$ cat hello.json
{
  "name": "ktr"
}

$ evans -f hello.json --package hello --service Greeter --call SayHello hello.proto | jq -r '.message'
# hello, ktr!

ちなみに、コマンドラインモードでは事前に使用する package、service、RPC 名を知っている必要があるため、インタラクティブモードとは違い引数を省略できません。しかし、Git プロジェクトルートに .evans.toml がある場合は、デフォルトで使用するものを記述することができます。

[default]
package = "hello"
service = "Greeter"

こうすると以下のようにシンプルにコマンドを指定できます

$ evans -f hello.json --call SayHello hello.proto

🤼 インタラクティブモード

インタラクティブモードは、「API を手動で検証したい」時のためのモードです。
こちらの方は、なにも考えなくても使えるようにつくっています。
補完機能が使えるため、package 名や service 名、RPC 名を覚えていなくても大丈夫です!
このモードは MySQL のクライアントである、 dbcli/mycli を意識しています。

github.com

実際のデモはこんな感じです 👇

demo

読み込んでいる proto ファイル

syntax = "proto3";

package helloworld;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloResponse) {}
}

enum Language {
  ENGLISH = 0;
  JAPANESE = 1;
}

message Person {
  string name = 1;
  repeated string others = 2;
}

message HelloRequest {
  Person person = 1;
  Language language = 2;
}

message HelloResponse {
  string message = 1;
}

サーバの実装

package main

import (
    "fmt"
    "log"
    "net"
    "strings"

    "golang.org/x/net/context"

    helloworld "github.com/ktr0731/evans/tmp"
    "google.golang.org/grpc"
)

type Greeter struct{}

func (t *Greeter) SayHello(ctx context.Context, req *helloworld.HelloRequest) (*helloworld.HelloResponse, error) {
    msg := "Hello, %s also %s!"
    if req.GetLanguage() == helloworld.Language_JAPANESE {
        msg = "こんにちは、%s と %s !"
    }
    return &helloworld.HelloResponse{
        Message: fmt.Sprintf(msg, req.GetPerson().GetName(), strings.Join(req.GetPerson().GetOthers(), ", ")),
    }, nil
}

func main() {
    l, err := net.Listen("tcp", "localhost:50051")
    if err != nil {
        log.Fatal(err)
    }

    server := grpc.NewServer()
    helloworld.RegisterGreeterServer(server, &Greeter{})
    if err := server.Serve(l); err != nil {
        log.Fatal(err)
    }
}

べんりですね。

インストール

macOS / Linux 向けのバイナリが GitHub Releases にあるので、それを使えます。
もちろん、go get で取得することもできます。
macOS であれば、brew を使ってのインストールもできます 🍺

$ brew tap ktr0731/evans
$ brew install evans

Issue / PR

このツールは LT 駆動開発によって誕生したので、テストがありません 😱
なので、一旦新規の機能開発はやめてテストを充実させようと思っています 🙇‍♂️
その後、スライドでも言及したような TODO タスクを消化していきたいと思っています。
もし使っていただける方がいましたら、ぜひ Issue でも PR でもどんどんいただけたらありがたいです!

ISUCON7 に出た

土曜日に ISUCON7 に出ていた。
チームは、自分と、同じ大学の友人一人。本当はもう一人いる予定だったけど、別な予定と被っていたらしく、二人のチームになった。

トラブルがあったようで、開始の時間が遅れて 13:00 からになったりと、運営の方もとても大変そうだった…。お疲れ様でした!
点数は2万点くらいで、なかなか残念な結果。事前に過去問を解いておくべきだったと思う。
やったことは、icons を MySQL から出すようにするのが一番大きかった気がする。
なぜか MySQL に icon がバイナリごと突っ込まれていて、これが一番のボトルネックになっていた。
なので、DB から取り出そうということになって、一番簡単であろうファイルへの書き出しを行った。
GET /icons/hoge の時は nginx の try_files ディレクティブでディレクトリに存在するか確認して、なければアプリに飛ばすようにし、アプリでは DB からの取り出しとともに書き出しも行うようにして以降はそのファイルが使われるように変更した。
Redis みたいな KVS でキャッシュすればもっと早くなったのかなーとか後で思ったりもした。

他にも、インデックスが貼られていないカラムにインデックスを貼ったり、N+1 を解消したりしていた。

使っていた言語は Go で、サーバ上で上手くビルドできなかった (vendoring ができていなかった?) ので、早々に諦めてローカルでビルドして scp を使って頑張っていた。
あと、ページングで OFFSET が使われていたので、これをどうにかしたかったけど、実装力と時間がなくて間に合わなかった。
普段開発しているとあまり時間に追われることがないので問題にならなかったけど、実装力が低くてつらい。

一番深刻なのが、nginx に関する知識の欠如とパフォーマンス計測の勘所が全然わからなかったことだと思う。
普段手を動かしていないことを本番でやろうとしてもできないということを身をもって痛感した。

この辺の反省を活かして来年は頑張っていきたい 💪

はてなインターンで最高の夏を過ごしてきた

明示的に言ってはいなかったのですが、この1ヶ月間、はてなサマーインターン 2017 に参加していました!

公式のページ 👇

developer.hatenastaff.com

TL;DR 用に言っておくと、最高の夏でした!!!

以下では、そのはてなインターンの思い出を振り返っていきたいと思います

はてなと自分

はてなは、はてなブログ (このブログもそう) や、はてなブックマークとかの Web サービスを作っている会社で、知っている人も多いかなと思います。
自分が一番好き (だった) サービスはうごメモはてなで、小学6年生のころに DSi を買ってもらってうごメモに夢中になっていました。
実際にやっていないとわからないと思うけど、うごメモうごメモシアターうごメモはてなとサービスを利用していって、それがきっかけでインターネットにのめり込むようになったという経緯があります。

ugomemo.hatena.ne.jp

高校 - 大学でエンジニアとして生きていきたいと思うようになってからは、エンジニアの視点としてもはてなを意識するようになりました。
また、去年の Mackerel チームだった id:upamune さんが自分の先輩だったので色々お話を聞いたりもしていました。
実際、はてなには自分の知っている著名なエンジニアがたくさんいて、今回応募したのもその二つがきっかけでした。

応募

はてなインターン 2017 の応募が始まって直後に JSON を書き始めた記憶があります。ちなみに、インターン生で最速でした。
JSON なのは、技術プロフィールを JSON 形式で提出しなければならなかったためです。
これから先、はてなインターンに応募する人はどんな内容を送ったか知りたいかな、と思うけど、自分の場合は取り敢えず中の人の目に留まるように今までつくったものをすべて列挙していました。
これは個人的な意見だけど、テンプレートの様なプロフィールを書くより自分がどんな理由でインターンに行きたいかを書くべきだと思います 🙌

そうして、エントリーし、面接を行って合格を頂いた。めちゃくちゃ嬉しくて、信じられなかった記憶があります。
ちなみに、今年ではてなインターンは 10 回目らしい、めでたい 🎉

事前課題

自分は Mackerel チームに配属されることになっていたので、ScalaJavaScript の事前課題がありました。
応募の際のプロフィールにも書いた気がするけど、Scala は一度も触ったことがなく、かなり苦戦していました。
それでもなんとか最後までやっていけたので、やる気次第でどうとでもなると思います 💪

前半課程

f:id:ktr_0731:20170908163504p:plain

前半課程は、インターン生全員ではてなの社員さんの方々からの講義を受け、課題をこなしていく形式で、各コースごとにメンターさんが2人付いていてわからないことがあればすぐに聞くことができるという最高の環境でした。
自分たちのメンターさんは id:syou6162 さんと、id:shiba_yu36 さんで、物凄くお世話になりました 🙇‍♂️
翌日くらいには課題へのコードレビューが行われて、全体でフィードバックを頂いたのでためになりました。
今年のキャッチコピーである、「Webサービス開発、上から下まで。」の通り、様々な種類の講義を受けられて非常に濃密でした。

初日に他のインターン生との顔合わせがあって、みんなレベルが高くて驚きました。
翌日からは、 Scala/Perl 基礎、SQL・DB、HTTP・WAF、JavaScript or iOS機械学習、デザイン・インフラ、AWS ハンズオン、サービス企画 と毎日色々な講義を受けることができて、午後は得た知識を使って演習課題を行うような形でした。
毎年 SQL・DB の課題が大変らしく、今年も自分を含めみんな苦戦していた…。

前半1週間でミニブログサービスを完成させ、後半1週間のうちの AWS ハンズオンで ECS にデプロイするところまで行い、覚えたばかりのことをすぐ実践的に活用できて楽しかったです。

JS 課題のマウスストーカーは Vim が振ってくるやつを、自由課題は Slack ライクなリアクションができる機能を開発しました!!

https://ktr0731.github.io/mousestalker/

f:id:ktr_0731:20170908172403p:plain
自由課題 / 不穏なリアクションが並ぶ

前半課程の合間

社長会という社長の id:chris4403 さんと、サービス・システム開発本部長の id:onishi さん、CTO の id:motemen さんたちとインターン生でごはんを食べる機会があります。
インターンに来てから知ったのですが、id:motemen さんはうごメモはてなのメインの開発者で、当時のうごメモはてなの話や、ずっと聞きたかったはてなランドの話なども聞けたので良かったです。

ちなみに、最終日には id:hakobe932 さんにうごメモはてなソースコードを見せていただいて当時の記憶を辿りつつ技術的にどんな仕組みだったのか知ることができましたw

前半課程と後半課程の合間

はてなの社員さんによる京都観光に連れて行ってもらいました!
哲学の道以外行ったことのない場所で、とても良かった…

f:id:ktr_0731:20170908174049j:plainf:id:ktr_0731:20170908174054j:plainf:id:ktr_0731:20170908174059j:plain
左から南禅寺禅林寺、鴨川デルタ

後半課程

後半課程では希望通り Mackerel チームに配属されました。
相方は id:cohalz で、Scala がめちゃくちゃできてすごかった!!
メンターは id:itchyny さんで、以前からブログを読んだり、GitHub を見ていたりしていて知っていたので、そんな方にメンターになって頂けるのかとびっくりしました。
Mackerel はバックエンドが Scala、フロントエンドが AngularJS と TypeScript でできていて、自分は割りとフロントエンド周りの実装をしていました。
ペアプロしたり、フロントエンドとバックエンドに分かれてに開発したり、一人一つの機能を開発したりと色々なやり方をしました。
二人で開発していると、いろんな気付きがあったりしてとても良いです。
今年の Mackerel チームは6機能開発 & 3回のリリースを行いました! 🙌

f:id:ktr_0731:20170911215926g:plain
初リリースの様子です

id:itchyny さんは、1を聞くと100を教えてくれるようなメンターさんで、とてもお世話になりました。自分たちだけではこれほどの成果を出すことはできなかったと思っています。
また、すべての機能のデザインは id:takuwolog さんに手がけて頂きました。
自分たちが開発した機能については id:daiksy さんに Mackerel の公式のブログで記事を書いて頂きました。
このように、Mackerel チームの方々には本当にお世話になりました。ありがとうございました!!!

mackerel.io

mackerel.io

f:id:ktr_0731:20170911221145p:plain

後半課程の合間

宇治に観光に行ってきました 🚄

syfm.hatenablog.com

環境

はてなインターンはすべてにおいて環境が良いです。
ホテルはもちろん用意されていて (しかもオフィスまで5分)、昼ごはんはオフィスで毎日まかないが出ます 🍣
ちなみに今年からシングル部屋になって LGTM 画像は手に入らなくなりました。

twitter.com

京都なので観光もできて、周りにあるご飯屋さんも美味しいところばかりです。(美味しい飯屋情報もあります)
何度か社員さんにごちそうにもなりました。

オフィスではお菓子やジュースが食べ・飲み放題です。

本当にお金を使いません

インターン自体も、最初の方で書いたとおり、メンターさんや社員さんが必ずいて、気軽にガンガン質問できます。
後半課程では大体のチームが何度か開発 → レビュー → リリースのサイクルを回すことができるので非常にスピーディな開発が体験できます。

リリース後、Mackerel を使って頂いているユーザさんや、はてなの社員さんから感謝の声が聞こえてめちゃくちゃ嬉しかったです。

f:id:ktr_0731:20170913003136p:plain
良いシールももらえます

感想

はてなの社員さんや同じインターン生たちの技術力やサービスに対する姿勢、考え方を見て非常に刺激を受けた4週間でした。
恐らく、こんなにインターン生のことを考えられて作られたインターンは他のどこにもないと思います。
最初の方でもいいましたが、少しでも興味があるならば絶対に応募すべきだと思います。
自分の今までやってきたことを見つめ直すいい機会になったかなと思うので、これからのエンジニア人生にこの最高の体験を活かせていけるようこれまで以上に頑張っていきたいと思います。
最高の夏をありがとうございました!!

他のインターン生の記事

hogashi.hatenablog.com

snowman-mh.hatenablog.com

ishikawa-pro.hatenablog.com

k3ntaroo.hatenablog.com

cohalz.hatenablog.com