Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ヘキサゴナルアーキテクチャを利用したLambda 関数のドメインモデルの実装 Live

ヘキサゴナルアーキテクチャを利用したLambda 関数のドメインモデルの実装 Live

ヘキサゴナルアーキテクチャを利用したLambda 関数のドメインモデルの実装 Live
AWS Summit 2022 Developer Zone (dev-09) セッション資料です。

Atsushi Fukui

May 27, 2022
Tweet

More Decks by Atsushi Fukui

Other Decks in Technology

Transcript

  1. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. Developer Zone ヘキサゴナルアーキテクチャを利⽤した Lambda 関数のドメインモデルの実装 Live Atsushi Fukui S E S S I O N I D : D E V - 0 9 Senior Solutions Architect, Serverless Specialist Amazon Web Services Japan
  2. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. ⾃⼰紹介 v名前 v福井 厚(ふくい あつし)Twitter: afukui@ v所属 vアマゾン ウェブ サービス ジャパン合同会社 vシニアソリューションアーキテクト サーバーレス スペシャリスト v関⼼領域 vソフトウェア アーキテクチャ、オブジェクト指向設計、アジャイル開発 v好きなAWSサービス vサーバーレステクノロジー全般、 AWS Code シリーズ、AWS Amplify
  3. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. 下川 賢介 シニア サーバーレス スペシャリスト ソリューションアーキテクト 技術統括本部 アマゾン ウェブ サービス ジャパン合同会社 Kensuke Shimokawa
  4. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. ⾃⼰紹介 Amazon Elastic Container Service AWS Step Functions AWS Fault Injection Simulator ⾦森 政雄 Ø 所属/役職 : DevAx(Developer Acceleration) チーム ソリューションアーキテクト Ø 好きなサービス
  5. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. 本セッションのきっかけと⽬的 • 以下のような質問を頂くことが多かった § AWS Lambdaでドメインモデルをどのように実装すれば良いのか – マイクロサービスをLambdaで実装したいがDDDも活⽤したい § Lambda関数のユニットテストはどのようにすれば良いのか – AWS環境にデプロイする前にLambda関数をテストしたい § AWSの他のサービスと連携する必要があるが、ドメインモデルはクリーンに 保ちたい – ドメインモデルとAWSサービスの呼び出しが混在するとコードの可読性が低下する § そこでドメインモデルをクリーンに保ち、単体テストを容易にする サンプル実装を提供。本⽇はこれをライブで解説します︕
  6. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. Lambda でユニットテストは難しい︖ ならばユニットテストが容易な構造にする
  7. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. Agenda • ドメイン駆動設計とは • ヘキサゴナルアーキテクチャとは • サンプルプログラムの紹介 • Lambda関数のユニットテスト • まとめ
  8. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. ドメイン駆動設計とは
  9. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. ドメイン駆動設計とは • Eric Evansが2003年に「ドメイン駆動設計(DDD)」を発表 § ドメインエキスパートが⽤いるドメイン内で共通の⾔語(ユビキタス⾔語)で モデリングを⾏いモデルと実装が常に連動しているスタイルで開発を⾏う⼿法 § ドメインへの理解が進むに従ってモデルは洗練され、それに伴ってコードも進化 していく § ドメインモデルはレイヤ化アーキテクチャなどによって、インフラストラクチャ コードとは分離されている
  10. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. ドメイン駆動設計 (Eric Evans - 2003) • 設計における意思決定とドメイン 設計の議論における技術的な⽤語の 広義のフレームワークを提供 • ユビキタス⾔語 ー ビジネスドメイン エキスパートと開発者の間の意思疎通 として利⽤される⽤語によって モデリングと設計を⾏う • 戦略的な設計のためのガイドライン 境界づけられたコンテキスト、 蒸留、⼤規模な構造の考察 • マイクロサービスによって再度注⽬ される
  11. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. モデル駆動設計を構成する⾔語のナビゲーションマップ モデル駆動設計 サービス エンティティ 値オブジェクト ファクトリ 集約 リポジトリ 利⼝なUI レイヤ化 アーキテクチャ
  12. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. 境界づけられたコンテキスト • 境界づけられたコンテキストは特定の モデルを適⽤できる限定された範囲 • コンテキストの境界を定めることで、 チームメンバーは何を⼀致させるべきで 何を独⽴して開発できるのかについての 理解を明確化し、共有できる https://www.martinfowler.com/bliki/BoundedContext.html Customer Ticket Product Product version Customer Product Territory Opportunity Pipeline Salesperson Defect Sales context Support context
  13. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. ヘキサゴナルアーキテクチャとは
  14. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. ヘキサゴナルアーキテクチャとは • ヘキサゴナルアーキテクチャは、別名 ポートとアダプタ アーキテクチャとも⾔われる • ポートとアダプタによってアプリケーションのコンポーネントが容易 に環境との間で疎結合に結ばれるソフトウェア設計のアーキテクチャ パターン https://alistair.cockburn.us/hexagonal-architecture/ • オリジナルは Dr. Alistair Cockburn が提唱 https://alistair.cockburn.us/coming-soon/
  15. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. Hexagonal Architecture Domain Model Ports Adapters Primary Actor Secondary Actor HTTP Request Event Message Queue … File Storage Database Queue …
  16. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. Hexagonal Architecture Domain Model Ports Adapters Primary Actor Secondary Actor HTTP Request Event Message Queue … File Storage Database Queue … アプリケーションはポートによって接続される アダプタは外界との糊の役⽬を果たす アプリケーションの外側にあってアプリケーションを駆動する側を プライマリアクター、駆動される側をセカンダリーアクターと呼ぶ
  17. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. サンプルプログラムの紹介
  18. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. aws-samples/aws-lambda-domain-sample GitHubでサンプルプロジェクトを公開 https://github.com/aws-samples/aws-lambda-domain-model- sample 本⽇はこちらのコードを解説 します︕
  19. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. サンプルドメインモデル • できるだけシンプルで理解しやすいようにするため、⼀部の 機能のみを実装 • ワクチン予約システム – ワクチン予約者は空いている枠を検索してワクチン接種の予約を⾏うことが できる – ワクチン予約者は空き枠がない場合は予約ができない – ワクチン予約者は2つまでの予約を⾏うことができる – ワクチン予約者は同⼀⽇時に2つの予約を取ることはできない
  20. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. サンプルドメインモデル(ワクチン予約システム) Recipient recipient_id: str email: str first_name: str last_name: str age: int add_reserve_slot(slot): void Slot slot_id: str reservation_date: datetime location: str vacant: bool is_vacant(): bool use_slot(): void
  21. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. サンプルアーキテクチャ AWS Cloud Amazon API Gateway AWS Lambda Amazon DynamoDB User Internet
  22. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. Demo: コード参照
  23. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. ドメインモデルクラス class Recipient: def __init__(self, recipient_id:str, email:str, first_name:str, last_name:str, age:int): self.__recipient_id = recipient_id self.__email = email self.__first_name = first_name self.__last_name = last_name self.__age = age self.__slots = [] @property def recipient_id(self): return self.__recipient_id ..... def are_slots_same_date(self, slot:Slot) -> bool: for selfslot in self.__slots: if selfslot.reservation_date == slot.reservation_date: return True return False def is_slot_counts_equal_or_over_two(self) -> bool: ..... ドメインモデルで定義されたピュアなビジネス ロジックのみが実装される。 外部の世界に対する知識を持たない。
  24. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. ポートクラス(from Primary) class RecipientInputPort(IRecipientInputPort): def __init__(self, recipient_output_port: IRecipientOutputPort, slot_output_port: ISlotOutputPort): self.__recipient_output_port = recipient_output_port self.__slot_output_port = slot_output_port def make_reservation(self, recipient_id:str, slot_id:str) -> Status: status = None recipient = self.__recipient_output_port.get_recipient_by_id(recipient_id) slot = self.__slot_output_port.get_slot_by_id(slot_id) ..... # --------------------------------------------------- # execute domain logic # --------------------------------------------------- ret = recipient.add_reserve_slot(slot) ..... if ret == True: status = Status(200, "The recipient's reservation is added.") else: status = Status(200, "The recipient's reservation is NOT added!") return status
  25. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. ポートクラス(from Primary) class RecipientInputPort(IRecipientInputPort): def __init__(self, recipient_output_port: IRecipientOutputPort, slot_output_port: ISlotOutputPort): self.__recipient_output_port = recipient_output_port self.__slot_output_port = slot_output_port def make_reservation(self, recipient_id:str, slot_id:str) -> Status: status = None recipient = self.__recipient_output_port.get_recipient_by_id(recipient_id) slot = self.__slot_output_port.get_slot_by_id(slot_id) ..... # --------------------------------------------------- # execute domain logic # --------------------------------------------------- ret = recipient.add_reserve_slot(slot) ..... if ret == True: status = Status(200, "The recipient's reservation is added.") else: status = Status(200, "The recipient's reservation is NOT added!") return status IRecipientInputPort(抽象クラス)を継承 コンストラクタで関連するポートクラスのインスタンスを 受け取る
  26. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. インターフェイスクラス( from Primary) from abc import ABCMeta, abstractmethod from status import Status class IRecipientInputPort(metaclass=ABCMeta): @abstractmethod def make_reservation(self, recipient_id:str, slot_id:str) -> Status: raise NotImplementedError()
  27. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. プライマリのアダプタはLambda • アダプタの役割は外部からのリクエストを内部アプリケーションに 伝えるための変換を⾏うこと • API Gatewayからの呼び出し(HTTPS)をポートクラスの呼び出しに 変換する役割はLambdaランタイムが⾏なっている
  28. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. ポートクラス(To Secondary) class RecipientOutputPort(IRecipientOutputPort): def __init__(self, adapter:IRecipientAdapter): self.__adapter = adapter def get_recipient_by_id(self, recipient_id:str) -> Recipient: return self.__adapter.load(recipient_id) def add_reservation(self, recipient:Recipient) -> bool: return self.__adapter.save(recipient) IRecipientOutputPort(抽象クラス)を継承
  29. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. アダプタクラス(To Secondary) class DDBRecipientAdapter(IRecipientAdapter): def __init__(self): ddb = boto3.resource('dynamodb') self.__table = ddb.Table(table_name) def load(self, recipient_id:str) -> Recipient: try: response = self.__table.get_item( Key={'pk': pk_prefix + recipient_id}) ... def save(self, recipient:Recipient) -> bool: try: item = { "pk": pk_prefix + recipient.recipient_id, "email": recipient.email, "first_name": recipient.first_name, "last_name": recipient.last_name, "age": recipient.age, "slots": [] } ... IRecipientAdapter(抽象クラス)を継承 このクラスはAmazon DynamoDBへのアクセス を実装するアダプター
  30. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. app.py def get_recipient_input_port(): return RecipientInputPort( RecipientOutputPort(DDBRecipientAdapter()), SlotOutputPort(DDBSlotAdapter())) def lambda_handler(event, context): body = json.loads(event['body']) recipient_id = body['recipient_id'] slot_id = body['slot_id'] # get an input port instance recipient_input_port = get_recipient_input_port() status = recipient_input_port.make_reservation(recipient_id, slot_id) return { "statusCode": status.status_code, "body": json.dumps({ "message": status.message }), } コンクリートクラスのインスタンスをコンストラクタ に渡して、RecipientInputPortクラスのインスタンスを ⽣成するファクトリ アダプター(Lambda)からポートへの呼び出し
  31. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. 依存関係の注⼊ RecipientInputPort RecipientOutputPort IRecipientOutputPort SlotOutputPort ISlotOutputPort DDBRecipientAdapter IRecipientAdapter DDBSlotAdapter ISlotAdapter
  32. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. Demo: 実際の動作確認
  33. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. Lambda 関数のユニットテスト
  34. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. Testing Pyramid 35
  35. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. Testing Pyramid 36 Pure
  36. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. サーバーレスのUnit Testは純粋なロジックに対して実施
  37. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. Unit Test対象の関数をTestableにする • 関数をTestable(テスト可能)にするとは︖ • y = f(x) の形にする • xに特定の値を与えるとyの値が決まる # add関数 def add(a, b): return a + b def test_add(): #unit test expected = 10 #期待する値 assert expected == add(5, 5)
  38. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. Pure Logicに対するUnite Test • 純粋な要件に対してテストケースを書く 他のAWSサービスとの結合⽅法に対する知識を含まない • テストが軽くなるため、開発やデリバリーを⾼速化できる • 外部のアーキテクチャが変更された時にも、テストケースが影響を 受けにくい テストの陳腐化が防げる テストのメンテナンスコストの軽減 • Pure Logicなので意図が伝わりやすい、理解しやすい テストケースから仕様を理解出来る
  39. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. Demo: ユニットテスト
  40. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. ドメインモデルクラスに対するユニットテストは容易 def test_add_slot_one(fixture_recipient, fixture_slot): slot = fixture_slot target = fixture_recipient target.add_reserve_slot(slot) assert slot != None assert target != None assert 1 == len(target.slots) assert slot.slot_id == target.slots[0].slot_id assert slot.reservation_date == target.slots[0].reservation_date assert slot.location == target.slots[0].location assert False == target.slots[0].is_vacant def test_add_slot_two(fixture_recipient, fixture_slot, fixture_slot_2): ..... def test_cannot_append_slot_more_than_two(fixture_recipient, fixture_slot, fixture_slot_2, fixture_slot_3): ..... def test_cannot_append_same_date_slot(fixture_recipient, fixture_slot): ..... ドメインモデルのピュアなビジネスロジックに対する ユニットテストは容易
  41. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. ポートクラスに対してはダミークラスの注⼊ class DummyRecipientAdapter(IRecipientAdapter): def load(self, recipient_id:str) -> Recipient: return Recipient(recipient_id, email, first_name, last_name, age) def save(self, recipient:Recipient) -> bool: return True @pytest.fixture() def fixture_recipient_output_port(): #SetUp recipient_output_port = RecipientOutputPort(DummyRecipientAdapter()) #execute testing yield recipient_output_port #TearDown recipient_output_port = None def test_recipient_port_recipient_by_id(fixture_recipient_output_port): target = fixture_recipient_output_port recipient_id = "dummy_number" recipient = target.get_recipient_by_id(recipient_id) assert recipient != None .....
  42. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. ポートクラスに対してはダミークラスの注⼊ class DummyRecipientAdapter(IRecipientAdapter): def load(self, recipient_id:str) -> Recipient: return Recipient(recipient_id, email, first_name, last_name, age) def save(self, recipient:Recipient) -> bool: return True @pytest.fixture() def fixture_recipient_output_port(): #SetUp recipient_output_port = RecipientOutputPort(DummyRecipientAdapter()) #execute testing yield recipient_output_port #TearDown recipient_output_port = None def test_recipient_port_recipient_by_id(fixture_recipient_output_port): target = fixture_recipient_output_port recipient_id = "dummy_number" recipient = target.get_recipient_by_id(recipient_id) assert recipient != None ..... 抽象クラスを継承したダミークラス Fixtureでターゲットクラスにダミークラスを注⼊して インスタンス化 ターゲットクラスのロジックをユニットテスト で確認
  43. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. ローカルで実⾏確認するためのmain.py def get_recipient_input_port(): return RecipientInputPort( RecipientOutputPort(DDBRecipientAdapter()), SlotOutputPort(DDBSlotAdapter())) def main(): recipient_input_port = get_recipient_input_port() status = recipient_input_port.make_reservation("1", "1") print(f"status_code: {status.status_code}, message: {status.message}") if __name__ == "__main__": main() app.pyと同じファクトリー。ダミークラスに置き換える ことも可能 以下のコマンドでローカルマシンから実⾏し、動作確認を⾏う ことが可能 $ python main.py
  44. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. まとめ § Lambdaでドメインモデルをどのように実装すれば良いのか → DDDのモデルをクラスに実装することは同じ。外部の知識を持たせない § Lambda関数のユニットテストはどのようにすれば良いのか → ドメインモデルクラスはピュアなビジネスロジックのテストが容易。 ポートクラスにはダミークラスを注⼊してテストを容易に § AWSの他のサービスと連携する必要があるが、ドメインモデルはクリーンに 保ちたい → Hexagonal Architectureを利⽤してドメインロジックと外部サービスの間を 疎結合に保つ
  45. Thank you! © 2022, Amazon Web Services, Inc. or its

    affiliates. All rights reserved.
  46. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. Lambda関数をどの単位で分割するのか • 1つのサブドメイン全体を1つの関数にする︖ • 個別にスケールしたいビジネスロジック単位に関数にする︖ • それともAPIごとにLambda関数にする︖
  47. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. コンテキストマップ Sales context Support context Marketing context 境界つけられたコンテキストだけでは、ドメインの 全体像を⽰すことはできない コンテキストマップは、境界づけられたコンテキスト を統合することにより、異なるが関連するユビキタス ⾔語のマッピングを処理する DDDでは境界づけられたコンテキストを統合するため の7つのパターンを説明 • 共有カーネル (Shared Kernel) • 顧客/供給者の開発チーム (Customer/Supplier Development Teams) • 順応者 (Conformist) • 腐敗防⽌層 (Anticorruption layer) • 別々の道 (Separate ways) • 公開ホストサービス (Open/Host service) • 公表された⾔語 (Published language)
  48. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. パブリッシュ/サブスクライブ • 特定ドメイン イベントのための論理的な発⾏者︓ ⼀貫した境界を適⽤する • 複数種類のカップリングに対応 • 個々のサブスクライバは個別の 境界づけられたコンテキストで ドメイン イベントに反応 • ドメインモデルのシンプルで効果的な ドメインイベントの発⾏⽅法︓軽量なオブザーバーパターン
  49. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. event [i-ʼvent] 名詞 状態が変更されたことを⽰す シグナル
  50. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. イベントとは • イベントは、状態の変化に対してサービス間で情報を共有するための 主要なメカニズムになる • イミュータブル – 過去は変更できない。コピーすることで容易に スケール • イベントは意味論的な意図を持ち過去時制の動詞として表現される 例︓ “customer_created” • 軽量で、”customer_id”のような境界コンテキストをまたがる共通の プロパティによって関連付けられる
  51. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. イベントは観察可能であり、指⽰ではない コマンドの指⽰ 請求書を 発⾏して ください。 承知 しました イベントの観察 Xさんが今 ⼩物を注⽂ しました 請求書を 送ります セールスレポート に追加します。
  52. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. イベントルーターによるサービスの疎結合化 プロデューサとコンシューマ を抽象化 イベントの選択とフィルタ
  53. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. ⾮同期化による応答性の改善と依存性の削減 同期コマンド Client Service A Service B ⾮同期イベント Client Service A Service B
  54. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. イベントストアによる弾⼒性の改善と スケーラビリティ サービスが処理するまでメッセージ をバッファリング イベントの発⾏ イベントストア イベントの購読 Business logic
  55. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. 信頼性、弾⼒性、独⽴したスケール性 注⽂ サービス 請求 サービス 倉庫管理 サービス 販売予測 サービス プロデューサ コンシューマ イベント ルーター ルーティング/ フィルタ/ ルール キュー キュー キュー
  56. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. イベント駆動デザインパターン
  57. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. イベント駆動デザインパターン • コレオグラフィ • 全体の作業を制御する指揮者は存在せず、個々のサービスに予め与えられた 動作条件に従ってサービスを実⾏ • コマンドクエリ責務分離 • データ ストアの読み取り操作と更新操作を分離
  58. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. コレオグラフィーパターンとは • 必要なすべての情報を含んだ最初のイベントを 1 つのメッセージに 保存して、最初のトランザクションを完了 • 他のサービスがそのメッセージを⾮同期的に取得し、それぞれの タスクを完了させる • サービスが疎結合になり、直接互いに影響を与えない • メッセージの保存と取得が⾮同期の関係になり、スケーラビリティと 信頼性が向上
  59. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. コレオグラフィーパターン ユーザー リクエストサービス リクエストキュー サービスA サービスB サービスC
  60. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. 実装例1: SNS、 SQS、 Lambdaの利⽤ ユーザー リクエストサービス Amazon SNS Amazon SQS Amazon SQS Amazon SQS AWS Lambda AWS Lambda AWS Lambda ファンアウト
  61. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. 実装例2: Amazon EventBridgeの利⽤ 配送 ポイント プレミアム会員 カート ⽀払 ⽀払い⽅法 認証 注⽂ 1分毎に実⾏ Events 会員 ステータス ⽀払認証 カートに ⼊れる 注⽂完了 Amazon EventBridge リクエストサービス イベントバス
  62. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. コマンドクエリ責務分離パターンとは • コマンドクエリ責務分離(Command-Query Responsibility Segregation︓CQRS)パターンはデータを更新するコマンドと参照 するクエリを分離することで、ユースケースに応じて個別にスケール することを可能とするパターン • データソースを分離することで異なるデータ構造を取ることも可能と なり、クエリ側はクエリで返すデータ転送オブジェクト(Data Transfer Object : DTO)に合わせた形のスキーマとすることで オブジェクト関係マッピング(Object Relational Mapping : ORM) のオーバーヘッドを軽減することも可能になる • コマンド側とクエリ側が結果整合性を許容する必要がある
  63. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. コマンドクエリ責務共有パターン ユーザー サービス ドメインモデル ドメインモデル ORM ORM データ転送 オブジェクト クエリ 更新
  64. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. コマンドクエリ責務分離(CQRS)パターン ユーザー コマンドサービス ドメインモデル データ転送 オブジェクト クエリ 更新 クエリサービス データ転送 オブジェクト ⾮同期 結果整合
  65. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. 実装例1︓ Kinesis Data StreamsとLambdaを 利⽤ フロントサービス Amazon Kinesis Data Streams AWS Lambda AWS Lambda Amazon Aurora 正規化テーブル ユーザー Amazon DynamoDB ⾮正規化テーブル
  66. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. 実装例2︓ DynamoDB StreamsとLambdaを 利⽤ ユーザー Amazon DynamoDB Streams ⾮正規化テーブル AWS Lambda Amazon Aurora 正規化テーブル フロントサービス
  67. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. イベントドリブンアーキテクチャ 選択における観点 Design Considerations
  68. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. AWSのメッセージングとイベントサービス イベントストア イベントルーター キュー ストリーム トピック イベントバス AWSネイティブ マネージド オープンソース Amazon SQS Amazon MQ Amazon SNS Amazon MQ Amazon Kinesis Amazon MSK Amazon EventBridge
  69. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. Amazon SQSによるハイボリュームなビッグデータ処理 AWS Cloud Amazon S3 AWS Lambda Amazon SQS AWS Lambda Amazon SNS Amazon SQS AWS Lambda Amazon SQS AWS Lambda Amazon SQS AWS Lambda Dead Letter Queue File Create/Upload Trigger Sending Message Receive Message Send Topic Subscribe Topic イベント情報をキュー に保存する責務 キューの情報とトピック として送信する責務 個別のドメインロジック を実⾏する責務
  70. © 2022, Amazon Web Services, Inc. or its affiliates. All

    rights reserved. その他の参考情報 • https://speakerdeck.com/_kensh/serverless-testing-2021 • https://speakerdeck.com/_kensh/serverless-testing