Introduction to the practice Reactive-DDD

Introduction to the practice Reactive-DDD

933291444e456bfb511a66a2fa9c6929?s=128

かとじゅん

March 18, 2018
Tweet

Transcript

  1. Introduction to the practice of Reactive DDD Junichi Kato (@j5ik2o)

    リアクティブDDD実践入門
  2. 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でエンジニアとして働いています
  3. 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 アジェンダ
  4. 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について
  5. Explain Reactive-DDD using a simulated project 模擬プロジェクトで解説

  6. 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 }
  7. 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
  8. Key design elements • Explain the following design elements in

    order キーとなる設計要素を順に説明 Domain modeling Command stack Query stack Controller Read-model updater
  9. 〜Domain modeling〜 ドメインモデルの設計

  10. 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
  11. 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
  12. 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
  13. • 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
  14. 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
  15. 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 ?
  16. 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
  17. 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
  18. 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
  19. 〜Command Stack〜 コマンドスタック

  20. 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 レイヤ化アーキテクチャ
  21. 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
  22. コマンドスタックの設計 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
  23. 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)
  24. Domain object example ドメインオブジェクトの例

  25. 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
  26. 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 ドメインイベントの設計
  27. Domain Event example ドメインイベントの例

  28. 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
  29. 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)
  30. 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)
  31. 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)
  32. Configurations for Aggregate • Configurations for akka-persistence-jdbc • Persist Domain

    Events to message column by Serializer, snapshot is into snapshot column 集約の設定(1/2)
  33. 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
  34. 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のメリット
  35. 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.
  36. 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
  37. 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
  38. 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
  39. 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
  40. 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
  41. 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
  42. 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
  43. 〜Query stack〜 クエリスタック

  44. クエリスタックの設計 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
  45. 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
  46. 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
  47. Read use case example • Same as the use case

    of Aggregate リードモデル用ユースケースの例
  48. Interface port example • read read-model by using Slick3 DAO

    リードモデル用のポートの実装
  49. 〜Controllers〜 コントローラ

  50. 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
  51. クエリスタックの設計 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
  52. Controller example • Combine the future of use case and

    akka-http route コントローラの例 Command Query
  53. 〜API Server〜 APIサーバのブートスラップ

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

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

  56. リードモデルアップデータの設計 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
  57. 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
  58. Tagging events • Implement WriteEventAdaptor • add ADT name as

    tag to Event • The following settings are required イベントのタグ付け
  59. 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 リードモデル用ユースケースの例
  60. 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 リードモデル用ユースケースの例
  61. Read-model updater bootstrap example • Call BankAccountReadModelUseCase#execute リードモデルアップデータのブートスラップの例

  62. 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. まとめ
  63. Thank you for listening! ご静聴ありがとうございました。

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