Model-Driven Design with Business Patterns Explained in Scala

Model-Driven Design with Business Patterns Explained in Scala

"Model-Driven Design Using Business Patterns" by Pavel Hruby published in 2006 is a book that provides useful patterns related to Domain-Driven Design(DDD). This book introduces universal modeling patterns for business applications called REA (Resource, Event, Agent).
Based on these REA structures, behavior patterns such as "date" and "classification" are also useful. I'm interested in how Scala expresses the patterns invented 10 years ago. This time I want to discuss some patterns from REA.

Scalaで解説する、ビジネスパターンによるモデル駆動設計 〜CQRS/Event SourcingにおけるREAモデルとは〜

2007年発刊のPavel Hruby著「ビジネスパターンによるモデル駆動設計」はドメイン駆動設計に関連する有益なパターンを提供している書籍です。この書籍ではREA(Resource, Event, Agent)というビジネスアプリケーションにおいて普遍的なモデリングパターンを紹介しています。こういったREA構造を基に期日や分類などの振る舞いのパターンも役に立ちます。10年に考案されたこれらのパターンをScalaで現代に再現するにはどうするべきか、私は興味を持っています。REAからいくつかのパターンを抜粋して議論したいと思います。

933291444e456bfb511a66a2fa9c6929?s=128

かとじゅん

October 17, 2020
Tweet

Transcript

  1. Model-Driven Design with Business Patterns Explained in Scala - REA

    Model in CQRS/Event Sourcing - かとじゅん( ) Scala Matsuri 2020 2020/10/17 Scalaで解説する、ビジネスパターンによるモデル駆動設計 CQRS/Event SourcingにおけるREAモデルとは @j5ik2o 1
  2. Who am I? Chatwork's Tech Lead. Recent Activities My job

    is building and testing CQRS/Event Sourcing system by akka-cluster. Published a thin Scala book in zenn.dev I have taken the following courses in and have been certified 誰? @j5ik2o 楽しいScala 気軽にはじめてみよう Lightbend Academy 2
  3. Agenda "Model-Driven Design Using Business Patterns" by Pavel Hruby, published

    in 2006, is a book that provides useful patterns related to domain-driven design. The book introduces a universal modeling pattern for business applications called REA (Resource, Event, Agent). I'd like to discuss some excerpts from REA. 3
  4. Agenda In Model-Driven Design Using Business Patterns: REA Structure Pattern

    Behavior Patterns REA構造パターンと振る舞いパターンを紹介します 4
  5. REA Structure Pattern 5

  6. About REA REA = Resource, Event, Agent Events mean things

    that happens in past, Reources mean non-event objects Agents mean people. REAとは 6
  7. The REA structure consists of Policy Level Operational Level 7

  8. Economic {Resources, Agents, Events} at Operational Level Economic Resources are

    scarce and useful to economic agents. The targets that you want to plan, monitor, and control. Economic Agents are individuals or organizations that can control economic resources and transfer control to individuals or organizations, or take control from others. Economic Events are those that represent an increase or decrease in the value of the economic resources controlled by a company. Some of them occur over time, such as sales of goods that occur immediately, rentals, and services. Event Resource Agent inflow outflow stockflow 経済リソース、経済エージェント、経済イベント 8
  9. Commitments, Contracts at Policy Level コミットメント、契約 A Contract is a

    collection of covenants with increasing and decreasing commitments. Based on the terms and conditions specified by the covenants, the contract may create further commitments. Penalties for failure to fulfill commitments can be expressed in the covenants A Commitment is a promise or obligation of an economic agent to perform some economic event in the future. A statement of order item represents a commitment to sell goods Contract Commitment Event Resource Agent stipulation fulfillment related_party reservation inflow outflow stockflow inflow outflow 9
  10. The Basic Concept of the REA Model If a company

    wants to increase the overall value of the resources under its control, it usually has to reduce the value of some of the resources REAモデルの基本的な考え⽅ 10
  11. Two Patterns of Increase or Decrease in Resources Exchange The

    process by which a company(as economic agent) receives economic resources from another economic agent and gives those economic resources to that economic agent in return Trading is an exchange process Conversion The process by which a company(as economic agent) uses or consumes economic resources for the production of new economic resources or the modification of existing economic resources. Production of goods is a conversion process 経済リソースの2つの増減パターン 11
  12. In the case, Sushi Restaurant すし屋の場合 12

  13. In the case, Sushi Restaurant Customers, vendors, employees and sushi

    restaurant are economic agents. Sushi, cash, labor force, and raw materials for sushi are economic resources There are three parts to the transaction process: sales, purchases, and labor force acquisition. <<Conversion>> Sushi Production <<Exchange>> Labor Procurement <<Exchange>> Sales <<Exchange>> Purchase すし屋の場合 13
  14. The Sales Process of a Sushi Restaurant Selling sushi is

    the process of exchanging sushi for cash Sushi and cash are economic resources The economic events that occur are Transfer of sushi ownership from the sushi shop to the customer, economic decline event that sells the product Transfer of cash ownership from the customer to the sushi shop, economic increase event of receiving cash <<Exchange Process>> Sale すし屋の販売プロセス 14
  15. REA Model for Sushi Sales The sales process is represented

    without contracts and commitments The customer supplies the cash and the sushi shop receives the cash. Sales are made by the sushi shop, where the sushi is supplied and received by the customer «agent» SushiRestaurant «resource» Money «increase_event» CashReceipted «agent» Customer «decrease_event» SushiSold «resource» Sushi «exchange» «inflow» «supply» «receive» «outflow» «receiver» «supply» すし販売のREAモデル 15
  16. Events Implementation イベントの実装 Separating events into two, such as and

    , allows you to separate payment and sales customers, or to manage sales and cash receipts of goods that occur at different times. Chronologically, the receipt of cash will always occur after the sale of the sushi. In this design, cash cannot be received first. If support the pre-order, need to revise the design. // A Sushi was sold case class SushiSold( id: SushiSaledId, toCustomerId: CustomerId, sushiType: SushiType, quantity: SushiQuantity, occurredAt: Instant ) // Cash was receipted case class CashReceipted( id: CashReceiptedId, sushiSaledId: SushiSaledId, fromCustomerId: CustomerId, amount: Money, occurredAt: Instant ) 16
  17. Expressing Rights Related to Economic Resources Inflow The relationship between

    increased economic events and resources is called an inflow Outflow The relationship between decreasing economic events and resources is called an outflow. 経済リソースに関連する権利を表現する «resource» Book «increase_event» BookBorrowed «agent» Library «agent» Reader Right to Read«inflow» 1 0..* Lender«supply» 1 0..* Borrower«receipt» 0..* 1 case class Book(id: BookId, name: BookName, ...) { // ... } case class BookBorrowed( id: BookBorrowedId, bookId: BookId, lenderId: OwnerAccountId, borrowerId: UserAccountId ) 17
  18. REA model of the sales process with sales orders 販売注⽂を伴う販売プロセスのREAモデル

    is a contract and are commitments Commitments and events represent a prefactual relationship «contract» SalesOrder «increase_commitment» Payment «decrease_commiment» Sales «agent» Customer «agent» SushiRestraunt «resource» Money «increase_event» CashReceipted «decrease_event» SushiSold «resource» Sushi «related_party» «related_party» «stipulations» «stipulations» «interdependence_of_exchange» «reservation» «reservation» «exchange_duality» «inflow» «receive» «outflow» «receive» «supply» «supply» 18
  19. The Concept of Reservations Commitment expresses what resources are associated

    with the economic events that occur later «commitment» RentalCommitment Line itemized lease agreement, etc. «event» RenatalEvent Actual use of the apartment «resource» Apartment Fulfillment 0..* 0..* Rental reservation the right to use 0..* 1..* Inflow move the right to use 1 0..* 予約という概念 19
  20. When reserving a resource type リソースタイプを予約する場合 If the commitment involves

    a resource type, it also involves an actual resource that matches the resource type at some point in the future. This is called reservation assignment. In hotel operations, reservations are related to room specifications until the guest's arrival date, but on the morning of arrival, the front desk clerk assigns a room number to each reservation beginning that day. ResourceType Resource DecreaseCommitment DecreaseEvent Reservation① Specification Outflow Fulfillment Reservation② 20
  21. Which Object is the Aggregate in the Reservation? ところで、予約における集約はどのオブジェクト? 21

  22. What is the model for the current state? Commitment is

    a promise that a future event will happen and Event is something that happened in the past. How do you model an aggregate that represents the current state? «resource_type» RoomPlan «resource» Room «commitment» BorrowRoom «event» RoomBorrowed Reservation① Specification Outflow Fulfillment Reservation② 現在の状態を表すモデルとは 22
  23. FYI: Event Storming(Design Level) A powerful domain analysis technique based

    on the domain events. 1. Find the command that generates the event. 2. Find an aggregate to receive that the command. User Event Command Aggregate Policy ReadModel UI invoked on generates translated into triggers invokes It's actually a CQRS/Event Sourcing system イベントストーミング(デザインレベル) 23
  24. REA Model in CQRS/Event Sourcing system The Commitment raises an

    Event; in Event Storming be called it the Command. Find the Aggregate from that the Commands. Event CommandAsCommitment Aggregate invoked on generates ⬇ BorrowRoom RoomBorrowed RoomReservation invoked on generates 24
  25. RoomReservation Aggregate Design RoomReservation is an aggregate that represents a

    room reservation If the Commands is accepted, the Events will be generated «resource_type» RoomPlan «resource» Room «agent» Customer «cmd» BorrowRoom «cmd_reply» BorrowRoomReply «event» RoomBorrowed «aggregate» RoomReservation id: RoomReservationId RoomPlanReservation def borrowRoom(borrowRoom: BorrowRoom): (RoomInstanceReservation, RoomBorrowed) RoomInstanceReservation invoked on generates customerId roomPlanId roomId specification RoomReservation集約の設計 25
  26. Examples of Reserved Objects(1/2) 予約の実装例(1/2) // 部屋 case class RoomPlan

    { id: RoomPlanId, name: RoomTypeName, roomType: RoomType, // Single, Double, ... maxCapacity: MaxCapacity withBreakfast: Boolean, smokingAllowed: Boolean } // 部屋 case class Room { id: RoomId, roomNumber: RoomNumber, // ... } // Borrow Room Commitment case class BorrowRoom( id: BorrowRoomId, roomPlanId: RoomPlanId, borrowDate: LocalDate, occurredAt: Instant ) // Room Borrowed Event case class RoomBorrowed( id: RoomBorrowedId, commitmentId: BorrowRoomId, roomId: RoomId, borrowedDate: LocalDate, occurredAt: Instant ) 26
  27. Examples of Reserved Objects(2/2) 予約の実装例(2/2) abstract class RoomReservation( id: RoomReservationId,

    customerId: CustomerId, roomPlanId: RoomPlanId, borrowDate: LocalDate, numOfNights: NumOfNights, createAt: Instant ) { ... } class RoomPlanReservation(...) exntends RoomReservation( id, customerId, roomPlanId, roomId, borrowDate, numOfNights, createAt) { // borrow room def borrowRoom(borrowRoom: BorrowRoom) : (RoomReservation, RoomBorrowed) = { require(roomPlan.id == roomPlanId) require(roomPlan.isSatisfiedBy(room)) (new RoomReservation(this, room.id), new RoomBorrowed(RoomBorrowedId(), id, room.id, borrowedDate, Instant.now())) } class RoomReservation( id: RoomReservationId, customerId: CustomerId, roomPlanId: RoomPlanId, roomId: RoomId, borrowDate: LocalDate, numOfNights: NumOfNights, createAt: Instant) exntends RoomReservation( id, customerId, roomPlanId, roomId, borrowDate, numOfNights, createAt) { ... } 27
  28. Example for Borrow Room UseCase, In State Sourcing... This is

    an example of implementation that looks good at first glance, but it's Double Committing with the state and the event... If only the fails, the complex actions to guarantee failure is needed, such as undoing the state update by the or retrying until the succeeds. To avoid these problems, be introduced Event Sourcing. Event Sourcing will be discussed next time. ユースケースの実装例 class BorrowRoomUseCase(...) { def execute(...): Future[Unit] = { val borrowRoom = ... for { roomReservation <- roomReservationRepository.findBy(borrowRoom.roomReservationId) (boomReservationUpdated, roomBorrowed) <- roomReservation.borrowRoom(roomCommitmente) _ <- roomReservationRepository.store(boomReservationUpdated) _ <- eventPublisher.publish(roomBorrowed) } yield () } } 28
  29. Behavior Patterns 29

  30. DueDate Pattern According to the description in the book... The

    DueDate is a value object representing a due date Determine if the specified due date has passed There are state transitions such as active, expired, completed, and canceled. DueDate value: LocalDate isDue(): Boolean confirm(l: Option[Task => Unit]): Unit complete(l: Option[Task => Unit]): Unit cancel(l: Option[Task => Unit]): Unit Active Expired Completed Canceled 期⽇パターン 30
  31. Refactoring The Design!!! Express only whether the due date is

    past due without having a state. The state to which the due date relates is the state of the task. Tasks should be modeled separately. The transition to the new state should be represented by a new instance(immutable) 設計の⾒直し DueDate value: LocalDate isDue(): Boolean confirm(l: Option[Task => Unit]): Unit complete(l: Option[Task => Unit]): Unit cancel(l: Option[Task => Unit]): Unit Active Expired Completed Canceled ⇰ Task id: TaskId status: TaskStatus assignee: EmployeeId assigner: EmployeeId description: TaskDescription dueDate: DueDate confirm(l: Option[Task => Unit]): Task complete(l: Option[Task => Unit]): Task cancel(l: Option[Task => Unit]): Task toDueDate(): DueDate Active Expired Completed Canceled DueDate value: LocalDate isDue(): Boolean 31
  32. DueDate with Task Pattern 期⽇とタスクのパターン Task id: TaskId status: TaskStatus

    assignee: EmployeeId assigner: EmployeeId description: TaskDescription dueDate: DueDate confirm(l: Option[Task => Unit]): Task complete(l: Option[Task => Unit]): Task cancel(l: Option[Task => Unit]): Task toDueDate(): DueDate Active Expired Completed Canceled DueDate value: LocalDate isDue(): Boolean The Due Date is a value object representing a due date.It determines if the specified due date has passed. To make tasks, TODOs, etc., hold Due Dates as targets related to Due Dates, so that they can determine when they should be completed by State transitions such as valid, due date, completed, and canceled may be considered for the Due Date 32
  33. Example Implementation of DueDate A value object to determine if

    it is before or after a deadline in isAfter/isBefore In the book, DueDate included state management, but we have separated that responsibility into task objects. 期⽇の実装例 final case class DueDate(dueDate: LocalDate, zoneOffset: ZoneOffset) { private val dueAsInstant = dueDate.atStartOfDay().toInstant(zoneOffset) def toLocalDate: LocalDate = dueDate def isAfter(instant: Instant): Boolean = { instant.isAfter(dueAsInstant) } def isBefore(instant: Instant): Boolean = { instant.isBefore(dueAsInstant) } } 33
  34. Example Implementation of Task タスクの実装例 State starts from Active When

    the due date comes, the state will transition to Due final case class Active private[sub] (id: TaskId, assignee: EmployeeId, assigner: EmployeeId, description: TaskDescription, dueDate: DueDate) extends Task { override def status: TaskStatus = TaskStatus.Active override def confirm(instant: Instant, listener: Option[Task => Unit]): Task = { // if it's overdue if (dueDate.isAfter(instant)) { // create a due date state task val newTask = Due(id, assignee, assigner, description, dueDate) li f h k Complete tasks or Cancel tasks Pattern match override def complete(listener: Option[Task => Unit]): Task = { val newTask = Completed(id, assignee, assigner, description, dueDate) listener.foreach(_(newTask)) newTask } override def cancel(listener: Option[Task => Unit]): Task = { val newTask = Canceled(id, assignee, assigner, description, dueDate) listener.foreach(_(newTask)) newTask } task match { case Task.Expired(_, assignee, assigner, _, _) => // ... case _ => // ... } 34
  35. Conclusion Although the Japanese edition is out of print, it

    is a valuable guidebook. Recommended for the following points. REA is the gateway to modeling. REA is the hints for CQRS/ES The behavior of the value object is also helpful. It is even better if you can use the guidebook as a reference for practical applications. まとめ 35
  36. The End 終わり 36