🚈

なぜ我々はRailsを選択したのか?Smart Craftバックエンドのご紹介

はじめに

Smart Craft テックリードの星井です。
前回の記事で Smart Craft の技術スタックの全体像についてお伝えしましたが、今回はバックエンドについてお話します。
Ruby on Rails / GraphQL な構成になっているので同じような構成を検討している方の参考になれば幸いです。

バックエンドのフレームワーク選定

新しくアプリケーションの開発をやるぞとなったときに、バックエンドで何を使うかというのは毎回頭を悩ませる人が多いのではないでしょうか?
フロントエンドに関しては最近だととりあえず React を使っておけば文句を言う人はいないと言う認識ですが(偏見)、バックエンドはいろいろあって迷いますよね。
自分は Rails 信者でして個人的に何かを作る時には脳死で Rails を採用することが多いですが、Smart Craft でのプロダクト開発は当然そんな安易に決めることはできませんでした。

Smart Craft の前身のプロダクト(日報 SaaS)では、バックエンドは NestJS を使用していました。バックエンド・フロントエンドともに TypeScript で書けるので開発者のスイッチングコストが小さいこともメリットの1つです。当然 NestJS も選択肢としてはありましたが、Smart Craft では色々迷った挙句に Rails を採用することにしました。
選定のポイントは色々ありますが、本題へ入る前に Smart Craft がやっているビジネスについて簡単にご紹介しておきたいと思います。

Smart Craftを取り巻くビジネス環境

「Smart Craft」は製造業のお客様に提供する SaaS プラットフォームです。
これまでオンプレミスの環境ではスクラッチで開発することが当たり前だった領域のシステムを、クラウドで安価に提供することを実現しています。
最初のコミットをプッシュしたのが 2022 年の 8 月、そこから 1 年ほど経った今、すでに複数の会社様に Smart Craft を実際の製造現場でご利用いただいています。
良いペースで開発を進められているのはないかと思いますが、Rails のフレームワークとしての優秀さの寄与は非常に大きいと感じています。

開発を進める上での要件はざっくり以下の様なものが挙げられます。

  • スタートアップ企業であるが故に、高速で機能を開発・提供していくことが求められる(高速に提供できなければ明日はない)
  • 今後の機能拡張などについては不確定な点も多く、あらゆる要件に対応していける柔軟性が求められる
  • 提供しているシステムの性質上、信頼性・セキュリティの高さが求められる

上記の要件はあらゆるサービスに関しても言えることで、当たり前といえば当たり前かもしれません。
しかし、製造現場向けシステムの領域は企業ごとにニーズが大きく異なるため、様々なお客様から日々ヒアリングを繰り返し、適切な仕様に落とし込むということを繰り返しながら開発を進めています。その中でどうしても一度実装した機能に手を入れるということは避けられないため、あらゆる未知の変更に対応できる柔軟さは欠かせません。
また、製造業では人命に関わるような製品を製造している企業も多くあります。そういったお客様にも実際にご利用いただいているため、一般コンシューマ向けのサービスとは少し違った緊張感があります。

なぜRailsを選択したのか?

私がRails信者だからです。

上で述べたビジネス環境の中で、なぜ Rails を選択したか。
本来技術選定という意味では他のフレームワークと比較するのが良いと思いますが、比較対象も無限にあって大変ですのでここでは Rails のメリット・デメリットを Smart Craft の要件に照らして見ていくことにします。

メリット

  1. 開発効率が良い

    ここは様々な要因があると思いますが、個人的にはコードの記述量が少なくて済む、というところが大きいと考えています。
    Ruby の言語としての機能の豊富さに加えて、Convention over Configuration(設定より規約)の原則に則ったフレームワークとしてのデザインによって私達が書かなければいけないコードの行数は少なくて済むケースが多いと感じています。そして我々はより業務ロジックに集中できています。
    Smart Craft が「製造業向け業務 SaaS」を提供している以上、業務ロジックが一定複雑になってしまうことは避けられないという面もあり、我々にとっては重要なポイントであると捉えています。

  2. ライブラリ(Gem)が豊富

    何かしらの機能が欲しくなった時、探せば必ず見つかると言っていいほど Rails の Gem は豊富に存在しています。
    自前の実装を減らすという点でも、より業務ロジックの実装に集中できるのは先人たちが開発してくれた Gem による恩恵も大きいと思います。
    一例として、Smart Craft ではマルチテナンシーを実現するためにactiverecord-multi-tenantという gem を使用しています。テナント間のデータが混ざってしまうことはセキュリティインシデントにもつながりかねないため慎重に注意を払って開発を進める必要がありますが、この gem により Smart Craft ではマルチテナントの仕組みにさほど大きな工数を払わずに済んでいるということが言えます。

  3. だいたいなんでもできる

    Ruby(や Rails)は時に黒魔術と呼ばれるようにメタプログラミング的な柔軟性も兼ね備えています(悪い文脈で語られることの方が多いですが)。
    一例として、Smart Craft では必要に応じて実行時に動的にクラスを定義することによってコードの共通化を図ったりしています(後述の Graphql の実装ではクラスの定義によって API のスキーマを定義することが求められるため)。
    当然やり過ぎるとコードを読むのが大変になるという負の側面もありますが、コードを共通化することを重視する場合にはどうしても必要になってくるケースもあるかと思います。
    私の経験では、例えば複数箇所に同じ様なコードが存在してしまった場合、Rails なら必ず何かしらの方法で共通化できる手段を見つけられる気がします。

デメリット

  1. 実行速度が遅い

    やはり Rails は機能が豊富な分、実行速度に難があると感じられている方も多いのではないでしょうか。
    一度 Go などの高速な言語で Web アプリケーションを実装したことがあると、Rails の実行速度はかなり気になってしまうところもあります。
    とはいえ、実際の開発でボトルネックになるのは大体データベースだったりするので、しっかりパフォーマンスを意識した実装ができていれば致命傷にはならないと考えています。

  2. 型がないため書いていて不安になる時がある

    型がないことはコード量を減らせる一方で、型があったなら実装時に気づけたはずのエラーに気づくことができません。
    以前別の会社で担当していたプロジェクトで TypeScript と生の JavaScript を両方書かなればいけない時がありましたが、TypeScript を書いた後に JavaScript を書いた時には突然不安な気持ちに襲われたのをよく覚えています。
    Rails のコードを書く上でも、どうしても開発者はそこに神経を使わないといけません。

  3. なんでもできるが故に、コードの品質を保つことが難しい

    Rails は簡単に Web アプリケーションが実装できてしまうためあまり開発経験がないエンジニアでも手が出しやすい一方で、その柔軟性の高さゆえにコードを綺麗に保つが難しいという側面もあります。
    Rails がややこしいところをうまく隠蔽してくれているためシンプルなアプリケーションの実装においては問題ありませんが、ある一定の複雑さを超えたときに開発者には Rails が暗黙に提供する仕組みをしっかりと理解したうえで応用していくことが求められます。そうなると途端に Rails のコードを綺麗でスケーラブルに保つことが難しくなってしまう印象があります。
    言い換えると Rails の品質が開発者の経験やセンスに依存してしまうという面があり、そこが Rails の難しさであるとも言えるのではないでしょうか。

ポイントとなったところ

メリットとデメリットは表裏一体になっているものもあり、結局どれを重視するかというプロジェクトごとの意思決定によるところが大きいと思います。
デメリットもありますが、Smart Craft ではそれを鑑みてもお釣りが来るほどのメリットを享受できていると感じています。

特に「型がない」と言うのは選択する上で大きなポイントではないでしょうか?
「型がない」が故にコード量を減らすことができて柔軟にコードの共通化などができる一方で、「型がない」が故に意図しないバグを埋め込んでしまうリスクも存在します。
最近ではフロントエンドも TypeScript を使用するのが主流になってきており、型がない言語を使用することに抵抗を感じる方も多いかと思います。
SmartCraft ではその辺りを補うために、model レイヤーでのバリデーションを積極的に実装することやテストコードのデータのバリエーションを増やすことを実践しています。
幸い、型がないことによる null 値参照のエラーや No such method 的なエラーはたまに発生しますほとんど発生しません。

また、Rails を使用して良かったと思う最も大きなポイントとして ActiveRecord の存在があります(ActiveRecord 自体は Rails に特化したものではありませんが、ActiveRecord を使いたい故に Rails を選択するというケースも多いのでないでしょうか)。
Smart Craft が対象としている製造業のお客様の業務は多岐にわたるため、どうしてもデータ構造が複雑になってしまう傾向にあります。
例えば Smart Craft で扱うデータに、特定の製品の製造を計画するために作成する「製造指示」というものがあります。ユーザーがその情報を参照する際には「製造実績」「担当者」「設備」「工程定義」など、あらゆる関連するデータを同時に閲覧できることが求められ、多数のテーブルをジョインしたクエリを発行する必要があります。
生の SQL から書こうとすると結構大変ですが、ActiveRecord の豊富な機能によってその辺りの実装に関してもかなり楽をできています。

なぜGraphQLを選択したのか?

Smart Craft のフロントエンドは React を使用しています。
最近の Web アプリケーションの開発では、React や Vue などの SPA のフレームワークを使用することが非常に多いのではないでしょうか。
そうなるとバックエンド側は必然的に API サーバとしての役割を担うことになります。
言い忘れていましたが、Smart Craft でも Rails は API モードです。

GraphQL の選択については、Apollo Client(Graphql クライアントのライブラリ)を使用するとフロントエンドがサーバー側とのやり取りの実装のところでかなり楽をできるというのが大きな動機です。そのため、フロントエンド側の要請が大きいというのが本当のところですが、バックエンド側にも少なからず恩恵があると感じています。

最近はフロントエンド側の API のクライアントコードを API のスキーマから自動生成させるのが主流になっているかと思います。例えば Rest API でバックエンドを実装した場合、OpenAPI などの仕様に沿ってスキーマ定義のファイルを生成することが求められます。
GraphQL の場合 GraphQL Ruby という gem を使用することでスキーマファイルの生成からパラメータの型チェックまでを行ってくれるため、その辺りのデザインに頭を悩ませる必要がなくなるというのが大きなメリットであると感じています。
もちろん Rest API においても様々な gem が公開されているので同じ様なことはできますが、スキーマファイルを生成するところなどは一定独自の工夫を凝らす必要があるかと思います。
Rails 自体に型がないという話をしましたが、GraphQL の実装としてパラメータの型を保証していくれるという点は、一定安心感をもたらしてくれるのではないでしょうか。

まとめ

色々とややこしい話をしてきましたが、大雑把に言えば Rails は難しい(簡単な様に見えて)けれども、うまく使うことができれば効率よく堅牢なアプリケーションが実装できるということです。
そして GraphQL を組み合わせることで、モダンなアプリケーション開発の枠組みにもしっかり対応できます。

巷では Rails は死んだ(死にかけている)などと言われることもあるようですが、Smart Craft で扱っているような複雑な業務をサポートする業務アプリケーションにおいて、Rails は理想的なフレームワークであると感じています。

ということで、Rails を使いこなすエンジニアの方、Smart Craft のビジネスに興味を持っていただいた方はぜひご連絡ください!

Smart Craft Tech Blog

Discussion