したがって、 パート1で説明した要件を設定したら、システムの設計に進むことができます。
記事の名前が示すように、設計における主なタスクは、インターフェイスをクエリとコマンドに分離することです。その後、ビジネスシナリオをデータを読み取るもの(クエリインターフェイス)とデータを変更するもの(コマンドインターフェイス)に分割します。 また、Commandを使用してデータを変更した後、Queryを介して使用可能なデータを更新するための最小遅延を提供します。
なぜCQRSなのか?
最近、インターフェイスメソッド( CQS )の分離、およびその後のクエリ/コマンドのインターフェイス自体が、アプリケーションアーキテクチャの開発において一般的な傾向になりました。 しかし、Magentoは人気のためCQRSを使用していませんが、読み取り操作と書き込み操作を個別にスケーリングできる柔軟で拡張可能な(特定のニーズへの適応)ソリューションを構築する唯一の方法である場合があるためです。
実際、コーディングでのSOLIDの理解と普及の結果として、CQRSに到達しました。 CQRSは、単一責任原則およびインターフェース分離原則の実装であり、従来のCRUDからの脱却です。
かなり前に、読み取り操作用にEAV(エンティティ属性値)データモデルをスケーリングする方法を考えたときにCQRS要素を取得し、このためのインデックス集計テーブルを導入しました。
CQRSの詳細とその意味は、MageCONF 2016で作成したプレゼンテーション( ビデオ 、 スライド )で聞くことができます。
ドメインエンティティの説明
Inventoryのサブジェクト領域には、6つの主要なドメインモデルがあります。
- ソース -商品を配置できる物理的な倉庫(店舗、倉庫)を表す責任があるエンティティ。
- ソースアイテム -エンティティバンチ、特定の物理ストレージ上の特定の製品( SKU )の量を表します。 また、製品が現在販売可能かどうかのステータスも保存します。
- 在庫は、複数の物理的な倉庫(ソース)の在庫を同時に表す仮想エンティティです。 物理的な倉庫の集合体です。 倉庫と在庫(接続に含まれる倉庫)間の接続は、管理者が管理パネルで、またはAPI呼び出しを介して設定します。
- ストックアイテム -インデックスエンティティは、ソースとストックの関係に基づいて構築され、特定のストックで利用可能な特定の製品( SKU )の量を表します。 仮想集約。
- 販売チャネル -最終顧客への販売が行われる販売チャネル。 Magentoの場合、これは(Webサイト、ストア、ストアビュー)の場合がありますが、販売チャネルは販売者が個別に決定できるため、一部の販売者にとっては国になるか、大規模な卸売りクライアントが独立した販売チャネルとして機能します。 実際、販売チャネルは販売が行われるコンテキストであり、これにより、業務の実行中に使用する必要がある株式を明確に決定するのに役立ちます。
- 予約 -注文の作成から特定の物理的な倉庫での商品数の減少までの間に販売する商品の現在のレベルを持つために作成された予約オブジェクト。 実際、予約オブジェクトは、注文の操作中に物理的な倉庫在庫(ソースアイテム)から商品のチェック、ロック、およびライトオフを実行する必要性を取り除くのに役立ちますが、特定の在庫内で販売可能な商品の価値はすぐに変化します。
この図は、上記のエンティティの相互作用を表しています。
したがって、インターフェイスをクエリとコマンドに分離できます。
操作の理論
主なタスクの1つは、注文プロセスを可能な限りアンロードすることです。 また、システムの状態を変更しないようにこの操作を行うことが理想的です(状態変更)。 これにより、不要なロックが排除され、チェックアウトのスケーリングが改善されます。
上記の図は、特定のコンテキスト(SalesChannel)で販売できる製品の数を表示する必要があるクエリAPI(StockItem)のみを使用して、カテゴリページのレンダリングなどの操作が実行されることを示しています。
外部ERPまたはPIMシステムとの同期操作では、コマンドAPI(SourceItem)を使用し、特定の倉庫の商品の数量を更新します。その後、StockItemを再構築する再インデックス付けにより、これらの更新が前面に表示されます。
注文する操作の場合、すべてがより面白くなります。
ステップで注文する
注文を行う操作は、2つの操作に分かれています。直接注文することで、買い手が参加し、支払いと注文の受諾の確認で終了します。 注文処理は、事実(数ミリ秒から数分から数時間の遅延を伴う)の後に行われます。その主なタスクは、どの倉庫から顧客に配送するかを決定し、注文完了後にこれらの倉庫の商品の数量を調整することです。
実際には、例としてこれらの操作をより詳細に検討します。
ソースA、ソースB、ソースCの3つの物理的な倉庫があるとします。SKU-1商品はそのような数量で保管されます。
- SourceItem A-20
- SourceItem B-25
- SourceItem C-10
この販売チャネルでは、ストックAの仮想集約を作成しました。これに、現在のすべての物理倉庫が接続されています(ソースA、ソースB、ソースC)。 SKU-1のStockItem Aの量は20 + 25 + 10 = 55です
したがって、買い手がウェブサイトにアクセスすると、システムは商品の数量を決定するために使用する在庫を正確に決定し、この在庫内の在庫アイテムをカテゴリのすべての製品(SKU-1)に使用します。
発注
バイヤーに30単位のSKU-1の購入を決定させます。
- SKU-1のStockItem Aの数= 55-在庫AのSKU-1製品のすべての予約数-ここでは0(これまで)で、販売できるかどうかを決定します予約が作成されていない)、55-0> 30、その後30個の商品SKU-1を販売できると判断します。
- 注文時には、特定の物理ストアが最終的に引き落とされるかどうかはわからないため、ソースアイテムエンティティは使用しません。 * このトピックについては、別の記事で説明します。この記事では、注文の一環として配送する倉庫を選択するアルゴリズムについて詳しく説明します。
- 同時に、StockItemのSKU-1の数を減らすことはできません。これは、読み取り専用に作成された読み取りプロジェクションだからです。 したがって、在庫AのSKU-1の予約を30単位で作成します。 予約の作成は、チェックなしで追加される追加のみの操作です。
- その後、注文チーム自体をさらに処理するためにキューに入れることができます。
現在のシステムの状態:
倉庫内の商品の数量SKU-1:
- SourceItem A-20
- SourceItem B-25
- SourceItem C-10
(-30)の量の在庫AのSKU-1の予約。
待ち時間が長くなるなどの理由でこの注文を処理できるようになるまで、別の顧客が私たちのサイトに来て、SKU-1商品を10ユニット購入したいと考えています。
システムは上記と同じ手順を実行し始めます。
SKU-1を10ユニット販売できるかどうかを確認します。 チェックは次のように実行されます。SKU-1のStockItem Aの数= 55-ストックAでのSKU-1製品のすべての予約数-この場合(-30)、55-30 = 25> 10、10個の商品を販売することを決定しますSKU-1ができます。
実際、イベントソーシングの状態は、集計データ(この場合はStockItem)の投影として定義され、この投影が形成された瞬間からデルタ時間に受信されたすべてのイベントが追加されます(この場合は予約です)。
注文処理
この段階では、どの物理的な倉庫が配送に参加するかを決定する必要があり、これらの倉庫については、出荷される商品の量の価値を減らします。
このパートでは、倉庫の選択を決定する責任あるアルゴリズム(次の記事で説明します)。 たとえば、アルゴリズムは、売り手にとって最も安いものは、ソースCとソースBの倉庫から30個の商品を送ることであると決定しました。
したがって、倉庫内のSKU-1商品の数量は変更する必要があります。
- SourceItem A:20
- SourceItem B:25-20 = 5
- SourceItem C:10-10 = 0
次に、最後に作成された予約オブジェクトを「ゼロ」にするために、在庫A内の(+30)単位で別の予約オブジェクトをSKU-1に作成します(-30 + 30 = 0)。 その後、チームを作成してStockItemインデックスを更新する必要があります(これは物理的な倉庫での商品の可用性の集約として構築されます)。これは非同期にすることもできます。
Magento MSI(マルチソースインベントリ)
この記事は、「CQRSとイベントソーシングを使用した倉庫管理システム」シリーズの2番目の記事であり、Magento 2の例を使用した倉庫管理システムの要件の収集、設計、開発について検討します。
開発が進行中であり、コミュニティエンジニアが関与しているオープンプロジェクト、およびプロジェクトとドキュメントの現在のステータスに精通できるオープンなプロジェクトは、ここから入手できます 。