Sinatra(Ruby製軽量フレームワーク)の使い道を本気で検証してみた

Sinatra(Ruby製軽量フレームワーク)の使い道を本気で検証してみた|ANDPAD Advent Calendar 2022 この記事は ANDPAD Advent Calendar 2022の 20 日目の記事です。

こんにちは、アンドパッドに今年の 9 月に入社しました、 田上(shuntagami)です。アンドパッドでは図面チームに所属していて、主にサーバーサイドを担当しています。Ruby と Rails を使うことが多く、Go や TypeScript を書くこともあります。

本記事の概要

以下のようなケース

  • 将来的に規模が大きくなることも想定されるアプリケーションの API サーバーを 0 から開発する際のメインフレームワークとして
  • 既存の大きく成長した Rails アプリケーションの一部をマイクロサービスとして切り出したいケース

において Ruby 製の軽量フレームワーク Sinatraを採用することが生産性高く開発を行う上で最適解のひとつになるのではと考え技術検証してみた、という記事です。経緯としては、元々は全く違う内容の記事を書くつもりでいて、その記事の説明で使う簡単なアプリケーションの作成に「ActiveRecord を使いたいけど Rails を使うほどではない」と思ったので Sinatra を使おうとしていたのですが、触ってみると「これ普通に大きいアプリケーションの開発にも使えるのではないか」と思い、本記事を書くに至りました。

Ruby x Rails の強み、好きなところ

前提として、アプリケーションを開発する上で Ruby x Rails を選択することは非常に理にかなっていると思っていて、個人的にも好きな言語とフレームワークの組み合わせの一つです。その理由を説明していきます。

ActiveRecord が強い

ActiveRecord とは Rails に標準装備されたデータベースアクセスライブラリ(一般に O/R マッパーと呼ばれると思うが機能がオブジェクトへのマッピングに留まらないのでこのような書き方をしている)です。「DB 層の抽象化」が非常に良くできていて、生産性高く、安全に WEB アプリケーションを開発する上で欠かせない機能だと思っています。また、ActiveRecord Migrationsによるデータベーススキーマ管理も非常に強力です。

RSpec が強い

「テストコードを素早く書けるか」というのも生産性高く開発を行う上で大切だと考えています。RSpec の豊富に用意された マッチャ(matcher)を駆使することで「期待動作」を簡単に記述することができます。個人的には change matcher をよく使っていて、例えば DB のレコードが正しく更新されたか、意図した数だけ作成・削除されたか、のようなテストを簡単に書くことができます。一方で、RSpec の記述の仕方が Ruby プログラミングとは異なる独自のものが多いので、学習コストが高くつくデメリットもあると思っています。matcher についてはこちらの記事にどんなものが使えるのか、わかりやすくまとまっています。

Rails console が強い

開発中に自分の書いたコードを簡単に手元で実行したり、デバッグ作業の際にも非常に重宝しています。また、個人的には SQL の EXPLAIN ステートメントに対応したものが ActiveRecord にも用意されているのでこれを使って「インデックスが意図したように使われているか」、「N+1 クエリになっていないか」というのをクエリの実行計画から確認するのにもよく使います。

なぜ Sinatra を検討するのか、Rails があるのに(結論: 思想が好み)

まずは Sinatra をそもそもよく知らない人のために最近流行りの ChatGPTに「Rails と Sinatra を比較して説明して」と聞いてみると以下のように返ってきました。

RailsとSinatraは、どちらもWebアプリケーションフレームワークです。
Rails
Railsは、Rubyで書かれたWebアプリケーションフレームワークです。Railsは、MVC(Model-View-Controller)アーキテクチャを採用しており、Webアプリケーションを作成する際に、データのモデルを分離して管理し、ビューとコントローラを分離することで、Webアプリケーションをよりスケーラブルで保守性の高いものにすることができます。 Railsは、大規模なWebアプリケーションを構築するのに適しています。Railsには、データベースを管理するための ActiveRecord、Webアプリケーションをテストするための MiniTest、Webアプリケーションを実行するための WEBrickなど、多くの機能が組み込まれています。 Railsは、Ruby on Railsコミュニティによって支援されており、広範な文献やチュートリアルが利用できます。

Sinatra
Sinatraは、Rubyで書かれた軽量なWebアプリケーションフレームワークです。Sinatraは、シンプルで柔軟なアーキテクチャを採用しており、Webアプリケーションをスムーズに構築できます。 Sinatraは、小規模なWebアプリケーションを構築するのに適しています。Sinatraには、データベースを管理するための機能はありませんが、ActiveRecordやその他のデータベース管理ライブラリと組み合わせることで、データベースを扱うこともできます。 Sinatraは、軽量であるため、既存のRailsアプリケーションの一部を拡張するような用途にも適しています。

概ね私が期待していたような回答です!補足すると、Sinatra には「必要最低限の機能だけ提供するから後は自分で拡張してね」という思想があると思っていて、これがいわゆる「フルスタックフレームワーク」と呼ばれる Rails と大きく異なるポイントだと思います。この「ミニマムで始めて拡張していく」という思想が好みなので、ActiveRecord や RSpec などの使いたいものだけを単体で無理なく導入することが出来るのであれば「シンプルだけどスケールできて Sinatra 最高!!」みたいになるのかもしれない、と考えました。

実際に検証

github.com

こちらのリポジトリで検証を行いました。(こちらでいい感じにSinatraのテンプレートを作ってあり、拡張もしやすそうだったので拝借させていただきました🙏)ディレクトリ構成は拡張性を考えて Rails ライクな、MVC っぽい感じにしました。また、Sinatra アプリをスケールさせるために最低限欲しい以下のようなことを検証しました。

  • ActiveRecord による OR マッピング
  • ActiveRecord による DB スキーマ定義、マイグレーション管理
  • アプリケーションサーバー「Puma」の導入(Sinatra にアプリケーションサーバーは入ってないので自分で入れる必要があります。Rails でも使っていて馴染みのある Puma を選定しました)
  • RSpec の導入
  • Committee gem の導入(「OpenAPI Specification と API 実装が合っているか」をテストできるライブラリで、RSpec とセットで業務でも重宝しています)
  • Rails console のようなことができること
  • i18nによる多言語化対応

また、チーム開発する上では must で欲しい以下のようなことも検証しておきました。(Rails に依存してないので実現可能であることはわかっていたけど)

  • コンテナ化
  • リンター(RuboCop)導入
  • 自動テスト・フォーマット(GithubActions)導入
  • dependabot によるパッケージの自動更新

ここまでできれば冒頭の「概要」で述べた「0 から作り始める API サーバーのメインフレームワーク」や「既存の Rails アプリの拡張機能」として十分に選択肢として考えられる気もしますが、以下については要検討かな、と考えています。

リクエストパラメーターの受け取り方

Rails においてはコントローラーでparamsという変数にアクセスすることでリクエストパラメーターを受け取ることができます。params[:key1], params[:key2]、、、のように簡単にアクセスできて便利なのですが、

  • paramsがコントローラー内のグローバル変数のようにスコープが広すぎる
  • パラメーターが増えるとparamsに入っている値を追うのが大変、見通しが悪くなる

という問題があり、これを解消するためにaction_argsを愛用しています。(デフォルト値や必須の値なんかも表現できて可読性が上がるので Rails に組み込みで欲しい)

Sinatra においてもparamsでリクエストパラメーターにアクセスするような設計になっており同じ課題が生まれそうなので、実際に業務で導入するなら解決策を用意しておきたいと思いました。

導入が難しい gem もある

Sinatra は MVC フレームワークではなく、「コントローラー」という概念もありません。つまり、Rails の Action Controller に依存した gem(devise など)は導入が難しそうなので事前に検証する必要がありそうです。「Sinatra のエンドポイントを Action Controller のアクションに結びつける」ようなこともできなくはないかもしれませんが、そこまでするなら普通に Rails を使った方がいいように思えます。

まとめ

「Sinatra 最高!!」という状況になるにはもう少し検証する必要がありそうですが、ユースケースや場合によっては最適解になることもありそう、という感想を持ちました!また、普段使っている Rails と比較することで改めて Rails の良さに気づけたのも良かったです。

アンドパッドではRuby on Railsはもちろん、様々な技術要素を活用して開発に取り組んでいます。 一緒に開発、挑戦していただける方を大募集しておりますので興味のある方は下記をご覧ください!

hrmos.co

engineer.andpad.co.jp

明日はマネージャーの櫻井さんから組織についての取り組みを紹介する予定です。お楽しみに!