RubyKaigi2017参加レポート(全日分)とスライドまとめ

f:id:vasilyjp:20180927090637j:plain

こんにちは、VASILYのバックエンドエンジニアの塩崎です。 9/17〜9/20にかけて広島で開催されたRubyKaigi2017に、VASILYから4人が参加しました。

3日間で約50個の講演があり、参加者も数百人を超えるであろう大変大規模なカンファレンスでした。 たくさんの講演の中で、VASILYのエンジニアが興味を持ったものを、この記事でいくつか紹介いたします。

スライドの紹介に問題がある場合はご連絡ください。

The many faces of module

Rubyのパパであり、弊社VASILYの技術顧問でもあるMatzさんの発表です。

Rubyに取り入れたsimulaやLispの機能を紹介しながら、オブジェクト指向での継承の利点と問題点を説明されていました。 特に多重継承の問題点に光を当て、Lispで発明されたflavorという機能の紹介をしていました。 この機能はRubyではMixinという名前で導入されました。

もともとはMixinを実現するためのものであるmoduleが現在では以下の7つの機能を持っていることを紹介していました。

  1. module as mixin
  2. module as namespace
  3. singleton
  4. module as set of methods
  5. module as unit od method combination(Module#prepend)
  6. module as refinement
  7. structural signature(提案段階)

前半の4つについては初期のRubyから備わっている機能ですが、後半のものは最近のRubyで拡張されたmoduleの機能です。

そして、RubyはもはやMatzさん個人の言語ではなく、私たちRubyコミュニティの言語である。 また、Rubyをより良いものにすることによって、世界をより良いものにしたいという言葉によって締められました。

Ruby Lauguage Server

Quipperの@mtsmfmさんによる、Ruby用のLanguage Serverの実装に関する話でした。 Language Serverとはエディターに対してシンタックスハイライト、Lint、コードフォーマットなどの機能を提供するプログラムです。 Language Serverがない場合は言語とエディタの組み合わせごとにこれらの機能を実装する必要があります。

Ruby用のLanguage Serverがまだなかったので、開発を始めたそうです。 syntax check機能については、ruby -cwコマンドを呼び出して対応しているそうです。 また、自動補完や、メソッド定義へのジャンプは開発中らしいです。 トップレベルの自動補完は動的解析によって行われているために、ファイルIOなどの副作用のあるコードを実行すると、実際に実行されてしまうという欠点もあるそうです。 今後の展望としては、まだまだ実装していない機能が多いため、それらを実装することや、syntax checkの指摘箇所を行単位からカラム単位にするなどが挙げられていました。

Ruby and Distributed Storage System

Treasure Dataの@tagomorisさんによる、planet scaleな分散ストレージシステムであるBigdamについての話でした。

TreasureDataに入力されるデータを最初に受け取る部分を作り直ししているそうです。 世界中にエッジロケーションを配置したplanet scaleなシステムになるそうです。

Bigdamは6つのマイクロサービスからなっており、システムそのものはJavaやGoで書かれているそうです。 Rubyは開発を円滑に進めるために用いたそうです。 開発の初期段階でRubyを使いmock serverやInterface testを作ってから、それぞれのマイクロサービスの開発を行ったそうです。 また、データ量が増加した時に、スケールするのかどうかの検証にもRubyを用いたそうです。

このシステムは最終的にOSSになる予定らしいです。 今から、公開が待ち遠しいですね。

Progress of Ruby/Numo: Numerical Computing for Ruby

筑波大の@masa16tanakaさんによる、Rubyでデータサイエンスを行うために必要なN次元配列演算ライブラリについての講演でした。

データサイエンティストがコードを書くときにはPythonを用いることが多く、Rubyを使ってデータサイエンスを行う人は決して多くはありません。 Pythonが広く使われている理由はpandansやmatplotlibなどの非常に充実したライブラリ群(SciPyスタック)にあるそうです。 そして、それらの土台をなしているのがN次元配列の計算を行うライブラリであるNumPyです。 そのため、Rubyのデータサイエンス用ライブラリを充実させるためには、まずこのNumPyのRuby版が必要です。

Numo::NArrayはまさにそのような目的のライブラリです。 NumPyが提供している363個の関数のうち、217個はすでにNArrayでもカバーされているそうです。 さらに、NumPyが提供している以下の3つの便利機能もNArrayに実装されているそうです。

  • view of slice
  • broadcasting
  • masking

速度の面ではまだNumPyには敵わない印象を受けましたが、速度に関する最適化には未着手とのことでしたので、これからさらに高速化していく余地は十分にあるそうです。

さらにNumoプロジェクトではNArrayだけではなく、さらに高度な計算を行うためのライブラリも提供されています。 線形代数ライブラリNumo::Linalg、科学計算ライブラリNumo::GSL、高速フーリエ変換ライブラリNumo::FFTWなどです。 内部的にNArrayを使っており、NArrayとの親和性が高いそうです。

これらのライブラリが充実することにより、Rubyでもデータサイエンスが行えるような未来を目指すという内容でした。

参考: Nomoのプロジェクトページ

Improve extension API: C++ as better language for extension

ClearCodeの@ktouによる、C++を使って拡張ライブラリを実装する話でした。

Rubyの拡張ライブラリを書くためにはCを使うことがほとんどかと思いますが、C APIは冗長な記法になりがちです。 そこで、Ext++というライブラリを作り、C++11で拡張ライブラリを実装できるようにしたそうです。 C++11では、モダンな機能が提供されており、シンプルな記法で拡張ライブラリの実装を行うことができるようです。 例えば、型推論やラムダ式、cast演算子のカスタマイズなどの機能です。 しかし、Rubyの例外は内部でsetjmpを使っているため、RAII(Resource Acquisition Is Initialization)との相性が悪いなどの問題点もあるそうです。

An introduction and future of Ruby coverage library

Cookpadでフルタイムコミッターになられた@mametterさんによる、Rubyのテストカバレッジライブラリの紹介とcoverage.soの拡充計画についてのお話でした。

Rubyでは、品質を保証するための実用的な手段はいまのところ、テストしかありません。 そしてテストの良さを計測するのにカバレッジはとても必要なものです。

カバレッジ計測だけでは仕様の漏れなどは発見できませんが、カバレッジ計測をうまく利用して設計の網羅性を高くすることは可能です。 理想的なカバレッジの上げ方は、「テストされていないコードを全体的から探し、どういう観点のテストが足りていないのかを振り返って考え、足りなかった観点のテストを全体的に確認しながら書いていく」という方法だそうです。

Rubyのカバレッジ計測についてですが、SimpleCovがgemとしてよく使用されています。SimpleCovは、coverge.soのラッパーです。 coverage.soは、発表者の遠藤さんが開発されたライブラリで、現在line coverageのみサポートしています。 しかし、line coverageだけでは後置ifなどの条件分岐を網羅することはできず、指標として弱いです。 なぜline coverageしかサポートしていないかというと、coverage.soはRubyのテストを拡充するために作ったものなので、他で使われることをあまり想定していなかったそうです。

そのため現在は、後方互換性を残しつつ機能を拡充する開発を行っているそうです。 実際に、branch coverageとfunction coverageの機能が最近コミットされています。

したいことはたくさんあるようで、メソッドのカバレッジ計測・&.のブランチカバレッジ対応・メソッドチェーンのメソッドごとのブランチカバレッジにも対応したいとおっしゃっていました。

カバレッジ等すべて丁寧にお話しされていたため、とてもためになる発表でした! coverage.soの機能拡充によりRubyの堅牢性向上が期待できますね!

参考: RubyKaigi 2017 の予稿

How Close is Ruby 3x3 For Production Web Apps?

AppFolioの@codefolioさんによる、Ruby3x3プロジェクトのために、ベンチマークを開発した話です。 実際のWebアプリケーションを用いて、Rubyのバージョンアップに伴いWebアプリケーション自体どれほど速度改善したかをご紹介されていました。

計測には、Discourseというコミュニティサイトをテスト対象のアプリケーションとして使用しています。 また、計測を行うための環境を定めたり、railsが起動しているインスタンスをDedicated Hostにしたりするなど、厳密な計測を行おうとする姿勢が伺えました。

結果としては、Rubyのバージョンが上がるについれて、徐々に速度は改善されています。 HTTPリクエストの処理時間については、Discourse自体がバージョンアップにより重くなったのを考慮するとRuby2.0.0からRuby2.4.1では150%程度速度が改善しているそうです。

また、初回リクエストにかかる時間に関しては、Ruby2.0.0からRuby2.4.1で30%程度改善されています。 Matzさんが、Rubyの速度改善にはwarm upの速度改善が重要とおっしゃっていましたが、warm upも少しづつではありますが、速度が改善されているようです。 また、ベンチマークであるrails_ruby_benchは公開されておりAWSやローカルで試すことができます。

参考 発表スライド rails_ruby_bench

Type Checking Ruby Programs with Annotations

SideCIの@soutaro、Rubyで型チェックを行う手法が紹介です。 Rubyで型チェックを行う取り組みは以前からありますが、コード内に型定義を書いておき、ランタイムでチェックを行う点がこの手法の特徴です。

型定義には大まかに2通りの記法があります。 1つはコメントでの定義、もう1つは別ファイルでの定義です。後者はC言語のヘッダーファイルでの宣言に少し似ています。

  • コメントでの型定義(test.rb)
# @type const Conference: Conference.module
# @type var year: Integer

conference = Conference.new(name: :RubyKaigi, year: 2017)
year = conference.name
  • 別ファイルでの型定義(hello.rbi)
class Conference
  def initialize:(name: String, year: Integer) -> any
  def name: -> String
  def year: -> Integer
end

※ 上記のコード例は発表者Soutaro Matsumotoさんのブログから引用しました。

この型チェックはsteepというgemになっており、誰でも試すことが出来ます。 型を明記できるのは画期的ですが、一方でRubyらしい簡潔さがやや失われてしまう印象も受けました。 しかし、ここで紹介された手法は、Ruby3に向けた型の議論に大きな影響を与えることになるでしょう。

参考: 発表者であるSotaro Matsumotoさんのブログ記事 発表中で紹介されていた、型チェックを行うためのgem steep

Busting Performance Bottlenecks: Improving Boot Time by 60%

Shopifyの@jules2689さんによる、Rubyスクリプトの起動時間改善に関する発表です。 Railsのrails serverの起動で数秒待たされた経験が誰しも1度はあるのではないでしょうか。

これを解消するために、まず原因の切り分けを行っています。 具体的にはコンパイル、YAMLの設定ファイル読込、定数参照に切り分けを行い、キャッシュにより起動時間を改善しています。 更にBundlerの速度がバージョン1.15で大きく改善されたことにも触れています。

スクリプトの起動で待たされることがなくなることで、エンジニアのモチベーションや生産性が改善されることが期待されます。

参考: 発表スライド

Smalruby : The neat thing to connect Rubyists and Scratchers

Kouji TakaoさんとNobuyuki Hondaさんによる、プログラミング初心者用の言語であるScratchと互換の機能をRubyで提供するという内容でした。

Scratchはifやwhileに対応するコード要素をブロックのように組み合わせてプログラミングを行う、Visual Programming言語です。 Scratchと同等の機能を持ったsmalrubyというライブラリを使い実際に島根で小・中学生にプログラミングを教えているそうです。 Scratchのコード要素をRubyに移植した時に、とても自然な形の表現になっていたのが印象的でした。

近年ではプログラミング教育への関心が高まり、2020年からは小学校でのプログラミング教育も始まる予定です。 そのような状況の中で、教育用言語としてのRubyを活用していこうという気概が感じられました。

参考: smalrubyのgithubリポジトリ

Writing Lint for Ruby

SideCiの@p_ck_さんによる、静的解析ツールであるLintと、Rubyの静的解析ツールの一つであるRubocopについての話でした。 Lintとはコードを静的に(コードを実際に動かさずに)解析を行い、バグを発見するためのものです。 例えば、以下のようなコードは構文的にはOKですが、実行時にエラーが発生してしまいます。

if 10 < x < 20

このようなコードやエラーは発生しないけど、意味が曖昧になってしまいがちなコードに対して指摘するのがLintです。 この講演ではRubyコードを抽象構文木に変換し、簡単な解析を行うLintの実装や、Rubocopに新しいCop(ルール)を追加する方法について説明していました。 特にLintがコードを静的に解析することによる利点・欠点についての説明が興味深かったです。 実際にプログラムを動かしてメソッドの入出力を確認するテストだけでなく、高速かつ全てのコードを網羅的に確認することができるLintも組み合わせることで、より品質の高いプログラムを書くことができると感じました。

参考: 発表スライド ブログ

Compacting GC in MRI

Githubという小さなベンチャー(笑)で働いている@tenderloveさんによる、compaction GCに関する発表でした。 GC compactionを行うことによって、Page Faultを減らし、Unicornの動作速度を上げることを目標としていました。

プロセスをforkした直後は親プロセスと子プロセスは同じメモリを共有します。 そして、親子のプロセスの間でメモリに差異が生じた瞬間になって初めてメモリーのコピーが実行されます。 この仕組みはCopy on Writeと呼ばれ、これが発生すると、スピードの低下の原因となります。 Copy on Writeはメモリーのページという単位で行われるため、メモリー内のオブジェクトの配置が断片化していると、Copy on Writeが多くのページで発生してしまいます。

そのため、GCにメモリの断片化を解消するためのcompaction機能を実装したそうです。 オブジェクトの移動を行った後に、そのオブジェクトへの参照を書き換えるという操作を行います。 現状の仕組みでは、Hashのキーになっているオブジェクトや、文字列リテラルなどの移動はできず、典型的なRailsアプリケーションの場合は、約46%のオブジェクトが移動可能だそうです。 しかし、最終的にはCで書かれた拡張ライブラリから参照されているオブジェクト以外の全てのオブジェクトを移動可能にすることを目標としていました。

VASILYでもアプリケーションサーバーとしてUnicornを使用しているため、この機能の実現によるスピードアップが楽しみです。

Development of Data Science Ecosystem for Ruby

Speeeの@mrknさんによる、RubyからPythonの関数を呼ぶためのライブラリであるPyCallに関する発表でした。

Rubyで作られたシステムに機械学習などの機能を組み込む場合には、Rubyだけで頑張る方法と、データ処理部分をPythonで作ってその間をJSON APIで繋ぐという2種類の方法があります。 しかし、前者ではできることに限りがあり、後者ではデータ転送のコストが必要です。

そこで、第3の選択肢としてのPyCallの紹介をされていました。 PyCallではRubyから直接Pythonを呼び出すため、データを転送するコストを低く抑えることができます。

講演の最中にはPyCallを使った、幾つかのデモが行われていました。 その中でも特にSSD300のモデルを読み込ませ、物体検出を行っていたのが印象的でした。

また、その後に開催されたワークショップでは、ハンズオン形式でPyCallの使い方をレクチャーしていただきました。 使ってみての感想としては、予想以上にPython感がなく、すごく自然な記法でPythonのメソッドを呼び出せることに驚きました。

VASILYでもRuby on Railで作られたシステムの中に機械学習を活用した機能を組み込むことが多いため、これらの技術は今後活用する機会があるかもしれません。

参考: PyCallを使ったデモアプリ pandasで可視化を行っています

API Development in 2017

Drecomのonkさんによる、JSON API開発についての発表でした。 HTTP通信を受け付けて、JSONを返すようなJSON APIをどのようにして効率的に開発するのかという内容でした。

JSON APIとnative clientを同時に作り結合テストをすると、思っていたのと違うJSONスキーマが返ってきて困った経験をしたことがある人は多いかと思います。 その1つの理由として、RESTfulなAPIはエントリーポイントに、どのリソースが返ってくるのかという情報は埋め込まれているものの、そのリソースがどんなJSON構造で返ってくるのかという情報がないことが挙げられます。 そのため、具体的なJSON構造はAPI serverのお気持ち次第ということになってしまいがちです。

この問題を解決するためにSchema First Developmentという手法を紹介していました。 この手法では、クライアント側とAPI側が最初にOpenAPI形式のSchemaを定義します。 そして、このSchemaに従うようにそれぞれの開発を行います。

Schemaを書かないと絶対にAPI開発ができないようにする仕組みを導入したことによって、Schamaが100%正しいドキュメントとして機能するようになったそうです。 さらに、Schemaとserializerの間で記述が重複していたため、SchemaからSerializerを自動生成したそうです。

また、RESTfulではないAPIとして最近注目されているGraphQLの紹介もありました。

OpenAPI形式はSwaggerで使われているSchema定義の形式であり、弊社のTECH BLOGにも紹介記事がいくつかありますので、よろしければそちらもご覧になってみてください。

tech.vasily.jp

tech.vasily.jp

まとめ

VASILYエンジニアはRubyを使って、サービス開発をしたいエンジニアを募集しています。 興味ある方は以下のリンクからご応募ください。

おまけ

広島食べ歩きの写真などを紹介します。

弊社の技術顧問であるMatzさんとの記念写真

f:id:vasilyjp:20170921125430j:plain

弊社CTO今村とマネキン餃子娘

f:id:vasilyjp:20170921125552j:plain

どんなに飲んでも飲み足りない系エンジニアと特大レモンサワー

f:id:vasilyjp:20170921125634j:plain

口いっぱいにおにぎりを頬張るフロントエンドエンジニア

f:id:vasilyjp:20170921125655j:plain

カテゴリー