概要
こういうことを実践できたらメンテナンスしやすいRailsアプリケーションを構築できるんだろうな、というポエムです。
前提
以下の条件を前提に書いています。
- 0→1の構築である
- 自由に技術を決められる
- モノリス
- モジュラモノリスは考えない
- 複数DBは考えない
スコープ
ざっと以下のことを考えたいと思います。
- フロントをRailsで構築するかどうか
- REST vs GraphQL
- RDBMS選定
- ライブラリ選定
- 静的解析
- rubocop
- モデリング
- つまりDB設計
- アーキテクチャ
- Yes MVC, No Layerd Architecture
- サービスクラスの是非
- Fat Controllerの避け方
- 自動テスト戦略
- RSpec
- (Playwright)
- コンテナ化
- 令和時代のRailsに最適化されたDockerfileの書き方
- インフラリソース
- クラウドプロバイダー選定(AWS, GCP, Azure, etc)
- IaC
- Terraform
- AWS CDK
ノンスコープ
下記はこの記事では扱いません、ごめんなさい🙏
余裕があれば続編で書きたいと思います。
- モニタリング
- ロギング
- オブザーバビリティ
- 認証
- セッション管理
- 自前実装 vs IDaaS
- キャッシュ戦略
- Redis
- 秘匿情報の管理
- rbsとの付き合い方
- バッチ
- gemのアップデート
- dependabot/renovate
- Railsのアップグレード戦略
- CI最適化
- テスト時間の短縮
- docker image buildの短縮
- デプロイ戦略
- BlueGreen
- カナリア
- ロールバック
- hotfix対応
- その他
- dev・staging・preview環境
- 開発環境のseedデータ
フロントをRailsで構築するかどうか
結論、分かりません。 ごめんなさい🙏
自分がRailsでフロントを構築したのはRails5の時でerb * jQueryで頑張っていました。
webpackerについては自分はお世話になることはありませんでした。Rails * Next.jsの構成でSPAを構築することが多かったので...。そうこうしているうちにwebpacker自体が非推奨になっていました。今はHotwire * importmap-railsがデフォルトっぽいですね。
今Rails 8アプリを作るなら何も足さないバニラ味にしよう(翻訳)
個人的にはTypeScriptなしではフロントエンドを実装する自信がないのでフロントはRailsでは構築しないかなあ、という感じです。 ただフロントエンドとバックエンドでアプリケーションを分けると
- CIどうしよう
- デプロイどうしよう
- セキュリティどうしよう(CSRFとか)
- リポジトリどうしよう(モノレポ VS ポリレポ)
みたいなことを考える必要があるのでその分メンテナンスコストが上がるのかなあ、と思いました。もちろん調べれば資料はたくさん出てくると思うのでやり切れるかどうか、な気がしました。
もしRailsでフロントを構築するなら
- slimやhamlなどのテンプレートエンジンは採用しない
- 依存gemが増える
- 少ない記述量 < 独自の記法による認知負荷
- Only My Rails Way で同じ意見が述べられていたので安心しました笑
- rubocop-erbを使う
- erbで直接ARを扱わない
- 基本的にインスタンス変数で参照する
<% Book.where(is_published: true).each do |book| %>
とか書かない
REST vs GraphQL
結論、分かりません。 ごめんなさい🙏
RailsはデフォルトではREST APIのみ構築できます。GraphQLを構築するにはgrpahql-rubyなどサードパーティ製のgemが必要です。 自分は実務でも個人開発でもRailsでGraphQLサーバは触ったことはあります。ただ0→1でスキーマを設計したり、実際に運用した経験がないのでどちらが良いかは分からないです。
個人開発で触った時のメモはGraphQLを素振りしてみたに書いていますので興味ある方は読んでみてください。(だいぶ古いですが...)
ちなみにRailsでGraphQLを構築してみてまず感じたのは
ロジックがapp/graphql配下に全て収まるので初見だとちょっと戸惑いそう ということです。
RESTであれば
- app/modelsにロジックを書いて
- app/controllersで呼び出す
という流れで実装すると思うのですが、GraphQLの場合
- app/modelsにロジックを書いて
- app/graphql/mutationもしくは app/graphql/resolverで呼び出す
という実装になるので意識を切り替える必要があるかな、と思いました。
そもそもどういったケースでGraphQLがフィットするのか?を理解する必要があるので、GraphQLが解決する問題とその先のユースケースなんかを読むと良いのかな、とか思いました。(saboyutaka氏のGraphQL関連の記事、めちゃ面白い...)
RDBMS選定
RDBMSも詳しく無いので PostgreSQLかMySQLのどっちがいいのか!
みたいなのはよく分からないです...。
もちろんRailsはPostgreSQLもMySQLも対応しているので、どちらかを採用したからといってそれ自体が開発のボトルネックになることはないのかなあと思います。
ただCloud SpannerやAmazon Aurora DSQLといったPostgreSQL互換の高機能なデータベースが存在するので、将来的なDBの乗り換えも視野に入れるならPostgreSQLを選択しておくのが無難なのかなあ、とか思いました。
ライブラリ選定
TODO: あとで書く
静的解析
Railsの開発で静的解析、といえばrubocopかなと思います。rubocopには様々なプラグインがありますので特に立ち上げ時で自由に設定できるのであれば片っ端から入れて後から徐々に緩める、という運用で良いのかなと思います。
下記は自分が設定した.rubocop.ymlです。こまめに bundle exec rubocop -A
を実行するかgit commit時やCIでチェックするか、いずれにせよ書き方を統一してレビューコストを発生させないことが大事かと思います。
require: - rubocop-rails - rubocop-performance - rubocop-rspec - rubocop-rspec_rails - rubocop-factory_bot - rubocop-rake
またrubocopを運用しているとmetricsabcsizeを幾つにするか、で議論が発生するかと思います。個人的には25~30くらいまでは許容して良いのでは、と思っているのですが、そもそも25~30になる前提の設計が良くないのでは?という意見もあるかと思います。こればかりはチームで議論して決める他ないかと思います。
余談ですが、エディタにRubymineを使うとメソッドのサジェストがいい感じだったりリファクタリングがガツガツ進むのでオススメです。
モデリング
モデリング、というよりRDBのテーブル設計の話ですね。
以下は セキュリティ、DB設計、パフォーマンス分析__。Railsを使ったWebアプリ開発をパワーアップする書籍6冊 からの引用です。
Railsアプリ開発について説明すると、Railsの本質は全力でDBに乗っかるところにあると思っています。Railsが便利で良くできているのはとどのつまりPostgreSQLやMySQLといったDBシステムが良くできており、RailsはそのDBの良さを下手にねじ曲げようとせず、極力素のまま引き出そうとしているからではないでしょうか。
何度も頷き「分かるな〜」って唸りながら読みました。なのでRailsでアプリケーションを構築するときはテーブル設計にリソースを割いた方が良いと思っています。良くないテーブル設計をすると
- モデルが歪になる
- 歪なモデルをカバーするために複雑なロジックが発生する
- 実装・変更コストが上がる
- 仕様変更のたびにさらに複雑なロジックになる
という悪循環が発生します。この悲劇を避けるためにも最初から上手にテーブルを設計し続ける技量が求められます。
アーキテクチャ
まず 守破離
の守
から。
を読むと良いと思います。
- 命名規則は一定に
- RESTなroutes定義を意識
- controllerは薄く、modelは厚く
- 依存gem(ライブラリ)は最小限に
- 複数テーブル(モデル)にまたがる処理の置き場所
など実務で意識すると良いポイントが素晴らしくまとまっています。スライド作成者のsinsoku氏のスライドはどれも素晴らしいのでぜひ読んでみて下さい。
次は守破離
の破
ですね。
よく話題に上がるのはサービスクラス。自分はサービスクラスが必要になる規模のRailsアプリケーションを構築したことがないので正直よく分からないです。ただ自分が調べた感じではサービスクラスは無い方が良い、という意見が多そうでした。
「今のプロジェクトいろいろ大変なんですよ、app/services とかもあって……」/After Kaigi on Rails 2024 LT Night
俺が悪かった。素直に間違いを認めるから、もうサービスクラスとか作るのは止めてくれ
サービスクラスを導入されている企業事例も調べてみたところ t_wadaさんにTROCCO®︎開発の悩みを壁打ちしてもらいました なんかがヒットしました。
Railsは、標準のMVCディレクトリ以外では比較的自由に名前空間を切ってしまっても問題ない。自分達の中である程度分類ができているのであれば切ってしまえばいい。
逆に言えば、models配下はトップレベルにファイルが並んでいないと何かと不都合がある。
複数モデルにまたがる保存処理がサービスクラスに置かれることは多いが、その必要があることは少ない。
最後は守破離
の離
なんですが、Rails開発における離
って何なんですかね...(自問自答)
なんかを参考に他社事例を見ると何か見つかるのでしょうか?
自動テスト戦略
TODO: あとで書く
インフラリソース
TODO: あとで書く
最後に
意外と筆が進まない...