プレイブック
CRUD (作成、読み取り、更新、削除) から CQRS (コマンド クエリ責任分離) まで: 問題はコードではなくモデルです (Crud CQRS)
CQRS とは何ですか? CRUD と CQRS の違いは何ですか? CQRS はどのような場合に使用する必要がありますか?大規模システムでは単一モデルでは不十分な理由を説明するガイド。
CQRS - 意思決定の構造
一部 1 の 4
CQRS はフレームワーク構文を使用しません。意思決定、規模、生産の緊張関係を考察する 4 部構成のエンジニアリング本。
CRUD が長年にわたり効果を発揮するのはなぜですか?
CRUDは悪くない。チームが 3 人の場合、1 つの製品を開発し、1 日に数百のリクエストに対応することになります。 Controller → Service → Repository → Database ストリームは完璧なソリューションです。速く、明確で、新しい開発者の頭に入りやすいです。```text
İlk gün
Product
↓
Controller
↓
Service
↓
Repository
↓
Database
破損はコードの品質ではなく、製品の成長によって発生します。最初は商品をリストするだけです。 6 か月後、マーケティング担当者はフィルターを要求します。販売にはランキングが必要です。操作はエクスポートをリクエストします。経営陣はダッシュボードを望んでいます。同じ `Product` パターンが、突然 20 の異なる目的を果たすことになります。text
Marketing → filtre
Sales → sorting
Operations→ export
Management→ analytics + dashboard
↓
aynı Product modeli
日常生活におけるその兆候は通常、無害なエンドポイントです。```text
Bugün
GET /products → 10 ms
Altı ay sonra
GET /products
↓ Category
↓ Reviews
↓ Seller
↓ Campaign
↓ Discount
↓ Stock
↓ Warehouse
↓ Shipment
↓ Favorites
aynı endpoint, farklı ekranları beslemek için büyür
```ジュニア向けの短い用語集:```text
📦 Aggregate
İş kurallarını bir arada koruyan domain nesnesidir.
📦 Invariant
Her koşulda doğru kalması gereken iş kuralıdır.
📦 Transaction boundary
Ya hep ya hiç birlikte kaydedilmesi gereken işlemlerin sınırıdır.
📦 Projection
Bir olayı, okuma için hazırlanmış yeni bir görünüme dönüştüren işlemdir.
📦 Read model / DTO
Ekranın ihtiyacı kadar alan taşıyan, okumaya uygun veri görünümüdür.
```この記事のストーリーはこの点から始まります。CQRS は、テクノロジーを変更することではなく、異なるモデルに異なる意図を与えることによって、この緊張を軽減します。
## CRUD がボトルネックを引き起こすのはどのような場合ですか?
CRUD アプローチでは、読み取りと書き込みが同じ表現で行われます。書く側は、ルール、一貫性、トランジションを維持したいと考えています。読み取り側には、高速なフィルタリング、小さな DTO、検索、並べ替え、および表示に適したフィールドが必要です。単一のモデルでこれらのニーズを同時に満たそうとすると、2 種類のコストが発生します。
1つ目は技術コストです。単純なリスト画面の場合、集計関係が読み込まれ、不要な結合が作成され、データ アクセスのコストが増加します。 2つ目は認知コストです。フィールドを追加すると、あるチームのレポートが修正されますが、別のチームのトランザクション ルールに影響します。```text
100 kullanıcı
→ tek API + tek model
→ CRUD yeterli
5.000 kullanıcı
→ liste, filtre, rapor, iş akışı
→ modelin niyetleri çatışmaya başlar
100.000 kullanıcı
→ okuma ve yazma yükü asimetrik
→ tek model değişimin maliyetini artırır
```この流れはどのプロジェクトでも同じように発生するわけではありません。シグナルはユーザーの数ではありません。このモデルがどのような責任を果たすのかは現時点では不明です。
## CQS: CQRS の小さいながらも重要な根幹
Bertrand Meyer のコマンド クエリ分離の原則はシンプルです。**質問をしても答えが変わってはなりません。**
- コマンドは状態を変更します。これには意図が含まれており、値を返す必要はありません。
- クエリは情報を返します。観測可能な状態は変わりません。
このメソッドレベルの規律により、API 設計がより予測可能になります。 `ApproveInvoice` はコマンドです。 `GetInvoiceSummary` はクエリです。 `UpdateInvoiceStatus` は技術的には可能ですが、ジョブの意図を隠します。
CQRS は、このアイデアをアーキテクチャ レベルにまで引き上げます。コマンド モデルでは、ビジネス ルールと不変条件が保持されます。クエリ モデルは、ユーザーまたはシステムが表示したいビューを生成します。同じテーブルを共有することもできます。 Kafka または Event Sourcing の 2 つのデータベースは必須ではありません。
## 単一モデルが衝突する場所
予約システムを考えてみましょう。書き込み側は、容量、キャンセル、支払い、およびタイムスロットのルールを維持する必要があります。したがって、強力な境界とトランザクションが必要です。一方、管理画面では、今日の稼働率、場所ごとの概要、今後の予約をすぐに確認したいと考えています。
これら 2 つのインテントを同じエンティティ グラフにフィードすると、通常は次の単純なフローになります。```text
GET /reservations
→ Reservation aggregate + Customer + Payment + Availability
→ domain kurallarıyla iç içe sorgu
→ yavaş ve kırılgan liste ekranı
```CQRS の答えは、2 つの個別の最適化目標を設定することです。```text
Command: ReserveRoom
→ kapasiteyi doğrula
→ kuralları uygula
→ transaction içinde kaydet
Query: GetDailyOccupancy
→ sadece tarih, lokasyon ve sayıları oku
→ ekrana uygun DTO döndür
```この区別により、書き込みモデルは正確性を求めて進化し、読み取りモデルは探索性と速度を求めて進化できます。これは、すべてのクエリが O(1) になるという意味ではありません。ただし、ドメイン グラフ全体ではなく、ターゲット ビュー内の行とフィールドの数にコストを近似することがよくあります。
## CQRS の決定信号
CQRS は流行っているから選ばれたわけではありません。次のシグナルは、同じ境界付きコンテキスト内に一緒に出現するときに意味を持ちます。
1. **タスクベースのインターフェイス:** ユーザーは、`Create`、`Update` を作成するだけではありません。確認、予約、配送の開始、または返金のリクエスト。コマンド名にはビジネス言語を含める必要があります。
2. **非対称負荷:** 読み取りトラフィックは書き込みトラフィックよりも大幅に高く、クエリ要件はドメイン モデルの形状とは異なります。
3. **ビジネス ルール:** 集計は複数の不変条件を維持します。単純なデータ更新だけではビジネス上の意思決定ができなくなります。
4. **独立した変化のリズム:** UI とレポートのニーズは、作成側のルールよりも早く変化します。
5. **オープンな境界コンテキスト:** 区別を実装する領域の言語、所有権、および成功基準が明確です。
これらはチェックリストではなく、決定の証拠です。通常、最も強力なシグナルは次のとおりです。チームが同じエンティティの動作と外観の両方を変更するために常に交渉している場合、モデルは 2 つの異なるジョブを実行していることになります。
## CQRS ではないものは何ですか?
CQRS を不必要に高価にする 5 つの不一致があります。
- CQRS はシステム全体を書き直すものではありません。複雑な境界付きコンテキスト内でのみ開始できます。
- CQRS は 2 つの物理データベースではありません。まず、コード内で論理的な区別を行うことができます。
- CQRS はイベント ソーシングではありません。これらは一緒に使用できますが、相互の前提条件ではありません。
- CQRS はメッセージ ブローカーの要件ではありません。最初はインプロセス ハンドラーで十分かもしれません。- CQRS は、すべての画面をマイクロサービスに変えることではありません。
特に、単純な管理パネル、浅いビジネス ルール、および低い変更率では、クラシック CRUD がより良い選択です。部品が少ないということは、操作が少なくなり、オンボーディングが容易になることを意味します。アーキテクチャの成熟度は、CQRS をどれだけ早く追加するかによって決まるわけではありません。それは、いつ追加すべきではないかをどのように判断するかによって測定されます。
## トレードオフ: 何を得るのか、何を支払うのか?
|収益 |価格 |
| --- | --- |
|ビジネス目的のコマンド |その他のモデルと契約 |
|使用シナリオに適した高速クエリ |重複データの管理 |
|読み書きの独立した進化 |観察すべき追加のフロー |
|非対称ロードでのスケーリング オプション |物理的な区別における究極の一貫性 |
したがって、CQRS の決定はフレームワークの選択ではなく、コスト関数によって決まります。追加する構造の複雑さは、削除するドメインや運用の複雑さよりも小さくなければなりません。
## 安全に始める方法
最も安全な通過は、物理的な分離ではなく、論理的な分離から始まります。コマンド名とクエリ名をビジネス言語ごとに分けます。クエリを表示に適した DTO にダウンロードします。コマンド側での検証、権限、不変制限を明確にします。測定を行います。ただし、読み取りボトルネックが判明している場合、または独立したスケールが必要な場合は、読み取りモデルを別のリポジトリに移動します。
このアプローチは、アーキテクチャ上の不可逆的な飛躍ではなく、学習システムを確立します。
この違いについては、次のセクションで説明します。コマンドとクエリのパイプライン、メディエーターの動作、トランザクション制限、および送信トレイの選択はどのように連携するのでしょうか?
## 最も混同されやすい概念```text
❌ CQRS = Event Sourcing
❌ CQRS = Microservice
❌ CQRS = Kafka
❌ CQRS = Event-driven architecture
✓ Bunlar birbirinden bağımsız yaklaşımlardır.
✓ Birlikte kullanılabilirler; birbirlerinin şartı değildir.
```責任の分離として、まず CQRS を検討してください。個別のデータベース、ブローカー、またはイベント ストリームは、十分なニーズを満たす場合にのみ追加する必要があります。
## 意思決定マトリックス
|サイズ |クラッド | CQRS |
| --- | --- | --- |
|コード起動の簡素化 |高 |中 |
|メンテナンスが簡単、シンプルなドメイン |高 |中 |
|非対称読み取りスケール |限定 |強い |
|高密度ドメイン ルール |時間の経過とともに難しくなります |より見やすくなった境界線 |
|運用コスト |低い |論理的識別は中程度、物理的識別は高 |
これはスコアカードではありません。コンテキストを可視化する意思決定ツールです。単純なドメインの場合、CRUD の高い単純性が大きな利点となります。
> **CRUD は小規模システムでは問題になりません。問題は、単一のモデルが異なる意図を同時に表現しようとすることです。 CQRS は、テクノロジーを変更することでではなく、責任を分離することでこの問題を解決します。**
FAQ
よくある質問
「CRUD (作成、読み取り、更新、削除) から CQRS (コマンド クエリ責任分離) へ: 問題はコードではなくモデルです」とは何ですか?
CQRS とは何ですか? CRUD と CQRS の違いは何ですか? CQRS はどのような場合に使用する必要がありますか?大規模システムでは単一モデルでは不十分な理由を説明するガイド。
主なポイントは何ですか?
CQRS書き込み→コマンド→ハンドラー→リポジトリ→データベース読み取り→クエリ→ハンドラー→モデル読み取り/DTO ```
この記事は誰に向けたものですか?
ソフトウェア アーキテクチャ、配信、生産に関する意思決定を実装するエンジニアおよび技術リーダー向け。
学んだエンジニアリング原則
- CQRS は CRUD を拒否するものではありません。もはや 1 つのモデルで 2 つの異なるニーズに対応できないことがわかりつつあります。
- アーキテクチャ上の区別は、システム全体に適用されるべきではなく、複雑さが集中する限定されたコンテキストに適用されるべきです。
- モデルが解決するドメインの複雑さよりもコストが低い場合、モデルは価値があります。
続きを読む
続きを読む
シリーズの次のシリーズ
CQRS (コマンドクエリ責任分離) パイプラインはどのように機能しますか?コマンドとクエリのフローの構造
CQRS リクエスト パイプラインとは何ですか? HTTP リクエストは、コントローラー、MediatR、パイプライン動作、ハンドラー、送信ボックス、読み取りモデルをどのように通過するのでしょうか?
同じシリーズ
分散システムにおける CQRS (コマンド クエリ責任分離): イベント、ブローカー、プロジェクション
CQRS は分散システムでどのように機能しますか?ドメイン イベント、メッセージ ブローカー、プロジェクション、送信ボックス、冪等性、および最終的な整合性の決定をエンドツーエンドで検査します。
同じシリーズ
本番環境における CQRS (コマンド クエリ責任分離): 一貫性、エラー、および回復戦略
CQRS は実稼働環境でどのように安全に機能しますか?一貫性の遅れ、イベントの重複、シーケンスの破損、投影の回復、再試行、DLQ および Saga 戦略。