この記事は株式会社SUPER STUDIOの2025年アドベントカレンダー1日目
https://qiita.com/advent-calendar/2025/super-studio
の記事になります。
初めに
先日会社のテックブログでAPI基盤開発記のとして、株式会社SUPER STUDIOで進めているAPI基盤開発について紹介しました。
今回はそのAPI基盤開発の中で形作ってきた開発指針について書きたいと思います。
課題
今回API基盤はRailsのAPIモードで作ることにしました。その理由としては幾つかありますが主に
- 開発メンバーの技術スタック
- Railsの開発しやすさ
- 気を付けて作れば、それなりのパフォーマンスは出せる
という点から判断しました。特にこの「開発のしやすさ」はRailsの売りだとは思いますが、ここは気を付けて作っていかないとメンテナンス性の低下が発生してしまいます。
開発がしやすい一方でメンテナンス性を低下させてしまうとは
Railsは規約に基づいたフレームワークです。クラス名など決められたルールで書いていくとRails側で読み取り動いてくれます。そのため動かすための設定が最小限でよく、作るべきものに集中できます。しかも最初からテストに関しても組み込まれていることも開発効率を上げる助けに鳴っています。(テストに関してはRSpecを使う場合、gemの登録や設定ファイルの生成などひと手間ありますが)
こういった点から開発に直ぐ着手でき、必要があればローカルでサーバも立ち上げて確認することが手間を掛けず出来ます。そのため新規サービスの立ち上げでRailsを使うというのはよく聞くと思います。ただ立ち上げたサービスはそれで終わりではありません。
その後も機能を追加し続けます。そしてテーブル数、データ量も増えてきます。そして関わる人数も増えてくるかもしれません。そういう歴史を重ねていく過程で開発ルール、指針がないとどうなるか・・・。
RailsはModel / Controller / View のフレームワークですが、ViewからもModelを参照することも出来るので、特に意識していないと知らないうちにView側のループ処理の中でModel経由でDB問い合わせを複数やっていたり(N+1)、ControllerやModelが肥大化していたり・・・。更にModelのコールバックを使いすぎて、データ更新を意図しないタイミングでしていたりなど・・・・。開発しやすい、つまり書きやすいがため注意しないとメンテタンス性の悪いコードも生まれやすくなっています。それに複数の人が関係するとカオスになっていきます。
ではどうしたか
API基盤は新しいサービスですが、メンテナス性を保つことを最初から意識したいと考え、開発指針を決め、それを元に進めることにしました。
開発指針
正直この指針は人によっては考え方も違うと思いますので、あくまでも一例として読み取っていただければと思います。
全体像は以下のようになります。
app/controllers
/errors
/forms
/infrastructures
/jobs
/middlewares
/models
/concerns/~~~.rb
/domains/~~~.rb
~~~.rb
/queries
/serializers
/usecases
/validators
デフォルトの状態から追加したものは
- errors
- forms
- infrastructures
- middlewares
- models/domains
- queries
- serializers
- usecases
- validators
になります。
errors
ここは各クラスで発生したエラーを格納しています。ログにどこで問題があったかを追いやすくするためにエラーも分けるようにしました。
入力値のバリデーションや値の整形を行うクラスです。ここでは入力値のフォーマットチェックなどDBの問い合わせが不要なバリデーションを行います。
infrastructures
DB以外の外部サービスへのアクセスを担当します。例えばredisやnewrelic、AWSのAPIなどです。
middlewares
ここは主にrackミドルウェアを格納しています。今回の場合はDBの切り替え処理や認証トークンチェックなどです。
models/domains
ドメインロジックを書くようにしています。今回はECサイトのAPI基盤になりますので、割引を含めた商品価格の計算、商品の在庫数の計算などです
queries
データの問い合わせ処理をここに書いています。例えば商品一覧の取得、商品詳細の取得などです。
serializers
APIのレスポンスはjsonで返していますが、どのようなJSONデータになるかをここで定義しています。
usecases
データの作成・更新・削除をここでかいています。例えば商品に対するレビューの登録、顧客の登録などです。
validators
バリデーションについて、Railsにデフォルトであるバリデーションとは違って独自に拡張する場合に、そのバリデーション処理をここに格納します。
何故この形にしたのか
この形を取った狙いは以下のポイントです。
- 各クラスの役割を明確にし、開発者が複数人になっても全体のクラス構成の一貫性を保つ
- クラス間の階層を意識して、DBへの問い合わせはどこで行うかを明確にしたかった
- 各クラスを大きすぎないようにしたかった
まず1つめのポイントですが、サービスが誕生してから長い月日が立つと関わる人も増えていきます。そうなると様々な考え方を持った人が開発に関わることになり、その時に開発指針がないと各々の考えでクラス設計を行い開発を進めます。そういうときに開発の指針がないと様々な思想が混じったキメラのようなクラス構成になってしまいます。そうなるとメンテナンス性は低下してしまいます。そういう状態をまずは防ぎたく、今回のような開発指針を定めました。
そして2つめのポイントについてですが、開発者にDBの問い合わせがいつ、どのように発生しているかを意識してもらいたいという考えからです。そこをある程度意識しないと規模が大きいサービスの場合にパフォーマンスに問題が起こってしまいます。パフォーマンスチューイングをするにしても、あちらこちらでDBへのアクセスがあるのと集約されているのとでは、対応のしやすさが大違いです。
最後に3つめのポイントについてですが、Railsで起きがちな「fat controller」や「fat model」のようにならないために各クラスを小さな単位に保つということです。これは技術的負債を最小限にし、メンテナス性、テストの容易性を保つ狙いがあります。
開発指針を浸透させるためにやったこと
これに関しては時間をある程度使ってチームメンバー間で何度も議論をしていきました。特にドメインロジックはどこに格納するかは時間を掛けました。そしてそれをチームメンバーが理解するためにペアプロやモブプロ、PRレビューでの指摘・議論を何度か経験して浸透させていきました。
改めて思うことは議論を重ねていくことで、納得感を持つことが浸透する鍵だということです。人間は感情の生き物なので違和感を感じていること身につかないものですが、心から納得しているものについては比較的容易に頭に入って身についていきます。
今後
今後はこの作ったルールが今の状況に適しているかを都度検査して進めようと思っています。時代は常に変化します。そしてサービスも日々成長し変化していきます。そういう変化に対し適したアプローチを取っているかを客観的に見て、API基盤を育てていきたいと思っています。