2017、2018 年の振り返り

年が明けて 2019 年になりました。良い機会なので、2017、2018 年の2年間を振り返ってみたいと思います。

この2年間は色々な変化がありました。仕事面とプライベート面の2つに大きく分けてまとめてみます。

仕事面の振り返り

2017 年は、スカウトというプロダクトのグロースを主に行なっていました。弊社(Wantedly)ではプロダクトごとにチームがあり、自分はチームの中の Tech Lead & Product Manager として、「アイディアを機能に落とし込み、プロダクトを成長させる」という役割を担っていました。ポジションやチームは変わりつつも、2016年以前とはそれほど変わらない働き方でした。

一方、2018 年はインフラチームへ移籍をしたため、働き方が大きく変わりました。

弊社のインフラチームは、「SRE」と「技術基盤」という2つの役割を持っています。SRE としては、「安定したサービスの提供」に責任を持っており、SLI/SLA の策定や監視、障害対応、サービスの可用性やスケーラビリティを向上させる取り組みなどを行なっています。技術基盤としては、「エンジニアの生産性を最大化させること」に責任を持っており、様々な CLI ツールの作成や機械学習基盤の構築、CI/CD フローの構築・改善などを行なっています。また、弊社のマイクロサービスアーキテクチャをより良いものへ作り変えることや、社内横断的に必要なマイクロサービス(e.g. ユーザーアカウントを扱うサービス、ログインフローを扱うサービスなど)の開発も技術基盤として取り組んでいます。

インフラチームへ移ったことで、より社内横断的に必要な開発を行うようになりました。

移籍後にやった事は、細かいものを除くと以下の2つです。

  • 機械学習基盤の整備
  • 社内横断的に必要なマイクロサービスの開発

機械学習基盤の整備

機械学習基盤については、「社内の機械学習エンジニアの生産性を高める」事をゴールにプロジェクトを進めました。成果は Rejectcon や AWS Dev Day で発表しています。会社としても個人としても、やった事をちゃんと外に出せたのは良かったかなと思います。

https://speakerdeck.com/south37/number-rejectcon2018 https://speakerdeck.com/south37/number-awsdevday

また、「機械学習の評価データ管理」のためにいくつかツールを作っていて、それらは OSS として公開しました。

後で「プライベート面の振り返り」で詳しく書きますが、2017年頃から自分自身が OSS 活動に積極的になり、仕事でもそれが活かされてきたかなと思います。

社内横断的に必要なマイクロサービスの開発

社内横断的に必要なマイクロサービスの開発も行なっています。こちらはまだ道半ばで、プロジェクトとしてはちょうど半分ほど終わったところです。基本的には RailsAPI server を書いているのですが、社内で広く使われるサービスである事から、「API の schema を定義し、その schema を反映した server の実装および client library の提供」を行うようにしています。

API schema をどう記述するかについては JSON Schema や OpenAPI などいくつか候補を考えたのですが、最終的には protocol buffer の「.proto ファイル」を利用することにしました。理由としては、1つは後々 grpc へ移行したいと考えているためそれが自然に出来るようにしたかったから、もう1つは .proto ファイルから OpenAPI format の JSON を出力できるため、OpenAPI のエコシステムを利用できたからです(e.g. Swagge UI)。「後々 grpc へ移行」と書いたように、今は grpc は利用しておらず、.proto で記述した format の JSON response を返す API server と、JSON response を parse して object へ mapping する client library を提供しています。

すぐに grpc を利用しないのは、現時点では HTTP/2 用の proxy を社内的に導入していないため、RPC に HTTP/2 を利用する基盤が整っていないからです。ただ、基盤の導入は進めようとしており、それが出来たタイミングで grpc へ移行したいと考えています。

「.proto ファイルで JSON response の schema を記述する」という取り組みは世の中的にほとんど行われていないので、自分で仕組みを整えながら開発を進めています。細かい部分は以下のように gem として切り出して OSS にしています。

ただ、まだメインの仕組みについては公開できていません。メインの仕組みについても、後々整理して gem 化した上で、OSS にしたいと考えています。

仕事面の振り返りまとめ

インフラチームへ移った事で、働き方が大きく変わりました。 自分の興味の方向性ともあっており、良い変化だったと思います。

プライベート面の振り返り

プライベート面では、2017 年以降、OSS 活動に積極的になったと感じています。

きっかけは、2017 年 3 月に同僚や他社の知り合いと一緒に何気なく始めた Meguro.rb という地域 ruby コミュニティです。Meguro.rb は目黒近辺の会社で持ち回りでホストと会場提供をしながら LT と懇親会をしていて、最初は Wantedlyドリコム、Viibar の3社だけで始めました。開催するうちに Livesense, ラクスル, アカツキ, freee, Quipper, CaSy, SUPERSTUDIO とホスト企業がどんどん増えていき、今ではホスト企業は 10 社になりました。

Meguro.rb を始めてから、LT 発表する機会が増え、発表があると発表のために何か成果を出そうというモチベーションが生まれました。それが、OSS 活動にもつながったと思います。

2017、2018 年に行った OSS 活動について

2017、2018 年に行った OSS 活動について、いくつかまとめておこうと思います。

以下はいくつかのプロジェクトに対して送った PR の一部です。

個人的には、一番上の「Ruby 本体に contribute 出来たこと」が一番嬉しかったです(PR 自体は Close されているが、それは Ruby の contribution の扱いの方針によるもので、変更自体は別の commit で取り込まれている)。やったのは、「Ruby の文字列補完(String Interpolation)のパフォーマンス改善」です。Ruby は自分が最も書き慣れており仕事でも使っている言語なので、そのベースの機能を改善出来たことはとても良い体験でした。また、String Interpolration はベーシックな機能なので、インパクトも大きいと感じてます。

この contribution は、Meguro.rb でも紹介しました。

その他、自作のツール/ライブラリも OSS としていくつか公開しました。

rucc と yard2steep は Meguro.rb で発表したのですが、反響があって嬉しかったです。

rucc は Ruby で書いた C 言語コンパイラです。作ったきっかけは、コンパイラの勉強の為に 8cc という rui314 さん作の C コンパイラのコードを読んでいた事です。読むだけでなく写経した方が勉強になると考え、さらにただ C から C へ写経しても面白くないので Ruby へ移植する事にしました。class 構造の整理や ruby の機能による書き換え、足りない機能の追加などはありますが、ロジックの大部分は 8cc を参考にしています。時間はかかりましたが、とても楽しかったです。

yard2steep は、Ruby コード中の YARD アノーテーションを元に静的型チェックを行うためのツールです。2018 年の RubyKaigi で紹介されたsteep という「Ruby で静的型チェックを行うためのツール」向けに、型定義ファイルを Ruby コード中の YARDアノーテーションを解析して生成します。steep の発表の際に、「YARD を利用したい」という声を聞いて試しに作ってみたものです。実は、RubyKaigi 中のコード懇親会というイベントでプロトタイプを作ったのが project を始めたきっかけで、手応えがあったのでそのまま作りきりました。最初は parser を手で書いていて、それが楽しかったです(正確な文法を反映していなかったので、後で Ripper ベースに書き換えてしまいましたが)。

OSS 活動についてまとめ

2017 年から、OSS 活動に以前に比べて積極的になり、OSS に対する心理的ハードルがどんどん下がっています。良い変化だったと思います。

英語学習について

2018年は英語に対するモチベーションが上がって、DMM 英会話をやってみたり、1つの本を Audible と Kindle 両方で買って英語音声を聞きながら英語文章を読んだり、映画を英語音声/英語字幕で観たりし始めました。

きっかけは色々ありましたが、仕事の関係で AWS re:Invent に行けたのも大きいです。自分にとって初の海外カンファレンスで、行列で隣り合った現地のアメリカ人と話したり、Pab Crawl でアメリカに長く住む中国人と話したり出来ました。実は行く数ヶ月前から細々と英語学習をしていたのですが、現地で会話してみて「丁寧にゆっくり話してもらわないと聞き取りが難しい」ことを痛感し、より英語学習へのモチベーションが上がりました。

これも、良い変化だったと思います。

まとめ

2017、2018 年の2年間を振り返ると、仕事面/プライベート面の両方でポジティブな変化がたくさんありました。 良い取り組みについては今後も継続して取り組んでいきたいですし、今後もさらにポジティブな変化を起こしていきたいです。

ISUCON7本戦に出場してきました

ISUCON7本戦に出場してきました。 結果はスコア0、最終的にはFAILで終わるという惨敗でした。

出場メンバーは会社の同僚との3人組で、予選と同様に他の2人がアプリケーション担当、僕がインフラ担当という役割分担をしました。

残念な結果となってしまい、とても悲しい気持ちなのですが、その思いを昇華させるためにも当日やったこと、考えていたことなどを記録しておこうと思います。 尚、悲しい結果に終わったこともあり、後悔や言い訳の多い見苦しい文章となっています。あらかじめご了承ください。

当日の流れ

10:00 にレギュレーションが閲覧できる様になりました。 しばらくは運営側でid, passwordの配布に時間がかかっており、コンテストが始まらなかったので、その間に3人でレギュレーションの読み合わせを行いました。単純に読んでいるだけでも、複雑なアプリケーションで単純な最適化は難しそうだなーという印象を受けました。

最初の30分は僕が各サーバーのセットアップ(git管理下に置く、各人がsshできる様にauthorized_keysを配置する、netdataの監視を仕込むなど)を行い、他2人がDBのデータの確認とアプリケーションのコードを読んでの概要把握を行いました。

その後、最適化の方法をざっくり話し合い、以下の方針を決めました。

  • 方針1. calc_status が明らかにヘビーだから、なんらかの形でキャッシュする必要はありそう
  • 方針2. dbを触ってる部分はRedisに載せていくと良さそう
  • 方針3. roomごとにスコア計算は完全に独立しているから、roomごとにhostを振り分けて、hostごとにデータを持つ様にしたらthroughputが出そう(この時点では、redisをhostごとに建ててそこにデータをstoreすることを考えていたので、redisの負荷が減りそうくらいのイメージで捉えていた)
  • 方針4. static file配信はいつもの様にnginxでgzipで配信すると良さそう

今振り返るとこの時点での方針は悪くなかったと思うのですが、結果的には「方針4」以外は実装が思う様に進まず、ほぼmergeされる事はありませんでした。

自分が後悔している事の一つは、この時アプリケーションを読んでいた同僚から「ロックが必要になる」という事を言われた際に、ロックの方法についてもうちょっと自分もアプリケーションを読み込んだ上で議論すべきだったという事です。 自分はアプリケーションのコードは1行も読んでなくて、ただ「DBでロックを獲得するコードがある」と言われて議論した結果、DBを捨ててRedisを使うならRedisのincrでロック獲得を記述できそうという結論になりました。この「Redisのincrで実装したロック」は動作はしたのですが、毎回ロック獲得トライをRedisに問い合わせて行うというコストの高い動作の為か、スコアアップには繋がりませんでした。後で同僚からは「ロックはroom_nameごとに独立してかければ良かった」と聞かされて、そこまでの知識があればこの時点でroomごとに処理するprocessを分けて、ruby内部でmutexを活用しようという提案ができたかも。。。と後悔しています。

現実には、同僚の一人が「方針1」を、もう一人が「方針2」を進め、僕は「方針4」を行った後、便利スクリプト集(deployやログ閲覧、アクセスログ回収、各ホストの状態チェックなどをローカルのマシンからコマンド一発で実行できるもの)の整備やちょっとしたパラメータチューニング(pumaが10processで動いてmemoryを結構使っていたのでprocess数を減らしてthread数を増やしたりしてた)、2人とのペアプロなどを行なっていました。

「方針4」は一応スコアに効いて、9,600ぐらいになりました。しかし、それ以降僕らのチームのスコアが上がる事はありませんでした。

同僚が2人とも苦戦していたので、僕は定期的にペアプロでハマり解消を手伝っていました。

「方針1」を進めていた同僚が「途中まで出来た」といってベンチにかけてみたところ、スコアは上がらないどころか若干下がっている様に見えたので、その時はもう少し実装を進めてスコアを上げてからmergeしようという話になりました。結局、その後そのブランチがベンチを通る事はなく、彼は最後までそのブランチで作業し続けることになりました。(余談ですが、スコアが上がらなかったのは、おそらく前述の通りRedisをロックに利用していた為では無いかと疑っています)

「方針2」を進めていた同僚もRedisでロックをかけていて、こちらもベンチがなかなか通らずずっとハマっていました。最終的にロックを色々な箇所に設定する事でベンチは通ったみたいですが、それは終了の30分前であり、スコアも上がりませんでした。

(尚、「スコアが上がらなくてもmergeだけでもしておこう」といって「方針2」の一部はmergeされたのですが、最終スコアはFAILになってしまいました。不思議に思ってコードを見返すと、分かりやすく「引数が無いメソッドコール」というバグがありました。「ベンチ通ったからmergeした」と聞いたのに悲しい。。。)

結果としては、1日を通して有効な変更をほぼ入れられず、やりたいことが実現できないまま終了してしまったコンテストとなりました。

反省

自分の反省点はいろいろありますが、大きいのは以下の2つだと考えています。

1つ目は、自分がアプリケーションを全く読み込まなかったことです。「アプリケーションの仕様」を理解してないことから、途中で2人とペアプロする際も「コード的な間違いの指摘、修正」に終始してしまい、「アプリケーションの仕様の範囲で可能な限り効率的な実装を考える」という事が出来ませんでした。特に、今回の問題は効率的な実装をするにはスレッドプログラミングの知識が求められるものになっていたと思うので、自分の知識は本当はもっと活かせたんじゃ無いかと思っています。

2つ目は、自分がアプリケーションコードをほとんど書かなかった事です。これは1つ目の反省とも繋がるのですが、アプリケーションを読み込んでない状態では改善のアイディアを考えづらく、さらに残り時間が少なくなるほど「これからアプリケーションに着手する」といった手が取りづらくなり、結果としてほとんどアプリケーションを書きませんでした。アプリケーションがボトルネックというのは初めから分かっていたので、インフラ作業を捨てるというのも1つの選択肢だったように思います。

自分は普段はアプリケーションエンジニアとして仕事をしており、ISUCONは貴重な「インフラ知識をつけることができる、インフラオペレーションに慣れる事ができる」機会となっています。カーネルミドルウェアのチューニングをしてマシンを効率的に利用したり、デプロイツールなどを自作して様々なタスクを自動化するのは僕にとって楽しくて、ISUCONではインフラ担当としての参加にこだわっていました。ただ、今回はそのこだわりが良く無い方向に働いたな、と感じています。

結論

今年は悔しい結果となったので、また来年頑張りたいです!!!

謝辞

運営の皆さん、お疲れ様でした。綺麗に整理されたコードで複雑なアプリケーションが実装されており、運営の皆さんの気合を感じました。取り組みがいのある、良い問題だったと思います。ありがとうございました。

ISUCON7予選をギリギリの18位で突破しました

会社の同僚と一緒にISUCON7予選に出場しました。 結果は18位、ギリギリでしたが何とか予選突破できました。事前にチームで練習したり、便利スクリプト集を仕込んだりしていたので、練習の成果がちゃんと発揮できてよかったです。

同僚が当日やったことについてブログを書いてくれました。余裕があれば、僕の観点からのISUCON7予選についてもブログ書きたいと思ってます。

RubyKaigi 2017 に行って来ました(3日目)

発表

10:00-10:40: Compacting GC in Ruby by @tenderlove

10:50-11:30: Ruby for Distributed Storage System by @tagomoris

https://www.youtube.com/watch?v=KrWhhgWHTwE&feature=youtu.be

13:00-13:40: Bundler 2 by @colby-swandale

13:50-14:30: JRuby at 15 Years: Meeting the Challenges by @headius & @enebo

14:40-15:20: Boosting Performance Bottlenecls: Improving Boost Type by 60% by @jules2689

https://jnadeau.ca/presentations/rubykaigi2017/

15:50-16:30: Improving TruffleRuby’s Startup Time with the SubstrateVM by @nirvdrum

16:40-17:40: Towards Ruby 3x3 performance by @vnmakarov

発表感想

あとで追記予定です。Performanceの話が色々聞けて良かったです。特に、TruffleRubyと最後のKeynoteでのMJitの話が、夢のある話で印象的でした。

全体振り返り

7本x3日 = 21本の発表と、LT12本を見ていて、振り返ると盛り沢山でした。 どれも面白かったですし、言語処理系やパフォーマンスに興味を持ってる自分としては、詳しい人の話を聞けて楽しかったです。JRubyやTruffleRubyもかなり注目しているので、中の人を見れたのが個人的にグッドでした。

懇親会では、以前から話してみたかったRubyコミッターの方たちと話せて、良い機会になりました。自分の中でのOSSへのモチベーションも上がった気がします。 総じて、行って良かったなーと思います。

RubyKaigi 2017 に行って来ました(2日目)

発表

9:40-10:40: Keynote by @matz

10:50-11:30: An introduction and future of Ruby coverage library10 by @mame

13:00-13:40: Improve extension API: C++ as better language for extension by @kou

slide.rabbit-shocker.org

13:50-14:30: Automated Type Contracts Generation for Ruby by @valich

14:40-15:20: Asynchronous and Non-Blocking IO with JRuby by @jkutner

15:50-16:30: Bending The Curve: Putting Rust in Ruby with Helix by @chancancode and @hone

16:40-17:20: Write once, run on every boards: portable mruby by @yurie

17:30-18:30: Lightning Talks

発表感想

Keynote by @matz

RubyのModuleをベースにして、色々なプログラミング言語の機能を取り入れながら、Moduleが色々な役割を担うようになってきたよって話でした。 最近増えたRefinementやprependの狙いや位置付けについて、matz本人から話を聞けたのは良かったです。こうしてまとめられてるのを見ると、確かにModuleは色々な役割を担っててなんだかんだで複雑になってる気もしました。個人的には、namespaceとしての利用が面白いと思ってます(rubyのrequireはただRubyコードを実行するだけでimport, exportみたいな概念はないので、Moduleとしてglobalな空間での衝突を避けないと大変なことになる。。。w)

An introduction and future of Ruby coverage library10

test の coverage とはなんぞやぞいうお話と、Ruby の coverage library をもうちょっと良いものにしようとしてるよというお話。 Ruby で test coverage を計測したことなくて気付いてませんでしたが、line coverageしか公式ではサポートしてない状態だったらしいです。機能追加してくれるのはありがたいと思います。

Improve extension API: C++ as better language for extension by @kou

C++Ruby の extension library を作るなら、こんな風に C++ の中で Ruby っぽく書けて良いよ、みたいな話でした。 APIを考えるのが好きみたいで、実際にlibraryとしてある程度動くものを作ってるのがすごいと思いました。発表中に「binding libraryを作りたいわけじゃない」と言ってましたが、むしろbinding libraryを作る際に役立ちそうだと思いました(Rubyのオブジェクトを触ったりRubyのメソッド定義がやりやすくなってるように見えたので)。

cf. https://github.com/jasonroelofs/rice

Automated Type Contracts Generation for Ruby by @valich

RubyMineの中の人による、Rubyのテストコードから型情報を集めてうまく集約して出力する仕組みを作っている(作った)というお話。 型情報を集約するロジックの話はなかなか面白かったですし、RubyMineが色々機能拡張してるのはすごいと思いますが、全てのケースをテストで網羅するのはちょっと難しそうだなーと感じました(発表してる人は、みんなの力を合わせれば可能だ、と言っていてちょっと夢を感じましたが)

Asynchronous and Non-Blocking IO with JRuby by @jkutner

JRuby で非同期ノンブロッキングIOを利用したいケースのサンプル実装として、RatpackとNettyを利用したHTTPサーバーアプリケーションを作ってみたよってお話でした。

cf. https://github.com/jkutner/jruby-ratpack-async-demo

JVM系だとPlay FrameworkもノンブロッキングIOとして有名な気がするので、JRubyから利用は出来ないのかが個人的にはちょっと気になりました。

Bending The Curve: Putting Rust in Ruby with Helix by @chancancode and @hone

Rust で Ruby の native extension を作る為のライブラリとしてHelixというものを作っていて、こんな感じだよというお話。 2年前のRubyKaigiでも話してるのを聞いていたので、ちょっと気になっていました。Rustのマクロを使い倒してるみたいで、強力なマクロシステムを持つ言語は良いなと感じました(Cのマクロはただの文字列置換ですが、Rustのマクロはparseした結果に触れるみたいです。コードを見てると、identtyの様にidentifierとtypeが明確に区別されていたので、変なミスや予想外の変換が防げて良さそうだと感じました)

Write once, run on every boards: portable mruby by @yurie

Rubyマイコン上で動くプログラムを書いてるよ、一度書いたプログラムを共通で使えるようにしていこうよってお話でした。 デモでトラブル続出していたので大変そうでした。

Lightning Talks

たくさん発表があって説明しきれないですが、みんな発表のレベルが高いしユーモアセンスもあって面白かったです。LTは自分も挑戦してみたいなーと思いました。

懇親会

mirakuiさん、matzさんみたいな前から話してみたかった方と話せてよかったです。 matzさんには写真まで撮ってもらえて、嬉しかったです。

matzさん

Rubyのeachやブロックはかなり先進的だと以前から思っていたので、どういう経緯で「eachメソッドという発想に至ったのか」みたいな話を聞きました。each的な存在はsmalltalkから着想を得たと言っていて興味深かったです(調べてみたら、smalltalkにはcollection closure methodと呼ばれるメソッド群が存在していて、その中にrubyのeachに相当するdoの他、select, sort などblockを受け取ってcollectionに作用するメソッドが存在することがわかりました。smalltalkすごい)。forwhileみたいなキーワードになってた方がメソッドよりもかなり簡単に最適化出来るはずで、どういう発想でそこに至ったのか気になってたので聞けてよかったです。ついでに、他のプログラミング言語にもiteratorを宣言する構文があった(関数の引数としてiteratorを渡せるようになっていた)という話を聞きましたが、言語の名前は忘れましたw

mirakuiさん

Cookpad CTO 大変ですか、みたいな話をしました(チーム編成、評価制度など)。 海外と国外の開発どう進めてますか、という話も興味があったし自社でも色々考えてる部分なので聞いてみました(海外と国内で大きくシステムを2分してる。海外はその中でさらに国ごとに機能を分けてる、それは料理は地域固有の文化に密接に結びついており、文化ごとに適切な表現や探し方、機能が異なってくるから、そうせざるを得ないと思ってる、など)。やはり、どのサービスも海外展開というと苦労してるんだなー、という印象を持ちました。

2日目総括

発表をたくさん聞けて大満足でした。特に、LTで「もっと長い時間で話せる内容の発表」がたくさんあり、全体のボリュームが割増されていた様に感じます。

RubyKaigi 2017 に行って来ました(1日目)

発表

10:30-11:30: Keynote by @n0kada

https://slide.rabbit-shocker.org/authors/nobu/rubykaigi-2017/

13:00-13:40: Fiber in the 10th year by @ko1

13:50-14:30: How Close is Ruby 3x3 For Production Web Apps? by @noahgibbs

http://bit.ly/kaigi2017-gibbs

14:40-15:20: Gemification for Ruby 2.5/3.0 by @hsbt

https://www.youtube.com/watch?v=VKm93Mwe__k&feature=youtu.be

15:50-16:30: How to optimize Ruby internal by @watson1978

16:40-17:20: mruby gateway for huge amount of realtime data processing by @naritta

17:30-18:30: Ruby Commiters vs the World

発表感想

Keynote by @n0kada

Rubyコミッターの日常はこんな感じですよ、というお話。 ライブコミットやスライドのライブ編集など、その場にいる事で楽しめるコンテンツが盛り込まれていて、会場で聞くことができてよかったです。Rubyのコードはコアっぽいところはそこそこ読んでるつもりですが、parse.yは複雑すぎて変更が難しくなってると感じます。。。

Fiber in the 10th year by @ko1

Fiberを10年前に作ったけど、意外なところで使われて嬉しかったし、ちょっと微妙な実装だったところを最近直したりしてたよ、みたいなお話でした。 Fiberはコルーチンやサブコルーチンの機能を実現できるので、個人的には結構好きだったりします(https://qiita.com/south37/items/99a60345b22ef395d424 みたいに async/await の実装に使えたりするので面白いです)。

How Close is Ruby 3x3 For Production Web Apps

Ruby3x3に向けてどれだけ早くなってるかを調べるために、Rails appを対象にしてbenchmarkをとってみたよ、という話。指標は色々あるけど、http requestを捌くthroughputで1.5倍くらい早くなってるとの事。 会社としてこういう取り組みをしてるみたいで、OSSへのモチベーションが高い会社なんだなーと思いました。

Gemification for Ruby 2.5/3.0

Rubyの標準ライブラリをGemに移行して行ってるよ、というお話。狙いとしては、Ruby本体からライブラリを切り離す事で「Ruby本体はバージョンアップできないけど特定のライブラリだけバージョンアップする」みたいな事をやりやすくしたいらしいです。 個人的には、Gemに移行する際に基本的にgithubにレポジトリを作ってるみたいだったので、外からコードが見えやすくなってコントリビュートのハードルが下がりそうなのが好感触でした。

How to optimize Ruby internal

watsonさんが3月頃からRubyにperformance改善のpatchを送り続けていた際に、どういう狙いでどういった変更を行ってたかを話していました。 自分もちょうどその頃Rubyのコードを読んだりRedmineのIssueを見たりGitHubのPRを見たりしていて、watsonさんの怒涛のperformance improvementのpatchも目撃していたので、どういうモチベーションだったのか聞けて良かったです。

mruby gateway for huge amount of realtime data processing

h2oのmruby handlerの中で外部通信を並列で行いたくて、その辺の処理をうまく記述するためにhttp_requestとFiberを組み合わせて書いてたよ、というお話。 僕の中ではFiberは基本的にloopと組み合わせて使う印象で、そのループがおそらくh2oの管理するイベントループなのが興味深かったです(もしかしたら何か勘違いしてるかも)。

Ruby Commiters vs the World

Ruby Commiter が会場のみんなから質問を受け付けて色々答えるセッションです。 EndohさんがCookpadのフルタイムコミッターになりましたっていうニュースの後で始まり、EndohさんがRubyへ型システムを載せようとしてる事から型の議論が熱かったです。matzさんは型を手で書くのはすごく嫌、どうしても入れるならせめて後から消せる形(コメントにメタ情報として記載)で、と言っていて、強い思い入れを感じました。個人的にはcompile時にstaticに型チェックして欲しい気持ちはあり、その為なら多少記述が増えても良いと思う派ですが、そこをテクノロジーで何とか記述させずに済ませたいという気持ちはわかるなーと言うスタンスです。

懇親会

  • Rubyコミッターの方とたくさん話せました。
  • 以前から話してみたかった人と話せたので、良い体験でした。

Watsonさん

彼の patch を参考にして自分も performance improvement の patch を書いたりしていたので、以前からお話ししてみたかった方でした。どうやって着手する箇所を見つけてるのか気になってましたが、やっぱりコードを端から見ていって直せそうな箇所を直す、というアプローチをとっていたらしいです。(普通のアプリケーションの速度改善なら profile をとってボトルネックを見つけて、という形で performance improvement は行いますが、Watsonさんはばらばらと色々な箇所に着手していたので、profiling とは別のアプローチが必要だよなーと感じていました。)

rheniumさん

自分のpatchのreviewを行なってくれた人で、調べるとすごく若い雰囲気を感じたのでどんな人か気になっていました。話すと、大学3年生らしく、やっぱり若かったです。どういう経緯でRubyコミッターになったのか、みたいな話をしました(openssl本体やopenssl gemにバグがあって修正patchを送っていたら、任命されたらしいです)。

Endohさん

実は2年前のRubyKaigiでお話ししたことがあり、さらに弊社CTOと大学の同級生というちょっとした繋がりもあり、覚えてくださっていて向こうから話しかけてくれました。とても嬉しかったです。Rubyの型システムをどういう形にするかは悩ましいけど、PythonのType Hintsっぽいものが落とし所としてはありえそう、みたいな話をしました。

k0kubunさん

llrbなどが良いアプローチだなーと思っていたので以前からお話ししてみたかった方でした。話しかけたら、向こうも自分を知ってくれていて、嬉しかったです(自分の書いたpatchを彼がスライドで取り上げてくれたことがあって、そこで認知してくれていました)。 Rubyを根本的に早くするにはJITやその中での様々なoptimizeが必要なはずで、whileみたいなキーワードは扱いやすい方だけどeachみたいなメソッド呼び出しのループは難しいよね(blockのinline化やメソッド再定義された時のdeoptimizeが必要)って話をしたら、「VradがJITに着手していて、『2ヶ月後にはCRubyのJITが作れる』らしいよ」と言っていました。すごいw Vradimir MakarovさんはRuby 2.4で内部のhash table実装高速化もしていてすごい人なので、期待したいです。

2016年振り返りと2017年に向けて考えている事

あけましておめでとうございます。気がつけば2016年もあっというまに過ぎ去り、2017年になりました。

新年明けたばかりで良い機会なので、2016年にどういう事をしたか、どういう事を考えていたかを振り返った上で、2017年に何をしていきたいか考えてみたいと思います。

2016年の仕事の振り返り

まずは仕事面での振り返りです。

僕は2015年4月から新卒のソフトウェアエンジニアとして働き始めたので、2016年は2年目として過ごす事になりました。

取り組む内容として「ソフトウェア開発というアプローチで『サービスを作る』」という部分は変わりません。ただ、2年間働いて積み重ねてきた事の結果として、取り組む内容や責任を持つ範囲が広がった様に思います。

2016年に取り組んでいたのは、主に「新規サービスの立ち上げ」や「小さく始まったサービスをリニューアルして本格的に始動させる」といった事で、エンジニア2人程度の小さなチームではあるものの、「チームのリーダー」として働く様になりました。

ここで「チームのリーダー」と表現したのは、サービスを開発するチームの技術的選択と人事的な評価に責任を持つのが求められる役割で、いわゆるテックリード+エンジニアリングマネージャーみたいなポジションです。初めての経験なのでどんなものかと思いつつ、最近はこの辺の話題がRebuild.fmのおかげでいろいろ盛り上がっていて参考になる情報も多かったので、手探りながらも取り組んでいました。

その他、弊社では会社の文化として「サービスの成長の為の"取り組み"にもエンジニアが責任を持つ」様にしているのですが、そこにはいつも難しさを感じています。弊社では、開発する機能や施策の決定、その効果に対してエンジニアが責任を持ち、サービスの成長を評価するための数字を目標として設定します。このあたりの取り組みは、過去に別のブログにもまとめました。目標に向けてのアプローチを自分で考える為、やりがいや責任感を強く感じる一方、より良い取り組みは無いだろうかと常に頭を悩ませる事にもなります。アイディアなども重要になって来る上に正解は無く、自由と責任はセットだなーと常に感じています。

「意思決定」という言葉はよく聞くものの、それに伴う「責任」について最近は考える様になりました。

2016年のプライベートの振り返り

プライベートを振り返ると、2016年はずっと本を読んだりコードを読んだりしていた様に思います。

僕はHajime Moritaさんという方を勝手に一方的に尊敬していて、彼のブログやツイート、Podcastでの発言をいつもありがたく読んだり聞いたりします。その中でも彼のRebuild.fm ep127に置ける「実装のアイディア(最適化のアイディア)はOSやプログラミング言語RDBみたいな昔から研究されてるソフトウェアの実装から盗める」発言を聞いて以来、コードを読むことに対するモチベーションが増しました。これが、本を読んだりコードを読んだりする事に専念していた主な理由の様に感じます。

備忘録も兼ねて、2016年に興味を持ったトピックをリンク付きでまとめて見たいと思います。(どうでも良いコメントですが、自分が読んでいた本や文章を振り返ってみたら、自分の興味の変遷が分かって面白かったです)

プログラミング言語処理系の実装

プログラミング言語処理系には昔から興味があり、言語処理系作成について記述した書籍(言語実装パターンコンパイラ―原理・技法・ツールなど)を興味ある部分だけつまみ食いしたり、特定の言語処理系について記述した書籍(Ruby under a microscopeなど)を読んだりしていました。

また、オンラインの媒体としては、48時間でSchemeを書こうLambda Calculus - Write You a Haskelを写経してみたり、8ccのcommitを最初から追いかけて写経してみたりしていました。

Parser の実装

プログラミング言語処理系の実装方法の中でも、自分の中で特に興味があったのは「Parser の実装方法」です。JSONSQL、汎用プログラミング言語などソフトウェアの至る所でParserは必要になる(情報を表現するにはその情報を表現する為のフォーマットとそのフォーマットから情報を取り出せるParserが必要になる)ものの、ほとんどの場合には既存の実装を用いて済ましてしまう為、自分で興味を持たない限り「どう実装されてるかを知る機会が無い」と感じていました。重要性の割に、自分はちゃんと仕組みを理解してないと感じたのです。

yaccの文法は昔勉強した事があったのですが、「yaccの使い方」が分かっただけで、内部で何をしてるか、あるいは他の方法が無いのかなどが気になってました。

という訳で書籍を読んだりコードを読んだりしてた訳ですが、結果として自分の中で知識が整理されて、すごく良かった様に思います。

まず、「文法」と一言で言っても、その文法のParserの作りやすさ、実行時間はその「文法」に依存します。文法が許すなら、LL(1)再帰下降Parserの様な「入力文字列長に対して線形の実行時間で処理できる」Parserを作ることができます。LL(1)再帰下降Parserはまた、1字先読みでdispatchすれば良いのでコードも読みやすく、手で書くのも簡単だったりします(JSON Parser くらいなら、自分で書く事も簡単にできます。まあ、僕の実装はmatchの判定しかしない&色々バグはあるんですが。。。)

一方、複雑な文法になると「固定長先読み再帰下降Parser」では次にmatchする文法規則は決定出来ず、matchを試して失敗したらバックトラックしてまた別の文法規則でのマッチを試して、、、といった動作が必要になります。この様にバックトラックが入ると、メモ化などをしない限り実行時間が入力文字列長に対して 指数関数的 に増大し、実装も複雑になります。その為、文法をどう設計するかはparserの実装に対して重要な意味を持ちます。

再帰下降Parserもバックトラックなどが入ると自分で一から書くのは大変になる為、parser generatorを利用したり、parser combinatorなどのライブラリを利用したりします。また、ボトムアップなparseを行う手法(LR法)もあったり、その為のparser generator(yacc など)を利用したりも出来ます。

parser generatorが何をやってるか、また自分でparserをイチから書くならどう書くか、parseが簡単な文法というのはどういったものか、parserを書く為に利用できるツールやライブラリにどういったものがあるか、といった事について自分の中で知識が整理されたので、スッキリしました。

正規表現エンジンの実装

正規表現エンジンの実装は昔から興味があったのですが、正規表現技術入門 がすごく勉強になりました。オートマトン理論ベースの実装とVMベースの実装の概念とコードがどちらも詳しく解説されていて、読むと正規表現エンジンに対する理解が深まりました。

計算理論の話

Parserや正規表現エンジンの勉強をしていたらだんだんオートマトンチューリングマシンに対してしっかりした理解をしておきたいと考える様になり、一時期計算理論の基礎を読んでいました。個人的に一番良かったのは非決定性に対する理解が深まった事だと思います。以前までNPの説明がイマイチピンと来てなかったのですが、非決定性チューリングマシンの動作やツリー状の探索パスがイメージできる様になった事で、しっくり来る様になりました。

変化に強いシステムを作る方法

仕事をする様になると「大きなコードベースに触れる機会」が増加し、コードを整理して「変化に強い状態を保つ重要性」を実感する様になりました。その為のテクニックには様々なものがありますが、特に同僚にオススメされたオブジェクト指向のこころという書籍が「デザインパターンというアプローチで変化に強いシステムを作る方法」を大変わかりやすくまとめていて、良い本だなーと思いながら読んでいました。個別のパターン以上に、「インターフェース・集約の利用、流動的要素のカプセル化」みたいな原則とその理由がまとまってるのが良かったです。

Concurrency

ムーアの法則の終焉が噂される現代において、Concurrencyの重要性は高まり続けています。しっかりと理解しておきたいと考えて、Concurrencyにも興味を持っていました。

Concurrency を実現しようと考えた時、最も一般的な方法はthreadを利用する事です。特にマルチコアを並列で動かそうと思うとカーネルthread(ここではgreen threadと違いカーネルにschedulingされるthreadという意味でこの用語を用いています。Unixであればpthreadを意味してます。)の利用が必要で、pthreadの利用方法についてインターネットサーバでのPthreadとepollPthreadsプログラミングを読んだりしていました。

また、その他のConcurrencyのプリミティブ、特に有名なのはEarlangのアクターやGoのgoroutineですが、それぞれの利用方法に加えて、どう実現されているのか、特にschedulerの実装がどうなっているかを解説した記事(How Erlang does schedulingThe Go scheduler)を読んだりもしてました。どちらもカーネルthreadをうまく利用してマルチコアを活用してくれるので、とても便利な道具だと思います。data raceやrace conditionといったthread programmingの複雑さに生身で立ち向かうのは辛いので、これらの抽象化はうまく活用したいです。

ちなみに、concurrency primitiveには他にも色々なものが存在しているらしく、Concurrent Programming for Scalable Web Architecturesの5章が良い感じにまとまっていました。通して読めてはいないですが、興味深いと思ってます。

分散システム

コアレベルでの並列化に加えて、マシンレベルでの並列化の重要性も高まっています。計算リソースの確保という意味ではHadoopやSparkが、またデータベースの地理的な分散や可用性の確保、書き込みのスケーラビリティの実現という意味ではCassandraなどがオープンソースの分散システムとして注目されていると思います。

自分はkuenishiさんのブログを読んで分散システム自体には興味を持っていたものの、具体例を知らないためにイマイチ理解できていませんでした。そこで一念発起してCassandraを読んで見たのですが、これがとても良い本でした。

まず、自分の中であやふやだった知識が明確になりました。結果一貫性、因果一貫性、強一貫性といった用語の明確な定義(読み込み時に、最新の書き込み結果を反映している事を保証するかどうかが違う)、CAP定理が意味する事、Cassandraがネットワーク分断時にどういった動作をするのか、コントロール可能な一貫性とはどういう事か、そういった事について理解を深める事ができました。それらはまた、分散システムの複雑さに Cassandra がどう立ち向かっているかについての理解でもあって、具体的な例を知れたのはとても良かったです(今後、別のシステムの説明を見たときの比較対象になるので)。

ちなみに、Cassandraは他のNoSQLや内部の細かいアルゴリズムの説明もしたりしていて、内容がとても充実していたのも魅力的でした。

その他、興味深かった本

Unix考古学という本を気まぐれで読んでいたのですが、これがかなり面白かったです。UnixC言語が生まれる時代的背景も興味深いですし、Unixベンダーが1980年代後半に争っていた話なども噂でしか知らなかったので面白かったです。

ピクサー流 創造するちからという本もかなり良かったです。これは、ピクサー、ディズニー社長のエド・キャットムルが映画制作というクリエイティブな作業を行うチームをどう作りあげてきたか、またどういう取り組みをしてきたかをまとめた本なのですが、エドが「常によく考え続けてる」ことを強く感じる本となっています。

個人的に強く印象に残ったのは、「ピクサーで作られるどんな映画も、作り始めた段階では例外なく駄作」という話です。彼らは毎回挑戦をするからこそ最初はひどい出来で、しかしそこから何度も何度も修正を加え続けるからこそ「素晴らしい映画」を作り上げられる事、それを経験からくる実感と共に語っているのが興味深かったです。映画制作の最中には「どうしようもないと行き詰まるタイミングが必ずやって来る」というのも、それを何度も経験して乗り越えてきたからこそ言える事だと思います。その為のプロセスを確立していて、プロセスやチームを信じられるというのもすごい話だと思いました。

2016年振り返りまとめと2017年の取り組み

2016年は「知りたい事、興味のある事についてちゃんと理解を深めよう」と思って過ごしていました。それはそれで学ぶことが多くて良かったのですが、一方で本を読んだりコードを読んでそのまま満足してしまうケースが多すぎた様に感じています。

2017年は、コードを書く事、特にそれをpublicにする事を強く意識していきたいと思っています。OSSへの貢献などは、興味がありつつも全く出来てない分野なので、取り組みたいと思っています。

仕事面では、取り組んでる内容に習熟することに加えて、「責任」というものとの付き合い方にも慣れていきたいと思っています。