何これ
今居る会社のメンバーはあまりRailsに慣れてなく、自分に質問が結構来るので社内向けwikiにまとめていた。
評判よかったのでせっかくなのでQiitaにも投稿。
個人的な思想も含まれてるので過信禁物。
必要になったら必要な分だけ導入する。
アーキテクチャ
Presenter
viewのために、データを用意する
controllerに記述してしまうとfatになってしまいがちなviewの特異的なロジック等を記述する
- viewと1:1
- イメージ的にはviewのためにデータを用意したりするために使う
- 基本的にpresenterに全部持たせて、controllerはpresenterを生成するだけにし、viewはpresenterから必要な値などを利用する
- 例: 画面上のオススメ記事一覧のために
recommend_articles
を用意したい
Decorator
modelのために、modelをデコレーションする
modelに記述してしまうとfatになってしまいがちなメソッドを記述する
- modelと1:1
- イメージ的にはアプリケーション全体で整形後のmodelの値を使いたいときに使う
- 例: modelの
last_name
とfirst_name
をlast_name + first_name
として使いたいのでfull_name
メソッドを定義する
Finder
複雑になりがちな検索クエリを生成する
modelに記述してしまうとfatになったり、スパゲッティ化してしまうクエリを記述する
友人がいい感じに実装してたので詳しくは以下
https://furaji.hatenablog.jp/entry/2020/05/09/043924
Service
複数model間にまたがる処理など、単一のmodelに書きづらい処理を記述する
- 基本的に単一責務でいきたいので、
動詞 + 対象 + Service
といった名前にする - 例: ユーザー生成時にUser modelだけでなく複数のmodelにまたがった処理をするので
CreateUserService
を作る - 使う側はできるだけServiceに関与しない
- 例:
CreateUserService.call(args)
で使う側は完結したい
ValueObject
オブジェクト(特にmodel)の値を値ではなくオブジェクトにすることにより、値に対する責務をもたせる。
- ActiveRecordなら
composed_of
が使えるので楽 - 例:
user.address
のaddress
を ValueObjectとしてクラスを分割すれば、User modelを汚すことなく、address
にのみ関心がある処理を書くことができる。user.address.tokyo?
など - Decoratorがmodel全体に関心があるのであれば、ValueObjectはmodel内の一つの値に関心がある
説明しづらいので丸投げ
https://qiita.com/okuramasafumi/items/16bcda8f6382a3db47c9
Concerns
rails new
したらまずは消せ
強力だが一番治安が悪くなりやすいので、適切な設計が必要。
modelやcontrollerの関心を切り出す。
この関心は、大体においては機能。
たとえば、
- サイトのメイン記事(Article)にタグ(Article::Tag)をいくつか紐付けたい
- サイトのお知らせ(News)にタグ(News::Tag)をいくつか紐付けたい
この場合、1と2はどちらもタグをつける/はずす といった関心があるので、Taggable
といったconcernsによってタグ周りの共通化が可能。
開発というものは要件定義段階で何も考えないと同じようで別な機能がいくつも出来がちなので、
要件定義段階からエンジニアが茶々をいれてシンプルにしていくと、共通化しやすくなる。
ルーティング
基本的にRESTful
たとえば、userのcsvをdownloadしたい場合、userに直接アクションはやしたくなるけど、
user/csv
でgetできるようにすると、RESTfulで何が起こるか明確だよねっていう話。
これを読んでうまく書こう
https://tech.kitchhike.com/entry/2017/03/07/190739
テスト
RailsについてくるのはMinitestだけど、デファクトスタンダードはRSpec.
あまり力強いテストコードを書くと、テストコードのテストが必要になってしまうので要注意。
- 「何をテストしたいか」を明確に
- DRYとかはあまり意識しなくてよい
- 基本的にオブジェクトは使い捨てでok
- 変に使い回すと意図しない影響が出たりするよ
- 時間が関係するテストは
travel_to
などを使って時間を操作する-
Time.now
とか使ったりすると時限爆弾が出来るからやめようね
-
これをよんでうまく書こう
https://www.betterspecs.org/