カメラを購入した

子供の成長を記録するために必要だという大義名分を掲げて、新しいカメラを購入した(2年半ぶり2回目)。

結論としてはソニーのα6400を購入した。良い瞳AFがついている比較的軽量な機種。子供の撮りやすさや取り回しを考えると、まぁそうだよねというところに落ち着いた感じ。35mmの純正単焦点をくっつけて、しばらくやっていく。

とにかく購入するまでにあれこれ、検討するフェーズが楽しかった。その瞬間は無限の夢が広がっていた。子供取るなら良いAFほしいよなーとか、ちゃんと趣味にしていくならフルサイズの沼に向かったほうが最終的なコスパがいいのではないかなーとか、なぜかα7IIがめちゃくちゃ安くなっていてフルサイズが10万そこらで買えるなーとか、ボディ内手ブレ補正どうなのかなーとか。Googleスプレッドシートで購入カメラ候補の属性とpros./cons.を整理して検討した。

このようなtweetをしたところ多方面よりアドバイスをいただき、たいへん参考になりました。

カメラは万年初心者なので、あらためて初心者用の基本の本とかを読み直して、学びを得ている。学習曲線の傾きが普段生きている大きいので楽しい。

カメラが追加されたことにより、さすがに学生の頃から使っているドライボックスに入らなくなってきたので、収納場所を考える必要があった。すわっ、これは防湿庫をついに買うときが来たかと盛り上がったものの、急に冷静になって家の納戸の整理を始めた。今、必要なのは防湿庫じゃない... 単に収納スペースが必要なんだ...。

何故か我が家の納戸は散らかっていて、それが、ずっと気になっていた。ついにそれに向き合ってめちゃくちゃ片付けをしたところ、生活がめちゃくちゃ改善した。みなさんカメラ買いましょう。

f:id:hakobe932:20191109193443j:plain
なんの変哲もない鴨川です

プログラミングRustを読んだ

プログラミングRust

プログラミングRust

  • 作者: Jim Blandy,Jason Orendorff,中田秀基
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2018/08/10
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る

ずいぶん積んであったので時間もあることだし読んだ。Rustについて構成が良く、あと分量があるのもあって、Rustの特徴である所有権の考え方への理解が深まった。

Rustではプログラミングのあらゆる場面で所有権の機構が関わってくる。そのためまずは所有権の話題についてしっかり理解したあとで、徐々に他の部分を理解する必要がある。なのでこの本では、2章の「Rustツアー」でマンデルブロ集合の描画プログラムを試すところでざっくりRustの雰囲気を教えてくれたあとで、さっそく4章の「所有権」で、重要な概念を学ぶことになる。そこからは、プログラミング言語の書籍によくある順番で、式やらモジュールやら構造体やらと順番に教えてくれる。

基本的な言語機能を学んで、所有権について雰囲気がわかってきたところで、後半くらいから所有権がからむとちょっと難しくなるクロージャやイテレータやコレクションの話題が登場する。このあたりは説明も充実しているし、コードもいろいろでてくるので、所有権についてウンウン考えながら読むことになる。すべてを読み終わるころには、自然と所有権の考え方が身についている(ような気がする)。

すばやく読んだし、あんまり手を動かしていないので、ばりばりRustが書けるかというとだいぶあやしいものの、Rustのコードをみてもだいたい雰囲気がわかるようになったし、この本を辞書代わりにすればRustを使っていける気がする。ただ、そもそもRustはシステムプログラミングのための言語なのですごく使いたくなる場面があるかはわかんないなと思う。WebAssemblyとかを、Fastlyのエッジコンピューティング環境で動かすとかはできそう。

近況

これは直接のお知り合いの方に向けた、個人的な近況の報告のための記事です。オープンインターネットを用いるのが最も適切に伝わりやすそうなので、このようにしていますが、関係のない方にはすいません。

新卒として2010年に入社した、はてなを退職しました。最終出社は4月26日でした。2008年に参加したインターンシップも含めて数えると10年以上はてなで働いていたことになります。

10年の中で本当にたくさんの方にお世話になりました。ずっとにこにこしながら働き続けてこれたのは、これまで出会ったはてなスタッフの皆様のお陰です。大変なこともあったけど、楽しかったな、達成できたな、と思えることのほうがたくさんあります。ありがとうございました。

特に、僕のわがままを聞いていろんなチームに配属してもらい、いろんなメンバーと働かせてもらったこと、チーフエンジニアとしてエンジニアのみんなが楽しく仕事をするサポートを任せてもらったことは、とても大事な経験になりました。自分を育ててくれたインターンシップの運営に関わることもできました。

退職の理由としては、10年の中で僕にもいろんな変化があって、最近では子供も生まれたりしたこともあり、ここらで新しいチャレンジをしてみようと思い立ったという感じです。なんかすごい出来事があって辞めるとかそういうわけではないです(念のため)。

10年もいると、思い出はめちゃくちゃたくさんあって、社内グループにエントリを書いておいたので、見られる人は見てもらえると幸いです。最後の行には、「最終出社日に開催したガンプラソンにて、 onishi さんが、”はこべさんを称える歌”全932番を熱唱してくれる」 を追加しておきました。

今後は、引き続き関西を拠点に、Webエンジニアを続ける予定です。技術勉強会や鴨川あたりにちょいちょい顔を出すと思いますので、また遊んでもらえるととてもうれしいです。これからもよろしくおねがいします。

最近読んだ本

ここ数ヶ月で読んだ本の感想です。 わりと技術書ではない本が多い。子供を寝かしつける時間に読んでるのだけど、薄暗い環境ではバックライトのついているKindleが大変便利。Kindleで出てない本はあまり読めない。

人を動かす 完全版

人を動かす 完全版

自己啓発本の元祖みたいな本で、原著は1937年くらいに書かれていて古い。SOFT SKILLSという本で紹介されていて読んだ。基本的に人間は自分の利益を一番に考えている、ということを前提に、他人の利益になることをあえてやっていくと、いろんなことがうまくいくよって話。いくつかのプラクティスに合わせて、具体的なエピソードがたくさん紹介されていておもしろい。著者は自分で伝記を書くくらいリンカーンが好きで、リンカーンまじすげーって気持ちにもなれる。

モチベーション3.0 持続する「やる気!」をいかに引き出すか (講談社+α文庫)

モチベーション3.0 持続する「やる気!」をいかに引き出すか (講談社+α文庫)

2009年くらいの本で、その当時よく話題になっていたのを思い出した。褒められたり罰せられたりするモチベーションよりも、自分が心の底からやりたいというモチベーション( = 内発的動機)の方がより創造的な成果を継続して出せるぞというような話。技術をマスターするには、何年もの間、継続して取り組む力が必要だから内発的動機がめちゃ大事って話があって、子育てとかで気をつけようって思った。

ビジョナリー・カンパニー ― 時代を超える生存の原則

ビジョナリー・カンパニー ― 時代を超える生存の原則

別の記事で感想を書いた。

NETFLIXの最強人事戦略 自由と責任の文化を築く

NETFLIXの最強人事戦略 自由と責任の文化を築く

結構前に読んだので記憶が曖昧。現在の事業に適した人を採用して、方向性が合わなくなった人には転職をおすすめするってのを、割とドライにやってるって話題が興味深かった。Netflixとしては検索機能が大事だと思っているときに、めっちゃFacebook連携をやりたい人がいたんだけど、SNSやりたければFacebookに転職しても良いのよって声かけて、最終的には出て行くことになったとか。なんなら転職のサポートをして推薦文を書いたりするらしい。基本理念を大事にして、その理念に賛同するメンバーを集めたり育てたりするという、ビジョナリーカンパニーのイメージにも近い感じがした。

イシューからはじめよ―知的生産の「シンプルな本質」

イシューからはじめよ―知的生産の「シンプルな本質」

結構まわりの人が話題にしていることが多い気がしてみて読んでみた。答えを出したいイシューに対して決められた期間で答えを出すためにどのような、考え方、取り組み方をすれば良いかについてすごく綺麗にまとめられていた。自ら問題を定義するような仕事をしている、(著者もそうであったように)研修者の方なんかにはとくに役立ちそうに感じた。そうでない仕事をしていても、やってきた課題を鵜呑みにせずにまずイシューを見つけるところから始めるのは良さそうに思う。自分がいま何を学ぶべきかをよく考えるけど、そういう場面でも学んだ結果として、自分にとってのどんなイシューに答えを出せるかは意識しても良さそうと思った。

逆境に弱い人、逆境に強い人

逆境に弱い人、逆境に強い人

自分は逆境に弱いなーってずっと思っていたところ、TwitterのTLにこの本のURLが流れてきてためしに読んでみた。大変なことでも、人生長いので大局的に見るとどうにでもなるよとか、普段からうじうじしてるとそれだけで体力を使うから、いざというときに力が出ないよとか、多量のエピソードとアドバイスがつらつら書かれている感じのスタイル。論理的には断言できなさそうなことも、どんどん断言されているので、読んでいてドキドキする。元気のない人を元気づけようとしている感じの本なのでそういう感じなのだと思う。とはいえ、いろんな資料への参照もあってしっかりした感じだし、ちょっと見方を変えて気楽に元気にやっていこって気持ちにはなれた。

振り返ると結構いろいろ読んでるけど、計画性はなく雑に読んでいる状態。いい本読みたい。

ビジョナリー・カンパニーを読んだ

ビジョナリー・カンパニー ― 時代を超える生存の原則

ビジョナリー・カンパニー ― 時代を超える生存の原則

普通に有名な本で、モチベーション3.0という本を眺めていたらおすすめされていて機運が高まり読むことにした。

著者は、アメリカの様々な業種の企業のCEOにアンケートを取り、そこから浮かび上がってきた卓越した18の企業と、それらに対応する比較対象の企業を18選び、その18組の企業について業績や基本理念、歴史といった様々な視点での調査を行っている。6年もの長い調査の結果、浮かび上がってきたビジョナリーな企業に共通する性質について紹介したのがこの本だ。

この本の原著は1994年に発売されているので、時代背景の違いは多少感じるものの、取り上げられているトピックについては企業で働いている僕のような個人が現代も共感できるものが多かった。ビジョナリー・カンパニーとして取り上げられている企業には、テクノロジー系だとヒューレット・パッカード、ソニー、IBMなどがなどがあった。

ビジョナリー・カンパニーを作り上げるポイントが本書ではいくつか挙げられているけれども、最も大事とされていて、自分としても印象に残ったのは「基本理念を維持し、進歩を促す」という慣行についてだ。つまり、企業の目的や価値観からなる基本理念を土台にすることで企業を継続し、それと同時に絶えず変化して進歩していくことで生き残るということだ。これらをどちらも諦めずに行えているかどうかがビジョナリーであるかの鍵となっている書かれている。太極図が挿絵に書かれていてそういう感じ。

言うのは簡単だけど、実際にやっていくのは、めちゃくちゃ難しいよねとは思う。まず基本理念を浮かび上がらせるのが大変だし、それを従業員が常に意識し続けられるようにするのも大変だし、常に進歩するってのもいろいろあって簡単ではないし。本書でもめちゃくちゃ難しいのでありとあらゆる工夫をし続けてがんばって維持するんじゃ、と書かれている....。18の企業がどういった工夫をしてきたかについては何章もかけて紹介されている。

工夫のなかでおもしろかったのは後継者を育てることの重要性について述べられているところだ。本書のビジョナリー・カンパニーの定義では企業が長く続いている(50年近く)ことが要求されており、経営者が代替わりしようとも、世代を超えて組織自体が繁栄し続けている企業に注目している。人間はいつか死ぬので、一人のカリスマがいるだけでは、組織が繁栄し続けることはできない。そのことに気づいて、数十年先の会社がどうなっていくかについて考えて、十分な時間をかけて基本理念を完璧に理解している後継者を育てた企業が長く継続しているのだ。自分としてはそういう時間スケールで考えたことがなかったので興味深かった。

本書では、企業のいろんな性質について、うまくいっている企業と、そうでない企業の具体例による比較がかなりの分量ある。それを読んでいると、自分の働いている環境ではここはうまくいっているな、ここはもう少しだなと、都度思い返すことになって、ある意味真剣に読んでいくことができた。気持ち的な負荷はまぁまぁあるので、疲れているときには読みづらかった。

企業はこうあるべきという大正解は別にないと思うものの、自分の中でうまくいってる企業の一般的なイメージが膨らんだので、読んでみてよかった。

grpc-gateway と使われてるProtocolBuffer周辺技術メモ

grpc-gatewayはHTTP2+ProtocolBuffer をプロトコルに用いるgRPCのサービスを、HTTP/1.1のRESTfulな JSON APIとして利用できるようにするリバースプロキシを生成してくれるツールだ。

厳密にはProtocolBuffersを処理するコマンドであるprotocのプラグインとして動作し、protocに読み込んだgRPCのサービス定義をもとにGoで記述されたコードを生成する。生成されたコードはHTTPサーバのハンドラになっていて、net/httpに登録して使えるようになっている。

ハンドラはHTTP/1.1でリクエストを受け取ると、リクエストに含まれるJSONを対応するProtocolBufferのメッセージに変換し、プロキシ先のgRPCサービスのメソッドを呼び出す。このgRPCサービスは、元にしたスキーマが同じであればGo以外の言語で実装されていても良い。そしてメソッドの呼び出し結果のProtocolBufferメッセージをJSONに変換してレスポンスを作る。

gRPCは利用したいが、既存のシステムから簡単に利用するためにREST APIの口を残したいだとか、管理用のAPI Explorer的なものを作るときにWebブラウザから直接利用できるREST APIがほしいだとか、そういった際に便利なツールである。

くわしくは作者であるyuguiさんの紹介記事やリポジトリのREADMEを読むとわかりやすい。

使い方などは上記の記事を読めば十分なので、この記事ではgrpc-gatewayを利用する過程で僕が学んだ gRPCやProtocolBufferに関する知見をまとめてみようと思う。メモ的なものだけど、役立つ資料へのポインタも貼っておくので何かの参考になればうれしい。

protocとプラグインによるコード生成

grpc-gatewayを利用する際には以下のようなコマンドを実行する。このコマンドの結果としてリバースプロキシのコードが生成される。

protoc -I... -I... --grpc-gateway_out=. path/to/your_service.proto

protocでは、--grpc-gateway_out のようなオプションを指定することでProtocolBufferのスキーマを元にしたコードの生成機能を利用できる。このオプションはプラグインの読み込みの仕組みになっていて、例えば --hogehoge_outのようにオプションをすると、protocがprotoc-gen-hogehogeという名前のコマンドが利用されるようになっている。

プラグインは標準入力からパース済みのProtocolBufferのスキーマ情報を受け取り、その情報を元に何らかの処理を行って、結果として生成するファイルの名前やその内容を標準出力に出力するというインタフェースになっている。標準入出力でやりとりされるデータがProtocolBufferのバイナリになっているのがおもしろい。

詳しい仕組みについては、yuguiさんによる以下の記事が参考になる。

ProtocolBuffer 定義ファイルのoption

grpc-gateway を利用する時使うProtocolBufferのスキーマは、例えば以下のようになる。

syntax = "proto3";
package articles;

import "google/protobuf/empty.proto";
import "google/api/annotations.proto";

// 省略

service ArticlesService {
    rpc Post(PostRequest) returns (PostResponse) {
        option (google.api.http) = {
            post: "/articles/post"
            body: "*"
        };
    };
    rpc Recent(google.protobuf.Empty) returns (RecentResponse) {
        option (google.api.http) = {
            get: "/articles/recent"
        };
    };
}

注目すべきは、optionという文法でメソッド定義に対応するURLのパス情報が記述されている部分だ。

ProtocolBufferのスキーマは基本的にはメッセージやサービス定義を記述する仕組みではあるが、grpc-gatewayのような生成ツールから利用する固有の情報を定義に追加して埋め込むこともできる。その埋め込みのための記法がoptionで、この例のようにメソッド追加の情報を記述する以外にも、幾つかの文法要素に情報を埋め込むことができる。

メソッドに対してoptionに指定できる属性は、MethodOptions型としてあらかじめ定義されいるが、独自にoptionを定義して属性を追加することもできる。option (google.api.http) = ...のような表記はgoogle.apiパッケージにおいて拡張されたhttp optionを設定するといった意味になる。

この話題についてもyuguiさんの記事が参考になりおすすめだ。

ProtocolBuffer と JSONの変換

ProtocolBufferの仕様には、ProtocolBufferとJSONのマッピングが含まれており、ProtocolBufferとJSONの相互変換は基本的に可能である。各言語のProtocolBufferのライブラリにもJSONへの変換機能が含まれていたりする。

golang/protobufを使ってGo向けに生成したProtocolBufferのメッセージ構造体にはJSONへの変換のためのタグが指定されているので、Goの標準のjsonライブラリを使えばProtocolBufferとJSONの相互変換は可能である。ただ一部のデータ型は標準のjsonライブラリを利用するだけでは変換が難しいため、jsonpbというより完全な相互変換が行えるライブラリも存在する。

grpc-gatewayの内部では、ProtocolBufferとJSONの相互変換を行っている。デフォルトではjsonpbを利用するようになっているが、より高速な標準のjsonライブラリを利用する設定にもできる。

このあたりの話題については以下の記事でも詳しい。

感想

grpc-gatewayはツールとして便利なだけでなく、ProtocolBuffer周辺の様々な技術が利用されているので、自然と知識が得られてよかった。あとyuguiさんのgRPCやProtocolBufferに関する資料がとにかく充実していて、技術的背景を理解できるようになって良かったので、一通り読むことをおすすめしたい。

gRPC周辺技術にはそこそこ慣れてきたのと、情報ソースもわかってきたので、ある程度実用的なものを作ってみるのが次のステップのようには思うので少し考えてみる。

gRPCのロードバランシング

先日の記事から引き続きgRPCについて勉強してる。

gRPCのサーバをプロダクトで利用する場合に気になるのが、ロードバランシングをどういう風にやったら良いのかということで、その部分について調べてみた。

TL;DR: gRPC Load Balancing を読めばだいたいわかる

gRPCのロードバランシングのポイントとしては、gRPCが基本的にはHTTP2上に構築された仕組みである*1ことに注意して考えると良さそうだった。

プロキシ によるロードバランシング

まず考えられるのは、gRPCのサーバとクライアントの間にプロキシを設置してロードバランシングを行う方法だ。

よくあるHTTP/1.1の世界で考えると、複数のWebアプリケーションサーバの前段にnginxのようなリバースプロキシを設置してロードバランシングする方法になる。

gRPCはHTTP/2を利用するので、この方法の場合リバースプロキシもHTTP/2を理解できる必要がある。これを実際に行うには、例えば、先月リリースされたNginxのgRPCサポート機能が利用できる。一方、AWSの環境でよく利用されるALBは、プロキシの後ろ側の通信がHTTP/1.1になるため利用できない(参考: gRPC アプリケーションを AWS で動かすときの注意点 ) 。

上記の方法ではL7でのプロキシを用いていたが、L4のプロキシでロードバランシングする方法も考えられる。TCPのコネクションレベルでロードバランシングを行うのでL7のプロトコルがHTTP/2でも影響をうけない。これを実際に行うには haproxyを利用したり、AWSのNLBが利用できる。

気をつけないと行けないのは、HTTP/2の利点を活かすためgRPCのクライアントがなるべく一つのコネクションを使い続けるような仕組みになっていることだ。L4のプロキシによるロードバランシングが働くのはTCPのコネクションを張るときなので、そのコネクションを利用している限りは同じサーバを利用し続けることになる。

例えば、Webアプリケーションが1リクエスト処理するごとにgRPCのコネクションを毎回張るような実装であれば、L4プロキシによるロードバランシングでも十分よく機能するだろう。一方、サーバ起動時に一度だけつくったgRPCクライアントを使い続ける場合、意図せず同じ一つのgRPCサーバとのみ通信をすることになるかもしれない。

クライアントサイド ロードバランシング

ロードバランシングというと前述のようなプロキシサーバを用いた形式を考えてしまうのだけれども(僕は)、gRPC界隈ではクライアントサイドでのプロキシの仕組みも充実している。

クライアントサイドロードバランシングは、gRPCのクライアントがいくつかの接続先のサーバを知っており、gRPCメソッドの呼び出し時などに適宜、利用するサーバを切り替えることでロードバランシングをする方法だ。プロキシサーバを中継しないため、高速に動作するが、gRPCクライアントの実装が複雑になる。実際クライアントサイドバランシングは、どのgRPCクライアントにも実装されているわけではなく、少なくともGoとJavaには実装があるような状態だった。

GoのgRPCのクライアントライブラリにはround robin 方式のロードバランサー(grpc.RoundRobin)だけが実装されている。この grpc.RoundRobin は接続先のサーバの名前解決をする naming.Resolver を受け取るようになっている。

naming.Resolverの実装としては、DNSを用いたものが付属していて、DNSにホスト名を問い合わせることで幾つかのサーバのアドレスを取得して、gRPCの接続先のサーバの候補に加えるという仕組みになっている。naming.Resolverはワンショットで動作するのではなく、定期的に名前解決を実行して、サーバの候補を更新する。naming.Resolverの実装はDNSを用いる必要はなく、例えばEtcdにサーバの一覧を問い合わせるといった実装も可能になっている。

このような名前解決の仕組みだけでなく、サーバ側の負荷をフィードバックする仕組みなど、様々なロードバランサーの機能をクライアントライブラリごとに実装するのは大変なので、その部分だけを別のシステムに移譲する、extenal load balancingという仕組みを利用することもできる。gRPCのロードバランシングのコンセプトまとめたドキュメントには、external load balancerについても説明されている。おもしろい仕組みだけどもあまり実装はないようである(僕は grpclb っていうのだけ見つけることができた)。

結局どうすればいいのか

gRPC Load Balancing という記事の最下部にユースケース別のロードバランシングのおすすめ表があるので、これを参考にしまくると良い。Kubernetesを利用する場合は deeeetさんの
Kubernetes上でgRPCサービスを動かす | SOTA がめちゃくちゃ参考になりそうだった。

自分としては運用のイメージのしやすさとしては、nginxのgRPCサポート機能を使うかL4のロードバランサーを気をつけて利用するのが良さそうには思った。

gRPCの利用シーンとしてはマイクロサービスのインターフェースがやはりいちばん考えられるので、クライアントサイドロードバランシングをうまく使いこなせれば、より効率的な構成にできそうには思うが、サーバ構成をアプリケーションからみて動的に解決できる状態にまずする必要がありそうで、まぁ準備が大変そうだなという感想。

おまけ

クライアントサイドロードバランシングの雰囲気をつかむために例になるようなgRPCのサーバとクライントを実装してみた。

上述した、Goに付属のgrpc.RoundRobinを用いている。これもGoに付属しているDNSを用いたnaming.Resolverを動作させようとすると、DNSの設定を行う必要があって大変なので、初期値として与えた固定のgRPCサーバの列を返すnaming.Resolver を雑に実装して試せるようにしている。

github.com

次のステップ

たぶん grpc-gatewayの雰囲気をみておくと良い。grpcのクライアントの感じとかも調べると良さそう。

*1:正確にはトランスポート層は別のプロトコルを利用することもできる