$30 off During Our Annual Pro Sale. View Details »

Introduction to the practice Reactive-DDD

Introduction to the practice Reactive-DDD

かとじゅん
PRO

March 18, 2018
Tweet

More Decks by かとじゅん

Other Decks in Technology

Transcript

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

    View Slide

  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でエンジニアとして働いています

    View Slide

  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
    アジェンダ

    View Slide

  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について

    View Slide

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

    View Slide

  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
    }

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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
    ?

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

  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
    レイヤ化アーキテクチャ

    View Slide

  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

    View Slide

  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

    View Slide

  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)

    View Slide

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

    View Slide

  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

    View Slide

  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
    ドメインイベントの設計

    View Slide

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

    View Slide

  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

    View Slide

  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)

    View Slide

  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)

    View Slide

  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)

    View Slide

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

    View Slide

  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

    View Slide

  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のメリット

    View Slide

  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.

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  43. 〜Query stack〜
    クエリスタック

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

  49. 〜Controllers〜
    コントローラ

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

  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
    リードモデル用ユースケースの例

    View Slide

  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
    リードモデル用ユースケースの例

    View Slide

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

    View Slide

  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.
    まとめ

    View Slide

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

    View Slide

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

    View Slide