#概要
「Laravelで同じ実装をドメイン駆動設計(DDD)とMVCで比較してみた(フロントはReact)」の検証で実装したECサイトを、Ruby on RailsとReactに移植してみました。ただ、Laravel版はMVC、DDD、軽量DDDの3種類で実装していましたが、Ruby on Rails版はMVCのみで実装しています。目的はLaravelとRuby on Railsのアーキテクチャの違いを知ることと、そこで得た知見を今後のソフトウェア開発に活かしたい事だった為です。見た目も機能もそっくりそのままLaravel版と同じです(バリデーションだけ若干簡略化しました)。 Ruby on RailsとReact初学者の為、至らぬ点が多々あるのはご容赦下さい・・・
#ソースコード
https://github.com/take-t14/rails-react-sample
#ミドルウェア
ミドルウェア | バージョン |
---|---|
PostgreSQL | 13.3 |
npm | 6.14.12 |
#フレームワーク・ライブラリ
フレームワーク・ライブラリ | バージョン |
---|---|
Ruby | 2.4.6p354 |
Rails | 5.2.6 |
React | 17.0.2 |
material-ui | 4.12.3 |
typescript | 4.4.4 |
sass | 1.38.0 |
#Ruby
Laravelで実装していた箇所は全面的にRuby on Railsの形で作り直しが必要でした。ただ、フレームワークのアーキテクチャがLaravelとRailsが似ているので、ほぼ文法の置き換えのみでいけました。
#React
ReactはerbからReactを呼び出す部分だけ工夫が要りましたが、Laravel版で実装していたReactのコンポーネントはほぼそのまま使えました。変更が必要だったのは、Reactへの値受け渡し部分のみでした。LaravelではbladeからReactへ値を連携する際json文字列に変換し、Reactでそのjson文字からオブジェクトへとパースしてました。とこらがRuby on RailsではerbでReactに値を連携する際json文字列にせずに渡せて、Reactでもjson文字列をパースせずともオブジェクトとして受け取れている状態となっていました。内部ではRuby on RailsからReactへ値連携時にjsonへ変換してるとは思いますが、react-railsというgemライブラリのreact_componentという関数を使ったのでそこはブラックボックスで中で何をしているかは分かりません。
#バリデーション
Laravel版ではFormRequestを使ってコントローラーに入る手間でバリデーションをかけていました。これはこれで便利なのですが、Ruby on RailsではActoveRecordにバリデーションチェックを実装する機構が用意されていてそれを用いました。ORMにバリデーションチェックの機能がついているのは非常に合理的だと感じました。理由は、FormRequestだと例えば商品詳細画面とカート追加APIで商品IDをバリデーションチェックする際、両方のリクエスト用に同じバリデーションを実装する必要が出てきます。一方ActiveRecordだと商品IDのバリデーションチェックはProductモデル一カ所に実装すればよく、実装の重複はありません。仕様変更の影響範囲も最小限になります。バリデーションチェックは、DBに近い層でやるActiveRecordのアーキテクチャが優れていると感じました。DDDの場合は商品IDのValueObjectへバリデーションチェックを実装する事で重複は避けられると思います。ただ、参考書籍「実践ドメイン駆動設計(Object Oriented SELECTION)」ではValueObjectへバリデーションチェックを実装するのは、ドメインモデルに責務を負わせすぎと言う記載が確かあったと思いますので、この辺は色々な議論はあるかも知れません。
#ファイル数・ステップ数
Laravelと同じ事を実現するのに、Runy on Railsだと実装量が圧倒的に少なくて済みました。Laravel版と比べて2/3位のステップ数におさまりました。言語仕様の違いもありますが、Ruby on Railsではコンポーネントのパスやファイル名が決まっていて、それらを定義する必要が無いのもあります。必要な事は予め用意されていて、徹底的に実装効率を上げる事に配慮されたフレームワークなのだと感じました。その反面、ファイルパスの配備先やファイル名はルールが定められており、独自にカスタムする事は出来ません。また、Active Recordのjoinでは記述形式が独特の書式すぎて、どう書いたら目的のjoinができるのかがわかりにくかったです。言語仕様が実装量を少なくしようとしすぎているのか、はたまた実装スタイルのスマートさを過度に目指しすぎているせいなのか、書式が妙に難解になっている感があります。
種別 | ファイル数 | ステップ数 |
---|---|---|
Laravel版(MVC) | 23 | 725 |
Ruby on Rails版 | 19 | 471 |
#パフォーマンス
ローカルのKubernetesの環境で実行する限りでは、体感ではキビキビ動いている用に感じました。ところが計測してみると、Laravel版と比較してRuby on Rails版は1.2〜8.2倍時間がかかっていました・・・まぁ7つの処理中5つが200ms未満だったので、許容範囲かなとは思います。ちなみにLaravelはPHP8ですがJITは無効。Rubyは2.4.6なのでJIT未対応バージョンでした。
機能 | Laravel(MVC)時間 | Laravel(MVC)メモリ | Rails時間 | Railsメモリ |
---|---|---|---|---|
商品一覧画面表示 | 118ms | 2750KB | 644ms | 3064KB |
商品詳細画面表示 | 20ms | 703KB | 163ms | 40KB |
カート追加API | 77ms | 646KB | 90ms | 20KB |
カート画面表示 | 47ms | 610KB | 70ms | 4KB |
注文画面表示 | 26ms | 610KB | 112ms | 0KB |
注文バリデーションAPI | 102ms | 822KB | 40ms | 440KB |
注文確定処理 | 193ms | 1363KB | 1399ms | 8912KB |