Rails:「Pagy」gemでRailsアプリを高速ページネーション(翻訳)

概要 原著者の許諾を得て翻訳・公開いたします。 英語記事: Paginating Ruby on Rails applications with Pagy 原文公開日: 2018/05/16 著者: Tiago Franco サイト: https://www.imaginarycloud.com/ Rails:「Pagy」gemでRailsアプリを高速ページネーション(翻訳) 私はRuby on Railsがバージョン0.8の頃から開発者として使っていることもあり、その間に誇大広告気味のRubyGemを星の数ほど目にしてきました。 成熟したソフトウェア開発コミュニティと同様、特定の用途では事実標準のgemとして永らえているライブラリもありますが、他の多くのライブラリは誰もサポートしてくれないまま、採用に値しない瓦礫の山を築いています。 用途によっては1つや2つgemをあえて追加することもありますが、ほとんどどの機能にもそれぞれに相応しいチャンピオンが君臨しているものです。 Railsの進化がたどった道 以下の図は、ここ10年の間に新しいライブラリやアイデアにコミュニティが貢献した様子を示しています。 当初のgem数は増加していますが、2015年をピークに以後は減少しています(成熟したとも言えるでしょうか)。私は、2018年のgem数は2009年とほぼ同レベルであろうと睨んでおり、この傾向が続くならば新しいgemの数は今後も減少し続け、安定期に入るでしょう。 ここからさまざまな疑問が湧き起こります。「Railsの潜在能力は2015年がピークだったのか?」「Railsというプラットフォームの採用も減少しているのか?」「むしろこれは成熟の証で、Railsは大企業が採用してよいものになったのだろうか?」 私としては、このデータだけでは何とも言えません。むしろそうした視点とは違うアプローチによって、今日の私たちの仕事に大きなインパクトをもたらす部分に着目してみたいと思います。 新しいgemの数が減少するに連れて、今の私たちの仕事に大きく影響するような画期的なものはなかなか出現しなくなるだろうと考えられます。しかしそんなことはありません。それを今から証明いたします。 Pagyとの出会い Ruby on Railsで開発したことがある方なら、アプリのindexページをwill_paginateやKaminariでページネーションしたことがおそらくあるでしょう。Rails経験の浅い方なら、今後そうしたページネーションgemを探すことになるでしょう。 PagyはRails向けの新しいページネーションライブラリです。パフォーマンスを念頭に置いて開発されており、かつ新規または既存のRailsアプリの使いやすさを損ないません。 はい、今皆さんが思っていることを当ててみせましょう。 「お、今度のページネーションgemこそ俺たちが求めていたもの…なわけないだろ!」 そこについては私も同感です。オープンソースでソリューションが分散してしまうのはよくないと思います。しかも、このPagy gemによってもたらされる改良点のいくつかは、既にKaminariでも実装が提案されたのですが、リジェクトされました。おそらく、改善にはKaminariのコア部分で大規模な変更が避けられなかったからでしょう。 何かが華々しく登場したら、ときにはそれが本当にベストなのかどうか一歩身を引いて考える必要があると、私は固く信じています。そしてページネーションについて言うなら、このgemには疑いの余地はありません。理由を説明しましょう。 この図がすべてを物語っていると私は信じています。 アプリが数百〜数千ものユーザーを同時にさばいている状態では、ちっぽけな機能を1つ足すだけでもリソースに大きな影響を及ぼすことは容易に想像が付きます。20ページに対して実施した1つのテストの結果を見ると、will_paginateはうまくやっている一方、Kaminariのメモリ容量は著しく増大しています。しかしPagyはwill_paginateよりさらに優秀です。数千人ものユーザーをさばこうとするとき、この違いがもたらすインパクトを今一度考えてみてください。 さらに詳しく見てみましょう。今度はそれぞれのgemのメモリフットプリントを比較します。 Kaminariと同じジョブを、Pagyは遥かに少ないメモリで実行できます。will_paginateもKaminariより省メモリではあるものの、Pagyと比べると7倍にものぼります。さらに皆さまに考慮いただきたいのは、will_paginateが最後にリリースされたのは1年も前のことで、リポジトリにはプルリクが何十個もたまったまま、最終コミットの日付は2017年7月のままになっている点です。 今仮に新規プロジェクトがスタートすることがあったとしても、will_paginateは選択肢には含めないでしょう。 はい、皆さんはここできっとこう思うでしょう。 「よっしゃ気に入った。ところでPagyが他のgemと比べてメモリフットプリントがここまで少ない理由が謎なんだけど、どうやってんの?」 よくぞ聞いてくださいました。ご説明いたしましょう。 実は私も、当初同じ疑問を抱いたのでした。 「Kaminariが生成するオブジェクト数が6,000個超えってどういうこと?」 もちろんwill_paginateの方が省メモリではあるものの、それでも20ページのページネーションでオブジェクト数が3,000個超えというのはあんまりです。一方Pagyのオブジェクト数は400個を下回っています。 Pagyの方が優秀な理由 pagyのどこがそんなに違うのでしょうか?ご説明いたします。 PagyはRubyオブジェクトではなくintegerで計算している Pagyのコアコードは60行にも満たない Pagyはアプリのモデルに癒着しておらず、HTMLやURLや複数形化(pluralization)や式展開を独自に生成する。 Pagyは、一般的なヘルパーではなく完全に特殊化したコードを用いている。 コードが専門化していることで、作者が1行ずつ丁寧にベンチマークを取っている(コードが100行もなければ十分可能です)。 上の理由のおかげで、pagy gemのコードはきわめて理解しやすいという実にうれしいおまけまでついています。 しかも拡張で機能を追加することも可能で、いくつかの拡張は組み込み済みなのですぐにでも使えます。 さらなる考察 私がRailsアプリを開発した当初はwill_paginateを使っていましたが、その理由は当時はその業務にベストだったからです。数か月後にKaminariがリリースされると、そちらに乗り移りました(なにぶんあまりにも昔のことなので、乗り換えた理由はよく思い出せません)。そしてつい数週間前にPagyがリリースされるまで、Kaminariを使い続けていました。 私が初めてPagyを知ったときに心底愕然としたのは、私がwill_paginateからKaminariに移行したときにパフォーマンスのことをまったく考慮していなかったことでした。後者は前者よりずっと遅かったにもかかわらず、です。今の私はパフォーマンスを考慮することを覚えました。 これまで私たちが設計・リリースしたアプリで、いったいいくつのgemを取り入れてはパフォーマンスを下げまくっていたことでしょう。 will_paginateやKaminariからPagyへの移行は実に簡単で、必要なコードはわずか数行で済みます。次回の私の記事では皆さまに関心を持っていただけるよう、具体的な移行方法を解説することをお約束いたします。 免責事項: 本記事の画像およびパフォーマンスはPagyの作者が行ったベンチマークテストを用いています。ベンチマークのソースコードはddnexus/pagination-comparisonでご覧いただけます。RubyGem採用の推移チャートには、こちらでご覧いただけるRubyGems.orgのデータを用いております。 訳注: Pagyリポジトリ リポジトリ: ddnexus/pagy 関連記事 Rails: パーシャルと`collection:`でN+1を回避してビューを高速化(翻訳) kaminariでRubyの地雷を踏んだ