ドメイン駆動型マイクロサービスの構築

Chandra Ramalingam

Follow

7月1日。 2020 – 18 min read

Image credits:

Microservices の「マイクロ」という用語は、サービスのサイズを示していますが、アプリケーションを Microservice にする唯一の基準ではありません。 チームがマイクロサービス ベースのアーキテクチャに移行する場合、アジリティの向上、つまり、自律的かつ頻繁に機能を展開することを目的としています。 このアーキテクチャ・スタイルの簡潔な定義を1つに絞るのは難しいです。 Adrian Cockcroft 氏によるこの短い定義が気に入りました。「コンテキストが限定された疎結合の要素からなるサービス指向アーキテクチャ」

これは高レベルの設計ヒューリスティックを定義していますが、マイクロサービスアーキテクチャには、かつてのサービス指向アーキテクチャとは異なるいくつかのユニークな特性があります。 以下に、それらの特徴のいくつかを紹介します。 これらといくつかの特徴は、Martin Fowler の記事や Sam Newman の Building Microservices など、十分に文書化されています。

  1. サービスには、任意の技術的抽象化ではなく、ビジネス文脈を中心とした明確に定義された境界線があります。 例えば、データベースを共有しない。
  2. サービスは障害に強い。
  3. チームは独立して機能を所有し、変更を自律的にリリースする能力を持つ。
  4. チームは自動化の文化を受け入れている。 たとえば、自動テスト、継続的インテグレーション、継続的デリバリーなどです。

    Loosely coupled service-oriented architectureでは、各サービスが明確に定義された境界コンテキストに囲まれており、アプリケーションの迅速、頻繁、かつ信頼できるデリバリーが可能になっています。

    Domain-driven design and Bounded contexts

    マイクロサービスのパワーは、その責任を明確に定義し、それらの間の境界を画定することから得られます。 ここでの目的は、境界内では高い結合力を、境界外では低い結合力を構築することである。 つまり、一緒に変化する傾向のあるものは一緒に属するべきということです。 現実の多くの問題と同様に、これは言うは易く行うは難しで、ビジネスは進化し、仮定は変化する。

    ドメイン駆動設計 (DDD) は、マイクロサービスを設計する際の重要なツールであり、私たちの意見では、モノリスを破壊したり、グリーンフィールド プロジェクトを実装したりする際に必要なツールです。 ドメイン駆動設計は、Eric Evans氏の著書で有名になったもので、ビジネスドメインの基本モデルに基づいてソフトウェアシステムを設計するのに役立つ、一連のアイデア、原則、パターンである。 開発者とドメインの専門家が協力して、ユビキタスの共通言語でビジネスモデルを作成します。 そして、これらのモデルを意味のあるシステムに結びつけ、これらのシステムとこれらのサービスに取り組むチームとの間のコラボレーションプロトコルを確立します。 さらに重要なことは、システム間の概念的な輪郭または境界を設計することです。

    Microservice Design は、これらの原則すべてが互いに独立して変更および進化できるモジュラー システムの構築を支援するので、これらの概念からインスピレーションを得ています。 ドメイン駆動設計の完全な概要は、このブログの範囲外です。 マイクロサービスを構築しようとしている人には、Eric Evans 氏の本を強くお勧めします

    Domain: 組織が何を行うかを表します。 以下の例では、RetailやeCommerceになります。

    Subdomain: 組織内の組織またはビジネスユニット。 ドメインは複数のサブドメインで構成される。

    ユビキタス言語:ユビキタス言語。 モデルを表現するための言語である。 下記の例では、Itemがそれぞれのサブドメインのユビキタス言語に属するModelである。 開発者、プロダクトマネージャ、ドメインエキスパート、ビジネス関係者は同じ言語に同意し、コード、製品ドキュメントなどの成果物にそれを使用する。 eCommerceドメインにおけるサブドメインとBounded Contexts

    Bounded Contexts。 ドメイン駆動設計では、境界付きコンテキストを “単語または文が表示される設定で、その意味を決定する” と定義しています。 要するに、モデルが意味を持つ境界を意味する。 上記の例では、”Item “はそれぞれのコンテキストで異なる意味を持つ。 Catalogコンテキストでは、Itemは販売可能な商品を意味し、Cartコンテキストでは、顧客がカートに追加した商品を意味する。 Fulfillmentコンテキストでは、顧客に出荷されるWarehouse Itemを意味する。 これらのモデルはそれぞれ異なり、それぞれが異なる意味を持ち、場合によっては異なる属性を含んでいます。 これらのモデルをそれぞれの境界内で分離および隔離することにより、モデルを自由に、曖昧さなく表現することができます。

    Note: Subdomains と Bounded contexts の区別を理解することが不可欠です。 サブドメインは問題空間、つまり、ビジネスがどのように問題を見るかに属し、一方、バウンデッド コンテキストはソリューション空間、つまり、問題に対するソリューションをどのように実装するかに属します。 理論的には、各サブドメインは複数の境界付きコンテキストを持つことができますが、私たちはサブドメインごとに1つの境界付きコンテキストを持つように努めています。

    How are Microservices related to Bounded contexts

    さて、マイクロサービスはどこに当てはまるのでしょうか? 各境界型コンテキストがマイクロサービスに対応すると言ってよいのでしょうか。 イエスでもありノーでもある。 その理由はこれから見ていきます。

    図2.境界付きコンテキストの境界または輪郭が非常に大きい場合がある。 Bounded context and microservices

    上の例で考えてみましょう。 Pricing bounded context には、Price、Priced items、および Discounts という 3 つの異なるモデルがあり、それぞれがカタログ項目の価格、項目リストの合計価格の計算、および割引の適用をそれぞれ担当します。 上記のモデルをすべて包含する単一のシステムを作ることもできるが、不当に大きなアプリケーションになる可能性がある。 それぞれのデータモデルには、前述したように、不変量とビジネスルールが存在する。 時間が経つにつれて、注意しなければ、システムは境界が不明瞭な泥の塊になり、責任が重複し、おそらく最初の場所であるモノリスに戻ってしまうかもしれません。 DDD では、これらのモデル (価格、価格付きアイテム、および割引) をアグリゲートと呼びます。 アグリゲートは、関連するモデルを構成する自己完結型のモデルです。 公開インターフェースを通じてのみアグリゲートの状態を変更でき、アグリゲートは一貫性と不変条件の保持を保証します。

    正式には、アグリゲートは、データ変更に対してユニットとして扱われる関連オブジェクトのクラスタです。 外部参照は、ルートとして指定されたAGGREGATEの1つのメンバに制限されます。

    図3.Aggregateの境界内では一貫性ルールが適用される。 Pricing Contextにおけるマイクロサービス

    繰り返しになりますが、すべての集計を個別のマイクロサービスとしてモデル化する必要はないのです。 図3のサービス(アグリゲート)についてはそうであることがわかりましたが、それは必ずしも規則ではありません。 特にビジネスドメインを完全に理解していない場合、複数のアグリゲートを単一のサービスでホストすることが理にかなっている場合もある。 注意すべき重要な点は、一貫性が保証されるのは単一のアグリゲート内だけであり、アグリゲートは公開インターフェースを通じてのみ変更可能であることである。 これらに違反すると、大きな泥の塊になる危険性があります。

    Context maps – A way to carve out accurate microservice boundaries

    Another essential toolkit in your arsenal is the concept of Context maps – again, from Domain Driven Design. モノリスは通常、異種のモデルで構成され、そのほとんどは緊密に結合されています。モデルはおそらく互いの詳細な情報を知っており、1つを変更すると別のものに副作用が発生する可能性があるなど、さまざまです。 モノリスを分解する際には、これらのモデル(この場合はアグリゲート)とその関係を特定することが重要です。 コンテキスト・マップは、まさにその助けとなるものです。 コンテキスト・マップは、さまざまな境界を持つコンテキストとアグリゲート間の関係を特定し、定義するために使用される。 コンテキストは、モデルの境界(上記の例では、価格、割引など)を定義しますが、コンテキスト・マップは、これらのモデル間および異なるコンテキスト間の関係を定義します。 これらの依存関係を特定した後、これらのサービスを実装するチーム間の適切なコラボレーション モデルを決定できます。

    Context maps の完全な探求はこのブログの範囲を超えていますが、例で説明しましょう。 以下の図は、e コマース注文の支払いを処理するさまざまなアプリケーションを表しています。

    1. カート コンテキストは注文のオンライン認証を行い、注文コンテキストは決済などのフルフィルメント後の支払い処理を行い、コンタクト センターは支払いの再試行や注文に使用した支払い方法の変更などの例外を処理する
    2. 簡単にするために、これらすべてのコンテキストが個別のサービスとして実装されると仮定しましょう。 つまり、これらはすべて同じユビキタス ドメイン言語(支払い方法、承認、および決済)に従っています。 5299>

    同じモデルが異なるコンテキストに広がっているもう 1 つの兆候は、これらすべてが 1 つの決済ゲートウェイと直接統合し、互いに同じ操作を行うことです

    図 4. 誤ったコンテキスト マップの定義

    サービス境界の再定義 – 集約を正しいコンテキストにマップする

    上記の設計 (図 4) には、非常に明白ないくつかの問題があります。 ペイメントアグリゲートは複数のコンテキストの一部である。 これらのサービス間の並行性の問題は言うに及ばず、さまざまなサービス間で不変性と一貫性を強制することは不可能です。 例えば、Ordersサービスが以前に提出された支払い方法の決済をポストしようとしている間に、コンタクトセンターが注文に関連する支払い方法を変更したらどうなるでしょうか。 また、異なるグループがこれらのコンテキストを所有する可能性があるため、支払いゲートウェイに変更があると、複数のサービスや潜在的に多数のチームに変更を強いることになることに注意してください。 変更された点はたくさんあります。

    1. Payments 集約は、新しいホームである Payment service を持ちます。 このサービスはまた、支払いサービスを必要とする他のサービスから支払いゲートウェイを抽象化します。 すべてのトランザクションは同じサービス境界内で発生し、並行処理の問題を回避できます。
    2. Payments aggregate は、ACL (Anti-corruption Layer) を使用して、支払ゲートウェイのデータ モデルから中核ドメイン モデルを切り離します。 Ports and Adaptersパターンを使用したこのようなサービスのアプリケーション設計については、今後の記事で詳しく説明します。 ACL 層には通常、支払いゲートウェイのデータモデルを Payments 集約データモデルに変換するアダプターが含まれます。
    3. Cart サービスは、顧客が Web サイトにいる間に支払い承認を完了しなければならない場合があるので、直接 API 呼び出しにより Payments サービスを呼び出します。 注文サービスは、ドメイン イベントを発行します (このブログで後ほど詳しく説明します)。 Paymentsサービスはこのイベントをリッスンし、注文の決済を完了します
    4. コンタクトセンターサービスには多くの集約がありますが、この使用例ではOrders集約にのみ関心があります。 このサービスは、支払い方法が変更されたときにイベントを発行し、Payments サービスは、前に使用されたクレジットカードを取り消し、新しいクレジットカードを処理することでそれに反応します。

    Fig.5. 再定義されたコンテキスト マップ

    通常、モノリシックまたはレガシー アプリケーションには多くの集約があり、境界が重なっていることがよくあります。 これらの集約とその依存関係のコンテキスト マップを作成することは、これらのモノリスから揉み出す新しいマイクロサービスの輪郭を理解するのに役立ちます。 マイクロサービス アーキテクチャの成功または失敗は、集約間の低結合とこれらの集約内の高結合に依存することを忘れないでください。 コンテキストに複数の凝集体がある場合でも、コンテキスト全体とその凝集体は、単一のマイクロサービスに構成することができます。 このヒューリスティックは、少し曖昧なドメインに特に有効だと思います。組織が新たに始めようとしているビジネスラインを考えてみてください。 分離の正しい境界について十分な洞察を持っていないかもしれませんし、集約の早すぎる分解は、高価なリファクタリングにつながる可能性があります。 2つのデータベースが一緒になっていることを発見したため、データ移行と一緒に1つのデータベースに統合しなければならないことを想像してみてください。

    Event Storming – サービス境界を識別する別のテクニック

    Event Storming は、システム内のアグリゲート (および、したがってマイクロサービス) を識別する別の重要なテクニックのひとつです。 これは、モノリスを破壊するときと、マイクロサービスの複雑なエコシステムを設計するときの両方に有用なツールです。 我々は、複雑なアプリケーションの1つを分解するためにこのテクニックを使用しました。そして、我々は、別のブログでEvent Stormingの経験をカバーするつもりです。 このブログの範囲では、簡単なハイレベルの概要を説明したいと思います。

    一言で言えば、イベント ストーミングは、アプリケーション (私たちの場合はモノリス) で働くチーム間のブレインストーミングで、システム内で発生するさまざまなドメイン イベントとプロセスを特定するために行われます。 また、これらのイベントが影響する集合体やモデル、およびその後の影響も特定する。 この演習では、チームは、重複するさまざまな概念、あいまいなドメイン言語、および矛盾するビジネスプロセスを特定します。 また、関連するモデルをグループ化し、集約を再定義し、重複するプロセスを特定します。 この演習を進めると、これらの集約が属する境界コンテキストが明らかになる。 イベントストーミングのワークショップは、すべてのチームが物理的または仮想的に一つの部屋に集まり、スクラムスタイルのホワイトボードにイベント、コマンド、プロセスをマッピングし始めると効果的である。 この演習の終わりには、以下のような通常の結果が得られます:

    1. Aggregates のリストを再定義しました。 これらは潜在的に新しいマイクロサービス
    2. これらのマイクロサービス間を流れる必要があるドメイン イベント
    3. 他のアプリケーションまたはユーザーからの直接の呼び出しであるコマンド

    イベント ストーミング ワークショップの最後のボードのサンプルを以下に示しています。 これは、正しい集約と境界のあるコンテキストに合意するための、チームのための素晴らしい共同演習です。 素晴らしいチーム構築の演習であることに加え、チームはこのセッションからドメイン、ユビキタス言語、および正確なサービス境界の共有理解を得て出てきます。

    図 6. Event Storming board

    Communication between microservices

    簡単におさらいすると、モノリスは単一のプロセス境界内で複数のアグリゲートをホストしています。 したがって、この境界内のアグリゲートの一貫性を管理することが可能です。 例えば、顧客が注文を出すと、商品の在庫を減らし、顧客に電子メールを送ることができます – すべて1つのトランザクション内で。 すべての操作は成功するか、失敗するかである。 しかし、モノリスを壊し、アグリゲートをさまざまなコンテキストに分散させると、何十、何百ものマイクロサービスを持つことになります。 これまでモノリスという単一の境界の中に存在していた処理が、複数の分散システムに分散されることになる。 これらの分散システムすべてにわたってトランザクションの整合性と一貫性を達成することは非常に困難であり、システムの可用性という代償を払わなければなりません。 したがって、CAP 定理が適用されます。「分散システムは、一貫性、可用性、および分割耐性 (CAP の ‘C’, ‘A’, ‘P’) という 3 つの望ましい特性のうち 2 つだけを提供できる」のです。 現実のシステムでは、パーティション トレランスは交渉の余地がありません。ネットワークは信頼性が低く、仮想マシンはダウンし、地域間のレイテンシは悪化します。 今、私たちは、最新のアプリケーションでは、可用性を犠牲にすることは良い考えではないことを知っています。

    図 7. CAP Theorem

    Design applications around eventual consistency

    複数の分散システムにわたってトランザクションを構築しようとすると、またモノリスの土地に行き着くことになります。 ただ、今回は最悪の分散モノリスになるでしょう。 いずれかのシステムが利用できなくなると、プロセス全体が利用できなくなり、しばしば顧客体験の不満や約束の失敗などにつながる。 さらに、あるサービスを変更すると、別のサービスも変更することになり、複雑でコストのかかるデプロイメントになることがよくあります。 したがって、可用性を優先するために、多少の不整合は許容できるようにユースケースを調整したアプリケーションを設計する方が良いのです。 上記の例では、すべてのプロセスを非同期にすることで、最終的に一貫性を持たせることができます。 約束したアイテムが後で倉庫にない場合、そのアイテムをバックオーダーにしたり、ある閾値を超えたアイテムのオーダーを停止したりできます。
    時折、異なるプロセス境界にある 2 つの集約に対して強力な ACID スタイルのトランザクションが必要なシナリオに遭遇することがあります。 これは、これらの集約を再検討し、おそらくそれらを 1 つに結合するための優れた兆候です。 Event StormingとContext Mapsは、異なるプロセス境界にあるこれらのアグリゲートを分割し始める前に、これらの依存関係を早い段階で特定するのに役立つだろう。

    Favor event-driven architecture

    Microservices can emit essential changes that happen to their aggregates. これらはドメイン イベントと呼ばれ、これらの変更に関心のある任意のサービスはこれらのイベントをリッスンし、そのドメイン内でそれぞれのアクションを取ることができます。 この方法は、あるドメインが他のドメインが何をすべきかを規定しないという行動的結合や、プロセスが正常に完了するためにすべてのシステムが同時に利用可能であることに依存しないという時間的結合を回避することができます。 これはもちろん、システムが最終的に一貫性を持つことを意味します。

    Fig.8. イベント駆動アーキテクチャ

    上の例では、Orders サービスがイベント「Order Cancelled」を発行しています。 イベントにサブスクライブしている他のサービスは、それぞれのドメイン機能を処理する。 Paymentサービスはお金を払い戻し、Inventoryサービスは商品の在庫を調整する、などです。

    1. プロデューサーは、少なくとも一度はイベントを生成することを確認する必要があります。 5299>
    2. 消費者は、べき乗の方法でイベントを消費することを確認する必要があります。 同じイベントが再び発生した場合、消費者側には何の副作用もないはずです。 また、イベントは順番に到着しないこともあります。 コンシューマーは、イベントの一意性を保証するためにタイムスタンプまたはバージョン番号フィールドを使用できます。

    いくつかのユースケースの性質上、イベントベースの統合を常に使用できるわけではありません。 Cart サービスと Payment サービスの間の統合をご覧ください。 これは同期的な統合であり、それゆえに注意しなければならない点がいくつかあります。 CartサービスがPaymentサービスからREST APIを呼び出して、注文の支払いを承認するように指示するという行動的結合と、Cartサービスが注文を受け入れるためにPaymentサービスが利用可能である必要があるという時間的結合の例である。 この種のカップリングは、これらのコンテキストの自律性を低下させ、望ましくない依存関係になる可能性がある。 この結合を回避する方法はいくつかありますが、これらのオプションすべてで、顧客に即時フィードバックを提供する機能が失われます。

    1. REST API をイベントベースの統合に変換する。 しかし、Payment Service が REST API のみを公開している場合、このオプションは使用できない可能性があります。
    2. Cart サービスは注文を瞬時に受け付け、注文をピックアップして Payment Service API を呼び出すバッチ ジョブがあります。
    3. Cart サービスはローカル イベントを生成し、それが Payment Service API を呼び出します。

    上流の依存関係の Payment service の障害および使用不能時の再試行を行う上記の組み合わせにより、より弾力性に優れた設計となることができます。 たとえば、Cart と Payment サービスの間の同期統合は、障害発生時のイベントまたはバッチ ベースの再試行によってバックアップされることがあります。 このアプローチは、顧客体験に付加的な影響を与えます。顧客が誤った支払詳細を入力した可能性があり、オフラインで支払いを処理する際に、その情報をオンラインで入手することはできません。 あるいは、失敗した支払いを取り戻すために、ビジネス上のコストが追加されるかもしれません。 しかし、カートサービスが決済サービスの障害に強いという利点は、その欠点を上回る可能性があります。 例えば、オフラインで支払いを回収できない場合、顧客に通知することができます。 要するに、ユーザー エクスペリエンス、回復力、および運用コストの間にはトレードオフがあり、これらの妥協を念頭に置いてシステムを設計するのが賢明です。

    消費者固有のデータ ニーズのためにサービス間のオーケストレーションを行わない

    あらゆるサービス指向アーキテクチャのアンチパターンの1つは、サービスが消費者の特定のアクセスパターンに合わせてしまうというものです。 通常、これはコンシューマ チームがサービス チームと密接に連携している場合に起こります。 もしチームがモノリシックなアプリケーションに取り組んでいたなら、彼らはしばしば異なるアグリゲートの境界を横断する単一のAPIを作成し、それゆえこれらのアグリゲートを緊密に結合することになるでしょう。 例を考えてみよう。 例えば、ウェブアプリケーションとモバイルアプリケーションの注文詳細ページでは、注文の詳細と、その注文に対して処理された返金の詳細の両方を1つのページで表示する必要があるとします。 モノリシックなアプリケーションでは、注文GET API(REST APIと仮定)は、注文と返金を一緒に問い合わせ、両方の集計を統合し、呼び出し元に複合応答を送信します。 アグリゲートが同じプロセス境界に属しているため、多くのオーバーヘッドなしにこれを行うことができる。 したがって、消費者は 1 回の呼び出しですべての必要なデータを取得できます。

    Orders および Refunds が異なるコンテキストに属する場合、データはもはや単一のマイクロサービスまたはアグリゲート境界内に存在しなくなります。 消費者に同じ機能を保持する 1 つのオプションは、Order サービスに Refunds サービスの呼び出しの責任を持たせ、複合応答を作成することです。 このアプローチでは、いくつかの懸念があります。 1. 注文サービスは、注文データとともに返金データを必要とする消費者をサポートするために、別のサービスと統合されます。 Refunds 集約の変更は Order 集約の変更につながるため、Order サービスの自律性が低下します。 Refunds サービスがダウンした場合、Order サービスはまだ部分データを送信でき、消費者は優雅に失敗できますか。

    3. 消費者が Refunds 集約からさらにデータを取得する変更が必要になると、変更を行うために 2 つのチームが関与します。 このパターンがプラットフォーム全体で続くと、さまざまなドメイン サービスの間で複雑な依存関係の網が張り巡らされることになります。 結局のところ、呼び出し元はアクセス パターンをよりよく知っており、これらのパターンに対するあらゆる変更を完全に制御することができます。 このアプローチでは、ドメインサービスをプレゼンテーション層から切り離し、コアビジネスプロセスに集中させることができます。 しかし、Web やモバイル アプリがモノリスからの 1 つの複合 API ではなく、異なるサービスを直接呼び出すようになると、低帯域幅ネットワーク上での複数の呼び出し、異なる API からのデータの処理およびマージなど、これらのアプリにパフォーマンス オーバーヘッドが発生する可能性があります。 このデザイン パターンでは、消費者 (この場合、Web およびモバイル チーム) が作成および管理するバックエンド サービスが、顧客にフロントエンド エクスペリエンスを提供するために、複数のドメイン サービスにわたる統合を純粋に管理します。 ウェブとモバイルのチームは、自分たちが対応するユースケースに基づいてデータコントラクトを設計できるようになった。 また、REST API の代わりに GraphQL を使用して、柔軟に問い合わせを行い、必要なものを正確に取得することもできます。 このサービスは、ドメイン・サービスを所有するチームではなく、コンシューマー・チームによって所有され、維持されることに留意することが重要です。 フロントエンドのチームは、ニーズに応じて最適化できるようになりました。モバイルアプリがより小さなペイロードを要求したり、モバイルアプリからの呼び出し回数を減らしたり、といったことが可能です。 以下のオーケストレーションの改訂版を見てください。 BFF サービスは現在、そのユースケースについて Orders と Refunds の両方のドメイン サービスを呼び出します。

    Fig. Backend for Frontends

    BFF サービスを早い段階で構築することも有用で、モノリスからのサービスの多くを破壊する前に、このサービスを構築できます。 そうしないと、ドメイン サービスがドメイン間オーケストレーションをサポートしなければならないか、Web およびモバイル アプリがフロントエンドから複数のサービスを直接呼び出さなければならなくなります。 これらのオプションは両方とも、パフォーマンスのオーバーヘッド、無駄な作業、チーム間の自律性の欠如につながります。

    Conclusion

    このブログでは、マイクロサービスの世界に踏み込むとき、より具体的には、モノリスを複数のドメインベースのマイクロサービスに分割するときに考慮すべきさまざまな概念、戦略、設計ヒューリスティックに触れました。 これらの多くはそれ自体で膨大なトピックであり、それらを完全に説明するのに十分な正義があるとは思いませんが、重要なトピックのいくつかとこれらを採用した私たちの経験を紹介したいと思います。 Further Reading (リンク) のセクションには、この道を追求したい人にとって役に立つ参考文献やコンテンツがいくつかあります。 これらの 2 つのブログでは、ドメイン駆動設計の原則と Ports および Adapters デザイン パターンを使用して、Cart マイクロサービスの実装についてコード例を交えて説明します。 このブログの主な焦点は、これら2つの原則/パターンが、アジャイルで、テスト可能で、リファクタブルなモジュール式アプリケーションの構築にどのように役立つか、つまり、私たち全員が運用している速いペースの環境に対応することができるかを示すことです。

    ドメイン駆動設計と Ports and Adapters パターンを使用した Cart マイクロサービスの実装 – Part 1

    ドメイン駆動設計と Ports and Adapters パターンを使用した Cart マイクロサービスの実装 – Part 2

    Further Reading

    1. Eric EvansのDomain Driven Design

    2. Vaughn VernonのImplementing Domain Driven Design

    3. Martin FowlerのMicroservicesに関する記事

    4. Sam NewmanのBuilding Microservices

    5. イベントストーミング

    7. フロントエンドのためのバックエンド

    8. 分散コンピューティングの誤謬

    9.

コメントを残す

メールアドレスが公開されることはありません。