🎠

UseCaseレイヤーって要るの?

に公開2

TimelabLynx というカレンダーサービスを開発している takahashi(@stak_22)です。

今回は、一般的な

Controller -> UseCase -> Domains

というドメイン駆動なレイヤリングに対して、「本当に UseCase は必要なのか?」という問いに向き合いたいと思います。
どちらもロジックを持ち得るレイヤーで、どう棲み分けするのが良いのでしょうか?

背景

以前に記事で、こんなお話を書かせていただきました。
https://zenn.dev/timelab/articles/2ab658f68a3d12

これは、MVCというレイヤー分けをして、それ以外にレイヤーを増やさないという、今のアプリケーションを鑑みて振り返ると誤った Rails Way への則り方でした。(もちろん前任者の当時の判断は環境や状況にあったものだったかもしれないので悪いことだとは思っていません)

これにより、CQRSの考え方を導入し、レイヤーを一枚増やし、controller が domains(commands/queries) に依存する構成に修正しました。

しかし、やがてこんな課題に出会いました。

「domains が domains に依存してしまう…!!!」

複雑なロジックを共通化するにあたり、domains が domains を呼び出す箇所が生まれました。ロジックを書く場所が domains (もしくは models)しか現状無いためです。
これでは、依存させたくない domains が依存を持ってしまうことになり、アーキテクチャの破綻になってしまいます。

では、UseCase はやはり必要なのではないか…?
しかし、別に UseCase を挟んだところで、今 Controller -> Domains でうまくいっている箇所においてはただ domains を呼ぶだけの UseCase ができ、あまりにそういうのが増えて冗長なのでは…?

そんな疑問が生まれました。

Domains と UseCase の役割

Domains UseCase
主な役割 ビジネスロジックの実装 ユースケースの実装
操作するもの Domainsオブジェクト Domainsクラス
ビジネスルール ドメイン固有のルールを実装 ユースケースに沿った手順を実装

つまり、全く異なるものです。

Domains とは、そもそもサービスを展開するビジネス上におけるドメイン知識を含みます。これがアプリケーションの知識を持つ必要は全く無いですし、Domainsのコードそのものがドメイン知識を持つドキュメントとしても在るべきです。

一方で UseCase は、ドメイン知識を纏った Domains をユーザーストーリーにあったユースケースの手順に合わせて実装されるものです。これがドメイン知識を知る必要はなく、ユースケースにあった Domains を利用するだけで良いということです。つまりだいぶ抽象化されたドメインという概念を扱うだけの、裏の苦労を知らないお客さん的なイメージです(?)

UseCase は必要か?

現在、Controller が Domains に直接依存しているアプリケーションという状況にあります。
ゆえに、UseCase の導入による弊害もあります。

  • Controller -> Domains でうまくいっている箇所においてはただ domains を呼ぶだけの UseCase ができてしまう。つまり、呼ばれたら domains を呼び出すだけという、冗長なクラスが増えていってしまう。

これはまぁ、全体に UseCase を挟むというルールにするにはエンドポイント数的にも不可能なので段階的にはなりますが、そもそも UseCase は option でいいんじゃないか…?
悩ましい。

他のエンジニアの方に相談しました。



うーんなるほど、たしかに、冗長な UseCase は増やさずとも良いのか。
Controller から直接 Domains に依存したところで問題はない気がする。(もし他の手続きが必要になったなら UseCase を挟むのはそこまで大変な作業ではない)

まとめ

UseCase がなくても問題はないと考えます。
しかし、Domains にはドメインとなるロジックを抽出し、UseCase はユースケースを実現するためのドメインを利用した手続きを書く、といったそれぞれの役割を明確に意識することが重要です。
これはもちろんアプリケーションの実装ルール次第ではありますが、それぞれの役割を明確に意識することで、UseCase にドメインロジックが生まれるなどの破綻を回避することができると思います。

参考記事

こちらの記事を参考にさせていただきました🙇‍♂️

https://zenn.dev/yamachan0625/books/ddd-hands-on/viewer/chapter11_domain_service

https://zenn.dev/osachi/articles/e06a38a34751d0

https://zenn.dev/enechange_blog/articles/use-case-and-domain-in-clean-architecture


記事に対するご意見ご感想などもお待ちしております!

💡タイムラボの最新情報はこちらから💡
公式X
コーポレートサイト
採用情報

Timelabテックブログ

Discussion

乳牛乳牛

冗長な多層レイヤ問題悩みますよね。単純なCRUD操作はわざわざユースケース層を挟まなくてもいいと思います。

ユースケース層を持ち込むモチベーションは基本的にテスタビリティと考えます。DDD/クリーンアーキテクチャの考えに沿っていればユースケース層まではインフラ非依存で、テストコード記述が容易になるはずです。
しかし、ユースケースがただのCRUDならテストすべきロジックも無いのでわざわざ挟むモチベーションは下がるというのは同感ですね。

mpywmpyw

CLI/HTTP の両対応要件がない限りコスパ悪いは分かります。ただ、今の時代 Claude Code にぶん投げて人間はレビューするだけみたいなコーディングスタイルが主流になってきており、以前ほど「コードが冗長なこと」がボトルネックにならないので、それを踏まえると安牌を取っておきたくなる気持ちはありますね。