メインコンテンツまでスキップ

第15章:総まとめ:よくある失敗・実務の落とし所・次の一歩🚀💖

ここまでで、ToDoミニアプリを使いながら CQS(Command / Query 分離)の「気持ちよさ」まで体験できたはず〜!🥳✨ この最終章は 「明日から実務で迷いにくくなる」 のがゴールだよ🧭💕


15-1. まずは“完成形の型”を1枚で🧩✨(迷子防止)

Summary Map

「CQS、わかった気がするけど…結局どんな形が正解?」ってなるよね😇 **超実務寄りの“ちょうどいい型”**はこれ👇

  • Command:状態を変える(副作用あり)🔧 → 例:追加、完了、削除、名前変更
  • Query:状態を読む(副作用なし)📖 → 例:一覧、検索、集計、表示用に整形

そして、依存関係ルール的には(ざっくり)こう👇 UI → アプリ層(Command/Query) → ドメイン の向きで依存するのが安全🧸🧱


15-2. 失敗トップ3😱(症状→原因→直し方)

Three Failures Podium

🥇 失敗1:Queryが更新してる😱💥

ありがち症状

  • getTodos() の中で「ついでに最終アクセス日時を保存」してる
  • getTodos() の中で「キャッシュを更新」「ログをDBへ保存」してる

なにが困る?

  • Queryのたびに状態が変わる → テストしにくい、バグが増える、キャッシュもしにくい😵‍💫

直し方(最短ルート)

  • “ついで副作用”を Queryの外側へ追い出す(ラッパー / ミドルウェア)🚪✨
  • どうしても時間が必要なら Date.now() を直で呼ばず 引数で受け取る(再現性UP)⏰

おまけ(2026の最新TS事情と相性◎) TypeScript 5.9 では tsc --init の初期設定がかなり“ガチ寄り”になってて、strict: truenoUncheckedSideEffectImports: true などがデフォで入る流れが強いよ(副作用に厳しめ)🧠✨ (TypeScript) さらに import defer で「モジュールの副作用を遅らせる」方向の提案も進んでるから、“副作用コントロール”はこれからも重要テーマだよ〜🍃 (TypeScript)


🥈 失敗2:Commandが返しすぎ🎁🐘

ありがち症状

  • addTodo() が「更新後の一覧」を返してる
  • completeTodo() が「画面表示用DTO」を返してる

なにが困る?

  • Commandが “Queryの仕事” を奪う → 関心が混ざる → 変更に弱い😵‍💫
  • 「更新ロジック」と「表示整形」が絡まって事故る💥

実務の落とし所(ここ超大事)⚖️✨ Commandが返してOKなのは、だいたいこのへん👇

  • ID(新規作成したID)
  • 成否(Result型とか)
  • 最小限の情報(たとえば楽観ロック用の version とか)

返しちゃダメ寄り👇

  • ❌ 更新後の一覧(=Query)
  • ❌ 画面表示用の整形済みデータ(=Query)

鉄板パターンCommand → Queryで再取得 🔁✨(わかりやすくて強い)


🥉 失敗3:分けたのに命名が微妙で読めない📛😇

ありがち症状

  • processTodo() とか handle() とか “何やるの?”って名前
  • Queryなのに update とか Commandなのに get とか混乱

直し方(命名テンプレ)

  • Command:addTodo, completeTodo, renameTodo, deleteTodo
  • Query:getTodos, findTodos, getTodoDetail, countCompletedTodos

コツ

  • Commandは「やること」=動詞が強い💪
  • Queryは「欲しいもの」=get/find/list/count が安定🍯

15-3. “実務の落とし所”ベスト7🏢✨(やりすぎ防止)

CQSは「守りすぎて苦しくなる」と本末転倒😇 現場でよくある“許されライン”をまとめるね👇

  1. CommandがIDを返す ✅(むしろ便利)
  2. Commandが Result を返す ✅(成功/失敗が明確)
  3. Queryで軽い整形はOK ✅(表示用DTOへの変換など)
  4. Queryで“保存”は基本NG ❌(ログ保存・最終閲覧更新など)
  5. ログ/メトリクスは外側へ ✅(ラッパーでやる)
  6. 時間・乱数は引数で注入 ✅(テストが楽)
  7. 依存は内側へ向ける ✅(UIからドメインへ依存を流す)

15-4. CQS と CQRS は別物だよ⚖️(やりすぎ注意)

  • CQS:1つのコードベースの中で「書く/読む」を混ぜない🧩
  • CQRS:さらに踏み込んで「読み取りモデルと書き込みモデルを分ける(場合によってはDBも)」みたいな世界🌍

初心者の勝ち筋はこれ👇 まず CQSで事故率を下げる → 必要になったらCQRSを検討、でOK🙆‍♀️✨ (いきなりCQRSに行くと設計コストが重い…!😵‍💫)


15-5. 卒業チェックリスト✅🎓✨(PR前に見るやつ)

✅ CQSチェック

  • Queryの中に保存/更新/送信がない?🙅‍♀️
  • Commandが「一覧」や「表示用DTO」を返してない?🐘
  • “ついで副作用”が混ざってない?(ログ、カウンタ、キャッシュ更新)👀
  • 時間・乱数・グローバルに依存してない?(必要なら引数/注入)⏰🎲

✅ 命名チェック

  • Commandは動詞が強い?(add/complete/delete…)🔧
  • Queryは get/find/list/count で自然?📖

✅ 依存関係ルール(超ざっくり)🧱

  • UIが直接DBやfetchを握ってない?(アプリ層に寄せる)🚪
  • ドメインが外部事情(UI/DB/HTTP)に引っ張られてない?🧸

15-6. ミニ卒業制作🎮💖(20〜40分でできる!)

ToDoアプリにこの3つを足してみて👇(CQSが効きまくるやつ✨)

① 期限つきToDo📅

  • Command:setDueDate(todoId, dueDate)
  • Query:getTodosDueSoon(now, days)

② フィルタ(未完了だけ表示)🔎

  • Query:getActiveTodos()

③ “完了を取り消す”↩️

  • Command:reopenTodo(todoId)

完成のコツ

  • Commandは状態だけ変える
  • 画面に出す形は Query 側で整える これだけでスッキリするよ〜🧼✨

15-7. AI(Copilot/Codex)を“最終章っぽく”使うプロンプト集🤖🪄

そのままコピって使えるやつ置いとくね💕

  • 「この関数、Command/Queryどっち?理由も3つで」🧠
  • 「このQueryに副作用が混ざる可能性を全部指摘して」👀
  • 「このCommandが返しすぎてるなら、最小の戻り値に直して」🎁➡️🪶
  • 「依存関係ルールを破ってそうな import を指摘して、直し案も」🧱
  • 「Vitestで Query のテスト雛形を3ケース作って」🧪✨ ※Vitestは 4.x 系が主流で移行ガイドも更新されてるよ📌 (vitest.dev)

15-8. 次に学ぶと強いロードマップ📚✨(CQSの次の一歩)

CQSを覚えた人が伸びる順番、だいたいこれ💪💕

  1. SoC(関心の分離):混ざりを減らす基本🧼
  2. DI(依存を外から渡す):Commandのテストが楽になる📦
  3. テスタブル設計:Queryは簡単、Commandは副作用を囲う🧪
  4. エラーモデリング:失敗の設計で実務が安定する🧯✨

15-9. さいごに🎀(ここだけ覚えて帰ってOK)

  • Queryは読むだけ📖(副作用ゼロが最強)
  • Commandは変えるだけ🔧(返しすぎ注意)
  • 迷ったら “Command→Queryで取り直す” 🔁✨
  • 命名が半分📛(読めれば勝ち!)

ここまで来たら、もうCQS初心者卒業だよ〜🎓🥳💖 次は、どれ進める?✨(SoC / DI / テスタブル / エラーモデリング)