大多數人軟體工程師都學過 MVC 框架,然而 Model 到底是什麼,只是單純對應資料的物件嗎?讓我們從 Domain-Driven Design 的理論基礎之一「模型」來討論 MVC 框架的 Model 是什麼,以及我們該如何使用它。
Rails Developer Foundation ver.OpenLearn Model Again
View Slide
CONSULTANT × SPEAKER蒼時弦也YouTube Coding Live Blog https://blog.aotoki.me Discord Discuss about RubyIntroduce About Me
Coding Happier About MeSenior 60% +10%Junior 18% +3%Junior 18% +3%Avg - 37%VSSenior 60% +3%Junior 18% +15%Junior 18% +15%Avg - 43%
What we talk about OverviewWhat is ModelWhat is ModelHow to ModelingCase Study
What we talk about OverviewWhat is ModelHow to ModelingHow to ModelingCase Study
What we talk about OverviewWhat is ModelHow to ModelingCase StudyCase Study
What is Model The ModelWhat is ModelAnyone have can sharing about it?
What is Model The ModelFloat100.0StringTWDVS MoneyTWD $100.0
What is Model The ModelInformationA model is an informative representation of an object, person or system.
What is Model The ModelFloat100.0StringTWDVS MoneyTWD $100.0Which one can “Pay”Pay
How to Modeling ModelingModelingHow to "modeling"
Value Object ModelingDataAmount=100.0+DataCurrency=TWDValueComposite ValueMoney=TWD,100.0
Value Object Modelingclass Moneyattr_reader :currency, :amountdef initialize(currency, amount)@currency = currency@amount = amountendend
Entity ModelingValueID=1+ValueMoneyEntityComposite EntityID=1, Balance=Money
Entity Modelingclass Walletattr_reader :id, :balancedef initialize(id, balance)@id = id@balance = balanceendend
Method ModelingEntityID=1, Balance=MoneyDeposit(Money) EntityID=1, Balance=Money
Entity Modelingclass Walletattr_reader :id, :balancedef initialize(id, balance)@id = id@balance = balanceendendsig { params(amount: Money).returns(Money) }def deposit(amount)@balance += amountend
The Payment App Case StudyThe Payment AppThe usage of “Model” in the real-world
Analytics Case StudyCustomerPayCommandTransfer to MerchantSystemPaidEventFailedEvent
Analytics Case StudyCustomerPayCommandTransfer to MerchantSystemPaidEventFailedEventGiven threre have a customer “Aotoki”And I logged as “Aotoki”
Analytics Case StudyCustomerPayCommandTransfer to MerchantSystemPaidEventFailedEventWhen I pay for the merchant “FamilyMart”
Analytics Case StudyCustomerPayCommandTransfer to MerchantSystemPaidEventFailedEventThen I can see “Pay for FaimlyMart successful”
Analytics Case StudyCustomerPayCommandTransfer to MerchantSystemPaidEventFailedEventThen I can see “Pay for FaimlyMart failed”
Specs Case StudyFeature:Scenario:GivenAndAndWhenThenPaymentPay to the merchantthere have a custoemrthere have a merchantI logged asI pay for the merchantI can see“Aotoki”“FamilyMart”“Aotoki”“FamilyMart”“Pay for FamilyMart successful”
Specs Case StudyRSpec.describe dodescribesubjectbefore doendit is_expected to have_textendend, type: :requestdo{ post payment_path, }customer = create(:customer, )sign_in customercreate(:merchant, ){ . ( ) }‘Payment’‘POST /payment’merchant_id: ‘fmart’, amount: 100name: ‘Aotoki’, balance: 100id: ‘fmart’‘Pay for FamilyMart successful’
Specs Case StudyRSpec.describe dodescribesubjectit is_expected to have_textendend, type: :requestdo{ post payment_path, }{ . ( ) }‘Payment’‘POST /payment’merchant_id: ‘fmart’, amount: 100‘Pay for FamilyMart successful’
Example Code Case Studydef createrender text: ‘Pay for FamilyMart successful’end
Example Code Case Studyclass Merchantinclude ActiveModel::Modelinclude ActiveModel::Attributesattribute :name, :stringalias_attribute :to_s, :nameend
Example Code Case Studydef createrender text:endmerchant = Merchant.new(name: ‘FamilyMart’)“Pay for #{merchant} successful”
Example Code Case Studyclass Customerinclude ActiveModel::Modelinclude ActiveModel::Attributesattribute :name, :stringattribute :balance, :integer def withdraw(amount)raise ArgumentError, ‘insufficient balance’ if amount > self.balanceself.balance -= amountendend
Example Code Case Studyclass Merchantinclude ActiveModel::Modelinclude ActiveModel::Attributesattribute :name, :stringalias_attribute :to_s, :nameendattribute :balance, :integerdef deposit(amount)self.balance += amountend
Example Code Case Studydef createmerchant = Merchant.new(name: ‘FamilyMart’)render text: “Pay for #{merchant} successful”endcustomer = Customer.new(name: ‘Aotoki’, balance: 100)payment_amount = params.require(:amount)customer.withdraw(payment_amount)merchant.deposit(payment_amount)
Example Code Case Studyclass Merchantdef deposit(amount)self.balance += amountendend< ApplicationRecord
Example Code Case Studyclass Customerdef withdraw(amount)raise ArgumentError, ‘insufficient balance’ if amount > self.balance self.balance -= amountendend< ApplicationRecord
Example Code Case Studydef createpayment_amount = params.require(:amount)merchant.deposit(payment_amount)render text: “Pay for #{merchant} successful”endmerchant = Merchant.find_by!(id: params[:merchant_id])current_customer.withdraw(payment_amount)ActiveRecord::Base.transaction domerchant.save!current_customer.save!end
Example Code Case Studydef createmerchant = Merchant.find_by!(id: params[:merchant_id])payment_amount = params.require(:amount)current_customer.withdraw(payment_amount)merchant.deposit(payment_amount)ActiveRecord::Base.transaction domerchant.save!current_customer.save!endrender text: “Pay for #{merchant} successful”endrescue ActiveRecord::RecordInvalidrender text: “Pay for #{merchant} failed”
Example Code Case Studyclass Moneyinclude ActiveModel::Modelinclude ActiveModel::Attributesattribute :value, :integerdef +(other)Money.new(value: self.value + other.value)enddef -(other)raise ArgumentError, ‘Money cannot be negative’ if other.value > self.valueMoney.new(value: self.value - other.value)endend
Example Code Case Studyclass Merchant < ApplicationRecorddef deposit(amount)self.balance += amountendendcomposed_of :balance,class_name: ‘Money’,mapping: %[balance value]
Example Code Case Studyclass Customer < ApplicationRecorddef withdraw(amount)self.balance -= amountendendcomposed_of :balance,class_name: ‘Money’,mapping: %[balance value]
Example Code Case Studydef createmerchant = Merchant.find_by(id: params[:merchant_id])current_customer.withdraw(payment_amount)merchant.deposit(payment_amount)ActiveRecord::Base.transaction domerchant.save!current_customer.save!endrender text: “Pay for #{merchant} successful”rescue ActiveRecord::RecordInvalidrender text: “Pay for #{merchant} failed”endpayment_amount = Money.new(value: params.require(:amount))
Example Code Case Studydef createmerchant = Merchant.new(name: ‘FamilyMart’)ActiveRecord::Base.transaction domerchant.save!current_customer.save!endrender text: “Pay for #{merchant} successful”rescue ActiveRecord::RecordInvalidrender text: “Pay for #{merchant} failed”endcontext = BuyingContext.newinput = PaymentInput.new(params)context.pay(to: merchant, from: current_customer, amount: input.amount)
Survey FeedbackSurvey https://www.surveycake.com/s/lbmn9