ヘキサゴナルアーキテクチャを利用したLambda 関数のドメインモデルの実装 Live AWS Summit 2022 Developer Zone (dev-09) セッション資料です。
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.Developer Zoneヘキサゴナルアーキテクチャを利⽤したLambda 関数のドメインモデルの実装 LiveAtsushi FukuiS E S S I O N I D : D E V - 0 9Senior Solutions Architect, Serverless SpecialistAmazon Web Services Japan
View Slide
© 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
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.下川 賢介シニア サーバーレス スペシャリストソリューションアーキテクト技術統括本部アマゾン ウェブ サービス ジャパン合同会社Kensuke Shimokawa
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.⾃⼰紹介Amazon ElasticContainer ServiceAWS Step Functions AWS Fault InjectionSimulator⾦森 政雄Ø 所属/役職 :DevAx(Developer Acceleration) チームソリューションアーキテクトØ 好きなサービス
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.本セッションのきっかけと⽬的• 以下のような質問を頂くことが多かった§ AWS Lambdaでドメインモデルをどのように実装すれば良いのか– マイクロサービスをLambdaで実装したいがDDDも活⽤したい§ Lambda関数のユニットテストはどのようにすれば良いのか– AWS環境にデプロイする前にLambda関数をテストしたい§ AWSの他のサービスと連携する必要があるが、ドメインモデルはクリーンに保ちたい– ドメインモデルとAWSサービスの呼び出しが混在するとコードの可読性が低下する§ そこでドメインモデルをクリーンに保ち、単体テストを容易にするサンプル実装を提供。本⽇はこれをライブで解説します︕
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.Lambda でユニットテストは難しい︖ならばユニットテストが容易な構造にする
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.Agenda• ドメイン駆動設計とは• ヘキサゴナルアーキテクチャとは• サンプルプログラムの紹介• Lambda関数のユニットテスト• まとめ
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.ドメイン駆動設計とは
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.ドメイン駆動設計とは• Eric Evansが2003年に「ドメイン駆動設計(DDD)」を発表§ ドメインエキスパートが⽤いるドメイン内で共通の⾔語(ユビキタス⾔語)でモデリングを⾏いモデルと実装が常に連動しているスタイルで開発を⾏う⼿法§ ドメインへの理解が進むに従ってモデルは洗練され、それに伴ってコードも進化していく§ ドメインモデルはレイヤ化アーキテクチャなどによって、インフラストラクチャコードとは分離されている
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.ドメイン駆動設計 (Eric Evans - 2003)• 設計における意思決定とドメイン設計の議論における技術的な⽤語の広義のフレームワークを提供• ユビキタス⾔語 ー ビジネスドメインエキスパートと開発者の間の意思疎通として利⽤される⽤語によってモデリングと設計を⾏う• 戦略的な設計のためのガイドライン境界づけられたコンテキスト、蒸留、⼤規模な構造の考察• マイクロサービスによって再度注⽬される
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.モデル駆動設計を構成する⾔語のナビゲーションマップモデル駆動設計サービスエンティティ値オブジェクトファクトリ集約リポジトリ利⼝なUI レイヤ化アーキテクチャ
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.境界づけられたコンテキスト• 境界づけられたコンテキストは特定のモデルを適⽤できる限定された範囲• コンテキストの境界を定めることで、チームメンバーは何を⼀致させるべきで何を独⽴して開発できるのかについての理解を明確化し、共有できるhttps://www.martinfowler.com/bliki/BoundedContext.htmlCustomerTicketProductProductversionCustomerProductTerritoryOpportunityPipelineSalespersonDefectSales context Support context
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.ヘキサゴナルアーキテクチャとは
© 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/
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.Hexagonal ArchitectureDomainModelPortsAdaptersPrimary Actor SecondaryActorHTTP RequestEvent MessageQueue…File StorageDatabaseQueue…
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.Hexagonal ArchitectureDomainModelPortsAdaptersPrimary Actor SecondaryActorHTTP RequestEvent MessageQueue…File StorageDatabaseQueue…アプリケーションはポートによって接続されるアダプタは外界との糊の役⽬を果たすアプリケーションの外側にあってアプリケーションを駆動する側をプライマリアクター、駆動される側をセカンダリーアクターと呼ぶ
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.サンプルプログラムの紹介
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.aws-samples/aws-lambda-domain-sampleGitHubでサンプルプロジェクトを公開https://github.com/aws-samples/aws-lambda-domain-model-sample本⽇はこちらのコードを解説します︕
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.サンプルドメインモデル• できるだけシンプルで理解しやすいようにするため、⼀部の機能のみを実装• ワクチン予約システム– ワクチン予約者は空いている枠を検索してワクチン接種の予約を⾏うことができる– ワクチン予約者は空き枠がない場合は予約ができない– ワクチン予約者は2つまでの予約を⾏うことができる– ワクチン予約者は同⼀⽇時に2つの予約を取ることはできない
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.サンプルドメインモデル(ワクチン予約システム)Recipientrecipient_id: stremail: strfirst_name: strlast_name: strage: intadd_reserve_slot(slot): voidSlotslot_id: strreservation_date: datetimelocation: strvacant: boolis_vacant(): booluse_slot(): void
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.サンプルアーキテクチャAWS CloudAmazon API Gateway AWS Lambda Amazon DynamoDBUserInternet
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.Demo: コード参照
© 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_idself.__email = emailself.__first_name = first_nameself.__last_name = last_nameself.__age = ageself.__slots = []@propertydef 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 Truereturn Falsedef is_slot_counts_equal_or_over_two(self) -> bool:.....ドメインモデルで定義されたピュアなビジネスロジックのみが実装される。外部の世界に対する知識を持たない。
© 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_portself.__slot_output_port = slot_output_portdef make_reservation(self, recipient_id:str, slot_id:str) -> Status:status = Nonerecipient = 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
© 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_portself.__slot_output_port = slot_output_portdef make_reservation(self, recipient_id:str, slot_id:str) -> Status:status = Nonerecipient = 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 statusIRecipientInputPort(抽象クラス)を継承コンストラクタで関連するポートクラスのインスタンスを受け取る
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.インターフェイスクラス( from Primary)from abc import ABCMeta, abstractmethodfrom status import Statusclass IRecipientInputPort(metaclass=ABCMeta):@abstractmethoddef make_reservation(self, recipient_id:str, slot_id:str) -> Status:raise NotImplementedError()
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.プライマリのアダプタはLambda• アダプタの役割は外部からのリクエストを内部アプリケーションに伝えるための変換を⾏うこと• API Gatewayからの呼び出し(HTTPS)をポートクラスの呼び出しに変換する役割はLambdaランタイムが⾏なっている
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.ポートクラス(To Secondary)class RecipientOutputPort(IRecipientOutputPort):def __init__(self, adapter:IRecipientAdapter):self.__adapter = adapterdef 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(抽象クラス)を継承
© 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へのアクセスを実装するアダプター
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.app.pydef 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 instancerecipient_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)からポートへの呼び出し
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.依存関係の注⼊RecipientInputPortRecipientOutputPortIRecipientOutputPortSlotOutputPortISlotOutputPortDDBRecipientAdapterIRecipientAdapterDDBSlotAdapterISlotAdapter
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.クラス図
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.Demo: 実際の動作確認
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.Lambda 関数のユニットテスト
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.Testing Pyramid35
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.Testing Pyramid36Pure
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.サーバーレスのUnit Testは純粋なロジックに対して実施
© 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 + bdef test_add():#unit testexpected = 10 #期待する値assert expected == add(5, 5)
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.Pure Logicに対するUnite Test• 純粋な要件に対してテストケースを書く他のAWSサービスとの結合⽅法に対する知識を含まない• テストが軽くなるため、開発やデリバリーを⾼速化できる• 外部のアーキテクチャが変更された時にも、テストケースが影響を受けにくいテストの陳腐化が防げるテストのメンテナンスコストの軽減• Pure Logicなので意図が伝わりやすい、理解しやすいテストケースから仕様を理解出来る
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.Demo: ユニットテスト
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.ドメインモデルクラスに対するユニットテストは容易def test_add_slot_one(fixture_recipient, fixture_slot):slot = fixture_slottarget = fixture_recipienttarget.add_reserve_slot(slot)assert slot != Noneassert target != Noneassert 1 == len(target.slots)assert slot.slot_id == target.slots[0].slot_idassert slot.reservation_date == target.slots[0].reservation_dateassert slot.location == target.slots[0].locationassert False == target.slots[0].is_vacantdef 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):.....ドメインモデルのピュアなビジネスロジックに対するユニットテストは容易
© 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():#SetUprecipient_output_port = RecipientOutputPort(DummyRecipientAdapter())#execute testingyield recipient_output_port#TearDownrecipient_output_port = Nonedef test_recipient_port_recipient_by_id(fixture_recipient_output_port):target = fixture_recipient_output_portrecipient_id = "dummy_number"recipient = target.get_recipient_by_id(recipient_id)assert recipient != None.....
© 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():#SetUprecipient_output_port = RecipientOutputPort(DummyRecipientAdapter())#execute testingyield recipient_output_port#TearDownrecipient_output_port = Nonedef test_recipient_port_recipient_by_id(fixture_recipient_output_port):target = fixture_recipient_output_portrecipient_id = "dummy_number"recipient = target.get_recipient_by_id(recipient_id)assert recipient != None.....抽象クラスを継承したダミークラスFixtureでターゲットクラスにダミークラスを注⼊してインスタンス化ターゲットクラスのロジックをユニットテストで確認
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.ローカルで実⾏確認するためのmain.pydef 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
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.まとめ
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.まとめ§ Lambdaでドメインモデルをどのように実装すれば良いのか →DDDのモデルをクラスに実装することは同じ。外部の知識を持たせない§ Lambda関数のユニットテストはどのようにすれば良いのか →ドメインモデルクラスはピュアなビジネスロジックのテストが容易。ポートクラスにはダミークラスを注⼊してテストを容易に§ AWSの他のサービスと連携する必要があるが、ドメインモデルはクリーンに保ちたい →Hexagonal Architectureを利⽤してドメインロジックと外部サービスの間を疎結合に保つ
Thank you!© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.Appendix
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.Advanced Topic
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.Lambda関数をどの単位で分割するのか• 1つのサブドメイン全体を1つの関数にする︖• 個別にスケールしたいビジネスロジック単位に関数にする︖• それともAPIごとにLambda関数にする︖
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.コンテキストマップSales context Support contextMarketing context境界つけられたコンテキストだけでは、ドメインの全体像を⽰すことはできないコンテキストマップは、境界づけられたコンテキストを統合することにより、異なるが関連するユビキタス⾔語のマッピングを処理するDDDでは境界づけられたコンテキストを統合するための7つのパターンを説明• 共有カーネル (Shared Kernel)• 顧客/供給者の開発チーム (Customer/SupplierDevelopment Teams)• 順応者 (Conformist)• 腐敗防⽌層 (Anticorruption layer)• 別々の道 (Separate ways)• 公開ホストサービス (Open/Host service)• 公表された⾔語 (Published language)
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.パブリッシュ/サブスクライブ• 特定ドメイン イベントのための論理的な発⾏者︓⼀貫した境界を適⽤する• 複数種類のカップリングに対応• 個々のサブスクライバは個別の境界づけられたコンテキストでドメイン イベントに反応• ドメインモデルのシンプルで効果的なドメインイベントの発⾏⽅法︓軽量なオブザーバーパターン
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.event[i-ʼvent] 名詞状態が変更されたことを⽰すシグナル
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.イベントとは• イベントは、状態の変化に対してサービス間で情報を共有するための主要なメカニズムになる• イミュータブル – 過去は変更できない。コピーすることで容易にスケール• イベントは意味論的な意図を持ち過去時制の動詞として表現される例︓ “customer_created”• 軽量で、”customer_id”のような境界コンテキストをまたがる共通のプロパティによって関連付けられる
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.イベントは観察可能であり、指⽰ではないコマンドの指⽰請求書を発⾏してください。承知しましたイベントの観察Xさんが今⼩物を注⽂しました請求書を送りますセールスレポートに追加します。
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.イベントルーターによるサービスの疎結合化プロデューサとコンシューマを抽象化イベントの選択とフィルタ
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.⾮同期化による応答性の改善と依存性の削減同期コマンドClient Service A Service B⾮同期イベントClient Service A Service B
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.イベントストアによる弾⼒性の改善とスケーラビリティサービスが処理するまでメッセージをバッファリングイベントの発⾏イベントストアイベントの購読Businesslogic
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.信頼性、弾⼒性、独⽴したスケール性注⽂サービス請求サービス倉庫管理サービス販売予測サービスプロデューサコンシューマイベントルータールーティング/フィルタ/ルールキューキューキュー
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.イベント駆動デザインパターン
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.イベント駆動デザインパターン• コレオグラフィ• 全体の作業を制御する指揮者は存在せず、個々のサービスに予め与えられた動作条件に従ってサービスを実⾏• コマンドクエリ責務分離• データ ストアの読み取り操作と更新操作を分離
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.コレオグラフィーパターンとは• 必要なすべての情報を含んだ最初のイベントを 1 つのメッセージに保存して、最初のトランザクションを完了• 他のサービスがそのメッセージを⾮同期的に取得し、それぞれのタスクを完了させる• サービスが疎結合になり、直接互いに影響を与えない• メッセージの保存と取得が⾮同期の関係になり、スケーラビリティと信頼性が向上
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.コレオグラフィーパターンユーザーリクエストサービス リクエストキューサービスAサービスBサービスC
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.実装例1: SNS、 SQS、 Lambdaの利⽤ユーザーリクエストサービス AmazonSNSAmazon SQSAmazon SQSAmazon SQSAWS LambdaAWS LambdaAWS Lambdaファンアウト
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.実装例2: Amazon EventBridgeの利⽤ 配送ポイントプレミアム会員カート⽀払⽀払い⽅法認証注⽂1分毎に実⾏Events会員ステータス⽀払認証カートに⼊れる注⽂完了AmazonEventBridgeリクエストサービス イベントバス
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.コマンドクエリ責務分離パターンとは• コマンドクエリ責務分離(Command-Query ResponsibilitySegregation︓CQRS)パターンはデータを更新するコマンドと参照するクエリを分離することで、ユースケースに応じて個別にスケールすることを可能とするパターン• データソースを分離することで異なるデータ構造を取ることも可能となり、クエリ側はクエリで返すデータ転送オブジェクト(DataTransfer Object : DTO)に合わせた形のスキーマとすることでオブジェクト関係マッピング(Object Relational Mapping : ORM)のオーバーヘッドを軽減することも可能になる• コマンド側とクエリ側が結果整合性を許容する必要がある
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.コマンドクエリ責務共有パターンユーザーサービスドメインモデル ドメインモデルORM ORMデータ転送オブジェクトクエリ更新
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.コマンドクエリ責務分離(CQRS)パターンユーザーコマンドサービスドメインモデルデータ転送オブジェクトクエリ更新クエリサービスデータ転送オブジェクト⾮同期結果整合
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.実装例1︓ Kinesis Data StreamsとLambdaを利⽤フロントサービス Amazon KinesisData StreamsAWS LambdaAWS Lambda Amazon Aurora正規化テーブルユーザーAmazon DynamoDB⾮正規化テーブル
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.実装例2︓ DynamoDB StreamsとLambdaを利⽤ユーザー Amazon DynamoDBStreams⾮正規化テーブルAWS Lambda Amazon Aurora正規化テーブルフロントサービス
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.イベントドリブンアーキテクチャ選択における観点Design Considerations
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.AWSのメッセージングとイベントサービスイベントストア イベントルーターキュー ストリーム トピック イベントバスAWSネイティブマネージドオープンソースAmazon SQSAmazonMQAmazon SNSAmazonMQAmazon KinesisAmazon MSKAmazon EventBridge
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.Amazon SQSによるハイボリュームなビッグデータ処理AWS CloudAmazon S3 AWS Lambda Amazon SQS AWS Lambda Amazon SNS Amazon SQS AWS LambdaAmazon SQS AWS LambdaAmazon SQSAWS LambdaDead Letter QueueFileCreate/UploadTrigger SendingMessageReceiveMessageSend Topic SubscribeTopicイベント情報をキューに保存する責務キューの情報とトピックとして送信する責務個別のドメインロジックを実⾏する責務
© 2022, Amazon Web Services, Inc. or its affiliates. All rights reserved.その他の参考情報• https://speakerdeck.com/_kensh/serverless-testing-2021• https://speakerdeck.com/_kensh/serverless-testing