Wansuko-cmd / Passon

3 stars 0 forks source link

CQSチックkにUseCaseを分ける #43

Closed Wansuko-cmd closed 2 years ago

Wansuko-cmd commented 2 years ago

概要

CQSチックにUseCaseを分けてみました!(まだinterfaceのみ)

実装したところ

interface

/watch

/update

/create

懸念点

モデルに対しての操作はxxxCommandとして1ファイルにまとめてしまいましょう!

ということは、今あるupdate, create, deleteを一つのファイルにまとめる感じでしょうか?

今回、createで作成したときにidとかが作成される関係で返り値が欲しいんですよね・・・(CQSの趣旨からがっつり離れていますが) これは、idを割り振るUseCaseを別に用意するべきなのか、もっといい方法などないでしょうか?

Index197511 commented 2 years ago

あらゆるメソッドは、アクションを実行するコマンドか、呼び出し元にデータを返すクエリかのいずれかであって、両方を行ってはならない。これは、質問をすることで回答を変化させてはならないということだ。

CQRSの考案でもこう述べられていたりして返り値を返すのはあまり一般的ではないみたいですね。 ここからは完全に僕自身の考えなのですが、どうしても苦しい場合は最低限の返り値(HTTPのステータスコード、サーバーから返されるcreatedAtなどのメタデータ、エラー)であれば返しても良いと思っています。 もちろん返り値を返すようにすることでQueryのようなものがCommand側に混じってしまうので紳士協定のようなコードにはなってしまいますが.... 他の解決策だともっと早い段階でUUIDを作成するとかですかね?CQRSによせる感じでcreateする際に

data class CreateParameter(
  val id: UUID,
  val email: String,
  val title: String
)

のようなパラメーターを渡すようにするとかですかね? createが返り値を返すパターンに遭遇したことがないのであまり的確な回答は出せないんですが、すべての操作をCQSに無理に寄せる必要はないのかもしれません:eyes: このへんの話は@blackbrackenとかが詳しかったりするかもしれないのでレビュワーに当てておくと良いかもです!

Wansuko-cmd commented 2 years ago

https://github.com/Wansuko-cmd/Passon/pull/43#issuecomment-1075215849

createが値を返してほしいのは

  1. UseCaseでIDの割り振りを行いたい(もっと言うならFactory)
  2. FactoryはViewModel, Viewに漏出させたくない(UseCaseModelの意味がなくなる) という感じです。

自分としては

て考えていたので、createでidを返すのが得策だ!ということを考えていた感じですね・・・

CQSっぽく書くなら、書かれているように

  1. UseCaseModelの生成用UseCaseを用意
  2. UseCaseModelを作成
  3. データベースに保存するためのUseCaseを呼び出し という感じになりそう?なのですが、いまいち3の役割が微妙と感じてしまって・・・

めちゃくちゃ偉そうで申し訳ないです・・・

Wansuko-cmd commented 2 years ago

https://github.com/Wansuko-cmd/Passon/pull/43#pullrequestreview-917302493

ということは、今あるupdate, create, deleteを一つのファイルにまとめる感じでしょうか?

例えば

update -> PasswordGroupとPasswordItemを同時にアップデートすることのみ許可

みたいに、どちらかというと(モデルを使った)アプリケーションの振る舞い中心に記述することで、より操作が分かりやすくする、ということを考えていたのですが

返り値を持つ or 持たないとかで副作用があるかどうかをはっきりさせる

ということを完全に見落としてました・・・

Index197511 commented 2 years ago

https://github.com/Wansuko-cmd/Passon/pull/43#issuecomment-1075236623 であれば値を返してしまっても良いような気がしますね....(エラーのハンドリングもありますし) この辺のCQRSを取り入れた際のcreate時にidやメタデータを返すか返さないか論争は結構繰り広げられていた感じがするので調べてみるとしっくりくるものがあるかもしれませんね:eyes:

Wansuko-cmd commented 2 years ago

ただ、そうなるとCQSから離れてしまうので、もしかしたら今回のケースだとCQSをとり入れるメリットはそこまで大きくない?気もします モデル考えずに使われ方で切っていくことが重要と思っていたのですが、そうでは無いとすればUseCaseがいたずらに大きくなってるだけになりそう?

Wansuko-cmd commented 2 years ago

CQSの話を見て気づいたのですが、RepositoryのほうをCQSっぽく書くのもいいかもしれないですね…(inputとoutputを分けはしないが、返り値の振る舞いは従う)

Usecaseでデータを作成 →Repositoryを用いていれる(エラーはそのまま投げる) →実行完了したら、Usecaseで作成しておいたデータを返す

みたいな感じです

https://little-hands.hatenablog.com/entry/2019/12/02/cqrs

Index197511 commented 2 years ago

CQSの話を見て気づいたのですが、RepositoryのほうをCQSっぽく書くのもいいかもしれないですね…(inputとoutputを分けはしないが、返り値の振る舞いは従う)

そうですね、CommandであればRepositoryに置くのが自然かもしれないですね(永続化まわりになるので)。 QueryServiceはUseCaseによった部分なのでそちらはUseCaseにおいてあげるとよさそうです!

Wansuko-cmd commented 2 years ago

QueryServiceを作ってみました!(テストはまだです)

Wansuko-cmd commented 2 years ago

まあ元からRepositoryにあるものをQueryServiceに持ってきただけではあるので問題なさそうな気がします!(DTO作っていないとか、テストが複雑になるという問題はありますが) あとはUseCaseをどうするか(集合単位の操作をするようにするかモデル単体の操作をするようにするか&CQRSっぽく書くか)なのですが、時間がないので現状のまま行くのがよさげだと思っています!

Index197511 commented 2 years ago

自分の中でちゃんと理由があってわけているのならば問題ないと思います!