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

2022 - 默默會 - 重新學習 MVC 的 Model

蒼時弦や
November 01, 2022

2022 - 默默會 - 重新學習 MVC 的 Model

大多數人軟體工程師都學過 MVC 框架,然而 Model 到底是什麼,只是單純對應資料的物件嗎?讓我們從 Domain-Driven Design 的理論基礎之一「模型」來討論 MVC 框架的 Model 是什麼,以及我們該如何使用它。

蒼時弦や

November 01, 2022
Tweet

More Decks by 蒼時弦や

Other Decks in Programming

Transcript

  1. Rails Developer Foundation ver.Open Learn Model Again

  2. CONSULTANT × SPEAKER 蒼時弦也 YouTube Coding Live Blog https://blog.aotoki.me Discord

    Discuss about Ruby Introduce About Me
  3. Coding Happier About Me Senior 60% +10% Junior 18% +3%

    Junior 18% +3% Avg - 37% VS Senior 60% +3% Junior 18% +15% Junior 18% +15% Avg - 43%
  4. What we talk about Overview What is Model What is

    Model How to Modeling Case Study
  5. What we talk about Overview What is Model How to

    Modeling How to Modeling Case Study
  6. What we talk about Overview What is Model How to

    Modeling Case Study Case Study
  7. What is Model The Model What is Model Anyone have

    can sharing about it?
  8. What is Model The Model Float 100.0 String TWD VS

    Money TWD $100.0
  9. What is Model The Model Information A model is an

    informative representation of an object, person or system.
  10. What is Model The Model Float 100.0 String TWD VS

    Money TWD $100.0 Which one can “Pay” Pay
  11. How to Modeling Modeling Modeling How to "modeling"

  12. Value Object Modeling Data Amount=100.0 + Data Currency=TWD Value Composite

    Value Money=TWD,100.0
  13. Value Object Modeling class Money attr_reader :currency, :amount def initialize(currency,

    amount) @currency = currency @amount = amount end end
  14. Entity Modeling Value ID=1 + Value Money<TWD, 100.0> Entity Composite

    Entity ID=1, Balance=Money<TWD, 100.0>
  15. Entity Modeling class Wallet attr_reader :id, :balance def initialize(id, balance)

    @id = id @balance = balance end end
  16. Method Modeling Entity ID=1, Balance=Money<TWD, 100.0> Deposit(Money<TWD, 100.0>) Entity ID=1,

    Balance=Money<TWD, 200.0>
  17. Entity Modeling class Wallet attr_reader :id, :balance def initialize(id, balance)

    @id = id @balance = balance end end sig { params(amount: Money).returns(Money) } def deposit(amount) @balance += amount end
  18. The Payment App Case Study The Payment App The usage

    of “Model” in the real-world
  19. Analytics Case Study Customer Pay Command Transfer to Merchant System

    Paid Event Failed Event
  20. Analytics Case Study Customer Pay Command Transfer to Merchant System

    Paid Event Failed Event Given threre have a customer “Aotoki” And I logged as “Aotoki”
  21. Analytics Case Study Customer Pay Command Transfer to Merchant System

    Paid Event Failed Event When I pay for the merchant “FamilyMart”
  22. Analytics Case Study Customer Pay Command Transfer to Merchant System

    Paid Event Failed Event Then I can see “Pay for FaimlyMart successful”
  23. Analytics Case Study Customer Pay Command Transfer to Merchant System

    Paid Event Failed Event Then I can see “Pay for FaimlyMart failed”
  24. Specs Case Study Feature: Scenario: Given And And When Then

    Payment Pay to the merchant there have a custoemr there have a merchant I logged as I pay for the merchant I can see “Aotoki” “FamilyMart” “Aotoki” “FamilyMart” “Pay for FamilyMart successful”
  25. Specs Case Study RSpec.describe do describe subject before do end

    it is_expected to have_text end end , type: :request do { post payment_path, } customer = create(:customer, ) sign_in customer create(:merchant, ) { . ( ) } ‘Payment’ ‘POST /payment’ merchant_id: ‘fmart’, amount: 100 name: ‘Aotoki’, balance: 100 id: ‘fmart’ ‘Pay for FamilyMart successful’
  26. Specs Case Study RSpec.describe do describe subject it is_expected to

    have_text end end , type: :request do { post payment_path, } { . ( ) } ‘Payment’ ‘POST /payment’ merchant_id: ‘fmart’, amount: 100 ‘Pay for FamilyMart successful’
  27. Example Code Case Study def create render text: ‘Pay for

    FamilyMart successful’ end
  28. Example Code Case Study class Merchant include ActiveModel::Model include ActiveModel::Attributes

    attribute :name, :string alias_attribute :to_s, :name end
  29. Example Code Case Study def create render text: end merchant

    = Merchant.new(name: ‘FamilyMart’) “Pay for #{merchant} successful”
  30. Example Code Case Study class Customer include ActiveModel::Model include ActiveModel::Attributes

    attribute :name, :string attribute :balance, :integer def withdraw(amount) raise ArgumentError, ‘insufficient balance’ if amount > self.balance self.balance -= amount end end
  31. Example Code Case Study class Merchant include ActiveModel::Model include ActiveModel::Attributes

    attribute :name, :string alias_attribute :to_s, :name end attribute :balance, :integer def deposit(amount) self.balance += amount end
  32. Example Code Case Study def create merchant = Merchant.new(name: ‘FamilyMart’)

    render text: “Pay for #{merchant} successful” end customer = Customer.new(name: ‘Aotoki’, balance: 100) payment_amount = params.require(:amount) customer.withdraw(payment_amount) merchant.deposit(payment_amount)
  33. Example Code Case Study class Merchant def deposit(amount) self.balance +=

    amount end end < ApplicationRecord
  34. Example Code Case Study class Customer def withdraw(amount) raise ArgumentError,

    ‘insufficient balance’ if amount > self.balance self.balance -= amount end end < ApplicationRecord
  35. Example Code Case Study def create payment_amount = params.require(:amount) merchant.deposit(payment_amount)

    render text: “Pay for #{merchant} successful” end merchant = Merchant.find_by!(id: params[:merchant_id]) current_customer.withdraw(payment_amount) ActiveRecord::Base.transaction do merchant.save! current_customer.save! end
  36. Example Code Case Study def create merchant = Merchant.find_by!(id: params[:merchant_id])

    payment_amount = params.require(:amount) current_customer.withdraw(payment_amount) merchant.deposit(payment_amount) ActiveRecord::Base.transaction do merchant.save! current_customer.save! end render text: “Pay for #{merchant} successful” end rescue ActiveRecord::RecordInvalid render text: “Pay for #{merchant} failed”
  37. Example Code Case Study class Money include ActiveModel::Model include ActiveModel::Attributes

    attribute :value, :integer def +(other) Money.new(value: self.value + other.value) end def -(other) raise ArgumentError, ‘Money cannot be negative’ if other.value > self.value Money.new(value: self.value - other.value) end end
  38. Example Code Case Study class Merchant < ApplicationRecord def deposit(amount)

    self.balance += amount end end composed_of :balance, class_name: ‘Money’, mapping: %[balance value]
  39. Example Code Case Study class Customer < ApplicationRecord def withdraw(amount)

    self.balance -= amount end end composed_of :balance, class_name: ‘Money’, mapping: %[balance value]
  40. Example Code Case Study def create merchant = Merchant.find_by(id: params[:merchant_id])

    current_customer.withdraw(payment_amount) merchant.deposit(payment_amount) ActiveRecord::Base.transaction do merchant.save! current_customer.save! end render text: “Pay for #{merchant} successful” rescue ActiveRecord::RecordInvalid render text: “Pay for #{merchant} failed” end payment_amount = Money.new(value: params.require(:amount))
  41. Example Code Case Study def create merchant = Merchant.new(name: ‘FamilyMart’)

    ActiveRecord::Base.transaction do merchant.save! current_customer.save! end render text: “Pay for #{merchant} successful” rescue ActiveRecord::RecordInvalid render text: “Pay for #{merchant} failed” end context = BuyingContext.new input = PaymentInput.new(params) context.pay(to: merchant, from: current_customer, amount: input.amount)
  42. Survey Feedback Survey https://www.surveycake.com/s/lbmn9