Slide 1

Slide 1 text

Introduction to the practice of Reactive DDD Junichi Kato (@j5ik2o) リアクティブDDD実践入門

Slide 2

Slide 2 text

Self Introduction ● Approximately 7 years Scala experience ● A backend software engineer at ChatWork: ○ Tech lead, Architect, DDD evangelist ○ ChatWork: the largest "business chat" service in Japan 自己紹介。ChatWorkでエンジニアとして働いています

Slide 3

Slide 3 text

Agenda ● Objective ○ Understanding Reactive DDD by a concrete example using Akka ● Contents ○ What is Reactive-DDD ○ Explaining Reactive-DDD using a simulated project ■ Domain Modeling ■ Command stack ■ Query stack ■ Controller ■ Read-model updater(RMU) ○ Conclusion アジェンダ

Slide 4

Slide 4 text

What is Reactive-DDD ● Vaughn Vernon's definition: Reactive-DDD means combining Actor and DDD.The objective is to eliminate the architecture overhead. The references are in the followings: ○ Vaughn Vernon: Reactive Domain-Driven Design - InfoQ ○ Reactive DDD with Scala and Akka ● The benefits are not only being Message-driven, but also Resilient, Responsive, and Elastic.Reactive-DDD may be Reactive System + DDD? ● In Scala, Akka is one of the best options to construct CQRS+ES system based on DDD リアクティブDDDについて

Slide 5

Slide 5 text

Explain Reactive-DDD using a simulated project 模擬プロジェクトで解説

Slide 6

Slide 6 text

Bank account API server ● Bank Account API server that can deposit and withdraw money ○ Deposit to a bank account ○ Withdraw from a bank account ○ Refer to transaction(deposit or withdraw) histories ● Source ○ https://git.io/reactive-ddd-example 銀行口座APIサーバの例 // Deposit to a bank account $ curl -X PUT \ http://localhost:8080/bank-accounts/XEe/events \ -H 'content-type: application/json' \ -d '{ "type": "deposit", "amount": 1000, "currencyCode": "JPY" }' {"id":"XEe","errorMessage":null}% // Refer to transaction histories on a bank account $ curl -X GET \ http://localhost:8080/bank-accounts/XEe \ -H 'content-type: application/json' { "id": "XEe", "values": [ { "type": "deposit", "amount": 1000, "currencyCode": "JPY", "createAt": 1520219459 } ], "errorMessage": null }

Slide 7

Slide 7 text

System configuration ● CQRS+ES(Event Sourcing) ● Separate DB to Write and Read ● Write - Read Flow ○ API(Write) →WriteDB→RMU→ReadDB→ API(Read) ● Actor based implementation 想定するシステム構成 Write DB Read DB API RMU Command Query Domain Event Read Model Domain Event SQL

Slide 8

Slide 8 text

Key design elements ● Explain the following design elements in order キーとなる設計要素を順に説明 Domain modeling Command stack Query stack Controller Read-model updater

Slide 9

Slide 9 text

〜Domain modeling〜 ドメインモデルの設計

Slide 10

Slide 10 text

Explore domain models ● Explore domain model candidates from words in requirements ○ A customer wants to deposit to his bank account, or withdraw from it ○ A customer wants to refer to transaction histories in his bank account ● Domain model candidates ? ○ Customer ○ BankAccount ○ Deposit, Withdraw ○ TransactionHistory ● Analyze the domain model from use cases ドメインモデルを探索する Customer BankAccount Deposit Withdraw Transaction History

Slide 11

Slide 11 text

Bank Account API Server Target use cases ● The target use cases are in the followings 対象のユースケース Deposits/Withdraws to his own bank account Refers to transaction histories in his own bank acount A Customer

Slide 12

Slide 12 text

Use case analysis(1/2) ● A customer deposits to his own bank account ○ In deposit screen(B), a customer(A) ■ puts money in ATM. ■ inputs(C) amount(E) of money(E). ■ clicks(C) confirm button. ○ The system(A) ■ confirms(C) money(E). ■ deposits(C) it to his own bank account(E). ■ saves(C) his own bank account(E) state. ● Same in withdraw case ユースケース分析(1/2) ● Annotations ○ A = Actor in use-case ○ BCE stereotypes ■ B = Boundary, interfaces for actor ■ C = Control, software-functions ■ E = Entity, domain objects

Slide 13

Slide 13 text

● A customer refers to transaction histories in his own bank acount ○ A customer(A) ■ puts(C) his own bank book(E) in ATM ■ clicks(C) button for it ○ The system ■ reads(C) transaction histories(E) in his own bank account(E) ■ updates(C) the bank book(E) Use case analysis(2/2) ユースケース分析(2/2) ● How to analyze BCE ○ Nouns are domain model candidates, or the ‘properties’ ○ Verbs tend to be 'methods' or 'relations' ● Terms not subject to systematization are irrelevant ● UI and I/O elements are irrelevant as well

Slide 14

Slide 14 text

Noteworthy analytical elements ● Domain model candidates ○ Bank Account(E) ■ Bank Account ID ■ Current Balance(unnecessary?) ○ Transaction History(E) ■ Occurred Date ■ Deposit or Withdraw type ■ Amount of money 注目すべき分析要素 ● Control candidates ○ Deposit ○ Withdraw

Slide 15

Slide 15 text

Boundary of Aggregate definition ● The responsibility of the Aggregate ○ maintain consistency, suppress direct relations to increase. ● Boundary ○ All objects that cannot exist without a bank account are included in Bank Account Aggregate. ○ Is Transaction History Aggregate? Or is it an object inside Aggregate? ○ Obviously a search for transaction history requires a bank account, but Aggregate with whole histories may consume huge memories. In this case, prefer on-demand DB queries to object references 集約境界の定義 BankAccount BankAccountId BankAccountName balance: Money BankAccountEvent BankAccountEventId Deposit or Withdraw amount: Money occurredAt: DateTime ?

Slide 16

Slide 16 text

Separate Read/Write responsibilities in Aggregate 集約上のR/W責務の分離 BankAccount ● Separate query responsibility from Aggregate, Aggregate concentrates on command responsibility. ● Domain events that occurred in Aggregate are persisted and are used for query responsibilities ● Not necessary to include BankAccountEvent by this responsbility separation. state transition Command side Query side BankAccountEvent BankAccountEventRecord RMU Dao, Record Write DB R/W separation Read DB

Slide 17

Slide 17 text

Allocating behaviors to domain models ● Focus on Entities and Controls ○ BankAccount and Deposit/Withdraw ● Controls are analyzed as the message to Entities ● Then find the appropriate Entity to receive the Control ○ Deposit/Withdraw is sent to BankAccount ● This analysis is reflected to code ○ bankAccount.deposit(amount, …) ○ bankAccountRef ! Deposite(amount, ...) ドメインモデルへの振る舞いの割り当て Deposit or Withdraw Bank Account Transition state

Slide 18

Slide 18 text

Does BankAccount itself work? ● Avoid dispersal of knowledge by behavior concentration to entities.But does BankAccount itself work? ● How did Alexander analyze the kettle? ○ A kettle is just a container to store water? ○ He analyzed the object to inform the boiling of water ● The analysis result changes depending on what kind of responsibility is given to the object 銀行口座自身が動作するのですか? just a container to store water? An object to inform the boiling of water

Slide 19

Slide 19 text

〜Command Stack〜 コマンドスタック

Slide 20

Slide 20 text

Layered Architecture ● Projects based on Clean Architecture ○ be simpler than the traditional layer style ● Direct dependency from outside to inside ● If use interface from use case, use indirect dependency ● Layers ○ Interface layer ■ HTTP, DB, Aggregates ○ Use case layer ■ Roles to combine tasks for workflow ○ Domain layer ■ domain objects レイヤ化アーキテクチャ

Slide 21

Slide 21 text

Layered Architecture example ● sbt project as a layer is one of approaches to the layered architecture プロジェクト構成の例 interface use-case domain infrastructure controller write use case read use case domain object aggregate dao, record port port(impl) port port(impl) command stack query stack

Slide 22

Slide 22 text

コマンドスタックの設計 interface use-case domain infrastructure controller write use case read use case domain object aggregate dao, record port port(impl) port port(impl) command stack query stack Designing command stack

Slide 23

Slide 23 text

Domain object and Aggregate ● Domain objects are the state of Aggregate ● Domain objects are simple objects represented by case classes and basic data types ● The internal state encapsulation by using Actors ○ The internal state can only be manipulated via messages ドメインオブジェクトと集約の関係 BankAccountAggregate(akka-actor) state: BankAccount(Entity) id: BankAccountId(VO) name: BankAccountName(VO) balance: Money(VO)

Slide 24

Slide 24 text

Domain object example ドメインオブジェクトの例

Slide 25

Slide 25 text

Stored domain events Aggregate design ● Aggregate is a Persistent Actor(stateful actor) ● Create a initial state by `OpenRequest` ● Use `DepositRequest` or `WithdrawRequest` to update the state. Also return the latest state for assertion. ● After receiving the command, change the state and persists the domain events ● Use Domain Events for Actor replaying 集約の設計 BankAccountAggregate BankAccount DepositeRequest DepositSucceede d Opened Deposited Withdraw change the state persist domain events return the response Append only persist replay

Slide 26

Slide 26 text

Domain Event Design ● Use Domain Events not only for actor replaying but also for systems integration (e.g. Read Model Updater) ● Use Domain event names in terms of domain knowledge, not terms for persistence ○ Opened ○ Deposited ○ Withdrawn ○ Closed ドメインイベントの設計

Slide 27

Slide 27 text

Domain Event example ドメインイベントの例

Slide 28

Slide 28 text

Aggregate example(1/4) ● Implement Persistent Actor ● Actor state type is domain object ● persistenceId is a string value combine aggregate name and id ● Release system resource by receive timeout 集約の例(1/5) aggregate-name + id number Handle the state of domain object

Slide 29

Slide 29 text

Aggregate example(2/4) ● Implement `receiveCommand` ● After receiving commands, persist domain events(persist method) ● `tryToSaveSnapshot` persists the latest state at that time ● Also reply the response for the request 集約の例(2/5)

Slide 30

Slide 30 text

Aggregate example(3/4) ● Implementation for deposit and withdraw ● The persisted format and storage depend on the akka-persistence plugin and its settings ● In this time, akka-persistence-jdbc 集約の例(3/5)

Slide 31

Slide 31 text

Aggregate example(4/4) ● Use `receiveRecover` to replay actor from Domain Events ● Complete recovery when `RecoveryCompleted` is received ● Accelerate actor replaying by using events and the latest snapshot. ● When SnapshotOffer, overwrite the state completely 集約の例(4/5)

Slide 32

Slide 32 text

Configurations for Aggregate ● Configurations for akka-persistence-jdbc ● Persist Domain Events to message column by Serializer, snapshot is into snapshot column 集約の設定(1/2)

Slide 33

Slide 33 text

Testing Aggregate ● Testing to stop/restart a persistent actor with state ● Replay the actor state across runtime 集約のテスト Replay actor state from events Persist domain events

Slide 34

Slide 34 text

akka-persistence benefits ● No need to implement DDD Repository: ○ akka-persistence provides entity writing functions ○ ActorSystem(#actorSelection, #actorOf) provides entity reading functions ○ Other query methods are in the query stack ● In-memory states act as cache ○ No need to poll the DB because the Actor keeps the latest state ○ Events is appended to journals, the state is restored from the log at restart ● However, the scaling strategy for stateful actors is required. For example use the following: ○ akka-cluster, akka-cluster-sharding ● In this time, use akka-cluster-sharding akka-persistenceのメリット

Slide 35

Slide 35 text

Node Shard Sharded Aggregate design (1/2) ● Sharding BankAccountAggregate by akka-cluster-sharding 分散された集約の設計 Node Shard … ShardedBankAccount Aggregate BankAccount ShardRegion ShardedBankAccountAggregates(proxy) ShardRegion REST I/F ShardCoordinator (Cluster Singleton) Shard Shard … … ShardRegion forwards commands to actors distributed on each Shard. ... ... ShardCoordinator manages Shard locations for ShardRegion.

Slide 36

Slide 36 text

Sharded Aggregate Design(2/2) 分散された集約の設計 ● Distribute stateful actors on each Shard by akka-cluster-sharding ● Start ShardRegion on each node. Use it to forward command to stateful actors ● Use ShardRegion.ExtractEntityId to extract the entity id from the command ● Use ShardRegion.ExtractShardId to extract the shard id from command

Slide 37

Slide 37 text

Sharded Aggregate example(1/2) 分散された集約の例 ● Override `unhandled` to add support for receive timeout behavior ● Send `Passivate` to Shard actor if no messages, then stop this actor received `StopBankAccount` from Shard actor

Slide 38

Slide 38 text

Sharded Aggregate example(2/2) 分散された集約の例 ● ShardedBankAccountAggregates encapsulates ShardRegion from the caller. It acts like a proxy ● Start ShardRegion when proxy is created ● Forward the received message to ShardRegion ● Note that it uses ClusterSharding# start instead of ActorSystem#actorOf

Slide 39

Slide 39 text

Designing write use case ● Provide methods to execute use cases ● the methods are a combination of akka-stream and Aggregate ● The use case is pipe-line to execute tasks, Not I/O responsebility ● I/O is supported by interface ports 集約用ユースケースの設計 Interface Layer UseCase Layer BankAccountAggregateFlowsImpl BankAccountAggregateFlows BankAccountAggregateUseCase BankAccountAggregates Domain Layer BankAccount ShardRegion BankAccountAggregate Output port

Slide 40

Slide 40 text

Write use case example(1/2) 集約用ユースケースの例 ● Implement use cases to support command operations only ● Enqueue requests and `Promise` object for response ● Promise completes after processing the request ● Use Aggregate via interface ports

Slide 41

Slide 41 text

Write use case example(2/2) 集約ユースケースの例 ● The Queue element type is Request and Promise[Response] ● Execute sink to complete Promise after Aggregate flow Use Aggregate via interface ports The openBankAccountQueue is a long running stream

Slide 42

Slide 42 text

Interface port example インターフェイスポートの例 ● Implement interface port ● The parameter types and return types of the methods depends on Use case layer ● However the implementation depend on interface layer ● Use ask pattern to combine Aggregate in the stream easily. Interface port(I/F) in use case ask to Aggregate

Slide 43

Slide 43 text

〜Query stack〜 クエリスタック

Slide 44

Slide 44 text

クエリスタックの設計 interface use-case domain infrastructure controller write use case read use case domain object aggregate dao, record port port(impl) port port(impl) command stack query stack Designing query stack

Slide 45

Slide 45 text

Read model example ● Designing read-models based on the domain events リードモデルの例 generate read-models auto generated using septeni_orignal/sbt-dao-generator Persist the latest sequence number in consideration of process stop

Slide 46

Slide 46 text

Designing read use case ● Support reading operations only ● Use DAOs via interface ports リードモデル用ユースケースの設計 Interface Layer UseCase Layer BankAccountReadModelFlowsImpl BankAccountReadModelFlows BankAccountReadModelUseCase BankAccountDao, BakAccountEventDao(by slick) Output port

Slide 47

Slide 47 text

Read use case example ● Same as the use case of Aggregate リードモデル用ユースケースの例

Slide 48

Slide 48 text

Interface port example ● read read-model by using Slick3 DAO リードモデル用のポートの実装

Slide 49

Slide 49 text

〜Controllers〜 コントローラ

Slide 50

Slide 50 text

Controller desgin ● The controller has akka-http routes ● The route invokes use case methods ● No ports because direct dependency is available コントローラの設計 Interface Layer UseCase Layer BankAccountReadModelUseCase Routes extends BankAccountController BankAccountAggregateUseCase

Slide 51

Slide 51 text

クエリスタックの設計 interface use-case domain infrastructure controller write use case read use case domain object aggregate dao, record port port(impl) port port(impl) command stack query stack Designing controllers

Slide 52

Slide 52 text

Controller example ● Combine the future of use case and akka-http route コントローラの例 Command Query

Slide 53

Slide 53 text

〜API Server〜 APIサーバのブートスラップ

Slide 54

Slide 54 text

API bootstrap example ● Boot akka-http server APIブートストラップの例

Slide 55

Slide 55 text

〜Read-model updater〜 リードモデルアップデータ

Slide 56

Slide 56 text

リードモデルアップデータの設計 interface use-case infrastructure read-model use case ReadJournal (akka-persistence-query) dao, record port port(impl) port port(impl) Designing read-model updater(1/2) Read DB Write DB domain Domain Event

Slide 57

Slide 57 text

Designing read-model updater(2/2) ● Sequentially read domain events per persistenceId(pid) to build read-models ● Note: ○ Should distribute the pid in charge if RMU num < pid num ○ Should reassign pid responsible for the failed node to another node ● This talk ignores the above issues, and shows a simple case as follows: ○ 1 Domain Event Type : 1 RMU instance. リードモデルアップデータの設計 pid = 1 pid = 2 Aggregate1 Aggregate2 RMU record1 record2 Handle specific domain event type Write DB Read DB

Slide 58

Slide 58 text

Tagging events ● Implement WriteEventAdaptor ● add ADT name as tag to Event ● The following settings are required イベントのタグ付け

Slide 59

Slide 59 text

Read-model use case example(1/2) ● `execute` method executes an endless stream ● `bankAccountReadModelFlows` and `journalReader` are ports for reading ● First, the latest sequence number is obtained from the DB, consume the events using the tag name ● In `projectionFlow`, the read-model is updated based on the domain events リードモデル用ユースケースの例

Slide 60

Slide 60 text

Read-model use case example(2/2) ● `projectionFlow` builds read-models by receiving the domain events and sequence number. ● Delegate the I/O resposibility to BankAccountReadModelFlows リードモデル用ユースケースの例

Slide 61

Slide 61 text

Read-model updater bootstrap example ● Call BankAccountReadModelUseCase#execute リードモデルアップデータのブートスラップの例

Slide 62

Slide 62 text

Conclusion ● Introduction of Reactive-DDD implementation example using Akka ● The main tools used are as follows: ○ akka-actor, akka-persistence, akka-cluster-sharding, akka-stream, akka-http ● Reactive-DDD gets a advantage as compared to non Reactive-DDD, because it benefits both reflection of domain knowledge into code and non-functional requirements. ● This book is recommended to learn the basics of Akka. まとめ

Slide 63

Slide 63 text

Thank you for listening! ご静聴ありがとうございました。

Slide 64

Slide 64 text

We’re Hiring!! http://corp.chatwork.com/ja/recruit/