Railsの設計思想にハマッた話

こんにちは。エンジニア歴数カ月の駆け出しエンジニアのえくれあです。
業務での主な使用言語はJavaで、中〜大規模開発に従事しています。

Java以外の言語も学びたく、Ruby on Railsチュートリアルを学習中です。
普段触ることの多いSpring系のフレームワークと違うことが多くハマったので、ハマった理由と、どう調べ、どう落とし所をつけたか書いておこうと思います。

## ハマった理由
* RailsにおけるMVCの役割分担の仕方がよくわからなかった。
* Spring Bootではビジネスロジックは@Serviceを付与したクラスに書くことになっているので、RailsにはServiceクラス無いの？ビジネスロジックどこに書くの？？と混乱した。
* データをオブジェクトとして保持するクラスはEntity/DTO/Formのように分けないのか？と思った。

## 解決のためにやったこと
* MVCや3層アーキテクチャについて調べる
* RailsとSpring Bootのアーキテクチャについて比較してみる
* オープンソースのRailsアプリのアーキテクチャを確認する
* Qiita Nightのアーカイブを見てみる

## Spring Bootのアーキテクチャについて
①責務分離
Spring BootはMVCを採用しており、プレゼンテーション層、ビジネスロジック層、データアクセス層の、3層アーキテクチャで実装することが多いことかと思います。

* プレゼンテーション層：ユーザーのリクエストをビジネスロジック層に渡し、適切な画面を返す。ControllerやViewなど。
* ビジネスロジック層：プレゼンテーション層・データアクセス層の仲介役としてデータチェックや処理を行う。Serviceクラスなど。つまり業務ロジックはここに属しますね。
* データアクセス層：データベースに対してCRUD処理を行う。

というように、役割ごとに処理をどの層(細かく考えていくと、パッケージやクラス)に書くべきかが分離されています。

②オブジェクト保持に関わるクラス
データを扱う際に、オブジェクトの扱い方に応じてクラスを分けることがあるのもSpring Bootの特徴かと思います。
* Entityクラス：DBとデータをやり取りするためのオブジェクトを保持するクラス
* Formクラス：入力パラメータをオブジェクトとして保持するクラス
* Dtoクラス：各やり取りに必要なオブジェクトのみを保持するクラス

これらのクラスをわざわざ分ける理由は、セキュリティの向上や、通信コスト削減、再利用性・拡張性の確保につながるためです。(これについては別記事作ろうと考えています)

【参考】
[【初心者向け】3層アーキテクチャ in Spring Boot](https://qiita.com/shibainuu/items/757c2e418459e4b51dd1)
[Spring Boot における各レイヤの責務](https://cs27.org/wiki/kobespiral2021/?SpringBoot/DTO)
[Spring Bootにおける DTO, Form, Entityの違い](https://cs27.org/wiki/kobespiral2021/?SpringBoot/DTO)
[Spring Boot API で DTO をエンティティへ自動的にマッピングする](https://auth0.com/blog/jp-automatically-mapping-dto-to-entity-on-spring-boot-apis/)

## Railsにおける設計思想
①責務分離
MVCを採用しているのはSpring Bootと一緒ですが、3層アーキテクチャで実装するというのは本来の設計思想とは外れるようです。
Spring Bootと大きく異なるのは、ビジネスロジック層としてServiceクラスを分離して実装することが想定されていない点です。(rails newしたときにservicesパッケージは自動生成されませんよね。)

では、ビジネスロジックはどこに書くのか。
Railsコミュニティでよく言われているのは"Thin Controller, Fat Model"です。
つまり、Railsの設計思想ではビジネスロジックはモデルに書くことが想定されているようです。
これは、DRY原則の担保やテスト容易性の観点においてメリットがあるそうです。

[Railsチュートリアル](https://railstutorial.jp/chapters/beginning?version=7.0#cha-beginning)でもこの思想にのっとってサンプルアプリを作成していきます。

【参考】
[Ruby on Railsを作ったプログラマはDavid heinemeier Hansson。Railsの設計哲学。](https://code-examples-ja.hateblo.jp/entry/2014/02/01/Ruby_on_Rails%E3%82%92%E4%BD%9C%E3%81%A3%E3%81%9F%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E%E3%81%AFDavid_heinemeier_Hansson%E3%80%82Rails%E3%81%AE%E8%A8%AD%E8%A8%88%E5%93%B2%E5%AD%A6%E3%80%82)

## オープンソースプロジェクトのアーキテクチャ
Railsの設計思想について理解したものの、アプリケーションの規模が大きくなりModelが肥大化することに伴う不都合が出てくるシチュエーションもあるのでは...?と感じました。

そこで、著名なRailsアプリがビジネスロジックをどう扱っているか、どこに書いているかを調べてみることにしました。


【参考】
[著名なオープンソースRailsアプリのapp/以下を見る](https://zenn.dev/takahashim/articles/ac725fb16ec7a11809c5)

上記リンクを覗くと、Serviceクラスを独自に実装しているプロジェクトがあることが分かります。

## Qiita Night参加企業様の事例
2023/11/21開催の[Qiita Night～Rails～](https://www.youtube.com/watch?v=baynYVfPdhc&t=3161s)において発表されていた[ラクスル株式会社](https://corp.raksul.com/)の[安尾様](https://qiita.com/yusuke_yasuo)が、「ビジネスロジックどこに書くの問題」に触れていました。

解決方法として、ビジネスロジックの扱い方についてチーム内共通認識を作っておく、という方法を提示されていました。

タイムリーに悩んでいた問題だったので、こうして一つの答えを示していただけていてとてもありがたく勉強になりました。
今回、いちプログラミング学習者としてこの問題に直面していたわけですが、業務においても共通認識をもって解決していかなければいけない課題だということに気づけたこともとても大きいです。

## まとめと感想
* 業務ロジックをどこで扱うか問題に正解はなく、企業はそれぞれ要件に合わせて扱い方を考えている。
→扱い方のパターン(Modelに書く、Controllerに書く、Serviceクラスを作る、etc)を知っておけば、それに合わせて対応できる。
→私の個人開発レベルでは、とりあえず気になる企業の真似をしてみよう。

* Railsにおけるオブジェクト保持に関わるクラスについてもう少し理解を深めたい。
→EntityとDtoを分けるようなRailsプロジェクトに関して紹介したWebサイトは少ないように思う。
→ActiveRecordをORMとして利用する便利さを殺さないためと理解している。

* 技術選定にはトレードオフが伴う。
→「○○フレームワーク最強卍卍」のようなものはなく、要件に合わせて技術選定をすることが重要。
→Spring BootはRailsに比べ記述が冗長になりやすいが大規模アプリケーションの運用保守に向いていそう。
→RailsはDRY、CoCの理念により記述量を少なくできる分隠蔽される処理がSpring Bootに比べて多くなりやすいが、短期間でリリースを繰り返していくような迅速な開発が求められる現場に向いていそう。