そ、そんなにこき下ろしているでしょうか…?
プログラミングにおいて教条的に何らかの思想を上から振り下ろす事に対して違和感を持っているだけのつもりで、代わりに何らかの思想を振り回す事が良いとも思っていません。
クリーンアーキテクチャの書籍では「データベースなんかは玄関のドアノブのパーツぐらいの重要度しか無いのでいつでもドアノブを取り替えれるようにだけしておいて本題に集中しろ」みたいな事を書いていたので流石にそれは無茶というか巨大プロジェクトがエアプなのかって感じる事はありました。改めて主張を整理したいと思います。
まずDBとドメインロジックをベッタリさせて書いているか?という問いですがYESです。特にGoogleの場合は「SpannerからMySQLに移行しよう」みたいな話はまず出てこないですし、仮に移行するならそういう独立したプロジェクトとしてチームで取り組む規模の話になることでしょう。またユニットテストでも可能な限り本物に近い環境を使うように努力せよという指針も公開されています。
https://testing.googleblog.com/2024/02/increase-test-fidelity-by-avoiding-mocks.html
ドメインロジックがベッタリしていると困るケースとしては他にロジック自体の意味がわかりにくくなるというケースがあります。ただこちらは純粋にコードの抽象度の話であって、不慣れな人がコードを書いたら抽象度の高い業務ロジックとDB実装側の都合から来る個々のコードが入り乱れて読みにくくなるのは「DDDを適用しなかったせい」ではなくて「コードの再利用性が低いせい」です。
オブジェクト指向や他のパラダイムの事を神格化して聖典のように崇める人もいますが、一介のコード書きから見たらそれらすべて「コード整理術」の一部でしかありません。膨れ上がり続けるソースコードと向き合って増加し続ける複雑さをどう整頓するかがすべてです。整頓することの恩恵を部屋の掃除程度にしか思ってない人もいますが、コードが整理されるとバグ修正も機能追加も「ここのモジュールが本来ではこうするべきだったから」という形で責任が分割されるのでプログラミングの難度が大幅に下がるという効能があります。言い換えれば、将来のプログラミングの難度を下げる事ができるのが良い抽象化、そうでないならどんなプラクティスも自己満足です。究極的には例えば通販なら注文ロジックの最上位が「店舗.発注(注文票)」ぐらいになっていれば「これからはこういう条件の注文が来た時は却下したい」等と仕様追加があった時にどこに手を加えるべきか自明になって便利、ぐらいの簡単な話です。
ここにおいてすべての値を値オブジェクトにラッピングするのは例えるなら整頓用の箱を大量に用意する事で部屋が整頓できると信じるようなものであって有害ですらあります。
クリーンとかオニオンとかそれぞれの言葉でロジックを階層化することで複雑さを閉じ込めたと主張する人は多いです。中にはただ単に教典にある形に近くなった事を喜ぶ人もいるかも知れません。僕がプログラミング初心者に何度も強調して伝えているのは「再利用する予定のないロジックでも再利用性を重視したコードを書け」という指針です。レイヤーを分ける事自体は善にも悪にもなりますが、そのレイヤー分けの良し悪しを決めるのは「直交性」です。レイヤーごとに責務が明らかで凝集性が高いコードを…などと説明してもピンと来ない事が多いですが「仮にこの部分だけを別の目的で使いまわすならどんなインタフェースが露出していれば使いやすいか、を考える事が自ずと責務の分割と凝集性を高めてくれます(最後はセンスの問題になりますが…)。再利用性を優先することが直交性を高める為の近道である、というのはプログラミングを始めたばかりの自分にも繰り返し伝えたい直感に反する経験則です。
再利用性を優先した結果、リポジトリパターンと呼べる形にコードが落ち着く事自体はそんなにおかしな話ではありません。アプリロジックという究極的には再利用性皆無の極北からグラデーションのように段階を経てOSやDBのAPIという普遍性の塊までの間をどのように整理区分するかがプログラマに課せられた仕事であって、聖典を振り回すような場所ではないと僕は考えています。
アプリのコードの優れたアーキテクチャには究極的には未来予知が必要になります。例えば「将来的にここに仕様変更が来ると思うので拡張余地を残した」といったドメイン知識の注入が効くケースは大いにあります。ただしそれが当たったからといってそのプラクティスがどこでも通用する物であることは意味しません。重要なのは将来の変更に対して頑健であることで、将来の変更を助ける方法は小難しいテクニックを使う事とは限りません。特に最近始まったばかりのサービスというのはプロダクトマネージャにすらどこに何が起きるかわからないものですから、その内部は煮え滾る溶岩のように柔軟であるべきです。拡張性やエンバグのしにくさ(セキュアコーディングとか言いますよね)よりもコードの書き直しやすさと消しやすさに重点を置いています。拡張性ではない書き直しやすさというのは説明がしにくい指標ですが、およそ消しやすさとほぼ同義です。アプリ側の都合で数千行のコードがまるっと要らなくなることはザラに起きますが、本当にその数千行を消して良いかを判断するパッチを作るとしてその複雑さが低いほど消しやすいコードです。やたらとインタフェースを切って拡張余地を量産する場合、実際に不要だった拡張余地自体を消すのはどこから依存されているかわからなくて追加の数倍の神経を使うので、そうならないように自信を持って消し飛ばしていけるようなコードを心がけて書いています。ある程度サービスの概形が固まってきてから内部を冷え固まらせていく作業は新機能追加やデバッグのタイミングでコードの再利用と称してゴリッと書き換えて行けばよくて、人によってはこれをリファクタリングと呼ぶ人もいるでしょう。
長くなったのでまとめると
あらゆる教条主義は基本的に嫌いだけど最終的に似るのは別に良い
凝集とか難しい言葉を使うより再利用性を意識する方が直交性に効く
依存が少なくて消しやすいコードは正義、コードが若い時ほど消しやすさを優先
こんな感じになります。プログラマごとに違う考えがあると思うので他の意見も聞いてみたいですね。