Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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. 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%
  2. What we talk about Overview What is Model What is

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

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

    Modeling Case Study Case Study
  5. What is Model The Model Information A model is an

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

    Money TWD $100.0 Which one can “Pay” Pay
  7. 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
  8. The Payment App Case Study The Payment App The usage

    of “Model” in the real-world
  9. 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”
  10. Analytics Case Study Customer Pay Command Transfer to Merchant System

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

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

    Paid Event Failed Event Then I can see “Pay for FaimlyMart failed”
  13. 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”
  14. 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’
  15. 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’
  16. Example Code Case Study def create render text: end merchant

    = Merchant.new(name: ‘FamilyMart’) “Pay for #{merchant} successful”
  17. 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
  18. 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
  19. 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)
  20. Example Code Case Study class Customer def withdraw(amount) raise ArgumentError,

    ‘insufficient balance’ if amount > self.balance self.balance -= amount end end < ApplicationRecord
  21. 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
  22. 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”
  23. 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
  24. Example Code Case Study class Merchant < ApplicationRecord def deposit(amount)

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

    self.balance -= amount end end composed_of :balance, class_name: ‘Money’, mapping: %[balance value]
  26. 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))
  27. 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)