🥳

5年間 Laravel を使って辿り着いた,全然頑張らない「なんちゃってクリーンアーキテクチャ」という落としどころ

に公開
6
GitHubで編集を提案

Discussion

mpywmpyw

勝手に懐疑的・否定的ブコメ&知り合いからの質問に回答コーナー
(名前は匿名化・本文は要約します)

Q1. 結局「どっかが太る」ってやってるし妥協点をどこに持っていくかの問題。 Model で良くない?

Model に書くことの問題点は,既に文中に書いていますが,もう少し具体例を挙げてみます。

メソッド名が衝突する

衝突回避のためのアプローチが複数あって,人によってはもちろん,同じ実装者でもモデルの種類ごとに一貫した命名がなかなか実現しにくいのがネックになりますね。

save() の衝突を回避するために,バリデーションがあることを重視するなら saveAfterValidated(),引数で受けている他リレーションの紐付けを重視して saveWithAssociatingCommunity() など,時と場合によって全く異なる命名になることが考えられます。

さらに後者において保存されるものが複数ある場合,そのユースケースをどっちのクラスに置くのか?という問題にも遭遇します。(本文記事中のユースケースの場合,複数モデルにまたがる場合は App\UseCases\ 直下に置いたりとか柔軟に対応できます)

あるいは save() を継承する というアクロバティックなこともできてしまいますね。実際自分もやったことはありますが, save() がもともと持っている $options = [] という引数を変えてしまうのはモヤモヤしたところでした。

ここまで解決策に悩んでしまって一貫した方針が取りづらい時点で,相当なデメリットだと思います。

例外クラスや Concerns に切り出したトレイトがモデルから遠くなる

ドメイン領域で本来はまとめられるはずのファイル群が技術的な面だけで分断されてしまいます。これに関しては爆殺アニメで有名なミノ駆動さんもアンチパターンとして紹介されていましたね。

モデル 1 ファイルに書いているうちは問題ありませんが,切り出そうとしたときにすぐに詰みます。また切り出さなければ,あなたは将来的に1000行を超えるファットモデルを作り上げていくことになります。

Q2. ここまでやるなら普通に Laravel のお作法でいいじゃん

さて,フレームワークとして導線を敷いてくれているのはここまでです。ここから先は,人によって大きく構成が変わってくる部分になります。

と途中で挙げましたが,フレームワーク側から「普通」とされるお作法がここまでしか用意されていないのが問題なんですよね。そこから先に何も知識が無い状態で行ってしまうと,必然的に Q1 に対する回答のような状態に陥ってしまいがちです。

Q3. 「○○が肥大化するから問題」が全然ピンとこない

Q1 にも関連しますが,これに関しては実際に 1000 行以上あるファイルと単一責務の 100〜200 行程度のファイルを両方触ってみた人にしかメリットが分かりにくいかもしれません。

  • Git がコンフリクトしやすく,複数人での同時作業がハイリスク。
  • 目的が全く違うのに,不必要に共通化されるメソッドが出てきてしまうおそれがある。またどの private protected メソッドがどの public メソッドのために存在しているのか分かりづらくなる。これを避けるためには可能な限りメソッド分割をしないということになるが,そんな何十年も前の構造化プログラミングの時代に戻ってもいいのか?

Q4. クリーンアーキテクチャと設計思想が違いすぎる,やっぱりサービス層付け足しただけじゃん?

クリーンアーキテクチャにおいて本来なら禁忌とされる形です。実態として「MVC + Service だよね」という声もありましたが,単一責務な Service は UseCase と呼ぶほうがしっくり来るので,これもクリーンアーキテクチャの亜種の1つとして存在を認めてもいいかなと考えています。

と書いている通り,こういう批判は来るのを元から想定しています。MVC とくっつけて MVUC みたいな呼び方してもいいとは思ってます,流行ればだけど。

Q5. 何故 Symfony + Doctrine にしないのだ…

Symfony 得意な人が現場に集まってるんだったら絶対そのほうがいいと思います(真顔)
Symfony ならお行儀のいいクリーンアーキテクチャも自然に書けますね。

  • もともとコンポーネントごとに依存関係を完全分離する思想が強く,再利用性が高くなっている(それゆえに Laravel も部品として採用できていたりする)
  • Repository パターンでの構成がフレームワーク側で推奨されているし,そのための機能が十分にある

Q6. 外部 API としてアクセスした先にあるデータベースがアプリケーションの中核になる場合は?

そういった場合は,アプリケーション中で Eloquent Model を使ったロジックの占める割合が低くなりますよね…?つまりこの点で妥協する必要性はなくなるので,胸を張って Repository パターンを導入すればいいと思います!

Q7. テーブル正規化されまくってて,超複雑かつ多機能なプロジェクトなんだけど?この案件でこの考え方使っても本当に大丈夫?

無理です。潔く Eloquent Model を今すぐ完全に捨てて,本気で DDD やる構えを見せなさい。いくらなんでも適材適所ってものがあるよ!

(…先日知り合いから恐ろしい話を聞いてしまった)

mpywmpyw

なんか DDD そのものを否定してるみたいに曲解されて延焼してたので,一応火消ししておきます🥺

Java とは言わず,最初から候補の優先度が Symfony > Laravel となる案件においても同様です。どのぐらいガチガチにやるかは言語によって違いは出てくるとは思いますが。

GroGro

ディレクトリ構成が記載されていて非常にイメージしやすかったです。
また、クリーンアーキテクチャを導入しようとして挫折した経験があるため腑に落ちました。

mpywmpyw

転職につき,所属部分を変更致しました。また今後このアーキテクチャについて, DDD ライクな手法,および Repository パターンとの比較について書きたい予定があるので,ご期待ください笑

いきなり記事にせず,考察が甘い部分をスクラップから推敲していこうと思いますので,ご協力いただける方はお願いします。

mpywmpyw

ドメインモデル貧血症対策について,記事に少し追記しました!

hk.者hk.者

雑みな私でも導入する気になれました!ありがとうございます!